第 18 章 多Agent并行开发的文件冲突 · Agent架构实操十八 开始测验

AI Agent 也会「抢地盘」?文件冲突怎么解

任务所有权≠文件系统隔离。Alice 认领「重构认证」Bob 认领「重构登录页」,两人都 write_file("config.ts") 后写者覆盖前写者。Task DAG/lease/协议都没错,冲突在另一层:共享同一片物理文件空间。
⏱ 约 15 分钟 🌳 Git Worktree 📦 三条独立状态线 +worktree

🎯 学习目标

学完能答
  • 任务所有权等于文件系统隔离吗?文件锁能解决吗?
  • Git Worktree 提供什么?和文件锁的区别?
  • 为什么不能把 worktree 塞进 Task schema?三条独立状态线是什么?
  • Binding 的状态机(reserved/active/kept/needs_review/removed)?
  • 有未提交改动/未集成提交/Git检查失败时,删除会怎样?
  • 工具执行前,可信工作目录如何解析到当前 claim 对应的 Worktree?

🧠 核心概念

点击展开。
1 · 文件锁不是答案

文件锁只能保证「同一时刻一个人写」,不能给两项并行工作提供独立版本:

Alice 获得 config.ts 锁并写入
-> Alice 释放锁
-> Bob 获得锁并写入
-> Alice 的结果仍被 Bob 覆盖

锁把并行写变成有序覆盖,没解决「两个候选改动如何分别保存、审查和集成」。Git Worktree 提供物理目录隔离,同时复用同一个 Git 对象库。

2 · Git Worktree 结构
repository-root/
├── .git/
├── .agent_tutorial/
│   ├── tasks.sqlite3
│   └── worktrees/
│       ├── alice/          branch: wt/alice
│       └── bob/            branch: wt/bob
└── source files            integration ref 所在主工作目录

Alice 和 Bob 可同时改 config.ts,但修改位于不同目录和不同分支。之后由明确 review/merge 流程决定哪一份进入集成引用。

3 · 不能把 worktree 塞进 Task:三条独立状态线
状态线回答的问题典型状态
Project Task工作是否未开始/执行中/已完成pending→in_progress→completed
Task Claim当前谁在租期内拥有执行权active/expired/cleared
Worktree Binding任务对应的隔离目录处于什么生命周期reserved/active/kept/needs_review/removed
不修改 Task schema SQLite 用独立 worktree_bindings 表,通过 task_id 外键关联。binding 创建也不把 Task 从 pending 推进到 in_progress。Lead 可先建 DAG、预留所有隔离目录,再启动队友;真正 Task 状态迁移仍只由 claim 和 complete 完成。
4 · Binding 状态机
  • reserved:binding 已在 SQLite 落库,但 Git 目录还没建成功——一条意图记录;git worktree add 失败就停在这里,任务仍 pending,自动认领捡不到它。
  • active:Git 目录和分支都已回读确认(读回 branch --show-current 证明),这条 binding 才可被认领和路由。顺序不能反:先落库再调 Git,孤儿副作用比多余状态记录严重得多。
  • kept:任务完成并已集成,worktree 保留(可后续删除)。
  • needs_review:有未提交改动/未集成提交/Git检查失败,删除请求变成 needs_review 并带 review_reason,目录和提交不被强制丢弃。
  • removed:clean worktree 已安全删除;binding 行留在库里当审计记录。

每次工具执行前,可信工作目录解析到当前 claim 对应的 Worktree:write_file 的 path 在 active binding 时解析到 wt/alice/,不是主目录。解析由 ToolContextProvider.resolve() 完成,排在 schema 校验之后、Hook 与权限之前——Hook 看到的就是最终执行上下文;解析失败报成对 tool_context_error,handler 零调用。不用 process.chdir();executionScope 是每回合新建的冻结对象,用 WeakMap 映射到 claim token,生命周期正好一轮;失效 claim 必须显式失败,绝不静默回落主目录——只有完全没声明 claim 才用主目录。

5 · 删除的安全边界

完成 A 并把 wt/alice 集成进明确引用后,clean Worktree 可安全删除。但 B 有未提交改动、未集成提交或 Git 检查失败时,删除请求变成 needs_review:

不强制丢弃 目录和提交不被强制丢弃,需人工审查。这避免 Agent 自动删掉有未保存工作的 worktree。重建 SQLite store 后,binding 和按顺序追加的审计事件完整恢复;审计表 append-only(trigger 拒绝 UPDATE/DELETE),binding 迁移和审计事件在同一事务提交,审计写失败迁移一起回滚。

集成判定用 branch tip 是否已包含在指定 integration_ref 里(merge-base --is-ancestor),不用 branch --merged;integration_ref 先 rev-parse --verify 解析成不可变 40 位 commit 再建 Worktree。git status 非零退出(出错)与空串(干净)必须区别对待,Git 报错不泄露 stderr。已是 kept/needs_review 的不重复迁移。validateRepository 要求 workspace 正好是仓库根,子目录不行。

▶️ 交互演示:Worktree 隔离

Alice 和 Bob 各自在独立 worktree 写同名 config.ts,主目录不出现该文件。注意三条状态线独立。

📁 主目录(main)

🌳 wt/alice

🌳 wt/bob

🔑 一句话总结

Git Worktree 给并行工作物理目录隔离 + 复用同一对象库;三条状态线独立,不塞进 Task

QA 测验