AI 编程AI Agent开发工具

为什么用了 git worktree,Agent 合代码时还是会删掉你的新逻辑

让 AI agent 去执行一个十几分钟的任务,我们通常不会干等着。大家可能会顺手修改其他代码、中途添加新需求,或者同时运行多个任务。在同一目录下这么操作很容易导致文件互相覆盖,因此现在流行的方法是使用 git worktree 为每个任务创建一个独立的目录。虽然编写代码时互不干扰,但在最后让跑完任务的 agent 把主分支的最新改动合并进来时,经常会出现一个奇怪的问题:合并看起来没问题,所有测试也都通过,但你或同事刚加到主分支的新函数却消失了。

为什么目录已经隔开了,合代码时既没报冲突,单元测试也没拦住?遇到半路改需求或合分支,到底怎么操作才安全?十月底公布的一项名为 SWE-Shift 的基准测试 测了 17 个主流编程系统,刚好把这件事的底儿摸清了。顺着它的实验数据和真实翻车现场看下去,就能明白 git worktree 为什么只管用一半,以及合代码时多做哪一个动作就能避开这个坑。

人在等 agent 的那二十分钟里干的事,为什么会让成功率掉一半

这项测试挑了多个真实开源仓库里的 120 个任务,专门还原开发里半路出状况的场景。研究人员设计了两组对照路径:先让 agent 跑到某个中间节点存下现场,再从同一个节点分出两条路线,一条不做任何外部改动直接跑完实验,另一条在同一个节点塞进一次常见的改动,比如人顺手改了代码,半路加了接口需求,或者队友往仓库里合入了一些新逻辑。

结果出来以后,所有十七个系统全都大滑坡。以最强的 GPT-6 Astra 为例,它在静止环境下能做完 67.35% 的任务,但一旦中途出现变动,完成率直接掉到 24.79%。如果要求它在静止线和变动线两边都顺利交卷,既通过原任务测试又不破坏新加的改动,这项成对成功率它只拿到 20.34%。其他前沿模型如 Claude Opus 也跌到两成左右。

掉下来的这大半任务里,比直接报错停机更麻烦的,是 agent 为了迁就自己的旧计划,悄悄删掉别人的新代码,偏偏原有的单元测试还能全部通过。开源评测仓库 里记录了一个真实的 Django 数据库迁移优化案例。当时 GPT-5.6 Sol 正在修改迁移模块里的索引操作逻辑,进度到六成,队友往同一个文件里合入了一段合法代码,新增了名为 can_reduce_index_with 的辅助方法,两边连行号都没有冲突。由于 agent 在前几步已经定好了自己的改法,它虽然试着调了一下这个新方法,但为了跑通原来的方案,最终在提交补丁时直接删掉了队友刚写的 can_reduce_index_with 方法。更棘手的是,仓库原有的 39 个单元测试随后全部跑通变绿,如果不专门检查队友的新接口还在不在,谁也发现不了这段逻辑已经丢了。

用 git worktree 把目录隔开,为什么只防住了一半冲突

看到这里,很多人第一反应是队友不该趁任务跑到六成还往同一个目录里合代码;如果一开始就用 git worktree 给每个任务分配独立目录,等写完再合,是不是就不会互相干扰了?我们在十月下旬讨论 多 agent 到底买到了什么 时也指出,编写代码时最怕多个执行者在同一目录下同时操作。使用 git worktree 隔离目录后,agent 在修改代码时看到的始终是一个静止环境,不会因为你的文件保存而变动,确实可以将执行成功率提升到静止环境的六成以上。

问题是,写完分支终究还是要合回主分支的,所以 git worktree 只是把外部环境的变化从执行中间推到了合并的那一刻。评测会把队友的改动分成两类:一类是改同一个文件,Git 会在合并时直接报告文本冲突;另一类则是改上下游关联文件中的接口约定,当前文件一行没动。后一种情况即使直接执行 git merge,也看不到一行的冲突,但合完以后两边代码的调用逻辑已经对不上了。如果这时让在 worktree 里忙活了半天的 agent 自己去执行 git rebase 解冲突或调测试,它面对的其实就是一次发生在任务最末尾的外部变动。

