你的编码智能体并不知道它在哪一个分支上。它以为它知道。十二轮对话前它看过 git status 的输出,它的上下文中有一份 CLAUDE.md 提到了会话开启时的分支名称,并且它观察到一个工具结果列出了五个当时正确的文件。从那时起,智能体就一直在基于那个快照进行静默推理。与此同时,你在另一个终端里运行了 git checkout main。智能体的 diff 顺利地写入了文件系统,因为操作系统并不关心这些字节属于哪个分支。这个 diff 在语义上是错误的,因为智能体对分支的心理模型已经落后了 300 个提交,且它所基于的父节点在你的工作树中已不复存在。
这就是分支状态漂移 (branch-state drift),它是数据库中“读-改-写”竞态 (read-modify-write race) 在编码智能体领域的翻版。智能体在第 N 轮读取世界状态,在第 N+1 到 N+k 轮之间修改计划,并在第 N+k+1 轮写回磁盘——而在这一时间窗口内的某个时刻,它脚下的世界已经发生了变化。没有异常抛出,没有工具返回错误。补丁被应用了。危害在下游显现:针对错误的基准分支开启了 PR,手动提交的代码被静默回滚,或者针对昨天刚迁移过的模式 (schema) 实现了新功能。
为什么文件系统对你们都在撒谎
Git 工作目录是一个投影。磁盘上任何时刻的字节都是最后一次检出的提交与工作树中任何未提交编辑的并集。智能体的工具——Read、Edit、Bash、Grep——都在这些字节上操作。它们的结果都不包含父提交信息。它们都不会注解“由于 HEAD 当前是 Y,所以该文件看起来像 X”。智能体在第 4 轮读取文件,并将其内容作为稳定的事实存储在上下文中。到了第 17 轮,那个提交和那个时刻都已不复存在。
同样的投影也会欺骗人类,但人类拥有外围信号——Shell 提示符中的分支、IDE 的状态栏、刚刚输入内容的肌肉记忆。除非有人专门接入这些信号,否则智能体一无所有。智能体观察分支状态的唯一窗口就是其最后一次工具运行的结果。如果该结果已是十二轮之前的,而你在此期间运行了 git pull --rebase,那么智能体就是在基于化石进行操作。
使其比人类犯错更糟糕的是恢复过程的不对称性。在编辑中途意识到自己在错误分支的人,通常能通过编译错误、缺失的导入或看起来不太对劲的名称发现问题。智能体发现不了,因为它对分支“应该长什么样”没有先验认知。智能体对“代码库包含什么”的模型仅限于它在本会话中读取过的内容,而这恰恰就是发生漂移的表面。
漂移的三种形式
分支状态漂移至少以三种结构截然不同的方式出现,且针对一种情况的修复方案并不适用于另一种。
第一种是单会话漂移 (single-session drift) :用户在智能体运行期间于另一个终端切换了分支。智能体下一次读取文件时返回的是新分支的内容,但其之前的上下文仍描述着旧分支。智能体在这种矛盾中进行推理,并得出一个两者都不匹配的 diff。
第二种是共享检出下的多智能体漂移 (multi-agent drift on a shared checkout) :两个智能体在同一个工作树上运行,其中一个智能体为了执行计划而切换了分支,导致另一个智能体看到的文件系统在其脚下发生了变化。第二个智能体读取到的“未提交更改”实际上是第一个智能体编辑到一半的状态,并试图通过扩展这些更改来提供帮助。由于每个智能体都基于不同的父节点进行推理,合并结果将变得语无论次。
第三种是长时间运行智能体针对移动远程分支的漂移 (long-running-agent drift against a moving remote) :智能体分配了一个耗时数小时的任务——重构、迁移或跨数百个文件的扫描——到它完成时,main 分支已经推进了 12 个提交。智能体的 diff 相对其开始时的提交是正确的,但相对其必须合并进去的提交则不再正确。文本合并 (textual merge) 虽然成功,但语义合并 (semantic merge) 却失败了。测试在各自的分支上都能通过,合并后却失败了。
每种形式都有不同的根本原因。单会话漂移源于缺失轮次前奏 (turn-prelude)。多智能体漂移源于缺失隔离原语 (isolation primitive)。长跑漂移源于缺失变基并重新验证 (rebase-and-revalidate) 的步骤。混淆它们会导致修复了一个问题却遗漏了其他问题。
工作树是底线,而非上限
2026 年主流的修复方案与 Git 本身为解决人类并发问题而推出的方案一致:专用工作树 (dedicated worktrees)。每次智能体运行都会获得一个由共享 .git 对象库支持的独立物理目录。两个智能体不会在工作树上发生冲突,因为它们并不共享工作树。在工作树 A 中切换分支不会干扰工作树 B。磁盘成本微乎其微——仅重复工作文件;引用、对象和远程跟踪分支仅存储一份。
工具如 Claude Code 的 --worktree 标志、Cursor 3 的 /multitask 以及像 cmux 和 amux 这样的编排工具都将其作为默认配置。大多数团队会保持两到四个并行智能体,因为人类的审核带宽在磁盘空间耗尽之前就会饱和。这种模式已经足够成熟,“给每个智能体一张独立的办公桌”已成为工作规范,而非实验性尝试。
But 工作树仅解决了第二种形式的漂移。它们是必要的,但并非充分的。它们防止了两个智能体互相破坏对方的文件系统视图。当某些因素——人、钩子、自动化流程——改变了智能体所属工作树的分支状态时,它们并不能防止智能体基于自身过时的 HEAD 快照进行推理。它们也无法防止长跑智能体在 main 分支已经移动的情况下完成任务。工作树只是整个体系得以立足的底座 (floor)。
轮次前导与分支固定 解决单次会话偏移(Single-session drift)的方案是“轮次前导(Turn-prelude)”:这是一个小的、确定性的状态块,Harness 在每一轮开始时都会重新读取,并将其插入到 Agent 的推理过程之前。一个最起码有效的“前导”应包含:当前的 HEAD SHA、当前分支名称,以及工作树脏状态(Dirty Status)的摘要。Harness 会将本轮的前导与上一轮进行对比。如果 HEAD 发生了移动、分支发生了变化,或者脏状态以一种非 Agent 导致的方式发生了翻转,Harness 就会将其视为一次“上下文失效事件”。
如何定义“失效”取决于 Harness 的设计哲学。激进的版本会从 Agent 的工作记忆中丢弃已缓存的文件内容,并在下一次编辑前强制重新读取。保守的版本则会以一种 Agent 无法忽略的方式向你提示这种偏差——“自你上一轮操作以来,HEAD 已从 abc123 移动到 def456;之前读取的文件可能已经过时”——并让 Agent 决定是否刷新。这两种方案都优于现状,即:保持沉默。
分支固定(Branch Pinning)将这种机制从“检测”扩展到了“强制执行”。Agent 会话会声明其预期操作的分支——在会话开始时传递、写入 Harness 配置,或从第一轮的前导中推断。随后的每一轮都会针对声明的分支进行断言。如果工作树不再该分支上,Harness 将拒绝应用任何编辑,并显式地报出偏差。这相当于带有版本列的乐观并发控制:操作被拒绝,而不是被悄无声息地错误应用。其代价是偶尔的中断;其价值是永远不会将补丁合并到错误的基线(Base)上。
快照、恢复与评估规范 偏移不仅是一个检测问题,也是一个恢复问题。一个已经在过时快照上推理了九轮的 Agent 无法简单地通过“切换分支”来继续工作——它的计划、记忆中的文件内容、以及尚未证实的假设,都与它认为自己所处的那个世界绑定在一起。最干净的恢复方式是将 Agent 的状态与其推理时的 Commit 一起进行快照,这样 Harness 就可以将 Agent 恢复到一个一致的(状态, 提交)对,而不是将过时的 Agent 硬拖进一个新世界。
这可以映射到 Git 自身暴露的相同原语:用于工作树的 stash(暂存),用于提交的 ref(引用),以及用于恢复的 (stash, ref) 配对记录。目前有几个开源 Harness 正在构建类似的机制——Beads、cmux 的分支观察器(Branch Watcher)以及 Hermes 的恢复原语,都在从不同角度指向同一种形态。这种趋同并非巧合。一旦你接受了 Agent 的上下文本身就是一个版本化对象,你对它所需的操作显然就是 Git 的操作:commit、branch、checkout、stash、rebase。
针对分支状态偏移的评估(Eval)必须是合成的,因为这种失败在单次运行中很少见,但累计起来却具有毁灭性。评估的形态通常是:启动一个会话,在运行中途通过并行进程触发分支切换,并根据 Agent 在下一轮中是检测到偏差并询问、还是直接采取行动来进行评分。变体包括:在 Agent 下方对 main 分支进行 rebase;在此 Agent 编辑时合并另一个并行 Agent 的 PR;推送一个触及 Agent 打开文件集的远程提交。评分标准不是“Agent 是否生成了可用的 diff”,而是“Agent 是否正确识别出它所处的世界已经发生了变化”。如果团队在发布编码 Agent 时没有在评估套件中加入这一类别,那么在面对最容易产生隐性且昂贵 PR 的失败模式时,就是在盲目飞行。
成本框架:负价值工作 一个分支错误的 PR 并不是可以随手丢弃的零价值工作。它是“负价值工作”。人类审阅者必须进行回溯式的 rebase 来理清哪些是 Agent 想要修改的,哪些是它意外还原的,哪些是新基线上已经存在的。期间提交的作者必须捍卫自己的更改,防止被 Agent 生成的补丁悄无声息地撤销。CI 系统在浪费时间测试一个本不该被组装在一起的树。错误会话消耗的 Token 是沉没成本,而纠正会话消耗的 Token 则是额外的支出。
这就是为什么“Agent 的 diff 成功应用(Applied Cleanly)”是一个具有误导性的成功信号。成功应用只是文本非重叠的特性,而正确性则是针对实际基线的意图体现。这两者之间的偏移,正是分支状态管理(Branch-state Hygiene)存在的意义。
这一切背后的架构认知是:Git 是一个有状态的系统,Agent 与它的关系必须被建模为一个针对动态目标的会话。Agent 并不是在读取一个静态快照。Agent 正在参与一个并发系统,其中其他写入者——人类、其他 Agent、自动化钩子——也在产生提交。数据库用于并发控制的每一个原语都有其编码 Agent 的对应物:轮次前导是读取快照,分支固定是乐观锁,工作树(Worktree)是物理隔离,快照与恢复则是事务日志。建立这四种机制的团队并不是在消除偏移,而是将偏移置于一个能被大声捕获的地方,而不是让它被静默发布。
不做这些工作的团队,实际上是在每一个编码 Agent PR 的关键路径上安装了一个隐性竞态条件(Race Condition)。它没有发出告警并不代表它没有触发,而只能说明系统没有检测器。增加检测器,然后开始修复它捕获到的问题。
会员专享
余下内容仅对会员开放。 会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。
— 完整文章,包含未公开存档的部分 — 可落地的工作框架,附带权衡与决策依据 — 新文章抢先看,先于公开发布 登录以继续阅读→ 随时取消 · 一次订阅,畅读全部