git pull命令输出消息意味着进入哪个分支

min*_*hua 2 git git-pull git-remote git-branch

假设远程br1仓库上有远程分支机构检查,master本地仓库上有分支机构.

  • 命令1:如果我做了一个" git pull origin br1:br1"它将远程拉br1入本地br1,并显示: 9188a5d..97d4825 br1 -> br1 9188a5d..97d4825 br1 -> origin/br1

  • 命令2:如果我只做一个" git pull",它会将远程拉br1入本地master,但它只显示以下内容: 9188a5d..97d4825 br1 -> origin/br1

我期待它也会显示" br1 -> master" 这样的东西.为什么没有表现出来?

" br1 -> br1" 是否意味着将远程拉br1入本地br1

这是什么br1 -> origin/br1意思?

更新:在VonC的帮助下,我发现了以下内容:

  • git pull更新所有跟踪分支.遥控器上的br1 -> origin/br1装置br1被拉入本地跟踪分支origin/br1.

  • git pull origin br1:br1将远程拉br1入本地br1并进入origin/br1.然后,之后的消息意味着相同的更改集也被拉入当前签出的分支(消息是Updating ...,它没有显示br1 -> master): $ git pull origin br1:br1 beb48a4..b344dd1 br1 -> br1 beb48a4..b344dd1 br1 -> origin/br1 Updating cca5a9b..b344dd1 Fast-forward file2 | 0 file3 | 0 4 files changed, 0 insertions(+), 0 deletions(-)

  • 以前我以为git pull拉进了当地的主人.事实并非如此.就是git pull origin br1:br1这样.

更新2:随着由托雷克说明,具体的问题是,该命令git pull origin br1:br1远程拉br1FETCH_HEAD其他动作序列后,随后将合并FETCH_HEAD到当前分支.

tor*_*rek 6

警告:很久.TL; DR版:你是在寻找git fetch输出和git fetch不影响你的master所有,它是git merge你的一部分git pull,影响你的master.但是,您git fetch正在更新远程跟踪分支origin/br1,在一种情况下更新甚至创建本地分支br1.

git pull 是一个方便的脚本

永远记住,这git pull只是一个为您运行两个其他git命令的便捷脚本:首先,git pull将您的参数传递给git fetch.一旦完成,git pull运行git merge(或者,如果指示git rebase),但原始问题中的所有引用操作都是纯粹发生的git fetch.("更新"部分中的一部分来自git merge,我稍后会介绍.)

如果未提供远程参数git pull,则pull脚本将从当前分支的配置中提取一个参数.在这种情况下,它提取的那个是清楚的origin.因此,如果您在git pull未指定的情况下运行origin,则实际上正在运行git pull origin.

如果你没有提供refspec参数git pull,pull脚本会从当前分支的配置中提取一个非常简单的参数- 在这种情况下,无论你看到什么git config --get branch.master.merge,显然是br1.所以这意味着如果你跑git pull origin,你实际上在运行git pull origin br1.1

此外,所有这一切都是那么就转嫁到git fetch,所以无论你跑git pull,git pull origin或者git pull origin br1,所有这些只是拉闸调用:

git fetch origin br1
Run Code Online (Sandbox Code Playgroud)

(你也可以手动完成,你会看到上面的内容).

我们将git fetch origin br1:br1在下面稍后介绍.

关于可能的误解的背景

让我们再次简要介绍一下您的安装声明:

假设远程br1仓库上有远程分支机构检查,master本地仓库上有分支机构.

目前在遥控器上签出的分支(如果有的话)通常是无关紧要的fetch.第一个(或第一个足够的)事情fetch是连接到远程并询问它是否包含所有引用及其相应SHA-1的列表(您可以看到git fetch运行时可以看到的内容git ls-remote).遥控器上的HEAD 列入该名单,这可以让你指挥你fetch使用它,但如果你不这样做,你fetch只是忽略它(遥控器上的HEAD大多只是用于控制在初始默认的初始分支git clone).

