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

eab*_*tes 15 git github

我正在学习Git并试图理解"跟踪"遥控器与定义"上游"关系(使用-u标签)之间的区别.

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

git push origin master
Run Code Online (Sandbox Code Playgroud)

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

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

git branch newbranch
git push -u origin newbranch
Run Code Online (Sandbox Code Playgroud)

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

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

tor*_*rek 14

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

Git将这个"跟踪"信息分解为两部分:远程名称 - 通常是单词origin,就像你正在使用的那样 - 然后是远程用来命名分支的git命令的名称.1 换句话说,如果您具有对远程的登录访问权限,并且您在那里登录并进入存储库,则可能会运行git log master以查看已提交的内容.

如果您查看.git/config文件,您将看到,对于每个"跟踪"某些内容的本地分支,这两部分.例如,假设您有一个名为的本地分支experiment,您已设置为跟踪origin/master.这将导致:

[branch "experiment"]
    remote = origin
    merge = master
Run Code Online (Sandbox Code Playgroud)

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

它实际上git fetch是更新origin/master等步骤,只有一旦完成,这个"跟踪"的东西是否有任何有用的效果.Git现在可以通过一些提交告诉你,你已经领先和/或落后了.并且,你现在可以运行一个命令,比如git log origin/master看看那里发生了什么 - 或者更有趣的是,git log --oneline master..origin/master看看你还没有的"他们的"提交:本质上,"fetch带来了什么" - git log --oneline origin/master..master并看到"你的"提交他们还没有.(如果你已经完成了合并或重组,那么看看你的fetch带来了什么已经太晚了,因为现在你已经拥有了他们所拥有的东西,因为你的合并或者rebase.)

所有这些都是古怪的git pull.该git 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上",并且分支X正在跟踪,那么也可以告诉你,如果你有未提交的提交,反之亦然.origin/Xgit statusXorigin/X

  • git merge并且git rebase:这些需要某种方式来了解要合并的内容或者要重新定义的内容.你可以明确地命名它,但如果你告诉你的git你的分支X正在跟踪origin/X,那么无论何时你在分支机构X,git merge或者git rebase知道该怎么做.

  • git branch --set-upstream-to origin/X:这是设置或更改当前分支跟踪内容的主命令.换句话说,如果你是在分支X现在,这个更新branch.X.remotebranch.X.merge你,这样你就不必使用两个单独的git config命令.您还可以使用git branch --unset-upstream删除跟踪信息.

  • git push:如果您没有提供其他信息,它会使用当前分支机构的"远程" - 其跟踪信息的前半部分 - 来决定调用哪个遥控器.无论你是否给出git push一个远程名称,下一部分取决于你是否给它一个"refspec".如果不这样做,则git push用于push.default决定使用什么refspec.

等等,什么是refspec?

refspec的第二个最简单的形式只是两个分支名称,它们之间有一个冒号,就像master:master.因为git push,左边的名称是你的分支名称,右边的​​名字是他们的 - 另一个git的分支名称.如果你省略了:你得到的最简单的形式,那里的远程端名称 - 跟随:-is的那个- 由一个有点复杂的过程选择(在git push文档中描述),这实际上取决于更多的配置变量以及你是否已经设置上游.

怎么样git push -u?这只是一个方便的快捷方式:就像git branch --set-upstream-to执行两个git config命令的快捷方式一样,是执行推送的快捷方式,然后执行操作.你必须为此做一个refspec来做任何有用的事情.git push -u refspecgit branch --set-upstream-topush

如果你给出一半"refspec" master怎么办?好吧,如上所述,你的git选择提供给遥控器的git的名称是通过一个复杂的过程找到的,但是如果你还没有设置一个上游(这很可能,如果你git push -u在第一时间做的话)它是将与您的本地名称相同.所以,git push -u origin master可能是"手段" git push -u origin master:master,而则意味着git branch --set-upstream-to origin/master,在最后.

