Git合并diff3风格需要说明 [英] Git merge diff3 style need explanation

查看:182
本文介绍了Git合并diff3风格需要说明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我合并了2个分支并出现了冲突,我需要一些提示,从哪里开始,等等。我用一些伪造的数据替换了代码,以便更易于阅读和讨论。

 <  aaaaaa 
|||||||合并的共同祖先
<< {<< 1,临时合并分支1
bbbbbb
=======
cccccc
>>>>>>> mybranch
dddddd
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HEAD
eeeeee
|||||||合并共同祖先
ffffff
|||||||合并共同祖先
gggggg
=======
>>>>>>>临时合并分支2
=======
hhhhhh
>>>>>>> mybranch


解决方案

临时合并分支标记)是diff3带有纵横交错冲突的结果。我会用一系列定义来解释这一点。



定义




  • merge base :两个合并分支最近分离的提交。当合并冲突发生时,对两个分支中的相同行进行了不同的更改。 merge base 包含那些行在任何分支改变它们之前的内容。

  • 合并的共同祖先:diff3输出额外的中间部分显示了它们在 merge base 中的行。这是两个分支机构的起点。

  • 交叉合并:合并历史记录,两个分支以不可能一直合并的方式合并快速合并。我在下面举一个例子。在纵横交错的情况下,有多个合并基

  • 临时合并分支:如果有多个合并基础,diff3尝试将它们合并在一起(使用临时合并分支)以形成一个共同祖先以显示在diff3的中间部分。这在没有冲突时可以无缝工作,但是当发生冲突时,您会在中间的合并共同祖先部分中看到临时合并分支的冲突标记。


示例十字交叉合并冲突情形



每当两个分支在不同点时间。

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

考虑这一系列事件: p>


  • m0 存在为原点/ m aster

  • 我使用一个提交 A
  • 创建一个功能分支 feature-A
  • m1 被其他人授予主人

  • 我开始一个新功能分支 feature-B 构建于 A

  • 我合并 origin / master m1 )转换为 feature-B 。它冲突,我解决它。合并提交是 B0

  • 我实现了功能B并将工作提交为 B1 feature-A 准备发货,所以有人将它合并到 master 。它冲突。他们解决它,但他们的决议不同于 B0 中的决议。合并提交是 m2

  • feature-B 准备发货,所以有人将它合并到 master 中。 git试图确定合并基础 ,但是 m1 A 基地。 git会在临时合并分支中合并 m1 A ,这会导致冲突。我们在合并的共同祖先部分看到diff3输出,类似于OP的问题。


读取输出



在diff3关闭的情况下,此合并冲突看起来就像这样:

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

首先,使用所有额外的标记,您需要确定实际冲突线是什么,所以你可以区分它与diff3共同的祖先输出。





aaaaaahhhhhh,那会好一点。 ; - )



在两个冲突解决方案冲突的情况下, aaaaaa hhhhhh



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





有了这个特定的合并历史,有两个以上的合并基地,这需要多个临时合并分支,然后合并在一起。当有许多合并基础和冲突时,结果会变得非常多毛,难以阅读。有些人说不用麻烦,只是在这些情况下关闭diff3。

另请注意,git内部可能会决定使用不同的合并策略来自动解决冲突,所以输出可能很难理解。如果可以的话,请理解它,但要知道它不适合人类消费。在这种情况下,当将 mybranch 合并到临时合并分支1 之间时发生冲突 bbbbbb cccccc 。行 dddddd 在临时合并分支之间没有冲突。然后,在将临时合并分支2 合并到 HEAD 时出现单独的冲突,其中包含多个共同的祖先。 HEAD 通过合并 ffffff gggggg 解决了冲突 eeeeee ,但临时合并分支2 通过删除(或移动)行来解决相同的冲突 ====== 临时合并分支2



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



避免所有这些



这些冲突是最糟糕的,但有一些行为可以帮助阻止它们。


  1. 避免交叉合并在上面的例子中,特性-B 合并 origin / master B0 。与主人约会是没有必要的(尽管有时我t是)。如果 origin / master 从未合并到 feature-B 中,则不会发生合并纵横交错, code> m3 A 作为唯一的合并基础是正常的冲突。

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


  2. 符合冲突解决方案。在这个例子中,只发生了临时合并基本冲突,因为 m2 B0 冲突决议。如果他们已经完全解决冲突,那么 m3 应该是一个干净的合并。意识到这是一个简单的纵横交错的合并,应该有相同的解决方案。其他情况可能正确地有不同的决议。当合并点之间有两个以上的合并基础和多个提交时,情况会变得更加复杂。也就是说,如果您在交叉情况下有意识地与冲突解决方案不一致,那么可以期待稍后的头痛。


