[英]In a Git cherry-pick or rebase merge conflict, how are BASE (aka "the ancestor"), LOCAL, and REMOTE determined?
在正常的 Git 合并冲突中,用于三向合并的文件的三个版本大致如下:
当一个Git cherry-pick产生merge conflict时,没有共同的祖先,严格来说,那么这些东西是怎么确定的呢? 关于变基也可以问同样的问题。
樱桃挑选
除非我误导了自己,否则如果你执行“git cherry-pick <commit C>”,那么你会得到:
如果不是很清楚为什么 BASE 应该是 C^,请参阅下面的“为什么”部分。
同时,让我们举个例子,看看 BASE可以是但通常不会是cherry-pick 过程中的共同祖先。 假设提交图看起来像这样
E <-- master
|
D
| C <-- foo_feature(*)
|/
B
|
A
并且您位于分支 foo_feature (因此带有星号)。 如果您执行“git cherry-pick <commit D>”,那么该 cherry-pick 的 BASE 将是提交 B,它是 C 和 D 的共同祖先。(C 将是本地的,D 将是远程的。)但是,如果你改为执行“git cherry-pick <commit E>,那么 BASE 将提交 D。(C 将是本地的,E 将是远程的。)
变基
对于背景上下文,rebase 大约是迭代的 cherry-picking。 特别是,在 master 之上重新定位主题(即“git checkout topic; git rebase master”)大约意味着:
git checkout master # switch to master's HEAD commit
git checkout -b topic_rebased # create new branch rooted there
for each commit C in master..topic # for each topic commit not already in master...
git cherry-pick C # bring it over to the new branch
finally, forget what "topic" used to mean and now defined "topic" as the HEAD of topic_rebased.
在此过程中应用的标签是正常的 cherry-pick 规则的扩展:
如果您想避免混淆,这意味着要记住有关 LOCAL 与 REMOTE 的一些事项:
即使您在启动 rebase 时位于分支主题上,在进行 rebase时LOCAL 也永远不会引用主题分支上的提交。 相反,LOCAL 总是指对正在创建的新分支(topic_rebased)的提交。
(如果没有牢记这一点,那么在一次讨厌的合并中可能会开始问自己,“等等,为什么说这些是本地更改?我发誓它们是在 master 上而不是在我的分支上进行的更改。”)
更具体地说,这是一个例子:
假设我们有提交图
D <-- foo_feature(*)
|
| C <-- master
B |
|/
|
A
我们目前在分支 foo_feature(用“*”表示)。 如果我们运行“git rebase master”,rebase 将分两步进行:
首先,来自 B 的更改将在 C 之上重放。在此期间,C 是 LOCAL,B 是 REMOTE,A 是 BASE。 请注意,A 是 B 和 C 的真正共同祖先。在这第一步之后,您将得到一个大致如下的图形:
B' <-- foo_feature
D |
| |
| C <-- master
B /
|/
|
A
(在现实生活中,此时 B 和 D 可能已经从树中剪除,但我将它们留在此处,以便更容易发现任何潜在的共同祖先。)
其次,来自 D 的更改将在 B' 之上重播。 在此期间,B'为LOCAL,D为REMOTE,B为BASE。 请注意,B 不是任何事物的相关共同祖先。 (例如,它不是当前 LOCAL 和 REMOTE B' 和 D 的共同祖先。并且它不是原始分支负责人 C 和 D 的共同祖先)。 在这一步之后,你有一个大致像这样的分支:
D' <-- foo_feature
|
B'
D |
| |
| C <-- master
B /
|/
|
A
为了完整起见,请注意在变基结束时 B 和 D 从图中删除,产生:
D' <-- foo_feature
|
B'
|
C <-- master
|
A
为什么要按原样定义 BASE?
如上所述,对于 cherry-pick 和 rebase,BASE 都是提交 C 的父级 (C^)。在一般情况下,C^ 不是共同的祖先,所以为什么称它为 BASE ? (在正常的合并中,BASE是一个共同的祖先。而 git 在合并方面的部分成功是由于它能够找到一个好的共同祖先。)
本质上,这样做是作为一种通过正常的三路合并算法实现“补丁”功能的方式。 特别是你会得到这些“不完整”的属性:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.