同事发来一个 fix.patch,执行 git apply fix.patch,终端甩出两行红字:error: patch failed,error: fix.patch: patch does not apply。文件就在眼前,就是打不上。
它只负责把补丁写进工作区,不建提交。失败九成是补丁和当前文件对不上,先别急着改代码。
先干跑,确认哪一行对不上
git apply --check fix.patch加 --check 只检查不落盘,能过再真正执行。想看改了哪些文件,加 --stat;想看详细过程,加 -v。
常见的三个原因
- 文件版本不一致:补丁基于旧版本生成,目标文件已经被别人改过,上下文行对不上。
- 行尾符不同:Windows 上是 CRLF,仓库里是 LF,整段匹配失败,可以试 --ignore-whitespace。
- 路径层级不对:补丁里是 a/src/main.js,要在仓库根目录执行;目录深了用 -p 调整层级。
打不上时的补救办法
改动不大,直接加 --reject:
git apply --reject fix.patch能打上的先打上,冲突片段存成 .rej 文件,手工合进去再删掉。仓库里有对应版本的对象,可以试三方合并:
git apply -3 fix.patch冲突会留在文件里,跟 merge 一样处理。如果补丁是 git format-patch 生成的邮件格式,带作者和提交信息,改用 git am,提交记录才留得住。
自己出补丁的规范动作
改完先 git diff 看一遍,再重定向到文件:
git diff > fix.patch要包含新文件,先 git add 再 git diff --cached。已经提交的单个提交,用 git format-patch -1 导出。
补丁里带二进制文件时,它默认处理不了,要加 --binary;这种补丁最好让对方直接发包,别硬合。
在仓库子目录里执行会找不到路径,先切到根目录,或者用 --directory 指定前缀。
结论:小补丁用 --reject 手工合最快,跨了好几个版本的大补丁别硬套,让对方基于当前分支重新生成。