git diff 生成补丁需在仓库根目录执行以确保路径正确;用 git apply 验证或仅应用内容,git am 还原完整提交;注意换行符、子模块、二进制文件及上下文行数等细节。

git diff 生成补丁文件时,路径和工作区状态决定 patch 能否被正确应用
补丁本质是文本差异描述,git diff 输出的内容是否包含完整路径、是否基于暂存区或工作区,直接决定别人能否用 git apply 或 git am 成功打上。常见错误是直接在子目录下运行 git diff,结果 patch 里路径变成 src/main.c,而目标仓库期望的是 ./main.c 或 project/src/main.c。
- 始终在仓库根目录执行
git diff,避免路径偏移 - 想只导出某次提交的修改,用
git diff HEAD~1 HEAD > fix.patch;想导出未暂存的改动,用git diff > unstage.patch;想导出已暂存但未提交的改动,用git diff --cached > staged.patch - 如果 patch 里出现
a/和b/前缀(如a/src/file.c),默认可被git apply处理;若目标仓库结构不同,加--directory=xxx参数重映射路径
git apply 和 git am 的核心区别:一个只改工作区,一个走完整提交流程
git apply 是纯内容应用,不创建提交、不检查签名、不处理 commit message;git am 则把 patch 当作邮件格式补丁(含 author、date、subject),还原成一次真实提交。选错命令会导致信息丢失或后续无法追溯。
- 用
git apply fix.patch快速验证补丁是否能干净应用——它不会动 index 或 HEAD,失败也不影响当前状态 - 确认无误后,想保留原始作者和提交信息,就用
git am fix.patch;注意 patch 文件必须符合 mbox 格式(开头有From xxx行和空行分隔),否则git am会报error: no email was found -
git apply --check fix.patch可预检冲突,返回非零码即表示有冲突,适合集成进 CI 脚本
跨仓库打补丁失败,大概率是 .git/config 或 submodule 配置惹的祸
两个仓库看似结构一致,但实际可能启用了不同的 core.autocrlf、core.eol 或 submodule 配置,导致 git apply 报 patch does not apply 或行尾混乱。这类问题不报具体行号,排查起来特别隐蔽。
- 打补丁前先统一换行符行为:在双方仓库都执行
git config core.autocrlf false,避免 Windows/Linux 混合环境下的^M干扰 - 如果 patch 含 submodule 修改,
git apply默认忽略它们;要用git apply --submodule,且目标仓库的.gitmodules必须已存在并匹配路径 - 补丁中修改了二进制文件?
git apply默认拒绝,需加--binary参数,否则直接报错退出
patch 文件里没有 commit id,靠什么确保修改不丢、不串?
补丁本身不带 SHA-1,也没有依赖图谱。一旦源提交被 rebase 或 force push,补丁内容虽在,但语义可能已失效——比如原 patch 是“修复 A 函数里的空指针”,但 A 函数已被重命名或拆分,此时应用补丁只会产生冲突或静默错误。
- 生成补丁时加上上下文行数:
git diff -U10(默认是 3 行),提升抗变更能力 - 在 patch 文件名或注释里手动记录来源:
fix-login-race-20240520-7a3f2b1.patch,其中7a3f2b1是原始 commit hash - 更稳妥的做法:用
git format-patch替代git diff,它自动生成带 header 的 mbox 补丁,并支持--cover-letter描述背景,适合团队间传递


















