我对git-pull
文档的这一部分感到有点困惑:
$ git pull origin next
这会在
next
暂时留下FETCH_HEAD
的副本,但不会 更新任何远程跟踪分支。
这种形式的git pull
实际上是否会从远程存储库获取新的提交到本地提交?
答案 0 :(得分:0)
非常简短的回答是肯定的:git fetch
获取他们的提交并将它们放入您的存储库。但git pull
文档在这里是错误的,只是一个小而重要的方式。
我建议避免 git pull
,至少在您熟悉它运行的两个命令的内部工作方式之前。相反,使用两个单独的命令:git fetch
,然后 - 假设您打算合并 - git merge
。但是,这确实值得一些解释。特别是声称这个
不会更新任何远程跟踪分支
通常是错误的,尽管在某些特定情况下它可能是正确的。对于Git 1.8.2之前的Git版本, 是正确的。
如文档所述,git pull
运行git fetch
,然后运行第二个Git命令,通常为git merge
。第一个(fetch)命令获取传递给git pull
的大多数选项和参数,尽管有一些选项被删除并传递给git merge
或git rebase
,甚至直接使用由git pull
本身。
在具体案例中:
git pull origin next
这运行:
git fetch origin next
指示git fetch
:
git config --get remote.origin.url
; next
(分支或标签,通常是分支)获取;和这里的文档是指这三个项目中的最后一个。但是,自Git版本1.8.2以来,Git现在执行Git文档调用的内容和#34;机会主义更新":如果Git带来了origin
next
,Git更新您自己的origin/next
,,即使它没有更新任何其他远程跟踪名称。 1 在所有情况下,git fetch
都会写入进入.git/FETCH_HEAD
哈希ID以及它带来的分支或标签的名称。
git merge
运行的后续git pull
使用此FETCH_HEAD
文件中的哈希ID,以及行上的消息不标记为not-for-merge
。请参阅以下有关FETCH_HEAD
文件内容的部分。
1 这种机会更新的机制特别曲折:Git读取git config --get remote.origin.fetch
的值,以了解如何重命名其他上的分支名称 Git在您的 Git存储库中将它们转换为远程跟踪名称时。如果您将此设置为其正常默认值之外的其他内容,或者如果没有设置,则即使在Git版本1.8.2或更高版本中,文档的声明也可能正确。
当然,如果您使用URL而不是远程名称,Git无法知道要更新哪些名称。所以在这个的情况下 - 当你运行时:
git fetch https://example.com/repo.git
例如- 无论是否向命令添加其他refspec,都不会更新远程跟踪名称。
git fetch
带来的 git fetch
真正重要的部分是它带来了提交。具体来说,它会在其存储库中引入其哈希ID 其 Git的提交,您的 Git在您的存储库中没有。 Git使用一些图论来根据你告诉git fetch
要获取的名称来确定需要从他们的存储库中提交什么提交以及其他什么对象。正常的默认值是所有分支名称和一些标记名称。
这些对象 - 主要是提交以及随之而来的文件 - 都由这些哈希ID标识。这是Git关注的哈希ID。你要么拥有具有哈希ID的东西,要么就是你没有;如果你不这样做,git fetch
会把它带过来。
一旦你拥有了这些对象,只要某些东西具有该对象的名称,或者该对象可以从到达,你的Git就会保留它们>有名字的东西。执行此操作的过程类似于Java,Python和Go等许多现代语言中的垃圾收集(以及许多较旧的语言,如Lisp及其大多数后代)。基本上,给定一些起点,Git遍历通过读取提交 2 形成的图形来获取它们的父哈希ID。在此图形遍历期间到达的任何提交或其他对象都引用并保留; 未到达的任何提交或其他对象都未被引用,并且有资格删除。
此处FETCH_HEAD
文件的内容计数:该文件中各行上的任何哈希ID都是引用的对象。因此,哈希ID的存在会保留对象,即使origin/next
永远不会更新(Git版本早于1.8.2,或脚注1中其他特殊但不太可能的条件之一)。
2 此说明省略了带注释的标记对象。这些也包含哈希ID并导致目标对象被引用(如果它是标记,提交或树对象则遍历)。请注意,每个提交都包含一个树对象的哈希ID。垃圾收集代码必须遍历此树对象,该对象包含更多对象ID,以将这些对象标记为已引用,当然还以递归方式遍历树中的任何子树。幸运的是,树不能引用除树和blob对象之外的任何东西,或偶尔使用的特殊gitlink,它是从子模块中获取的哈希ID,但不会在此处遍历。
FETCH_HEAD
查看FETCH_HEAD
文件 - 它的纯文本,易于阅读 - 你会发现类似这样的内容:
3e5524907b43337e82a24afbc822078daf7a868f branch 'master' of [url]
fc54c1af3ec09bab8b8ea09768c2da4069b7f53e not-for-merge branch 'maint' of [url]
61856ae69a2ceb241a90e47953e18f218e4d5f2f not-for-merge branch 'next' of [url]
fc16284eae5b5a7c4786612ba2c254f3f23b1086 not-for-merge branch 'pu' of [url]
9125ddae1445fd35a9e52a21f926a2785a2583b8 not-for-merge branch 'todo' of [url]
(哈希ID和名称等等当然会有所不同)。这来自git fetch
,没有任何限制;一个专门针对next
并且打算用于合并的内容将改为:
61856ae69a2ceb241a90e47953e18f218e4d5f2f branch 'next' of [url]
由于您运行的 next git fetch
将覆盖 FETCH_HEAD
文件,如果没有远程跟踪名称记住此哈希ID, future git fetch
可以使对象61856a...d5f2f
符合垃圾回收的条件。但是,如果您已将合并到您自己的分支中,您的分支名称指向一个提交,当通过提交图表后,最终指向{{1通过引用它来保护Grim Collector的提交。
(请注意,61856a...d5f2f
有一个选项-a
或--append
,可以将追加告诉git fetch
文件。但是,这可能会导致FETCH_HEAD
git merge
运行,因为现在可能有多行而不是标记为git pull
。所以它很少有用将not-for-merge
与-a
一起使用的想法 - 你真的需要知道你在这里做了什么。)