如果你提供更全面的refspec,比如git push -u origin experiment:feature,这将推动你的experiment分支origin,要求origin调用它feature,然后做一个--set-upstream-to origin/feature.请注意,此时,本地分支的上游名称与本地名称不同.Git对此很好; 只要确定你也是.:-)

git有更聪明的技巧:

  • 如果你运行并且还不存在,并且有一个"明显的"远程跟踪分支,例如,git将创建一个已经跟踪的新本地.(也就是说,本地分支将其设置为和设置为.)git checkout branchbranchorigin/branchbranchorigin/branchremoteoriginmergebranch

  • 如果你运行,git会自动设置本地分支来跟踪相应的远程跟踪分支.(您可以配置git是否需要它,但这是默认值.)git branch local-name remote-tracking-name

摘要:git fetch更新跟踪使用的内容(origin/*条目,用于远程origin).一旦完成 - 包括如果它通过使用git pull,运行git fetch3 - 完成,那么你会看到来自命令的更多信息git status; 和命令就像git rebase用它来知道如何做rebase,而不必再告诉它了.

还有一个有趣的转折:任何分支的"上游"都可以在您自己的本地存储库中.要实现此目的,请remote将该分支设置为.(文字点),并将其设置为分支merge的名称.您不必知道如何执行此操作,因为您可以执行此操作git branch --set-upstream-to master,例如,使您当前的分支跟踪自己的跟踪master.

"传入"和"传出"

Mercurial用户可能想知道如何获得hg incoming或的效果hg outgoing.前者告诉你你的上游有什么,你没有.后者告诉你你拥有什么,他们没有.事实证明,这在现代git中很容易做到,因为git有一个特殊的语法@{u},可以找到当前分支的上游.

换句话说,如果你是在mastermaster轨道origin/master,@{u}(你可以拼出的@{upstream})只是另一种方式来写origin/master.所以origin/master..master只是一种更长的写作方式@{u}..master. 而且,如果你在master,HEAD也是名字master,省略分支名称告诉git使用HEAD,所以@{u}..就足够了.

如上所述,在您运行git fetch相应的遥控器之后,您可以使用它git log来查找"他们拥有的您没有的东西"和"您拥有的不具备的东西".您必须运行此git fetch步骤(并且此时希望发生合并或rebase).

所以:

git config --global alias.incoming '!git fetch && git log --oneline ..@{u}'
git config --global alias.outgoing '!git fetch && git log --oneline @{u}..'
Run Code Online (Sandbox Code Playgroud)

(在某些shell中,你可能需要\在前面!或其他引用技巧前面,并且通过运行可能更容易通过编辑器插入别名git config --global --edit).

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


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

2git pull实际上早于遥控器和远程跟踪分支.由于这个原因,它仍然有各种各样的怪异.

3如果您的git版本低于1.8.4,则在git pull运行时git fetch,该fetch步骤不会更新远程跟踪分支.这是一个功能,但它是一个糟糕的功能,更新的git版本更新.但这确实意味着,如果你有一个旧的git,你应该警惕使用pull脚本:这是一个不方便的方便.

4修正了编辑:我不小心写了alias.incoming = git log ....假设Git别名是其他git命令(如log),所以你想省略git部分,除非整个别名以感叹号开头!,在这种情况下整个别名被传递给shell运行.我居然忘了,现在,别名如何工作回来时,所有的命令都拼写类似git-log,git-branch,git-fetch,等等,但它必须是那么复杂... :-)


Dan*_*owe 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
Run Code Online (Sandbox Code Playgroud)

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


jub*_*0bs 5

"跟踪"和"上游"是相关术语."跟踪"意味着将本地存储库的分支上游分支(即位于远程存储库中的分支)相关联.例如,

git push -u origin newbranch
Run Code Online (Sandbox Code Playgroud)

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

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

git push -u origin master
Run Code Online (Sandbox Code Playgroud)

因为origin/master已经设置为master上游分支.换句话说,master已经设置为跟踪origin/master.