学习Git:跟踪与设置上游(-u)的遥控器?

时间:2015-11-03 15:35:23

标签: git github

我正在学习Git并试图理解“跟踪”远程和定义“上游”关系(使用-u标记)之间的区别。

对于master to origin / master,我一直在使用

git push origin master

似乎自动定义了一种关系(虽然我不确定它是什么)。

对于分支机构,我一直在使用

git branch newbranch
git push -u origin newbranch

我知道这会设置一个上游关系,但我再也不理解这种区别。

有人可以解释一下这个区别吗?

3 个答案:

答案 0 :(得分:10)

这里的两个答案都是正确的,但我会描述潜在的机制,因为在我发现它是什么之前,我发现了"追踪"的全部概念。非常神秘。

Git打破这个&#34;追踪&#34;信息分为两部分:遥控器的名称 - 通常是单词origin,就像您正在使用 - 然后是远程上的git命令用于命名分支的名称。 1 换句话说,如果您具有对远程的登录访问权限,并且您在那里登录并进入存储库,则可以运行git log master以查看已提交的内容。< / p>

如果您查看了.git/config文件,您会看到,对于每个本地分支机构来说,&#34;跟踪&#34;什么,这两部分。例如,假设您有一个名为experiment的本地分支,您已将其设置为跟踪origin/master。这将导致:

[branch "experiment"]
    remote = origin
    merge = master

但是这个跟踪分支的内容还有一个部分:当你运行git fetch origin时,master上的分支origin上有新内容,fetch 1}}步骤更新您的本地origin/master。这个名称 - 首先是远程名称origin,然后是斜杠/,然后是遥控器上显示的分支名称,就是如何看到遥控器上发生了什么。完成git fetch后,它会将远程的分支名称(以及它们的分支提示的相应SHA-1)复制到本地存储库,并使用前面的远程名称重命名它们。 / p>

实际上git fetch步骤更新了origin/master等等,只有在完成后才会执行此操作,并且&#34;跟踪&#34;东西有任何有用的效果。 Git现在可以通过一些提交告诉你,你已经提前和/或落后了。而且,您现在可以运行git log origin/master之类的命令,看看那里发生了什么 - 或者更有趣的是,git log --oneline master..origin/master看看&#34;他们的&#34;承诺你还没有:基本上,&#34; fetch带来了什么&#34; - 和git log --oneline origin/master..master来看&#34;你的&#34;承诺他们还没有。 (如果你已经完成了合并或重组,那么看看你的fetch带来了什么已经太晚了,因为现在你已经拥有了他们所拥有的东西,这是因为你的合并或重组。)

所有这些中的古怪是git pullgit pull命令实际上只是首先运行git fetch的快捷方式,然后运行git merge(或者,如果您重定向它,git rebase)。要单独执行这些步骤,请运行git fetch origin,然后git merge origin/mastergit rebase origin/master。由于历史原因, 2 git pull获取分支的远程名称,在本例中为master,而不是名称它最终被重命名为你的存储库。

因此,以此为背景,让我们看一些命令:

  • git fetch remote:根本不需要任何分支名称。它调用给定的远程,询问它现在所有分支的位置,并更新您的存储库,在origin/名称下记录所有这些更新(以免影响任何本地分支)。换句话说,这会更新您的分支机构可能(或可能不会)跟踪的名称,但它不需要知道什么是或不跟踪什么。

  • git status:如果它在分支X&#34;上表示您已经&#34;并且分支 X 正在跟踪{{1 }},origin/X还可以告诉您,如果您在 git status 上提交了不在X上的提交,反之亦然。

  • origin/Xgit merge:这些需要一些方法来了解要合并的内容或者要重新绑定的内容。您可以明确地命名,但如果您告诉您的git您的分支git rebase正在跟踪X,那么无论何时您在分支origin/XX或{ {1}}会知道该怎么做。

  • git merge:这是设置或更改当前分支跟踪内容的主要命令。换句话说,如果您现在在分支git rebase上,则会为您更新git branch --set-upstream-to origin/XX,这样您就不必使用两个单独的{{} 1}}命令。您还可以使用branch.X.remote 删除跟踪信息。

  • branch.X.merge:如果您没有提供其他信息,它会使用当前分支&#34;远程&#34; - 其跟踪信息的前半部分 - 来决定哪个远程信息打电话来。无论您是否给git config一个远程名称,下一部分取决于您是否给它一个&#34; refspec&#34;。如果您不这样做,git branch --unset-upstream使用git push来决定使用哪种refspec。

<等等,什么是refspec?

第二种最简单的refspec形式只是两个分支名称,它们之间有一个冒号,如git push。对于git push,左侧的名称是您的分支名称,右侧的名称是他们的另一个git&#39; s-branch名称。如果省略push.default,您将得到最简单的表单,其中远程端名称 - 跟随master:master的名称 - 由一个稍微复杂的过程选择(在git push documentation中描述) ),这实际上取决于更多的配置变量以及您是否设置了上游。

git push怎么样?这只是一个方便的快捷方式::是执行两个:命令的快捷方式,git push -u是执行推送的快捷方式,然后执行操作git branch --set-upstream-to也是如此。你必须给git config一个refspec来做这件事。

如果你给出一半&#34; refspec&#34;像git push -u refspec?好吧,如上所述,git选择提供给远程git的名称是通过一个复杂的过程找到的,但如果你还没有设置上游(这是如果您首先进行git branch --set-upstream-to,那么它很可能会与您的本地名称相同。所以push可能&#34;意味着&#34;最后,master 表示git push -u