I've merged 2 branches and conflicts appeared, I would need some hints where it starts where it ends, etc. I've replaced the code with some faked data to make it easier to read and talk about.

<<<<<<< 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

解决方案

What you're seeing in this example (with Temporary merge branch markers) is the result of diff3 with a criss-cross merge conflict. I'll explain this with a sequence of definitions.

Definitions

  • merge base: The commit where the two merging branches most recently diverged from. When a merge conflict occurs, different changes were made to the same lines in both branches. The merge base contains what those lines were before either branch changed them.
  • merged common ancestors: diff3 outputs an additional "middle" section showing the lines as they were in the merge base. This is the starting point for both branches.
  • Criss-cross merge: A merge history where two branches merge into each other in ways that one could not have been a fast-forward merge. I give an example below. In a criss-cross merge situation, there are multiple merge bases.
  • Temporary merge branch: When there are multiple merge bases, diff3 attempts to merge them together (using temporary merge branches) to form a single common ancestor to show in diff3's middle section. This works seamlessly when there are no conflicts, but when there are conflicts, you see the temporary merge branch's conflict markers inside the middle merged common ancestors section.

Example criss-cross merge conflict scenario

A criss-cross merge occurs whenever two branches merge into each other at different points in time.

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

Consider this sequence of events:

  • m0 exists as origin/master
  • I create a feature branch feature-A with one commit A
  • m1 gets committed to master by someone else
  • I start a new feature branch feature-B that builds on A
  • I merge origin/master (m1) into feature-B. It conflicts, and I resolve it. The merge commit is B0.
  • I implement feature-B and commit the work as B1.
  • feature-A is ready to ship, so someone merges it into master. It conflicts. They resolve it, but their resolution differs from the resolution in B0. The merge commit is m2.
  • feature-B is ready to ship, so someone merges it into master. git tries to determine the merge base, but m1 and A both qualify equally as merge bases. git merges m1 and A in a temporary merge branch, which results in a conflict. We see diff3 output in the merged common ancestors section, similar to the OP's question.

Reading the output

With diff3 off, this merge conflict would look simply like this:

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

First, with all the extra markers, you'll want to determine what the actual conflicting lines are, so you can differentiate it from the diff3 common ancestor output.

aaaaaahhhhhh, that's a little better. ;-)

In the case where two conflict resolutions are conflicting, aaaaaa and hhhhhh are the two resolutions.

Next, examine the content of the merged common ancestor.

With this particular merge history, there were more than 2 merge bases, which required multiple temporary merge branches which were then merged together. The result when there are many merge bases and conflicts can get pretty hairy and difficult to read. Some say don't bother, just turn off diff3 for these situations.

Also be aware that git internally may decide to use different merge strategies to auto-resolve conflicts, so the output can be hard to understand. Make sense out of it if you can, but know that it was not intended for human consumption. In this case, a conflict occurred when merging mybranch into Temporary merge branch 1 between bbbbbb and cccccc. Line dddddd had no conflicts between the temporary merge branches. Then a separate conflict occurred when merging Temporary merge branch 2 into HEAD, with multiple common ancestors. HEAD had resolved the conflict by merging ffffff and gggggg as eeeeee, but Temporary merge branch 2 resolved that same conflict by deleting (or moving) the line (thus no lines between ====== and Temporary merge branch 2.

How do you resolve a conflict like this? While technical analysis may be possible, your safest option is usually to go back and review the history in all the involved branches around the conflict, and manually craft a resolution based on your understanding.

Avoiding all this

These conflicts are the worst, but there are some behaviors that will help prevent them.

  1. Avoid criss-cross merges. In the example above, feature-B merged origin/master as B0. It's possible that this merge to stay up-to-date with master wasn't necessary (though sometimes it is). If origin/master was never merged into feature-B, there would have been no merge criss-cross, and m3 would have been a normal conflict with A as the only merge base.

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

  2. Be consistent with conflict resolutions. In the example, the Temporary merge base conflict only occurred because m2 and B0 had different conflict resolutions. If they had resolved the conflict identically, m3 would have been a clean merge. Realize though that this is a simple criss-cross merge that ought to have had the same resolution. Other situations may rightly have different resolutions. Things get more complicated when there are more than 2 merge bases and multiple commits between the merge points. That said, if you are knowingly inconsistent with conflict resolutions in criss-cross situations, expect headaches later.

这篇关于Git合并diff3风格需要说明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