38

我已经合并了 2 个分支并且出现了冲突,我需要一些提示,它从哪里开始到哪里结束,等等。我用一些伪造的数据替换了代码,以使其更容易阅读和讨论。

<<<<<<< HEAD
    aaaaaa
||||||| merged common ancestors
<<<<<<< Temporary merge branch 1
    bbbbbb
=======
    cccccc
>>>>>>> mybranch
    dddddd
<<<<<<< HEAD
    eeeeee
||||||| merged common ancestors
    ffffff
||||||| merged common ancestors
    gggggg
=======
>>>>>>> Temporary merge branch 2
=======
    hhhhhh
>>>>>>> mybranch
4

2 回答 2

51

您在此示例中看到的(带有Temporary merge branch标记)是 diff3 的结果,具有交叉合并冲突。我将用一系列定义来解释这一点。

定义

  • merge base:两个合并分支最近偏离的提交。当发生合并冲突时,对两个分支中的相同行进行了不同的更改。合并基础包含这些行在任一分支更改它们之前的内容。
  • 合并的共同祖先:diff3 输出一个额外的“中间”部分,显示合并基础中的行。这是两个分支的起点。
  • 交叉合并:一种合并历史,其中两个分支以一种不可能是快进合并的方式相互合并。我在下面举一个例子。在纵横交错的合并情况下,有多个合并基础
  • 临时合并分支:当有多个合并基础时,diff3 尝试将它们合并在一起(使用临时合并分支)以形成一个共同的祖先,以显示在 diff3 的中间部分。当没有冲突时,这可以无缝地工作,但是当有冲突时,您会在中间合并的共同祖先部分中看到临时合并分支的冲突标记。

交叉合并冲突场景示例

每当两个分支在不同的时间点相互合并时,就会发生交叉合并。

m3 *
   |\
   | \
   |  * B1
   |  |
m2 *  * B0
   |\/|
   |/\|
m1 *  * A
   | /
   |/
m0 *

考虑以下事件序列:

  • m0作为原点/主控存在
  • feature-A我通过一次提交创建了一个功能分支A
  • m1被别人致力于掌握
  • 我开始了一个新的功能分支feature-B,它建立在A
  • 我将origin/master( m1) 合并到feature-B. 它冲突,我解决它。合并提交是B0.
  • 我实现了 feature-B 并将工作提交为B1.
  • feature-A已准备好发货,因此有人将其合并到master. 它冲突。他们解决了它,但他们的解决方案与B0. 合并提交是m2.
  • feature-B已准备好发货,因此有人将其合并到master. git 尝试确定合并基数,但m1两者A都等同于合并基数。git 合并m1A在一个临时合并分支中,这会导致冲突。我们在合并的共同祖先部分看到 diff3 输出,类似于 OP 的问题。

读取输出

关闭 diff3 后,此合并冲突将如下所示:

<<<<<<< HEAD
    aaaaaa
=======
    hhhhhh
>>>>>>> mybranch

首先,使用所有额外的标记,您需要确定实际冲突的行是什么,以便将其与 diff3 共同祖先输出区分开来。

与合并的共同祖先的冲突模糊

aaaaaahhhhhh,这有点好。;-)

在两个冲突解决方案发生冲突的情况下,aaaaaa并且hhhhhh是两个解决方案。

接下来,检查合并的共同祖先的内容。

合并的共同祖先冲突,分组

有了这个特定的合并历史,就有超过 2 个合并基础,这需要多个临时合并分支,然后将它们合并在一起。当有许多合并基础和冲突时,结果可能会变得非常复杂且难以阅读。有人说不要打扰,只需针对这些情况关闭 diff3 即可。

另请注意,git 内部可能决定使用不同的合并策略来自动解决冲突,因此输出可能难以理解。如果可以的话,请理解它,但要知道它不是供人类食用的。mybranch在这种情况下,合并到Temporary merge branch 1betweenbbbbbb和时发生了冲突cccccc。Linedddddd在临时合并分支之间没有冲突。Temporary merge branch 2然后在合并时发生了单独的冲突HEAD,具有多个共同的祖先。HEAD已通过合并ffffffggggggas解决了冲突eeeeee,但Temporary merge branch 2通过删除(或移动)该行(因此======and之间没有行)解决了相同的冲突Temporary merge branch 2

你如何解决这样的冲突?虽然技术分析可能是可能的,但您最安全的选择通常是返回并查看围绕冲突的所有相关分支的历史记录,并根据您的理解手动制定解决方案。

避免这一切

这些冲突是最严重的,但有一些行为将有助于防止它们。

  1. 避免交叉合并。在上面的示例中,feature-B合并origin/masterB0. 这种与 master 保持最新的合并可能不是必需的(尽管有时是这样)。如果origin/master从未合并到feature-B中,则不会出现交叉合并,并且m3会与A作为唯一合并基础的正常冲突。

    m3 *              m3 *
       |\                |\
       | \               | \
       |  * B1           |  * B1
       |  |              |  |
    m2 *  * B0   VS   m2 *  |
       |\/|              |\ |
       |/\|              | \|
    m1 *  * A         m1 *  * A
       | /               | /
       |/                |/
    m0 *              m0 *
    
  2. 与冲突解决方案保持一致。在示例中,临时合并基础冲突仅发生,因为m2并且B0具有不同的冲突解决方案。如果他们以相同的方式解决了冲突,那m3将是一次干净的合并。意识到这是一个简单的交叉合并,应该具有相同的分辨率。其他情况可能有不同的解决方案。当合并点之间有超过 2 个合并基础和多个提交时,事情会变得更加复杂。也就是说,如果您在纵横交错的情况下故意与冲突解决方案不一致,那么以后会很头疼。
于 2015-10-29T16:43:18.710 回答
2

这是一篇关于git 的 diff3 合并样式的文章。它指出在这种风格中很难判断是添加还是删除了行。

如果您正在寻找特定信息,我建议您完善您的问题。很难说出你在问什么。

于 2013-06-07T18:29:35.887 回答