详细介绍Git分支合并冲突时的三方合并算法(原理深度游)

落晨酱_7609

落晨酱_7609

2026-07-01

224人浏览

原创

三方合并必须找共同祖先,因为git需以该基准点区分“谁修改了哪行”:若无base,无法判断相同变更是双方共识还是单方操作,易致误冲突或静默丢代码。

详细介绍git分支合并冲突时的三方合并算法(原理深度游)

三方合并为什么必须找共同祖先

Git 不是简单对比两个分支的最新文件,而是必须定位到 HEAD 和 MERGE_HEAD 的最近共同祖先(merge base)。没有这个基准点,就无法判断某行变化是“你加的”还是“对方删的”。比如两份文件都少了同一行,可能是你删了、对方也删了(应保留删除),也可能是你没动、对方删了(应采纳删除)——只有通过三方比对才能区分。

Git 底层用 get_merge_base() 在提交 DAG 中递归搜索,若存在多个候选祖先(如 Octopus 合并),还会进一步筛选最低公共祖先。一旦找错 base,后续所有差异计算都会失准,轻则误报冲突,重则静默丢代码。

冲突标记

当 diff_tree_merge() 发现同一文件在 ancestor→HEAD 和 ancestor→MERGE_HEAD 两组差异中,都修改了完全重叠的行范围时,Git 就会拒绝自动合并,并在工作区文件里写入冲突标记。

这些标记不是 Git “插入”的文本,而是由 merge-recursive.c 中的 traverse_trees_recursive() 在写入工作区时主动注入的:

  • 到 <code>======= 之间是 HEAD 分支的变更内容(即你本地暂存区 Stage 2 的快照)
  • ======= 到 >>>>>> feature-x 之间是 MERGE_HEAD 分支的变更内容(即远端 Stage 3)
  • 中间不会出现 Stage 1(base)的原始内容——它只存在于 Index 中,供 git diff --ours 或 git diff --theirs 调用

Index 里三个 stage 是怎么共存的

冲突发生后,git ls-files -u 会列出同一个文件名对应三行输出,每行带不同 stage 编号和 blob hash。这说明 Git 的 Index(暂存区)此时不再是一维表,而是一个支持多版本映射的结构。

GitHub Safe Sync
GitHub Safe Sync

检查、触发并清理使用安全同步 GitHub Actions 工作流的 GitHub 镜像仓库,用于 Codex 需要进行仓库镜像同步时。

下载

Stage 1/2/3 并非临时状态,而是 Git 合并引擎的正式接口设计:

  • Stage 1 存的是共同祖先版本的 blob hash,不可编辑,仅作比对依据
  • Stage 2 是当前分支(HEAD)修改后的版本,对应你本地工作区“看起来应该保留”的内容
  • Stage 3 是待合并分支(MERGE_HEAD)的版本,代表对方的意图
  • 执行 git add <file></file> 后,这三个 stage 记录会被清空,Index 回归 Stage 0 单一状态

很多人以为手动删掉冲突标记就完了,其实只要 Stage 1/2/3 还在 Index 里,git status 就永远显示 Unmerged paths,git commit 也会被拒绝。

为什么 git merge --no-ff 能帮你避开部分隐性冲突

--no-ff 强制创建 merge commit,表面看只是多一个提交节点,实际影响深远:它把每次合并的三方关系(base + ours + theirs)固化为一次明确的提交对象,后续 git blame 或 git log --merge 都能回溯到该次合并的完整上下文。

更关键的是,它避免了 fast-forward 合并带来的“历史扁平化”问题——如果连续几次 FF 合并,共同祖先可能退回到数周前的某个旧提交,导致后续合并时 base 过老,把本可自动解决的修改判为冲突。而带 merge commit 的历史,让 Git 总能找到更近、更准确的 base。

真正容易被忽略的点是:--no-ff 不改变三方算法本身,但它让 base 的选取更稳定、更可预期。这不是“防冲突”,而是“让冲突更可信”。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
自建git服务器
自建git服务器

git服务器是目前流行的分布式版本控制系统之一,可以让多人协同开发同一个项目。本专题为大家提供自建git服务器相关的各种文章、以及下载和课程。

2023.07.05

5439

9

git和svn的区别
git和svn的区别

git和svn的区别:1、定义不同;2、模型类型不同;3、存储单元不同;4、是否拥有全局版本号;5、内容完整性不同;6、版本库不同;7、克隆目录速度不同;8、分支不同。php中文网为大家带来了git和svn的相关知识、以及相关文章等内容。

2023.07.06

1640

6

git撤销提交的commit
git撤销提交的commit

Git是一个强大的版本控制系统,它提供了很多功能帮助开发人员有效地管理和控制代码的变更,本专题为大家提供git 撤销提交的commit相关的各种文章内容,供大家免费下载体验。

2023.07.24

954

5

git提交错误怎么撤回
git提交错误怎么撤回

git提交错误撤回的方法:git reset head^:撤回最后一次提交,恢复到提交前状态。git revert head:创建新提交,内容与之前提交相反。git reset :使用提交的 sha-1 哈希撤回指定提交。交互式舞台区:标记要撤回的特定更改,然后提交,排除已撤回更改。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.09

3557

7

git怎么对比两个版本的文件内容
git怎么对比两个版本的文件内容

要对比两个版本的 git 文件,请使用 git diff 命令:git diff 比较工作树和暂存区之间的差异。git diff 比较两个提交或标签之间的差异。git diff 输出显示差异块,其中 + 表示添加的行,- 表示删除的行, 表示修改的行。可使用 gitkraken、meld、beyond compare 等可视化工具更直观地查看差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.09

3241

6

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

2023.08.14

5056

4

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

20

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

0

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

0

12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
vscode手册
vscode手册

共0课时 | 0人学习

Git 教程
Git 教程

共21课时 | 7.9万人学习

Git版本控制工具
Git版本控制工具

共8课时 | 1.8万人学习