如果您提供更全面的refspec,例如git push -u origin master,则会将git push -u origin master:master分支推送到git branch --set-upstream-to origin/master,要求git push -u origin experiment:feature将其称为experiment,并且然后做一个origin。请注意,此时,本地分支的上游名称与本地名称不同。 Git对此很好;只要确定你也是。 : - )

git有更聪明的技巧:

  • 如果您运行origin并且 feature 尚不存在,那么就是单个&#34; &明显#34;远程跟踪分支,例如--set-upstream-to origin/feature,git将创建一个已经跟踪git checkout branch的新的本地 branch 。 (也就是说,本地分支的origin/branch设置为branch,其origin/branch设置为 remote 。)

    < / LI>
  • 如果您运行origin,git会自动设置本地分支以跟踪相应的远程跟踪分支。 (您可以配置git是否要这样,但这是默认设置。)

摘要:merge更新跟踪使用的内容(branch条目,用于远程git branch local-name remote-tracking-name)。完成后 - 包括使用git fetch运行origin/* 3 - 然后完成后,您会看到来自origin等命令的更多信息;和git pull之类的命令使用它来知道如何进行rebase,而不必再告诉它了。

还有一个有趣的转折:任何分支&#34;上游&#34;可以在您自己的本地存储库中。为此,您将该分支的git fetch设置为git status(文字点),将git rebase设置为分支的名称。您不必知道如何执行此操作,因为您可以执行remote,例如,让您当前的分支跟踪您自己的.

&#34;传入&#34;和&#34;传出&#34;

Mercurial用户可能想知道如何获得mergegit branch --set-upstream-to master的效果。前者告诉你你的上游有什么,你没有。后者告诉你你有什么,他们没有。事实证明,这在现代git中很容易实现,因为git有一个特殊的语法master,用于查找当前分支的上游。

换句话说,如果您依靠hg incominghg outgoing跟踪@{u}master(您可以将其拼写为master)只是写origin/master的另一种方式。因此,@{u}只是编写@{upstream}的更长方式。 ,如果您origin/masterorigin/master..master也会命名@{u}..master,省略分支名称会告诉git使用master,所以HEAD就足够了。

如上所述,在您在相应的遥控器上运行master后,您可以使用HEAD来查找他们所拥有的内容,而不是&#t;#34 ;和&#34;你拥有的他们没有&#34;。您必须运行此@{u}..步骤(并且希望此时发生合并或重新绑定)。

所以:

git fetch

(在某些shell中,您可能需要git log前面的git fetch或其他引用技巧,通过运行{{1}可能更容易在编辑器中插入别名})。

当然,您可以将git config --global alias.incoming '!git fetch && git log --oneline ..@{u}' git config --global alias.outgoing '!git fetch && git log --oneline @{u}..' 部分更改为您喜欢的任何选项。 (而且我喜欢离开\步骤让我自己手动运行自己,例如,将别名简化为! 4 这主要是为了避免不断纠缠上游。)

1 如果您的分支机构名称与他们的名称相同,则您将无法看到此分支。但是一旦你开始大量使用分支机构,你可能会找到几个跟踪上游相同的分支机构,然后它真的很重要。

2 git config --global --edit实际上早于远程和远程跟踪分支。由于这个原因,它仍然有各种各样的怪异。

3 如果你的git版本早于1.8.4,那么当--oneline运行git fetch时,alias.incoming = log --oneline ..@{u}不会更新远程跟踪分支。这是一个功能,但它是一个糟糕的功能,更新的git版本更新。但这确实意味着,如果你有一个旧的git,你应该警惕使用git pull脚本:这是一个不方便的方便。

4 在编辑中修复:我不小心写了git pull。假设Git别名是其他git命令(如git fetch),因此您希望省略 fetch部分,除非整个别名以感叹号pull开头,在这种情况下,整个别名将传递给shell运行。我现在忘记了,当所有命令拼写为alias.incoming = git log ...loggit等时,别名如何处理,但它一定不那么复杂......: - )

答案 1 :(得分:8)

git push origin master明确地说“将本地分支'master'推送到名为'origin'的远程”。这没有定义持久关系,它只执行一次这样的推送。请注意,假定远程分支被命名为“master”。

git push -u origin master是相同的,除了它首先在本地分支“master”和名为“origin”的远程之间添加持久跟踪关系。和以前一样,假设远程分支被命名为“master”。

如果您已经使用-u进行了推送,那么已经定义了该关系。将来,您可以简单地说git pushgit pull,git会自动使用已定义的远程跟踪分支,而不会被明确告知。

您可以使用git branch -vv查看跟踪关系,这将列出您的本地分支及其当前的HEAD提交,如果已设置,还会列出远程跟踪分支。这是一个例子。

$ git branch -vv
* master                   58a0d68 [origin/master] Fix CSS regression bug
  migration_tool           2a24ff7 [origin/migration_tool] [#906] Fix table layout problem
  topic-ajax-timeouts      fe854f2 Adjust timeouts to be more realistic

这里显示了3个分支及其当前的HEAD提交和提交消息。在前两个,指定了跟踪分支,但第三个分支没有跟踪远程分支。

答案 2 :(得分:5)

“跟踪”和“上游”是相关术语。 “跟踪”表示将本地存储库的分支与上游分支相关联,即位于远程存储库中的分支。例如,

git push -u origin newbranch

设置本地newbranch的跟踪信息,以便生活在远程仓库中的newbranch称为origin(即您的本地仓库在昵称下知道的远程仓库{ {1}})被认为是您本地origin的上游分支...并执行推送。

如果您通过克隆来获取本地存储库,则无需运行

newbranch

因为git push -u origin master 已经设置为origin/master的上游分支。换句话说,master已设置为跟踪master