前言
我们的日常开发都是多人协作式开发,必然会遇到不同的人在不同的分支上对同一份代码做了改动。
这种情况下,当我们合并这两个分支时,版本管理工具(比如 Git
) 必须考虑如何处理这些改动,应该保留/丢弃哪个分支的哪些改动。
版本管理工具的合并流程分两种:
- 自动合并:版本管理工具判断自己就可以合并改动,则自动合并,适用简单的、没有复杂冲突的合并
- 手动合并:工具搞不定,只能人工来介入
合并算法
three-way merge
:三路合并recursive three-way merge
:递归三路合并
three-way merge - 三路合并
我们有三个文件 P
, A
, B
,其中:
P 是原始文件,我们把它的内容分成四个部分 X Y Z W
。
A:修改了 Z & W
,Z -> Z1, W -> W1
B:修改了 Y & W
,Y -> Y1, W -> W2
现在我们要合并 A & B。
三路合并的过程:
X
部分在 P, A, B 相同,保留X
到最终文件Y
部分在 P, A 相同,B 修改成Y1
,保留Y1
到最终文件Z
部分在 P, B 相同,A 修改成Z1
,保留Z1
到最终文件W
部分在 P, A, B 中均不相同,需要手动处理代码冲突,手动合并代码
算法特点:
- 合并的两个文件必须拥有 唯一的共同祖先(如果有多个共同祖先,需要使用下面的
recursive three-way merge
算法) - 同一块代码,在三个文件(两个修改文件+原始文件)只出现了两个版本:可以自动合并
- 同一块代码,在三个文件(两个修改文件+原始文件)出现了三个版本:只能手动合并
实现软件
- diff3
- diff
Git
resolve
recursive three-way merge - 递归三路合并
如果要合并的两个文件有 多个共同祖先,则把这些共同祖先合并成一个文件,然后就可以 三路合并 了。
注意:合并共同祖先为一个文件 本身就是三路合并,如果这些祖先的共同祖先不止一个,又要重复上面的过程;
这是一个递归的过程,这就是 recursive three-way merge
。
Git 合并策略
Git 提供了多种合并策略:
resolve
: 传统的three-way merge
recursive
:recursive three-way merge
,当我们pull
或merge
时默认这种合并算法。octopus
:合并多于两个分支时默认这种算法
参考资料
- https://en.wikipedia.org/wiki/Merge_(version_control)