完整,正确的答案有多个部分.首先,我们必须首先进行正常的三向合并(在Git中需要使用-s递归或-s
resolve,如果使用-s递归,则查找单个合并库和另外两个提交).但是,您可能希望跳到第三部分.
正常三向合并所需的元素
要进行任何合并,您需要:
>合并基础提交B,1
>当前提交L(左侧,又名HEAD),其中B为祖先,
>另一个提交R,也有B作为祖先.
由于“is ancestor”允许提交图中的节点相等(技术上它是先前或相等的≼比较),因此可能有B = L和/或B =
R.但是,如果是这种情况,那么就没有合并是必需的,如果你强制合并(使用git merge –no-ff-这意味着B =
L和L≺R;两个非强制情况是“快进”而不是实际合并和“没有合并“错误”将没有合并冲突.因此我们可以假设合并基础在合并的两侧之前.
1使用–allow-unrelated-histories,如果L和R没有最低共同祖先节点,则可以在空树中使用Git替换实际的基本提交.但是,这会导致所有标识的文件添加/添加冲突.
给定合并,冲突所需的元素
接下来,要在某个文件路径中发生冲突,您需要我称之为“高级别”冲突或“低级别”冲突(或两者).为此,Git必须识别(即匹配)B,L和R中的文件.由于能够添加新文件,重命名文件和删除文件,这不要求文件具有相同的名称在所有三个提交中.特别是:
>如果路径P存在于B,L和R的所有三个中,则具有路径P的三个文件被一起识别. (也就是说,有一个路径PB,比如path / to /
foo.txt,它有一个匹配的PL路径/到/ foo.txt和PR路径/到/
foo.txt.显然这个文件是“同一个文件”在整个合并期间,所以Git将三条路径标识为一个文件.)
>或者,最多可能有三个不同的路径,PB path / to / basename,PL path2 / to2 / left,以及PR path3 /
to3 / right.这些中的一个或多个可能甚至不存在.这导致:添加/添加冲突,如果∄PB和PL =
PR;重命名/删除冲突,如果PB等于左路径或右路径之一,但另一路径不存在;或者重命名/重命名冲突,如果PB≠PL≠PR.
如果还没有高级别冲突(添加/添加,重命名/重命名或重命名/删除),则可能仍存在重命名/修改或重命名/删除冲突,只要blob的哈希ID(文件内容)
)由两个或三个路径名称命名不匹配.
所有这些“高级别”冲突都会导致合并冲突,但不会导致任何冲突标记.为此,我们现在必须实际将基本文件与两个侧文件合并(这意味着所有三个文件必须存在,或者对于添加/添加案例,我们将一个简单的空文件作为基本版本).
此合并可能有也可能没有自己的冲突.如果合并增加了低级别冲突,我们将获得冲突标记.如果没有高级别冲突(所有三次提交中的路径相同)但需要完全合并(哈希值都不同),我们可能会与冲突标记产生低级别冲突.
Git需要什么来解决文件中的冲突
要在工作树中的一个文件中获得合并冲突,Git必须看到左侧和右侧版本都更改了相同的行,但是以不同的方式进行了更改.
(请记住,所有三个哈希值必须不同,因此Git正在组合一组变化,实际上是差异PB PL与差异PB PR的变化.)
最明显,最不容易混淆的案例
最明显的情况发生在一边(让我们先选择左边)说:
unchanged context
-changed line
+replacement 1
more unchanged context
另一个说:
unchanged context
-changed line
+replacement 2
more unchanged context
这里删除一行或多行,而是插入一行或多行,但插入的行不匹配.在这种情况下,合并冲突样式将其表示为:
unchanged context
<<<<<<< left-label
replacement 1
=======
replacement 2
>>>>>>> right-label
more unchanged context
diff3上下文样式将此呈现为:
unchanged context
<<<<<<< left-label
replacement 1
||||||| merged common ancestors
changed line
=======
replacement 2
>>>>>>> right-label
more unchanged context
如果我们只是添加文本,但在同一行添加不同的文本,我们也会遇到合并冲突.同样,来自每一侧的添加文本显示在冲突标记中. (如果我们将相同的文本添加到双方 –
作为新文本,或作为更改行的替换文本,Git将获取此添加的一个副本,并且没有冲突.)
有些令人困惑的案件
如果一个但不是两个替换行都是空的 – 即,如果左侧或右侧的diff读取:
unchanged context
-changed line
more unchanged context
然后缺少合并或diff3样式标记文件中的一个但不是两个替换行. (如果两个diff只删除原始行,则没有冲突:Git只删除一个.)
同样,如果一方在另一方删除的行的上方或下方添加一行,则会发生冲突.这次冲突表明保留 – 然后添加a的一侧有所有线,而另一侧没有线.例如:
some merge conflict.
Line that will conflict.
+add line below it
Rest of the
VS:
some merge conflict.
-Line that will conflict.
Rest of the
(如果添加上面的行而不是下面的行,也会出现相同的情况).
这是diff3冲突风格非常有用的地方.以下是其中一种情况的整个合并文件:
We need a base file
in which to make
some merge conflict.
<<<<<<< HEAD
||||||| merged common ancestors
Line that will conflict.
=======
Change the line that will conflict.
>>>>>>> b2
Rest of the
base file for the
merge conflict example.
请注意,现在很明显 – 或者至少不那么神秘 – 有一条线条会读取线条会发生冲突.在基本版本中,我完全从左侧HEAD版本删除,并替换为右侧b2版本中的不同行.