Git篇(7):Git 检测差异的原理——为什么合并会出现冲突

Git 在检测差异时,不是像 Word 那样按"字节对比",也不是按"行号硬比对",而是用 最长公共子序列(LCS, Longest Common Subsequence)算法 来找出改动区域(diff hunk)。

流程可以这样理解:

  1. 找到两个版本的文件(来自不同 commit 的 blob)。
  2. 用 LCS 算法比对两份文本,定位哪些行相同、哪些行不同。
  3. 把不同的地方划分成"差异块 hunk"
  4. 输出成 diff 格式,再用于 merge 或显示。

👉 所以,Git 的差异检测是基于"行内容 + 相邻上下文",不是行号。


可视化:差异检测的例子

假设共同祖先版本(C2):

css 复制代码
A
B
C
D
E

远程提交(C3)改了 B → B'

css 复制代码
A
B'
C
D
E

本地提交(C4)改了 D → D'

css 复制代码
A
B
C
D'
E

第一步:找共同祖先

C2 就是共同祖先(A-B-C-D-E)。


第二步:算 diff

  • C2 → C3 的 diff:
css 复制代码
- B
+ B'
  • C2 → C4 的 diff:
diff 复制代码
- D
+ D'

第三步:定位差异块

Git 会生成两个差异块(hunk):

  • hunk1:涉及 B 的改动
  • hunk2:涉及 D 的改动

第四步:合并

Git 尝试把 hunk1 和 hunk2 应用到 C2:

  • hunk1 改 BB'
  • hunk2 改 DD'

结果合并后:

css 复制代码
A
B'
C
D'
E

👉 自动合并成功,因为两个 hunk 不重叠。


冲突的例子

共同祖先(C2):

css 复制代码
A
B
C

远程提交(C3):B → X

css 复制代码
A
X
C

本地提交(C4):B → Y

css 复制代码
A
Y
C

diff

  • C2 → C3 的 diff: - B + X
  • C2 → C4 的 diff: - B + Y

hunk 对比

Git 发现两个 diff 都作用在同一个位置(B),修改冲突,无法自动决定保留 X 还是 Y

于是标记冲突:

markdown 复制代码
A
<<<<<<< HEAD
Y
=======
X
>>>>>>> origin/main
C

Git 的差异检测原理总结

  1. 基于 LCS 算法,找出文件两版本的最长公共子序列。

  2. 把"非公共部分"标记为差异块(hunk)。

  3. 合并时:

    • 如果 hunk 不重叠 → 自动合并
    • 如果 hunk 重叠 → 冲突

总结与比喻

Git 检测差异就像两个人修改一本书:

  • Git 会先找到书里大家都没改过的段落(LCS)("行"是比较的最小单位);
  • 把大家改动的部分标记出来(hunk)(连续的差异行);
  • 如果改动在不同段落,直接合并;
  • 如果改动在同一行文字,Git 没法替你做决定,就报冲突。

在此强调,从头到尾,都不涉及"行号"的比较,这是误解的根源。


相关推荐
老友記4 小时前
git cherry-pick使用
git
练习时长一年5 小时前
git常用命令总结
大数据·git·elasticsearch
hadage2337 小时前
--- git 的一些使用 ---
开发语言·git·python
4***V20213 小时前
GitLab Pages配置
git·gitlab·github
CelineCoding13 小时前
git 处理异常操作
git
E***q53914 小时前
Git版本控制常见问题
git
sulikey20 小时前
从入门到精通:如何自己编写高质量的 .gitignore(面向工程实践)
git·gitee·编辑器·gitlab·github·gitignore·gitattributes
青靴1 天前
轻量级 CI/CD:Git Hooks 自动部署 Node.js 应用(CICD-demo)
git·ci/cd·node.js
哟哟耶耶1 天前
git-git cherry-pick(从分支挑选特定提交-哈希值)更改应用到当前分支
git
无限进步_1 天前
C语言动态内存管理:掌握malloc、calloc、realloc和free的实战应用
c语言·开发语言·c++·git·算法·github·visual studio