核心答案:Diff(差异对比)找出两个文本的最小改动集:− 开头的是旧文件被删除的行,+ 开头的是新增的行,无符号是上下文。背后核心算法是 LCS(最长公共子序列)——保留不变的部分,剩下的就是差异。

Diff 是什么

Diff 输出两个文件的「最小编辑脚本」:把文件 A 变成文件 B,需要删哪些行、加哪些行。

应用:Git 版本对比、代码审查(PR)、配置变更审计、论文修订对比、法律合同改订对照。

+/- 号怎么读

```diff

@@ -1,3 +1,4 @@

共同的上文行

-旧文件中这行被删除了

+新文件中这行是新增的

+这一行也是新增的

共同的下文行

```

  • @@ -1,3 +1,4 @@:hunk 头——旧文件从第 1 行起 3 行,新文件从第 1 行起 4 行
  • 空格开头:上下文(两边都有,用于定位)
  • 逐字符 diff 中:~~删除线~~ 与 高亮 标记词级差异

算法原理

LCS(最长公共子序列)思路

  1. 找出两文件相同行的最长序列(保序但不必连续)
  2. 不在 LCS 中的旧文件行 = 删除
  3. 不在 LCS 中的新文件行 = 新增

动态规划:dp[i][j] = A 前 i 行与 B 前 j 行的 LCS 长度

  • A[i] == B[j]:dp[i][j] = dp[i−1][j−1] + 1
  • 不等:dp[i][j] = max(dp[i−1][j], dp[i][j−1])

Myers 算法:Git 实际使用,把问题转为「最短编辑距离」图搜索,时间复杂度 O((N+M)D),D 为差异行数——差异越小越快。

Git diff 实战

```bash

git diff # 工作区 vs 暂存区

git diff --cached # 暂存区 vs 上次提交

git diff main..dev # 两分支差异

git diff HEAD~3 # 当前 vs 3 个提交前

git log -p file.txt # 单文件逐版本 diff

```

读 PR 的技巧:先看 hunk 头(@@ 行)了解改动位置,再看 +/- 行;大改动配合 --stat 看文件级概览。

合并冲突基础

冲突产生:同一文件的同一区域,两个分支都改了——Git 无法自动取舍:

```

<<<<<<< HEAD

当前分支的内容

=======

合并进来的内容

>>>>>>> feature

```

解决步骤

  1. 打开冲突文件,理解两边改动意图
  2. 手动编辑保留正确版本(或两者合并)
  3. 删除 <<<<<<<、=======、>>>>>>> 标记
  4. git add 标记解决,完成合并

预防:小步提交、频繁同步主干、同一文件的热点区域模块化拆分。

常见误区

  • 「diff 显示的是新文件内容」:diff 显示的是变化指令,不是任何一边的完整文件
  • 移动代码块 = 删除+新增:diff 无法识别「移动」,一块代码换位置显示为大段 − 和大段 +,属正常现象
  • 空行/缩进改动无意义:空白变化同样产生 diff(代码审查噪音),可用 git diff -w 忽略空白
  • 冲突标记直接提交:<<<<<<< 标记忘了删就提交,直接把语法错误带进仓库——合并后先编译/测试再提交

常见 diff 场景对照表

场景命令/方式输出特点
工作区 vs 暂存区git diff未暂存的改动
暂存区 vs 上次提交git diff --cached已暂存待提交
两分支对比git diff main..dev分支间全部差异
两文件对比diff a.txt b.txt行级差异
目录递归对比diff -r dir1 dir2含新增/缺失文件
只看变更统计git diff --stat每文件增删行数

unified diff 格式速读表

标记含义
@@ -a,b +c,d @@旧文件第 a 行起 b 行 → 新文件第 c 行起 d 行
行首 −旧文件有、新文件删掉的行
行首 +新文件新增的行
行首空格上下文(两边都有)
--- / +++旧/新文件名与版本

实例:@@ -10,7 +10,6 @@ 表示从第 10 行起,旧文件 7 行内容在新文件变成 6 行——即净删 1 行。代码审查时先看 @@ 头定位,再看 +/- 行确认改动意图。