diff -u 是什么
diff 比较两个文件或目录的差异,-u 让它输出统一格式(unified diff):带 --- 与 +++ 文件头、@@ 区块位置,以及若干行上下文。这个格式被 patch、git apply 与各类代码评审工具共同采用,是「变更如何被描述与传输」的通用语言。
基本信息
| 适用平台 | Linux/Unix(diffutils;GNU diff 与 BSD diff 选项略有差异) |
|---|---|
| 命令语法 | diff -u 旧文件 新文件 > 变更.patch |
| 常用选项 | -u 统一格式 -r 递归比较目录 -N 缺失文件当空文件 -q 只报告是否不同 --label 自定义文件名标签 |
| 典型组合 | diff -ruN 旧目录 新目录 > 整树补丁 |
| 退出码 | 0 无差异、1 有差异、2 出错,脚本里要注意 1 不是失败 |
典型使用场景
- 比较配置改动:把备份与当前配置 diff 一下,确认改了什么
- 生成补丁交付:把修复整理成 .patch 发给对方应用
- 代码评审准备:目录对目录比较,先看清整体改动范围
- 排查「改过但没生效」:确认当前文件确实与预期版本一致
- 版本核对:确认两台机器上的同一配置是否一致
常用示例
常用示例
diff -u app.conf.bak app.conf > app.patch # 单文件补丁
diff -ruN conf.old conf.new > site.patch # 整目录补丁,含新增与删除
diff -u --label a/app.conf --label b/app.conf old new > app.patch # 固定路径标签
diff -q conf.old/app.conf conf.new/app.conf # 只想知道是否不同
diff -u <(sort a.txt) <(sort b.txt) # 排序后再比内容集合补丁头字段读法
| 标记 | 含义 | 注意 |
|---|---|---|
| --- 旧文件 | 被比较的源文件与时间戳 | 路径里通常带 a/ 前缀 |
| +++ 新文件 | 目标文件与时间戳 | 对应 b/ 前缀 |
| @@ -x,y +m,n @@ | 区块在两侧文件中的起止行号 | 应用时的定位依据 |
| 以空格开头 | 上下文行 | 两侧一致,用于校验位置 |
| 以 - 开头 | 删除的行 | 只在旧文件中存在 |
| 以 + 开头 | 新增的行 | 只在新文件中存在 |
| Binary files differ | 二进制文件无法生成文本差异 | 需改用 cmp 或校验和对比 |
补丁头里的 a/ b/ 前缀决定应用时 patch 的 -p 参数:a/ b/ 风格对应 -p1,没有前缀的本地文件对应 -p0。用 --label 可以把路径固定成想要的形态,避免因为临时目录不同而生成难以应用的补丁。
比较目录时加 -N:否则新建的文件不会出现在补丁里,应用时会缺文件。git diff --no-index 也可以用来比较两个不在仓库里的目录,输出同样可以用 git apply。
上下文行数可以调:默认 3 行,-U0 只输出改动本身适合机器处理,-U5 或更多上下文适合给人评审。上下文越多,补丁越容易读,但在原文稍有偏移时越难应用成功;给自动化用的补丁可以酌情减少上下文,给人看的则相反。