diff -u 是生成标准补丁的唯一推荐命令,因其提供上下文行、兼容 patch 和 git;目录比对需路径一致,git diff 更安全因含元信息和完整路径;应用失败主因是上下文不匹配,需用 -p 参数裁剪路径。

用 diff -u 生成标准补丁文件
绝大多数场景下,diff -u 是唯一该用的命令。不加 -u 生成的是老式 normal 格式,patch 工具默认不认,Git 也完全不兼容。
常见错误是直接 diff old.c new.c > patch.diff,结果打不上补丁——因为没上下文行,patch 找不到匹配位置。
-
diff -u a/file.c b/file.c > file.patch:两个文件比对 -
diff -u old/ new/ > project.patch:整个目录树(注意路径必须一致) - 如果目录名变了(比如从
v1.2改成v1.3),用-p1或-p2控制路径裁剪层级
git diff 生成的补丁为什么更安全
Git 的 git diff 默认带元信息(commit hash、作者、时间)、完整路径、空行分隔,patch -p1 能稳稳识别。手写 diff 容易漏掉这些,导致应用时找不到文件。
典型问题:在子目录里执行 diff -u ../src/a.c ./a.c,生成的补丁里路径是 --- ../src/a.c,而目标机器上没有 ../src/,patch 直接失败。
- 推荐做法:
git diff HEAD -- path/to/file.c > fix.patch - 如果没 Git,就老老实实用相对路径:进到项目根目录,再跑
diff -u old/ new/ - 补丁里出现
--- /dev/null表示新增文件,+++ /dev/null表示删除——这些patch都能处理,但要求补丁格式完整
patch 应用补丁时最常卡在哪
不是语法错,而是“找不着地方”。patch 默认只尝试精确匹配行号和上下文,哪怕只差一个空格、多一个注释,都会报 Reversed (or previously applied) patch detected! 或直接跳过。
真实场景中,目标代码往往已改动过,不能指望原封不动回滚。这时候得靠参数干预:
patch -p1 :去掉补丁里第一级路径前缀(如把 <code>a/src/main.c变成src/main.c)patch -p1 --fuzz=2 :允许最多 2 行上下文不匹配(慎用,可能糊弄过去改错地方)-
patch -p1 --dry-run:先试跑,看哪些文件会动、哪些会失败,别等改完了才发现崩了
补丁里带二进制文件?别硬来
diff 对二进制文件默认只输出 Files a/binary and b/binary differ,生成的补丁无法被 patch 应用。这不是 bug,是设计如此。
如果你真需要分发含二进制变更的补丁(比如更新一个预编译的库),要么换方案,要么提前转换:
- 用
git format-patch——它会 base64 编码二进制变更(但接收方也得用git am) - 手动用
xxd -p binary.bin > binary.hex,再 diff 文本,应用时再xxd -r -p还原(麻烦但可控) - 更实际的做法:补丁只管源码,二进制文件单独下载、校验、替换
路径、空格、上下文行数、二进制支持——这些点不显眼,但每个都足以让补丁在凌晨三点部署时静默失败。










