版本控制中的三方合并

在学习Git时,一般会学到Git的合并方式,除了快进之外,还有三方合并(three way erge)。三方合并也是Subversion等传统版本控制软件的合并策略。本文讲解什么是三方合并,为何需要三方合并,为何不使用两方合并。

考虑以下两个分支,其中1bdd3be5d6c1b0e2为这两个分支的Git版本号

1bdd3be5 d6c1b0e2
1
2
3
4
5
5
4
3
2
1

要将他们合并,请问合并后的文件是什么样?

这里不能根据上下文语义确定内容,读者看到这里估计都懵了。

但是如果知道1bdd3be5d6c1b0e2的共同祖先呢?如下图,1bdd3be5修改自ba8beb31d6c1b0e2也修改自ba8beb31。请问这两个分支将如何合并?

ba8beb31
<---- 5
4
3
4
1
—->
1bdd3be5 d6c1b0e2
1
2
3
4
5
5
4
3
2
1

经过分析,我们把修改的行用*标识出来。

ba8beb31
<---- 5
4
3
4
1
—->
1bdd3be5 d6c1b0e2
*1
*2
 3
 4
*5
 5
 4
*3
*2
 1

这样一看我们就清楚了,只需要把差异项合并,合并后的文件就是
1
2
3
2
5

由此可见共同祖先对于分支合并是非常重要的,没有共同祖先,我们就难以确定如何合并,遑论机器了。这同时也说明,“两方合并”是不可行的。

不同的共同祖先对合并有影响吗,答案是肯定的。见下一个例子,设37b21605为那两个分支的共同祖先,差异行已标出。

37b21605
<---- 5
2
3
2
1
—->
1bdd3be5 d6c1b0e2
*1
 2
 3
*4
*5
 5
*4
 3
 2
 1

这个情况下的合并结果为
1
4
3
4
5

所以,如果版本控制系统不能正确确定两个版本的共同祖先,则会造成意外的合并结果。

现在回归到Git与Subversion,鉴于Git以链表方式存储版本,非常容易确定两个分支的最近共同祖先

https://github.com/gqqnbig/git-conflict-test

发表评论

电子邮件地址不会被公开。

:wink: :twisted: :roll: :oops: :mrgreen: :lol: :idea: :evil: :cry: :arrow: :?: :-| :-x :-o :-P :-D :-? :) :( :!: 8-O 8)