先记住这个答案
补丁因上下文行不匹配而失败时,不能直接重试或强制应用。标准恢复链路是:(1) 读取文件最新内容,丢弃过期副本;(2) 基于新内容重新生成补丁或 unified diff;(3) 若上下文仍不匹配,改用小范围锚点编辑,用唯一标识行定位;(4) 每次尝试后执行类型检查或测试确认。避免无休止重试并设置上限。
- 先重读文件,丢弃过期上下文
- 重新生成 diff,不直接强制应用
- 锚点编辑仍是二级可靠手段
补丁失败的两阶段恢复机制
统一 diff 要求前后几行上下文完全匹配。当文件已与 Agent 持有的副本不同,老化内容导致 hunk 定位失败。恢复机制第一动作是重读文件,以当前工作区为基准刷新上下文,拒绝使用模糊匹配或强制跳过,因为会误改代码。
重读后重新生成补丁,基于新行号和内容。若仍失败,往往是跨多行上下文因编辑器自动格式化而变化,此时降级到锚点编辑:选取补丁区域内不随格式化改变的标识符或注释行作为锚点,只替换目标片段。锚点编辑每次处理一个原子变更,降低单次失败影响。
外部改动导致补丁拒不应用
在维护 config.py 时,Agent 生成补丁修改 load_config 的默认值。该文件刚被另一进程新增了参数校验逻辑,函数整体下移,第一版补丁因上下文偏移失败。Agent 重读完整文件,发现目标区域已被重构,重新生成 unified diff 仍因旧上下文片段不存在而失败。
Agent 降级为锚点编辑:先用 grep 在文件中定位到 DEFAULT_TIMEOUT = 这一行(确认出现次数为 1),再以它为锚点,用 search/replace 块替换整行内容。补丁应用后运行单测验证,成功。该方式不依赖行列,但强制锚点唯一性,避免误改相似代码。
恢复流程的失效边界与代价
重读文件不能解决所有失败:当目标区域被全部重写、锚点字符串消失或出现多次时,锚点编辑也失效。这可能意味着代码库结构已偏离任务假设,继续自动恢复只会扩大改动范围。此时应中止应用,将异常反馈给规划层,由人确认是否调整任务目标。
恢复流程并非免费:每次重读文件都消耗令牌,且可能引入新的不一致。如果重试超过 2 次仍失败,应停止自动循环,改为向用户报告。git apply --reject 可能留下残缺文件,不适合 Agent 无监督执行;必须保持整个恢复过程对工作区的原子性,失败时不落盘任何部分 hunk。
容易答错的地方
- 用 --3way 总能解决
--3way需要 patch 记录 blob 标识且本地有对应对象。当外部改动已提交且不包含该 blob 时,冲突仍会出现,不能替代上下文刷新。- 多次重试同一补丁
- 如果文件没有变化,重试必然同样失败。必须重读文件并考虑降级锚点编辑,否则浪费令牌且无法推进。
面试官还会怎么问?
为什么不用 git apply --reject?
--reject 会把能应用的部分写入文件,剩余写入 .rej,工作区被部分修改,Agent 难以可靠清理,违背原子性原则。
如何判断应降级锚点编辑而非继续重新生成 diff?
当重读后确认改动点仍存在,但连续多行上下文因格式变化无法稳定匹配时,改用单一锚点;若锚点内容不唯一,需扩大锚点或放弃。
重读文件时是否需要读取全部内容?
不需要,按被修改文件的路径读取即可。若多个文件补丁都失败,应分别刷新。可用 git diff 对比副本差异,但 Agent 需要真实文件内容。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。