三路合并 —— Git 学习笔记 17

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013490896/article/details/83049840

三路合并

和其他版本控制系统不同,Git 提供的合并冲突解决方案并不会聪明过头,不会尝试自动将所有问题都解决。Git 的设计哲学是智能判断一个合并是否可以非常容易地自动完成,如果自动化方案不可行,就不要自作聪明地去尝试解决它,最好让用户自己去解决合并冲突。

文件层面

通过比较共同的祖先(base)、当前分支(ours),待合并分支(theirs),Git 采用三路合并算法生成合并结果。该算法至少在文件目录层面非常简单。其规则如下:

祖先(base) HEAD(ours) 分支(theirs) 结果 说明
A A A A
A A B B 如果一方修改了某个文件,选择修改版的文件
A B A B 如果一方修改了某个文件,选择修改版的文件
A B B B 如果双方拥有相同的变更,选择修改过的版本
A B C merge 如果一方包含与另一方不一样的变更,那么在内容层面存在合并冲突

内容层面

如果是最后一行的情况,那么 Git 就会在内容上尝试合并。我们举个例子,假设提交图如下:

B-C-D  master(*)
 \
  E-F  dev

目前所在分支是 master,当尝试把 dev 合并入 master 分支时,base 是提交 B,ours 是提交 D,theirs 是提交 F.

B、D、F 三个提交都有 foo.c 这个文件,它们的内容分别如下:

在这里插入图片描述

请问 Git 会怎么合并 ours 和 theirs 呢?

当然需要参考他们的共同祖先 base, 下图标出了ours 和 theirs 分别与祖先不同的地方(用下划线及蓝色背景表示)。

在这里插入图片描述

祖先(base) HEAD(ours) 分支(theirs) 结果 说明
A A A A
A A B B 如果一方修改了某一行,那么这一行选择修改版的
A B A B 同上
A B B B 如果某一行双方拥有相同的变更,则选择修改过的行
A B C conflict 如果某一行双方都修改了,且修改得不一样,则报告冲突,需要用户解决

根据上表的规则,合并过程类似这样:

在这里插入图片描述

可以看到,第四行,双方都修改了,且各自修改的内容不一样,所以 Git 不知道怎么解决,所以就把问题抛给用户了。

递归三路合并(Recursive three-way merge)

三路合并算法的基础是找到被合并文件的共同祖先文件。在遇到十字交叉合并(criss-cross merge)时,不存在独一无二的最小共同祖先。如下图所示,merge D 和 F 时,发现 C 和 E 都是它们的公共祖先,这可怎么办,C 和 E 哪一个作为 Base 呢?

B--C--D  master
 \  \/
  \ /\
   E--F  dev

Git 的策略是:先合并 C 和 E 得到一个虚拟的公共祖先 G,把这个 G 作为 Base. 那如果合并 C 和 E 的时候发现他们的公共祖先也不止一个怎么办?所以就要递归进行了。

如下图:合并 M 和 N,发现他们的共同祖先有2个——L 和 K,于是合并 L 和 K,又发现他们的祖先不止一个——I 和 J,于是合并 I 和 J,就这样递归下去。

B--C---D--I--L--M     master
 \         \/ \/  
  \        /\ /\
   E---F--J--K--N     dev

参考资料

【1】《Git 高手之路》,人民邮电出版社

【2】https://stackoverflow.com/questions/4129049/why-is-a-3-way-merge-advantageous-over-a-2-way-merge

【3】http://blog.fedeoo.cn/2017/02/22/git-合并策略-之-recursive/

猜你喜欢

转载自blog.csdn.net/u013490896/article/details/83049840