首页 > 解决方案 > 来自差异排序差异的异常合并冲突?

问题描述

我在 Git 中有一个异常的合并冲突。这是一个我从未打算保留的测试合并,但我想了解为什么Git 将其报告为冲突。

我已经使用十六进制编辑器在合并的两侧获取受影响文件的SHA -1 哈希,并由此确认文件在合并的两侧至少7 行之前和通过到至少28 行之后,所谓的冲突。这意味着实际上不存在冲突,并且它不可能是空格、行尾、奇怪的 Unicode 规范化或不显示字符的问题。

冲突看起来完全像这样:

<<<<<<< HEAD



#### Where To Put Untracked Intermediate Files

=======



#### Where To Put Untracked Intermediate Files

>>>>>>> theirs

根据@torek 的建议,我也尝试过使用merge.conflictstyle=diff3,这会导致不同的标记,但本质上是相同的非冲突:

<<<<<<< HEAD
This is a preceding big long line, added by both sides, simplified for this post.
||||||| 87377e6
=======
This is a preceding big long line, added by both sides, simplified for this post.

>>>>>>> theirs


<<<<<<< HEAD
||||||| 87377e6
#### Where To Put Intermediate Files
=======
#### Where To Put Untracked Intermediate Files
>>>>>>> theirs

<<<<<<< HEAD
#### Where To Put Untracked Intermediate Files

This is an edited big long line which I have simplified for this post.
||||||| 87377e6
This is a big long line which I have simplified for this post.
=======
This is an edited big long line which I have simplified for this post.
>>>>>>> theirs

(我已经为这篇文章更改了一些行,但是不同的行保持不同。)

仔细研究发现,三者之间的冲突,HEADtheirs上述不谋而合。在这种情况下,冲突标记的排列与我稍后注意到的 git-diff 行顺序差异一致,但在其他方面没有任何意义。

在新存储库中重现

这是重现它的过程,从头开始在新存储库的空目录中,并拥有base.txt,ours.txttheirs.txt手头 - 稍后将详细介绍:

$ git init
Initialized empty Git repository in //bla/bla/bla/bla/bla/repo/.git/

$ cp ../test-files/base.txt .
$ mv base.txt file.txt
$ git add file.txt
$ git commit -m "Set base"
[main (root-commit) 30f2d24] Set base
 1 file changed, 2169 insertions(+)
 create mode 100644 file.txt

$ git checkout -b theirs
Switched to a new branch 'theirs'

$ rm file.txt
$ cp ../test-files/theirs.txt .
$ mv theirs.txt file.txt
$ git commit -am "Set theirs"
[theirs d5abe2c] Set theirs
 1 file changed, 81 insertions(+), 46 deletions(-)

$ git switch main
Switched to branch 'main'

$ rm file.txt
$ cp ../test-files/ours.txt .
$ mv ours.txt file.txt
$ git commit -am "Set ours"
[main a7cde04] Set ours
 1 file changed, 217 insertions(+), 49 deletions(-)

$ git merge theirs --no-ff
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.

此时会有两个地方file.txt有冲突标记(merge.conflictstyle=diff3使用时更多)。第一个,在第 408 行,如帖子顶部所示。第二个在第 2353 行的文件末尾附近,并有合理的解释。

调查

我已经使用 gitk 确认文件模式100644在所有提交中。

为了解释发生了什么,在上述过程之后,我运行了这些:

git diff :1:file.txt :2:file.txt > 1-2.txt
git diff :1:file.txt :3:file.txt > 1-3.txt
git diff :2:file.txt :3:file.txt > 2-3.txt

该文件2-3.txt不包含字符串Where To Put Untracked Intermediate Files

1-2.txt并且1-3.txt 确实包含字符串,分别作为 a@@ -372,34 +389,42 @@@@ -372,34 +388,42 @@hunk 的一部分。请注意,这些大块比报告为冲突的区域要长得多

我打开ours.txttheirs.txt在十六进制编辑器中,仔细找到这些大块的起点和终点,并获取他们的 SHA-1。 哈希是相同的。

不过,我确实找到了一个可能的线索:

git-diff 行顺序差异

hunks的a/and文件在and之间b/显示相同的内容,但是它们在 diff 输出中的呈现方式并不完全相同。有 7 行的跨度未按相同顺序列出,即使它们的排序在功能上是等效的:1-2.txt1-3.txt

对于1-2.txt这些行,加上为清楚起见的以下行,如下:

 
 
-#### Where To Put Intermediate Files
 
-This is a big long line which I have simplified for this post.
+#### Where To Put Untracked Intermediate Files
+
+This is an edited big long line which I have simplified for this post.

因为1-3.txt它们如下:

+
 
 
-#### Where To Put Intermediate Files
+#### Where To Put Untracked Intermediate Files
 
-This is a big long line which I have simplified for this post.
+This is an edited big long line which I have simplified for this post.

, 1-2.txt和文件在运行和不运行之间是相同1-3.txt的。2-3.txtmerge.conflictstyle=diff3

问题

文件

base.txt, ours.txt, 并且theirs.txt在我最初的测试中与 ~2300 行 Markdown 文件密切相关。

我最初在一个实际的存储库中遇到了这种冲突,在该存储库中,两个分支之间反复进行了挑选和合并。我在运行 a 时遇到了它,git merge --squash无意提交,看看分支收敛了多少。起初我认为冲突是由于摘樱桃(它可以做这样有趣的事情),但我越想越觉得没有意义,因为当双方以相同的方式更改文件时,这不应该是冲突。

所以,在merge抱怨之后,在做出任何决定之前,我运行了这些:

git show :1:the-actual-file.md > base.txt
git show :2:the-actual-file.md > ours.txt
git show :3:the-actual-file.md > theirs.txt

在新的存储库中复制合并非常有效地排除了复杂性,例如挑选樱桃作为解释。

ours.txt并且theirs.txt有许多不冲突的变化,我无法仅基于异常冲突来重现一个简单的例子。但是,我能够在三个文件的“净化”版本上重现,其中所有行都被替换为它们的 SHA-1 十六进制字符串,这会产生与上图相同的冲突模式和git diff行。有兴趣的可以下载:base.txtours.txttheirs.txt

标签: gitgit-mergegit-diff

解决方案


推荐阅读