云计算百科
云计算领域专业知识百科平台

Git 合并原理:三向合并与冲突判定

Git 合并原理:三向合并与冲突判定

Git 合并的本质是:找到共同祖先 → 三向比对 → 自动合并或报冲突。理解这个模型,遇到任何合并场景都能准确预判结果。

一、三向合并(Three-Way Merge)

1.1 为什么需要三向合并

直觉上合并两个文件只需要比较这两个文件(二向合并),但仅凭两个文件无法确定改动归属。

例如两个分支同一行代码:

  • 分支A:Print("hello")
  • 分支B:Print("world")

Git 无法判断:是 A 改了、B 改了,还是两边都新增了。

1.2 共同祖先(Common Ancestor)

三向合并引入一个共同祖先作为参照基准。Git 合并时比较的三个版本:

  • Base(祖先):两个分支分叉之前的版本
  • Ours(当前分支):所在分支的最新版本
  • Theirs(待合并分支):要合并进来的分支的最新版本

合并逻辑以 Base 为参照:

场景BaseOursTheirs合并结果
1 o o b 取 b
2 o a o 取 a
3 o a a 取 a
4 o a b 冲突

简而言之:以 Base 为参照,谁改了就用谁的;两边都改了且不同,就冲突。

1.3 冲突的本质

冲突的本质是三方都互不相同。相对于共同祖先,当前分支和待合并分支对同一处都做了修改,且修改内容不同。

Git 在冲突文件中标记双方内容:

<<<<<<< HEAD
(当前分支的内容)
=======
(待合并分支的内容)
>>>>>>> branch-name

二、合并策略

2.1 Fast-forward(快进合并)

触发条件:当前分支是待合并分支的直接祖先,两个分支没有分叉,存在线性路径。

做法:Git 将当前分支指针直接移动到目标分支的最新提交,不产生新的合并提交。

main → A ← B ← C (feature)

git checkout main
git merge feature

main/feature → A ← B ← C

特点:历史保持线性;如需强制生成合并提交,使用 git merge –no-ff。

2.2 Recursive(递归三向合并)

触发条件:两个分支有分叉,无法快进合并。这是 Git 合并有分叉分支时的默认策略。

核心算法:递归寻找路径最短的共同祖先节点(即 merge base),以其为 base 进行三向合并。

2.3 多个共同祖先的处理

当两个分支存在多个共同祖先时,Git 会先递归地将所有共同祖先合并成一个虚拟提交(virtual commit),再以这个虚拟提交作为新的 base 进行三向合并。这就是"递归"二字的由来——不断向上追溯,直到找到唯一共同祖先。

源码层面,递归合并算法实现在 Git 源码 merge-recursive.c 中,单文件三向合并在底层由 xdl_merge 函数完成。

2.4 其他策略

策略说明
Ours 保留当前分支内容,忽略待合并分支改动
Theirs 采用待合并分支内容
Octopus 同时合并两个以上分支

三、详细示例

3.1 简单三向合并

B (ours): 文件1=6, 文件2=2
/
A (base): 文件1=1, 文件2=2
\\
C (theirs): 文件1=8, 文件2=24

当前在 B 分支执行 git merge C:

文件BaseOurs (B)Theirs ©结论
文件1 1 6 (改了) 8 (改了) 冲突
文件2 2 2 (未改) 24 (改了) 取 24

文件1 需手动解决冲突,文件2 自动变为 24。

3.2 多个共同祖先(递归合并)

合并 B 和 D 时,共同祖先有 A 和 C 两个:

B
/ \\
A C
\\ /
D

处理流程:

  • 先合并 A 和 C:找到 A 和 C 的共同祖先(假设为 O),三向合并得到虚拟提交 X
  • 再以 X 为 base,用 X、B、D 进行三向合并
  • 虚拟提交 X 就是"递归"产生的中间结果。

    3.3 一个经典陷阱:revert 后重新合并

    A → B (dev新增http.js) → E (合并到master) → E' (revert撤回合并)
    \\ /
    dev继续开发 → D (新增main.js,import http.js)

    再次将 D 合并到 master 时,http.js 文件消失,且没有任何冲突提示。

    原因:revert 一个 merge commit 不会改变共同祖先的位置。Git 认为 http.js 在 master 上已经被删除(通过 revert),而 dev 上虽然存在,但合并时"删除"操作的优先级更高,于是文件就消失了。

    理解 Git 的合并原理,才能避免这类"Git 有 bug"的错觉。

    四、总结

    核心概念说明
    三向合并 比较 Base、Ours、Theirs 三个版本,以 Base 为参照判断改动
    共同祖先 合并的基准点,决定哪些改动是"新增的"
    Fast-forward 无分叉时的指针移动,不产生合并提交
    Recursive 有分叉时的默认策略,递归处理多个共同祖先
    冲突 三方都不同时产生,需手动解决
    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Git 合并原理:三向合并与冲突判定
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!