但是,当地仓库中的当前分支重要,原因有两个:

  • 如果你不提供额外的参数git pull,它会根据你当前的分支找到它们; 和
  • fetch成功,git pull运行或者git merge还是git rebase,它采用当前分支.

同样,当前的分支master,以便pull将使用branch.master.remotebranch.master.merge作为默认的远程的Refspec参数.2 这就是我们如何从原始输出中推断出这些是originbr1.

git fetch

回过头来git fetch,它做的是与远程git服务器进行一些比较,以找出哪些引用(主要是分支和标签)可用以及它们对应的SHA-1值是什么.一旦有了这些信息,它就会查看你要求它带来哪些参考资料.如果你列出了一个特定的引用br1,那就是它将带来的一个引用.

当然,除了每个引用之外,它还必须带来任何新对象(提交本身及其关联的树和文件,以及任何父提交及其所需的树和文件),以便从中获取所有历史记录.特别指向后退.无论你已有的历史,当然,它可以跳过.3

正如VonC已经指出的那样,git的行为在git 1.8.4及更高版本中发生了变化.过去的情况是,如果你运行,你的refspec会覆盖你的git配置条目中的那个遥控器的规则,但现在它只是从中选择.默认情况下,名为remote 的规则集是,因此refspec会从此规则集中选择一个项目.git fetch remote refspecgit fetch remote refspecorigin+refs/heads/*:refs/remotes/origin/*br1


让我们停下来看看如果git fetch只运行三个参数会发生什么,如下所示:

$ git fetch origin
Run Code Online (Sandbox Code Playgroud)

在这里,您指示您的本地git连接到遥控器,找出它有什么,并带来所有分支机构.它的方式(和原因)如上所述:它连接,获取列表,然后查询输出git config --get-all remote.origin.fetch.4 这是"refspecs"列表,每git config --get-all行一个.

由于该标准线(一个单行)remote.origin.fetch+refs/heads/*:refs/remotes/origin/*,你的本地git会采取相匹配的所有引用名refs/heads/*.也就是说,它将占用所有分支origin,因为分支只是"名称以refs/heads/" 开头的引用".它是什么用这些分支是由该的Refspec的右侧确定的:它代替refs/heads/refs/remotes/origin/.

结果是"远程跟踪分支".如果遥控器有一个分支master,你的本地git会将其转换为origin/master.如果遥控器有a br1,你的本地git会将其转换为origin/br1.对于遥控器上的每个分支,您将获得一个名称以(本地)远程跟踪分支开头的分支origin/.


回到我们的情况git fetch origin br1,我们现在可以看到会发生什么:我们的本地git带来了br1,结果是一个分支,所以它的全名是refs/heads/br1.因此,它匹配标准remote.origin.fetch行并被refs/heads/br1转换为refs/remotes/origin/br1,这导致git打印出来origin/br1:

9188a5d..97d4825  br1        -> origin/br1
Run Code Online (Sandbox Code Playgroud)

这个名字br1左边的是遥控器上的参考的短名称,该名称origin/br1右边是参考的短名称git fetch已更新.

在过去你会看到类似的东西 - 你仍然可以看到它:

* branch            name       -> FETCH_HEAD
Run Code Online (Sandbox Code Playgroud)

这表明在遥控器上git fetch找到了一个名为name(即表格的引用refs/heads/name)的分支,并将其带到您的本地仓库并将其放入FETCH_HEAD.什么是FETCH_HEAD?这是一个特殊的文件,几乎只存在于git pull脚本中.(它的工作原理很像参考,但它有一个特殊的格式,可能包含多个SHA-1.)


现在我们(终于)准备好解决这个问题了br1:br1.在这里,你告诉当地人git fetch带来参考br1.它通常调用遥控器,发现它br1真的refs/heads/br1,并带来引用和任何需要的对象 - 但这次,除了咨询该remote.origin.fetch行之外,它还将新的SHA-1写入指定的引用中.

在这种情况下,您指定br1没有资格:不refs/heads/br1,不refs/remotes/origin/br1,只是br1.在这种情况下,git看到它是refs/heads/遥控器的引用,这意味着它是一个分支; 所以git refs/heads/也会在你的最后添加,并创建或更新你自己的refs/heads/br1.

换句话说,这会创建或更新您的本地分支br1.

此外,git仍然应用该remote.origin.fetch行,它仍然是+refs/heads/*:refs/remotes/origin/*,因此它仍然更新您的远程跟踪分支origin/br1(全名refs/remotes/origin/br1). 这就是你获得Command 1输出的原因.

git merge

怎么样FETCH_HEAD?好吧,这是其余部分git pull重新出现的地方:执行该git fetch步骤后,pull脚本运行git merge或者git rebase.它合并的内容(或转换为)是文件中留下的任何内容git fetchFETCH_HEAD(有一些特殊的外壳和其他注意事项,我不会在这里讨论).

如果当前的分支master,但您指示git pullorigin br1,它是git merge带来一步master了解最新的br1. 更确切地说,合并让您能更新您的副本origin/br1作为时间的git fetch结束,它可能是刚过你git fetch完了,别人做了git push该更新的br1遥控器上.

如果可能的话,合并是一个"快进"合并,但我再也不会在这里详细介绍.我会注意到它是可能的,所以它已经完成了; 这是Fast-forward更新中的一行.

在任何情况下,合并都会引入当前分支(master)自当前分支和目标提交的合并基础以来的更改(文件中git fetch剩余的原始SHA-1,FETCH_HEAD也是新的SHA-1)origin/br1,在一种情况下,新的或更新的本地分支的新SHA-1 br1).

在1.8.4之前版本的git中,origin/br1远程跟踪分支不会更新.FETCH_HEAD尽管如此,一切仍然可以在文件中运行,如果有的话,它甚至比在新的gits中令人困惑,在那里我们可以说你现在是最新的,origin/br1而不必非常严格和挑剔" br1因为它是在你跑的时候在遥控器上git fetch".

什么是加号?

眼尖的读者可能已经注意到了++refs/heads/*:refs/remotes/origin/*.此+符号表示"强制更新".通常,在更新分支引用时 - 以refs/heads/-git 开头的任何引用都不允许更新,除非它是"快进"标签更新.在refspec中设置force标志允许进行特定更新.使用--force命令行还允许更新,和所有其他参考的更新.换句话说,加号只是一个更具针对性(单个refspec)的版本--force.


1这是夸大其辞:有时它使用三个参数git fetch.

2对于远程位始终为true,但refspec位可能为空,pull脚本在git fetch完成后确定要在以后应用哪个refspec .

3默认情况下,该fetch操作还将引入与其引入的任何提交ID匹配的任何标记名称引用.如果你git fetch自己运行,你可以改变fetch处理这些的方式,但如果你只是让它git pull运行,git fetch你将得到这种默认行为.请注意,做出这些决定的是你的本地git:远程git只是向你的本地git显示所有内容,然后你的git决定是否向你的存储库添加标签.

4从技术上讲,git fetch只调用执行此操作的C代码,而不是实际运行git config --get-all.在任何情况下,如果有多个配置条目remote.origin.fetch,git fetch origin确实应用所有这些条目.它的做法虽然有点复杂,但我会在这里略过一些血腥的细节.

5远程跟踪分支实际上只是名称以其开头的引用refs/remotes/,就像本地分支是名称以其开头的引用一样refs/heads/.这是git中的一般内容:您的标记是名称以其开头的引用refs/tags.该git stash脚本使用单个特殊引用refs/stash.Git的"注释"存储在refs/notes/,你可以创建自己的引用:只需选择一个不同的起始字符串,并希望将来没有其他人选择相同的新git功能.:-)