在正常的Git合并冲突中,三向合并的三个版本的文件大致如下:
当一个Git樱桃挑选产生合并冲突时,没有共同的祖先,正确地说,那么这些事情是如何确定的?关于rebase也是如此。
答案 0 :(得分:36)
<强>樱桃挑选强>
除非我误导自己,否则如果你做“git cherry-pick&lt; commit C&gt;”,那么你得到:
如果不能立即清楚为什么BASE应该是C ^,请参阅下面的“为什么”部分。
与此同时,让我们举一个例子,看看BASE 可以,但在挑选时,通常不会是共同的祖先。假设提交图看起来像这样
E <-- master
|
D
| C <-- foo_feature(*)
|/
B
|
A
你在分支foo_feature(因此是星号)。如果您执行“git cherry-pick&lt; commit D&gt;”,则该樱桃选择的BASE将提交B,这是C和D的共同祖先。(C将是LOCAL,D将是REMOTE。)但是,如果您改为“git cherry-pick&lt; commit E&gt;”,那么BASE将提交D.(C将是LOCAL,E将是REMOTE。)
<强>底垫强>
对于背景上下文,rebase大致是迭代的挑选。特别是,在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.
在此过程中应用的标签是正常樱桃挑选规则的扩展:
如果您想避免混淆,这意味着需要牢记LOCAL与REMOTE:
即使您在启动rebase时处于分支主题, LOCAL也从未引用主题分支上的提交 当一个rebase正在进行中时。相反,LOCAL总是引用正在创建的 new 分支的提交(topic_rebased)。
(如果一个人没有牢记这一点,那么在一次令人讨厌的合并期间,人们可能会开始问自己,“等等,为什么说这些是本地的变化?我发誓他们是对主人,而不是我的分支。“)
更具体地说,这是一个例子:
假设我们有提交图
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
为了完整性,请在图表中删除rebase B和D末尾的注释,产生:
D' <-- foo_feature
|
B'
|
C <-- master
|
A
为什么BASE按原样定义?
如上所述,对于cherry-pick和rebase,BASE都是提交C的父(C ^)。在一般情况下,C ^不是共同的祖先,为什么叫它BASE? (在正常的合并中,BASE 是的共同祖先。而git在合并方面的成功部分归功于它能够找到一个好的共同祖先。)
基本上,人们通过普通的three-way merge算法来实现“补丁”功能。特别是你会得到这些“不完整”的属性: