同事发来一个 patch 文件,git apply fix.patch 敲下去,回来一行 error: patch failed,后面跟一串行号。文件明明是对的,问题多半在路径或者上下文。
git apply 干的事很单纯:把 diff 里的改动写进工作区,不建提交,不动暂存区。它不会帮你解决冲突,对不上就整份拒绝。所以用之前先验证,比事后回滚省事。
先跑 --check 再真打
git apply --check fix.patch只验证不落盘,有冲突立刻报出来。git apply --stat fix.patch看改了哪些文件、加删多少行,先确认是不是你要的那份。git apply -v fix.patch输出详细匹配过程,能定位到具体哪一段失败。
失败最常见的三个原因
- 路径前缀层数不对。patch 里写的是 a/src/main.c,你在子目录里执行,试试 -p0 或 -p2 调整剥离层数。
- 目标文件已经被改过,上下文行对不上。先 git stash 或者切到干净分支再打。
- 换行符不一致。Windows 上 core.autocrlf 打开后,diff 里的行尾和本地文件对不上,整段都算冲突。
和 git am 别搞混
git am 读的是 git format-patch 生成的邮件格式补丁,会把作者和提交信息一起保留,适合把别人的提交搬过来。git apply 只改文件,提交信息得自己写。拿到还没落地的 .patch,先打开看头部有没有 From、Subject,有就走 am。
实在对不上又不想手工改,可以加 --3way 让 git 尝试三方合并,冲突处会留标记;或者 --reject 生成 .rej 文件,手工挑能打上的部分。这两种都会留下半成品,打完记得 git diff 过一遍再提交。
补丁打完先别急着提交,git status 看一眼有没有多出 .orig、.rej 这类临时文件,有就说明有部分没应用成功。确认改动范围只有补丁里那些文件,再走 add 和 commit。放到 CI 里跑的话,把 --check 放在前置步骤,能提前拦住对不上的补丁。