在 libgit2 标头中,我读到在 fetch 之后,如果在分析期间发出快进信号可用,那么需要的是简单检查所获取的提示(并更改 head/<branch>)。这似乎是合乎逻辑的,但是我想知道如何将 refs/heads/<branch> 与 remotes/<remote>/<branch> 区分开来?提交中嵌入了父项——这构成了一个历史记录,而应该有两个历史记录,其中两个历史记录都有额外的“合并”提交。那么快进是如何实现的呢?它确实导致 SHA 哈希在两个历史记录中重复,所以 libgit2 似乎有它的意义。
2 回答
由于 Git 是一个 CVCS,本地 repo 和远程 repo 在逻辑上可以被视为一个 repo。refs/heads/master(r)
在refs/heads/master
远程仓库中。
远程主机已被其他人更新。
现在我们想通过远程主机更新本地主机git pull origin master
。
首先git fetch origin master
在内部运行并remotes/origin/master
更新。这实际上是一个快进合并。remotes/origin/master
从 移动C
到E
。
然后git merge remotes/origin/master
运行。refs/heads/master
通过快进合并更新。它也从C
到移动E
。
如果refs/heads/master
在拉取之前由我们更新,那将是真正的合并。拉之前就像
这里我们有两个选择,git pull origin master
或者git pull origin --rebase master
。
获取过程是相同的。
没有--rebase
,这将是一个真正的合并。
有了--rebase
,这将是一个变基。
P
现在可以忽略它,因为它现在没有被任何分支或标签引用。
以最后一种情况为例,如果我们现在推refs/heads/master
送到远程,refs/heads/master(r)
将通过远程 repo 中的快进合并进行更新。
“快进”根本不是合并,它只是将分支指针设置到合并的“他们”一侧。
考虑一些历史:
1 -- 2 -- 3 -- 4 -- 5 -- 6
并考虑我的master
分支在提交 4,而服务器的master
分支在提交 6。
如果我希望将父级的主分支合并到我的(可能作为拉取的一部分),合并的第一步是找到合并基础,或者这两个提交之间的共同祖先。
在这种情况下(上图),4是4 和 6 之间的共同祖先。因此,本地没有服务器没有的提交,因此您可以简单地“快进”您的分支,将其指针更新为指向 6。这样做不会丢失任何数据(尽管您也不会创建任何数据 - 如果您使用“不快进”选项强制进行实际合并,那么您将在 4 到 6 之间创建一个新的合并提交。
所以 libgit2 的git_merge_analysis
函数,它识别合并是否可以快进,实际上只是检查“你的”分支是否是你自己与“他们的”分支的共同祖先。
当然,这不是典型的合并案例。考虑:
F -- G
/
A -- B -- C -- D -- E
在这种情况下,如果您在G
本地提交并且上游在提交,E
那么您的共同祖先是C
并且不可能快进,您必须执行真正的合并。