导致git合并冲突的原因和案例是什么?

时间:2017-06-04 22:17:06

标签: git

  1. 什么是

    • 必要且充分的条件,和/或

    • 所有案件或一些常见案件

    会导致git merge报告合并冲突吗?

    git merge如何确定一行或一些行是否包含 合并冲突?

  2. 例如,我有时会看到如下情况,其中一种情况

    中的Part 1Part 2为空
    <<<<<<< HEAD
    (Part 1)
    =======
    (Part 2)
    >>>>>>> some-other-branch
    

    看起来不太可能与我发生合并冲突。那么有什么可能的原因呢 这样的案件有合并冲突吗?

  3. 比较git merge报告的合并冲突 git diff报告的差异是否正确

    • git diff报告的差异可能不一定在git merge报告的合并冲突的位置,

    • git merge报告的合并冲突可能不一定在git diff报告的差异的位置?

  4. 感谢。

1 个答案:

答案 0 :(得分:8)

完整正确的答案有多个部分。首先,我们必须首先进行正常的三向合并(在Git中需要使用-s recursive-s resolve,如果使用-s recursive,则需要找到一个合并基数和两个其他承诺)。但是,您可能希望跳到第三部分。

正常三向合并所需的元素

要完成任何合并,您需要:

  • 合并基地提交 B 1
  • 当前提交 L (左侧,又名HEAD B 作为祖先,
  • 另一个提交 R ,它还有 B 作为祖先。

因为&#34;是祖先&#34;允许在提交图中的节点相等(技术上它是先前或相等的比较),它可能有 B = L 和/或 B = R 。但是,如果是这种情况,则不需要合并 ,如果强制进行合并(使用git merge --no-ff - 这意味着 B = L L≺R;两个非强制案例是&#34;快进&#34;不实际合并和&#34;没什么要合并&#34;错误)没有合并冲突。因此,我们可以假设合并基础位于合并的两侧之前。

1 使用--allow-unrelated-histories,如果 L R 没有最低共同的祖先节点。但是,这会导致所有已识别的文件添加/添加冲突。

给定合并,冲突所需的元素

接下来,要在某个文件路径中出现冲突,您需要我称之为&#34;高级别&#34;冲突或低水平&#34;冲突(或两者兼而有之)。为此,Git必须识别 B L L R 中的(即匹配在一起)文件。由于能够添加新文件,重命名文件和删除文件,因此不要求文件在所有三次提交中都具有相同名称。特别是:

  • 如果路径 P 存在于 B L R 的所有三个中,则三个文件包含路径 P 一起识别。 (也就是说,路径 P B ,例如path/to/foo.txt,其匹配 P L path/to/foo.txt P R path/to/foo.txt。显然这个文件是&#34;同一个文件&#34;整个合并,因此Git将这三个路径标识为一个文件。)
  • 或者,最多可能有三条不同的路径, P B path/to/basename P L path2/to2/left P R path3/to3/right。这些中的一个或多个可能甚至不存在。这导致:添加/添加冲突,如果∄ P B P L = P R ;重命名/删除冲突,如果 P B 等于左路径或右路径之一,但另一路径不存在;或重命名/重命名冲突,如果 P B ≠P L ≠P R

如果还没有高级别冲突(添加/添加,重命名/重命名或重命名/删除),则可能仍存在重命名/修改或重命名/删除冲突,只要blob的哈希ID由两个或三个路径名称命名的(文件内容)不匹配。

所有这些&#34;高水平&#34;冲突导致合并冲突,但不会导致任何冲突标记。为此,我们现在必须将基本文件与两个侧文件合并(这意味着所有三个文件必须存在,或者对于添加/添加案例,我们将一个简单的空文件作为基本版本)。

此合并可能有也可能没有自己的冲突。如果合并增加了低级别冲突,我们将获得冲突标记。如果没有高级别冲突(所有三次提交中的路径相同)但需要完全合并(哈希值各不相同),我们可能会与冲突标记发生低级冲突。

Git对文件中的冲突需要什么

要在工作树中的一个文件中获得合并冲突,Git必须看到左侧和右侧版本都更改了同一行,但以不同方式更改了 。 (请记住,所有三个哈希值必须不同,因此Git将diff PB PL中的一组更改与diff PB PR中的更改结合起来。)

最明显且最不容易混淆的案例

最明显的情况发生在一方(让我们先选择左侧)说:

 unchanged context
-changed line
+replacement 1
 more unchanged context

和另一个说:

 unchanged context
-changed line
+replacement 2
 more unchanged context

这里删除一行或多行,而是插入一行或多行,但插入的行不匹配。在这种情况下,merge冲突样式将其表示为:

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

然后缺少mergediff3样式标记文件中的替换行的一个但不是两个。 (如果两个差异只是删除原始行,则没有冲突: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.

请注意,它现在显而易见 - 或者至少是神秘 - 在基本版本中有一行读取Line that will conflict.,我完全删除了左侧HEAD版本,并替换为右侧b2版本中的其他行。