这是一种基于逐行分析的翻译方式,答案有点“是”又有点“不是”,即上下文确实很重要,但它的重要性却很棘手。初看可能会高估或低估它的重要性。
可以先浏览相关问题的
此回答,以了解背景信息。接下来,我们假设
base
是(唯一的)合并基础(例如,通过标记特定提交命名为
base
,如
git tag base $(git merge-base HEAD other)
),而
HEAD
是我们在
b1
分支上的提交,某个其他分支
b2
则命名为另一个提交。
接下来,我们查看两个差异:
git diff base HEAD
git diff base b2
如果我们发现文件
F的三个版本都不同(因此在两个输出中均出现,且更改不同),那么我们必须本质上逐个差异块进行处理。在差异块重叠但产生不同更改的情况下,Git会声明冲突。但是——这似乎是您的问题——“产生不同更改”到底意味着什么呢?
我认为最好通过示例来说明。例如:
$ git checkout b1
[checkout messages here - but I was already on b1]
$ git diff base HEAD
diff --git a/basefile b/basefile
index df781c1..e4f9e4b 100644
--- a/basefile
+++ b/basefile
@@ -4,6 +4,7 @@
+
并且:
$ git diff base b2
diff --git a/basefile b/basefile
index df781c1..c96620e 100644
--- a/basefile
+++ b/basefile
@@ -4,7 +4,6 @@
-# 1. Redistributions of source code must retain the above copyright
请注意,虽然这些更改没有涉及到同一行,但从某种意义上来说,它们也确实会涉及到同一行。我添加了第7行(将旧的第7行推到第8行),并删除了旧的第7行。这些显然是“同一”行。因此:
$ git merge b2
Auto-merging basefile
CONFLICT (content): Merge conflict in basefile
Automatic merge failed
让我们放弃这次合并,转而考虑分支b3
的最新版本(在我的设置中,b1
和b3
的合并基础与b1
和b2
的合并基础相同)。
$ git merge --abort
$ git diff base b3
diff --git a/basefile b/basefile
index df781c1..e2b8567 100644
--- a/basefile
+++ b/basefile
@@ -5,7 +5,6 @@
-
$ git merge --no-edit b3
Auto-merging basefile
Merge made by the 'recursive' strategy.
basefile | 1 -
1 file changed, 1 deletion(-)
这次没有冲突,即使两个
diff hunks 涉及同一区域。第二个 diff 删除了一行没有“touching”添加的行,所以 Git 认为这是安全的。
如果你继续尝试,以同样的方式,你会发现哪些看似重叠的更改成功地合并在一起,哪些会导致冲突。显然,直接重叠的更改,例如,两者都删除原始行 42 并插入不同的新行 42,将会冲突。但所有更改都总是表示为“删除某些现有行(虽然可能没有)”,后跟“添加某些新行(虽然可能没有)”。一个更改 - 即使只是更改、添加或删除行内的一个单词 - 也会删除一个非零数量的现有行并添加一个非零数量的新行。纯删除(一个或多个完整行)
添加零行,而纯插入
删除零行。最终,问题变成:“我们和他们的更改是否都触及了相同的行号?”上下文几乎变得无关紧要,除了当删除零行或插入零行时,上下文本身“是”行,在某种意义上。(如果这个说法让人难以理解,那是我的错。;-))
(还要记住,如果你在工作时修改“到目前为止合并的”文件,你必须在查看一个更改是否触及“相同”的行时使用
原始基础文件的行号。由于“我们”和“他们”都有
相同的基本版本,这是一个容易的捷径。)
三方合并不是补丁
请注意,这与应用
补丁不同,后者在没有公共基础版本的情况下完成。在补丁的情况下,上下文被更广泛地使用:diff hunk header 提供了搜索上下文的位置,但由于它可能被应用于文件的不同版本,上下文允许我们(和 Git)在
不同的行上进行相同的更改,只要上下文仍然匹配。
patch
工具在这里使用不同的算法(一个“最大模糊”因素,向上 / 向下查找那么多行)。Git 不会做模糊因素;如果需要,它将一直搜索到文件的开头或结尾。但是,在决定上下文不匹配之前,它确实有调整空格的选项。
使用git apply
应用补丁时,您可以添加-3
或--3way
以允许Git读取index
行,这些行提供了文件blob的部分或完整哈希ID。左侧的哈希ID是文件先前版本的哈希ID:请注意,在上面的所有差异中,“basefile”的“基础”版本具有ID df781c1
。如果Git能够从该ID找到唯一的blob,则可以假装那是合并基础,并将一个合并基础与HEAD
进行比较,将补丁本身视为另一个差异,并通过这种方式进行三方合并。这有时使得git apply
能够成功,而patch
则会失败。