Git 合并 diff3 样式需要说明 [英] Git merge diff3 style need explanation
问题描述
我合并了 2 个分支并出现了冲突,我需要一些提示,它从哪里开始到哪里结束等等.我用一些伪造的数据替换了代码,以便于阅读和讨论.
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
推荐答案
你在这个例子中看到的(带有 Temporary merge branch
标记)是 diff3 与交叉合并的结果冲突.我将用一系列定义来解释这一点.
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.
- merge base:两个合并分支最近偏离的提交.当发生合并冲突时,对两个分支中的同一行进行了不同的更改.merge base 包含这些行在任一分支更改它们之前的内容.
- 合并的共同祖先:diff3 输出一个额外的中间"部分,显示它们在合并基础中的行.这是两个分支的起点.
- 纵横合并:合并历史,其中两个分支以一种不可能是快进合并的方式相互合并.我在下面举一个例子.在交叉合并的情况下,有多个合并基.
- 临时合并分支:当有多个合并基时,diff3尝试将它们合并在一起(使用临时合并分支)以形成一个共同祖先 显示在 diff3 的中间部分.这在没有冲突时无缝地工作,但是当有冲突时,您会在中间合并的共同祖先部分中看到临时合并分支的冲突标记.
- 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.
每当两个分支在不同的时间点相互合并时,就会发生纵横合并.
A criss-cross merge occurs whenever two branches merge into each other at different points in time.
m3 *
|
|
| * B1
| |
m2 * * B0
|/|
|/|
m1 * * A
| /
|/
m0 *
考虑这一系列事件:
m0
作为 origin/master 存在- 我用一次提交
A
创建了一个特性分支 m1
被其他人承诺掌握- 我在
A
上创建了一个新的功能分支 - 我将
origin/master
(m1
) 合并到feature-B
中.它发生冲突,我解决了它.合并提交是B0
. - 我实现了功能 B 并将工作提交为
B1
. feature-A
已准备好发布,因此有人将其合并到master
中.它冲突.他们解决了它,但他们的分辨率与B0
中的分辨率不同.合并提交是m2
.feature-B
已准备好发布,因此有人将其合并到master
中.git 尝试确定 merge base,但m1
和A
都同样符合合并基础.git在一个临时合并分支中合并m1
和A
,导致冲突.我们在合并的共同祖先部分看到了 diff3 输出,类似于 OP 的问题.
feature-A
feature-B
m0
exists as origin/master- I create a feature branch
feature-A
with one commitA
m1
gets committed to master by someone else- I start a new feature branch
feature-B
that builds onA
- I merge
origin/master
(m1
) intofeature-B
. It conflicts, and I resolve it. The merge commit isB0
. - I implement feature-B and commit the work as
B1
. feature-A
is ready to ship, so someone merges it intomaster
. It conflicts. They resolve it, but their resolution differs from the resolution inB0
. The merge commit ism2
.feature-B
is ready to ship, so someone merges it intomaster
. git tries to determine the merge base, butm1
andA
both qualify equally as merge bases. git mergesm1
andA
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.
关闭 diff3 后,这个合并冲突看起来就像这样:
With diff3 off, this merge conflict would look simply like this:
<<<<<<< HEAD
aaaaaa
=======
hhhhhh
>>>>>>> mybranch
首先,使用所有额外的标记,您需要确定实际的冲突行是什么,以便将其与 diff3 共同祖先输出区分开来.
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,那好一点.;-)
aaaaaahhhhhh, that's a little better. ;-)
在两个冲突解决方案冲突的情况下,aaaaaa
和hhhhhh
就是两个解决方案.
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.
在这个特定的合并历史中,有超过 2 个合并基础,这需要多个临时合并分支,然后将它们合并在一起.当有许多合并基础和冲突时,结果会变得非常复杂且难以阅读.有人说不要打扰,只需在这些情况下关闭 diff3.
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.
另请注意,git 内部可能会决定使用不同的合并策略来自动解决冲突,因此输出可能难以理解.如果可以,请理解它,但要知道它不是供人类食用的.在这种情况下,在bbbbbb
和cccccc
之间将mybranch
合并到Temporary merge branch 1
时发生了冲突.行 dddddd
在临时合并分支之间没有冲突.然后在将Temporary merge branch 2
合并到HEAD
时发生了单独的冲突,具有多个共同的祖先.HEAD
已经通过将 ffffff
和 gggggg
合并为 eeeeee
解决了冲突,但是 Temporary merge branch 2
通过删除(或移动)该行(因此 ======
和 Temporary merge branch 2
之间没有行)解决了同样的冲突.
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.
这些冲突是最糟糕的,但有一些行为可以帮助防止它们.
These conflicts are the worst, but there are some behaviors that will help prevent them.
避免交叉合并.在上面的例子中,
feature-B
将origin/master
合并为B0
.可能不需要这种合并以与 master 保持同步(尽管有时是这样).如果origin/master
从未合并到feature-B
中,就不会有合并纵横交错,m3
会是一个正常的与A
作为唯一的合并基础发生冲突.
Avoid criss-cross merges. In the example above,
feature-B
mergedorigin/master
asB0
. It's possible that this merge to stay up-to-date with master wasn't necessary (though sometimes it is). Iforigin/master
was never merged intofeature-B
, there would have been no merge criss-cross, andm3
would have been a normal conflict withA
as the only merge base.
m3 * m3 *
| |
| |
| * B1 | * B1
| | | |
m2 * * B0 VS m2 * |
|/| | |
|/| | |
m1 * * A m1 * * A
| / | /
|/ |/
m0 * m0 *
m2
和B0
有不同的冲突解决方案.如果他们以相同的方式解决了冲突,m3
将是一个干净的合并.意识到这是一个简单的交叉合并,应该具有相同的分辨率.其他情况可能有不同的解决方案.当合并点之间有 2 个以上的合并基础和多个提交时,事情会变得更加复杂.也就是说,如果您在纵横交错的情况下故意不同意冲突解决方案,那么以后可能会头疼.
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屋!