Git apply 补丁验收:--check 只预检,--cached 只修改暂存区
拿到一份补丁后,直接应用到正在工作的目录,会让原有修改与外来修改混在一起。更可靠的第一步是看补丁将改哪些文件,再用与最终应用模式一致的选项预检。检查通过只说明当前内容能匹配,并不意味着补丁已经生效。
git apply 默认修改工作区,--cached 只修改索引,--index 则要求并更新索引与工作区。三者的目标不同,预检也要跟随目标选择。尤其在暂存区和工作文件已经不一致时,不能拿一种模式的检查结果替另一种模式作保证。
用一个两行文件对照三个区域
下面保存为 demo.sh,用 Bash 和 Git 运行。脚本只在新建临时仓库演示,先提交 red,再把它改成 blue 生成本地补丁。生成后恢复工作文件,从同一基础状态检查应用过程;补丁保存在仓库外的临时目录。
第一次只应用到索引,分别读取索引、工作文件和 HEAD,核对三个区域的内容。随后在另一份新克隆里使用 --index,同步更新两处;最后在第三份克隆里制造上下文不匹配,确认预检失败且文件保持原样。
AI概念示意图:以抽象物件说明本文主题,不代表真实界面或运行结果。
set -euo pipefail apply_demo=$(mktemp -d) git init -q -b main "$apply_demo/source" cd "$apply_demo/source" git config user.name Demo git config user.email demo@example.invalid git config commit.gpgsign false printf 'red\nkeep\n' > color.txt git add color.txt git commit -qm base printf 'blue\nkeep\n' > color.txt git diff -- color.txt > "$apply_demo/change.patch" git restore -- color.txt git apply --cached --check "$apply_demo/change.patch" test "$(git show :color.txt)" = $'red\nkeep' git apply --cached "$apply_demo/change.patch" test "$(git show :color.txt)" = $'blue\nkeep' test "$(cat color.txt)" = $'red\nkeep' test "$(git show HEAD:color.txt)" = $'red\nkeep' printf 'cached: index=blue; worktree=red; HEAD=red\n' git clone -q "$apply_demo/source" "$apply_demo/both" cd "$apply_demo/both" git apply --index --check "$apply_demo/change.patch" git apply --index "$apply_demo/change.patch" test "$(git show :color.txt)" = $'blue\nkeep' test "$(cat color.txt)" = $'blue\nkeep' printf 'index: index=blue; worktree=blue\n' git clone -q "$apply_demo/source" "$apply_demo/mismatch" cd "$apply_demo/mismatch" printf 'green\nkeep\n' > color.txt if git apply --check "$apply_demo/change.patch" \ > "$apply_demo/check.log" 2>&1; then printf 'unexpected check success\n' >&2 exit 1 fi test "$(cat color.txt)" = $'green\nkeep' printf 'check failure: worktree remains green\n'
预检的对象要与应用动作一致
第一行应显示索引为 blue,而工作区和 HEAD 仍为 red。--check 没有修改索引,真正变化发生在下一次 apply。第二行确认 --index 同时更新索引与工作文件。第三行说明不匹配的补丁被拒绝,预检没有把 green 改成别的内容。
只改索引之后,普通 git diff 会比较工作区与索引,看起来可能像准备把 blue 改回 red;git diff --cached 才是准备提交的改动。遇到这种状态先确认比较方向,不要把差异方向误当成补丁应用反了,也不要立即执行批量暂存覆盖索引。
--index 还要求相关路径的索引与工作区内容一致,即使补丁看上去能分别套用,也可能因两处状态不同而拒绝。把两处当成一个需要保持一致的操作目标,有助于理解这个约束;已有本地修改时应先隔离并检查。
能应用不等于行为正确
预检通过后,到真正应用之前如果文件又变化,结果仍可能不同。因此检查和应用应尽量在同一个受控现场连续进行。自动化流程还应核对补丁来源、涉及路径与预期基础版本,不能把一次成功退出当成永久有效的许可。
默认应用遇到无法匹配的片段会失败。--reject 会改变处理方式,可能应用部分片段并留下拒绝文件,不适合在不了解差异时随手加入。本例没有使用它,也没有通过忽略空白或扩大模糊匹配来掩盖基础版本的问题。
git apply 本身不创建提交,也不完整导入作者和提交说明。若拿到的是带提交信息的邮件补丁系列,应评估 git am 的对应流程。文件差异传输与提交历史传输有不同目标,先确认收到的材料类型,再选择处理工具。
验收时先看改动范围,再看索引和工作区差异,最后运行与变化有关的测试。补丁能够成功定位文本,只证明机械套用成立;是否保持功能、是否漏改关联文件,以及结果该不该提交,都需要独立判断。


