Files
analysis_claude_code/s17_worktree_isolation/README.zh.md
2026-07-31 03:54:12 +08:00

6.7 KiB
Raw Blame History

s17: Worktree Isolation — 各干各的,互不干扰

English · 中文 · 日本語

s01 → ... → s15 → s16 → s17s18 → s19 → s20 → s21

"各干各的目录, 互不干扰" — 任务管目标, worktree 管目录, 按 ID 绑定。

Harness 层: 隔离 — 并行执行的目录隔离。


问题

s16 中Alice 和 Bob 都在同一个目录下工作。Alice 的任务是"重构认证模块"Bob 的任务是"重构 UI 登录页"。

Alice write_file("config.py", ...)。Bob 也 write_file("config.py", ...)。两个人改同一个文件,互相覆盖,而且无法干净地回滚,因为已经分不清每处改动来自谁。

s15-s16 解决了"谁干什么"(任务系统)和"怎么通信"(消息总线),但没解决"在哪干"。


解决方案

Worktree Overview

Git worktree 让你在同一仓库中创建多个独立的工作目录每个目录都有自己的分支。Alice 在 .worktrees/auth-refactor/ 下工作Bob 在 .worktrees/ui-login/ 下工作,两者互不干扰。

沿用 s16 的 MessageBus、协议和自治认领机制。本章新增

能力 作用
create_worktree 为任务创建独立目录 + 独立分支
bind_task_to_worktree 把任务和工作目录绑定(不改状态)
remove_worktree / keep_worktree 完成后清理或保留
validate_worktree_name 拒绝路径穿越和非法字符

工作原理

创建:任务-Worktree 绑定

def create_worktree(name: str, task_id: str = "") -> str:
    validate_worktree_name(name)       # 只允许 [A-Za-z0-9._-]{1,64}
    path = WORKTREES_DIR / name
    ok, result = run_git(["worktree", "add", str(path), "-b", f"wt/{name}", "HEAD"])
    if not ok:
        return f"Git error: {result}"
    if task_id:
        bind_task_to_worktree(task_id, name)
    log_event("create", name, task_id)
    return f"Worktree '{name}' created at {path}"

def bind_task_to_worktree(task_id: str, worktree_name: str):
    task = load_task(task_id)
    task.worktree = worktree_name       # 只写 worktree 字段
    save_task(task)                     # 状态保持 pending等队友 claim

绑定规则:一个任务绑定一个 worktree。绑定不会改变任务状态。任务仍是 pending,队友自动认领时才推进到 in_progress。这样 Lead 可以提前创建任务和 worktree队友 idle 时自然认领带 worktree 的任务。

队友工具的 cwd 切换

每个队友都有一个 wt_ctx 字典,用来记录当前 worktree 路径。队友认领绑定了 worktree 的任务后,运行时会更新 wt_ctx;该队友的 bashread_filewrite_file 随后都在对应的 worktree 目录下执行:

# 队友线程内部
wt_ctx = {"path": None}

def _run_claim_task(task_id):
    result = claim_task(task_id, owner=name)
    if "Claimed" in result:
        task = load_task(task_id)
        if task.worktree:
            wt_ctx["path"] = str(WORKTREES_DIR / task.worktree)
    return result

def _run_bash(command):
    return run_bash(command, cwd=wt_ctx["path"])  # 在 worktree 下执行

收尾Keep 还是 Remove

任务完成后,两个选择:

def remove_worktree(name: str, discard_changes: bool = False) -> str:
    # 安全检查:有改动时默认拒绝
    if not discard_changes:
        files, commits = _count_worktree_changes(path)
        if files > 0 or commits > 0:
            return "有未提交改动,使用 discard_changes=true 强制删除,或 keep_worktree 保留"
    ok, _ = run_git(["worktree", "remove", str(path), "--force"])
    if not ok:
        return "删除失败"
    run_git(["branch", "-D", f"wt/{name}"])
    log_event("remove", name)

def keep_worktree(name: str) -> str:
    log_event("keep", name)
    return f"Worktree '{name}' kept for review (branch: wt/{name})"

Keep = 留着分支,等人工 review 后合并到主分支。Remove = 有改动时默认拒绝,需要 discard_changes=true 确认。系统不会自动 complete task任务完成由队友的 complete_task 显式触发。

事件流:可审计

每次生命周期操作写入日志,方便排查:

def log_event(event_type: str, worktree_name: str, task_id: str = ""):
    event = {"type": event_type, "worktree": worktree_name,
             "task_id": task_id, "ts": time.time()}
    # append to .worktrees/events.jsonl

事件类型包括 create(创建)、remove(删除)和 keep(保留)。日志用于人工排查;恢复流程可以通过 git worktree list 重建当前 worktree 集合。

run_git返回成功/失败

def run_git(args: list[str]) -> tuple[bool, str]:
    r = subprocess.run(["git"] + args, cwd=WORKDIR, ...)
    return r.returncode == 0, output

create_worktreeremove_worktree 只在 git 命令成功后才写事件日志,保证日志反映真实状态。


相对 s16 的变更

组件 之前 (s16) 之后 (s17)
工作目录 所有 Agent 共享 WORKDIR 每个任务可绑定独立 git worktree
Task 数据 id/subject/status/owner/blockedBy + worktree 字段
队友工具 cwd 始终 WORKDIR 认领带 worktree 的任务时自动切换
新函数 create_worktree, bind_task_to_worktree, remove_worktree, keep_worktree, validate_worktree_name
worktree 安全 name 校验 + 有改动时拒绝删除
事件日志 events.jsonl 生命周期审计
Lead 工具 团队与任务工具 + create_worktree、remove_worktree、keep_worktree
队友工具 任务与文件工具 工具不变bash/read/write 使用已认领任务的 worktree cwd

试一下

cd learn-claude-code
python s17_worktree_isolation/code.py

试试这个 prompt

请并行重构认证模块和登录页面,确保两部分改动不会互相干扰。

观察重点:两个 worktree 的 git status 输出是否显示不同的分支?队友认领带 worktree 的任务后bash 命令是否在 worktree 目录下执行?remove_worktree 对有改动的 worktree 是否拒绝?.tasks/ 中的任务在绑定后状态是否仍为 pending


接下来

Agent 团队能在隔离的工作空间中自组织了,但 Agent 的能力仅限于我们为它编写的 bash、read、write、task 等工具。

如果用户已经有了自己的工具怎么办?比如一个公司内部的 Jira API、一个自建的部署系统

s18 MCP Plugin → 给 Agent 装一个插件系统。外部工具通过标准协议接入Agent 不需要知道它们是谁写的。