git merge diff3 风格需要解释

Posted

技术标签:

【中文标题】git merge diff3 风格需要解释【英文标题】:Git merge diff3 style need explanation 【发布时间】:2013-06-04 03:32:39 【问题描述】:

我已经合并了 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

【问题讨论】:

这个差异很奇怪。你能告诉我们原来的分支吗?原始文件是否包含合并标记 &lt;&lt;&lt;&lt;&lt;&lt; 【参考方案1】:

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

定义

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

交叉合并冲突场景示例

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

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

考虑这一系列事件:

m0 作为 origin/master 存在 我创建了一个功能分支feature-A,其中一次提交A m1 被其他人致力于掌握 我启动了一个新的功能分支feature-B,它建立在A 之上 我将origin/master (m1) 合并到feature-B。它冲突,我解决它。合并提交是B0。 我实现了功能 B 并以 B1 的身份提交工作。 feature-A 已准备好发货,因此有人将其合并到 master。它冲突。他们解决了它,但他们的分辨率与B0 中的分辨率不同。合并提交是m2feature-B 已准备好发货,因此有人将其合并到 master 中。 git 尝试确定 合并基数,但 m1A 都可以作为合并基数。 git 在一个临时合并分支中合并m1A,这会导致冲突。我们在 合并的共同祖先 部分看到 diff3 输出,类似于 OP 的问题。

读取输出

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

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

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

aaaaaaahhhhhh,这有点好。 ;-)

在两个冲突解决方案发生冲突的情况下,aaaaaahhhhhh 是两个解决方案。

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

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

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

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

避免这一切

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

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

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

【讨论】:

嗯,你添加了两次相同的答案?:***.com/a/33419598/456814. 是解决这个问题的方法,在第 3 步和第 4 步之间,将 A 从 master 中重新定位?一般来说,我讨厌合并提交,所以我不会在那里有 b0,但我对这个“交叉合并”是新手,所以我想看看如果没有合并提交,这种交叉合并是否可能。 @Tommy 正确。如果你和你的队友变基以使你的历史是线性的,那么如果你的历史在你的场景中是线性的,那么不可能有多个合并基地,因此不可能有一个纵横交错的合并。【参考方案2】:

这是一篇关于git's diff3 merge style 的文章。它指出在这种样式中很难判断是添加还是删除了行。

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

【讨论】:

很好的链接,谢谢。我对这篇文章的理解不同:很难区分默认冲突样式中的添加/删除(未显示),但 diff3 包含 ||||||| 标记以提供上下文,使我们能够推断更改是添加还是删除。

以上是关于git merge diff3 风格需要解释的主要内容,如果未能解决你的问题,请参考以下文章

git中Please enter a commit message to explain why this merge is necessary.

git提示Please enter a commit message to explain why this merge is necessary

git中Please enter a commit message to explain why this merge is necessary.

git中Please enter a commit message to explain why this merge is necessary.

git fetch, merge, pull, push需要注意的地方

Git-解释“Swap file .MERGE_MSG.swp already exists”的问题