就 Git 而言,这是正确的合并结果。
Gitgit merge通过将两个分支提示与一个通用合并基础进行比较来工作。也就是说,如果你绘制提交图,它看起来像这样:
o--o--L <-- branch1
/
...--o--o--*
\
o--o--R <-- branch2
branch1然后将(commit L) 与branch2(commit )合并的结果R将通过比较 commit 的内容(*两个分支派生的公共点)与 commit 的内容和 commitL的内容来计算R。
无论从*到L发生在左侧。无论从*到R发生在右侧。Git 将这两个“发生的事情”结合起来,将这些结合后的更改应用于 的内容*,如果一切顺利,则从结果中进行新的提交。
但是您正在使用--allow-unrelated-histories. 仅当没有共同提交时才需要这样做:我们绘制 和 的历史L并R发现它们从未偏离共同点。例如,我们可能会得到:
A--o--o--...--L <-- branch1
B--o--...--o--R <-- branch2
whereA和Bare都是根提交。那么Git应该使用什么作为共同的起点,以找出从那时起发生了什么变化?
人们可以为自己选择的各种起点争论不休,但 Git 的答案是:使用空提交。 也就是说,使用--allow-unrelated-histories,Git 假装有一个根本没有文件的共同提交:
A--o--o--...--L <-- branch1
/
*
\
B--o--...--o--R <-- branch2
比较*空的 commit 和 commit L,Git 发现上面的每个文件branch1都是以它在L. 与 相比*,RGit 发现上面的每个文件branch2都是以它在R. 无论这些文件在哪里匹配,一切都很好:我们只需要那个文件。无论哪里L有一个文件R没有,反之亦然,一切都很好:我们只是拿那个文件。无论在哪里都有一个文件L,R但它们的内容不同,我们就会有合并冲突。
由于您使用-X theirs了 ,Git 通过采取“他们的”更改来解决每个冲突(“他们的”是您命名的提交,而不是您作为 的提交HEAD),因为是空的合并基础提交。
如果你想让 Git 假装其他提交是合并基础,你可以使用git replace --graft插入一些假的父链接。例如,假设您想在任意选择的提交 C 处将两者假绑定在一起:
A--o--o--...--L <-- branch1
/
B--...--C--...--R <-- branch2
以便 Git 将与C和L进行C比较R。就其本身而言,您在链git merge中选择哪个提交并不重要。任何提交都可以(包括它们自己) ,但请注意 Git 只会“看到”自您选择的提交以来的更改(由于-vs-和-vs-的差异)。因此,在链中选择一些适当的提交并运行:A--...--LALCLCR
git replace --graft <hash-ID-of-chosen-commit> <hash-ID-of-C>
并且 Git 现在将使用替换(移植)提交而不是选择的提交。Agit merge现在将使用 的内容C作为公共源。(您可以在git merge退出后立即删除嫁接,即使它以合并冲突退出。因此,您可以编写一个插入嫁接、运行git merge和删除嫁接的小脚本,以与任意选择的祖先合并。只需插入它L只要在线就作为替换,或者只要B--...--R在线就插入作为替换。)RA--...--L