git - 来自差异排序差异的异常合并冲突?
问题描述
我在 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
(我已经为这篇文章更改了一些行,但是不同的行保持不同。)
仔细研究发现,三者之间的冲突,HEAD
与theirs
上述不谋而合。在这种情况下,冲突标记的排列与我稍后注意到的 git-diff 行顺序差异一致,但在其他方面没有任何意义。
在新存储库中重现
这是重现它的过程,从头开始在新存储库的空目录中,并拥有base.txt
,ours.txt
和theirs.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.txt
并theirs.txt
在十六进制编辑器中,仔细找到这些大块的起点和终点,并获取他们的 SHA-1。 哈希是相同的。
不过,我确实找到了一个可能的线索:
git-diff 行顺序差异
hunks的a/
and文件在and之间b/
显示相同的内容,但是它们在 diff 输出中的呈现方式并不完全相同。有 7 行的跨度未按相同顺序列出,即使它们的排序在功能上是等效的:1-2.txt
1-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.txt
merge.conflictstyle=diff3
问题
- 为什么行的顺序不同?
- 是否
git diff
承诺它将使用功能等效的排序集合中的哪一行排序? - 是否
git merge
假设如果 for a hunk 的字面文本输出git diff
不相同,则该 hunk 是冲突? - 如果不是,为什么这会表现为冲突?
- Git 用户如何避免这种情况?
文件
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.txt、ours.txt和theirs.txt。
解决方案
推荐阅读
- powershell - 我需要在 Powershell 中获取我的 smb 共享的网络路径并将其输出到文本文档
- c# - 打开的 Oracle 连接过多
- python - Python 脚本使用的内存超出了应有的范围
- javascript - 在 javascript 中更改 Textarea 的值
- python - XlsxWriter 未向空单元格添加底部边框
- python-3.x - 如何抓取伪装成 unicode 的 href(例如 \u003ca href=\)
- sql - 这个 SQL 查询和连接是如何在 dplyr 中完成的?
- c - JUMP 表接近 .text 部分的末尾
- node.js - 管道流到 axios 请求正文
- javascript - 文本输入占位符返回不应该的内容