收到 AI 的代码补丁,先用 git apply --check 试一下

阿哲 Lv.2 2026/10/23 16:20:44 浏览 0

AI 发来一份补丁,git apply 报了错,先别马上再试。如果上一次用了 --reject,有些改动可能已经贴进文件,只是另一些没贴进去。此时直接重跑,面对的已经不是原来的工作区。

下面做了一个两文件的小例子:标签比较逻辑从 lower() 改成 casefold(),同时更新策略标记。坏补丁里,第一份文件的上下文对得上,第二份却引用了旧内容。

图中是本地教学项目的实际命令结果排版,补丁路径在图表中已简写;验证器实际传入材料包中的完整路径。这不是模型生成补丁的成功率。完整项目、好坏补丁、测试、复现脚本和提示词都已打包:

下载最小项目、好坏补丁、完整提示词与隔离复现脚本

先看补丁,再检查能不能应用

本文只用 Git 风格的 unified diff。如果 AI 输出的是 *** Begin Patch 那类专用工具格式,不能直接当作这里的 .patch 文件使用;让它按 git diff 格式重新提供,或者使用对应的工具入口。

解压后,需要 Python 3.10+ 和已安装的 Git。下面只操作附件里的 base 教学目录,不要直接拿自己的项目照跑:

cd base
git init -q
git add labels.py policy.py test_labels.py
git apply --stat ../good.patch
git apply --check ../good.patch

--stat 帮你先看涉及哪些文件;仍要用文本编辑器打开补丁看具体改动。--check 成功时通常没有输出,看实际退出码是否为 0;它不代表已经修改文件,也不代表改法正确。

确认预检成功后,再单独运行:

git apply ../good.patch
git diff -- labels.py policy.py
python -m unittest -v test_labels.py

初始材料的 4 项测试中有 2 项失败,应用好补丁后应为 Ran 4 tests、OK。git add 只是在这个新建教学目录里记录三份基线文件,使后面的 git diff 能显示实际工作区改动;这里没有创建提交,也没有修改 Git 全局配置。

这些命令要分别执行。前一步失败就停下来检查,别用分号把后面的应用、测试也一起跑掉。预检之后若文件又被改了,实际应用时仍可能失败。

同一份坏补丁,三种走法

随包 verify.py 会复制出独立的临时项目,再运行这些反例,不修改 base 或你的真实项目。回到材料包的根目录运行:

python verify.py

这三次都从原始基线开始,实际结果为:

命令退出码labels.pypolicy.py.rej
git apply --check stale.patch1未改未改无
git apply stale.patch1未改未改无
git apply --reject stale.patch1已改未改policy.py.rej

材料包已实际解压复跑,7 个场景的验证均通过,包含基线失败、好坏补丁、反向预检,以及“预检通过后文件又变化”的情况。本机版本为 Git 2.52.0、Python 3.12.14;这不是对所有错误情形的事务保证。

在这个例子里,普通 git apply stale.patch 因为有 hunk 无法应用,整份补丁被拒绝,两份源文件哈希均未变化。加上 --reject 后则会尽量应用可用部分,并把失败块写入 .rej。所以“退出码非零”本身,不能用来推断“没有改任何东西”。

读者不必在真实项目里重演 --reject。遇到失败,先看实际文件差异、拒绝原因和 .rej,不要盲目重试或顺手清掉不理解的改动。

给 AI 的要求写成可验收的动作

包里有完整 prompt.txt,核心要求如下:

请为这个教学项目生成一个标准 Git unified diff,先读取 labels.py、policy.py 和 test_labels.py,再给出补丁。

任务目标:
- normalize_label(value) 对字符串先去掉首尾空白,再按本例约定做 Unicode casefold。
- 让 Straße 与 STRASSE 归一化后相等,ASCII 与中文用例保持符合测试要求。
- 将 policy.py 的 MODE 更新为 casefold,使配置与实现一致。

改动范围:
- 只允许修改 labels.py 和 policy.py。
- 不修改、删除或跳过 test_labels.py 中的测试,不增加依赖,不改其他文件。

输出要求:
- 输出标准 Git unified diff,包含 diff --git、---、+++ 与正确的 @@ 上下文。
- 路径使用 a/labels.py、b/labels.py、a/policy.py、b/policy.py,使补丁能在这两个文件所在的项目目录应用。
- 不使用 *** Begin Patch 或 *** Update File 等编辑工具专用格式。
- 不把整份文件内容冒充差异补丁,不在补丁里夹入解释文字。
- 根据刚读取的实际文件生成上下文,不自行猜测旧文件内容。

如果你具备运行工具,只在教学项目副本中先运行 git apply --check 检查候选补丁;预检成功后再应用,并运行 python -m unittest -v test_labels.py。
预检失败时停止,不用 --reject 或忽略上下文的办法强行贴入,不为了通过而改变测试。
报告实际执行的命令、退出码和测试结果;不能运行时明确说明未运行,不能把计划执行写成已经通过。

本例的两个补丁是手工构造的固定材料,没有让模型实际调用工具。Straße 与 STRASSE 的测试只是这次教学任务的规则;不要把所有账号、显示名称或数据库主键都顺手改为 casefold()。

补丁能贴上,只证明这次应用检查通过。 仍要读实际差异、运行相关测试;测试覆盖不到的需求、性能和兼容性不能据此宣布解决。Git 预检也不是运行不可信代码的沙箱。

资料:Git《git-apply》、OpenAI《Apply Patch》《Codex Prompting Guide》、Python《str.casefold》,2026-10-23 重新核对。这里只使用 Git 默认工作区应用方式,不把其失败行为套到其他编辑工具。

评论 0

发表评论

登录后参与讨论

登录

暂无评论