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 没法替你做决定,就报冲突。

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


相关推荐
bigHead-1 小时前
Git合并操作详解:安全高效地合并远程分支
git·安全·elasticsearch
C_心欲无痕1 小时前
ts - 交叉类型
前端·git·typescript
秋饼2 小时前
【K8S测试程序--git地址】
git·容器·kubernetes
小龙15 小时前
【Git 报错解决】本地无有效提交无法推送(`src refspec main does not match any`)
git·github·报错
小扶苏15 小时前
删除git全局账号信息并设置成新的账号密码命令
git
Greg_Zhong17 小时前
Git创建任务分支进行开发,最后合并主分支master【纯git命令执行过程】阐述
git
眯眼因为很困啦19 小时前
GitHub Fork 协作完整流程
前端·git·前端工程化
AlexDeng20 小时前
Git 中模糊搜索分支名称并创建本地跟踪分支
git
jxm_csdn1 天前
递归工程工厂:Claude Code + Git Worktrees + Tilix/Tmux 的“AI分身”编码团队
人工智能·git
码咔吧咔1 天前
Git 中 pull.rebase = true 的作用与设置方法详解
git