git worktree 挡住了执行期间的文件互相覆盖,但挡不住合并时刻带着长历史的 agent 删掉主分支的新代码。

为什么越接近写完越容易改崩,给再多 token 预算都没用

把外部变动推迟到任务最末尾,听起来比中途打断更安全,但实验测出来的结果正好相反。研究人员专门对比了在任务进度一成到九成之间引入变动的影响。在任务刚起步的前三成进度里遇到变动,agent 往往还能顺着新情况调整计划;可一旦到了七成至九成的收尾阶段,正好对应写完代码准备合并或最后关头改需求的节点,GPT 和 Claude 系列的成对成功率反而比早期干预还要再跌 12 到 20 个百分点。

面对这种收尾阶段的下滑,很多人会本能地想多加些 token 预算。研究组把变动后的可用 token 预算从一百万一路放大十六倍到 1600 万,结果发现预算超过四百万以后,成对成功率的涨幅连 0.3 个百分点都不到。问题不出在预算不够,真正拖后腿的是窗口里攒下的旧对话历史,多给的 token 全都花在顺着老计划反复跑同样的旧测试上了。

在最初的几十步里,agent 读到的文件行号、踩过的旧报错、定下的修改方案全都留在对话窗口里,这种长历史让它对眼前新出现的改动视而不见。评测里有个专门测试旧证据失效的实验:任务中途环境变了,终端已经印出新的报错,但 17 个受测系统的成对成功率一下子掉到零,它们全信了自己在几十步前记在上下文里的老结论,不再回头重核现场代码。

目录隔离管执行,清空历史管合并:落到日常就三步

要让 agent 重新核对眼前的代码,就得先把它脑子里那套老结论清掉。评测对比了几种挽救的方法,只有清空变动前的旧对话历史,并且让系统重扫当前工作区的文件状态和差异,才带来了明显的成功率提升。这一步让成对成功率增加了六到九个百分点。微软研究院的分支清理实验 也验证了这一点:他们让模型分叉尝试不同的方案,然后把冗长的中间推理删掉,只保留阶段结论,任务得分就从单次长跑的 0.47 涨到了 0.78。如果只做常规的摘要压缩,老思路依然会残留在摘要里面把后续步骤带偏。我们在 GPT-6 长任务指南的分析 中聊过,现在很多平台都支持在任务不停的情况下半路插话改要求,并自动把长历史压缩成摘要。这套功能适合修补小偏差,但如果任务已经跑到后半程,外部代码或接口变了,光靠压缩和插话就不够用了,直接清空历史重开窗口才管用。

变动后把 token 预算放大 16 倍几乎无效,关掉旧窗口、换干净窗口做合并才能把成对成功率拉回来。

把这些实验结论用到日常开发里,只要求我们把同一个窗口继续执行的习惯改掉,分成三步来走。第一,平时查代码、做计划、做代码审阅多开几个窗口并行读没问题,但动手改代码默认只留一条主线,能不并发写就不并发写。第二,如果你需要一边等 agent 一边自己改代码,或者想同时试探两套改法,就用 git worktree 先把目录隔开,让每个 agent 在完全静止的目录里把初稿跑完。第三,到了要把 worktree 合回主分支,或者任务过半你想改需求的时候,先让原来的窗口把代码提交存盘,然后直接关掉这个旧窗口;接着新开一个没有任何历史包袱的干净窗口,只把主分支的新改动和当前分支的补丁差异发给它,明确交代以主分支的最新接口为准完成合并。

当然,看前面那组跌到两成的数字时,也不用觉得平时十次合代码有八次会崩。这 120 个场景中的外部变动是研究人员用确定性脚本在固定的进度节点注入的。同时,它的评判标准非常严格,要求变动前后所有检查点都通过才算成功,如果漏了一个就判定为失败,因此这些百分比不能直接当作日常开发中事故的频率。但它确实揭示了两个真实的痛点:任务到后期 agent 改不了旧计划,并且会顺手把主干上新加的代码删掉。用 git worktree 来隔离执行期,再用清空历史来帮助它在合并期理解现场,二者结合才能真的有用。

鸭哥每日手记

日更的深度AI新闻和分析