Git Worktree 并行
CC 把 worktree 做成了一等能力:--worktree flag、EnterWorktree/ExitWorktree 工具、subagent isolation、.worktreeinclude、fail-closed 自动清理、非 git VCS hook 替换。Codex CLI 完全没有 worktree 管理——并行隔离押在云端容器(cloud-tasks)上。
Git Worktree 并行
结论
这是两家差异最悬殊的一章。CC 把 git worktree 产品化成了并行隔离的地基:入口有 CLI flag(--worktree/-w,可配 --tmux)、会话中工具(EnterWorktree/ExitWorktree)、subagent 参数(isolation: "worktree")三层;目录固定 .claude/worktrees/<slug>、分支 worktree-<slug>;配套解决了 worktree 的所有工程脏活——gitignored 文件复制(.worktreeinclude)、node_modules 软链(worktree.symlinkDirectories)、sparse checkout、husky hooksPath、settings.local.json 传播;清理是 fail-closed 的 30 天扫描(有未提交/未推送内容绝不删);甚至留了 WorktreeCreate/WorktreeRemove hook 让 SVN/Perforce 用户整体替换 git 实现。Codex CLI 则完全没有 worktree 功能:源码里 worktree 只出现在「检测当前目录是不是 worktree」的 git 工具函数里,并行多任务的隔离答案是 cloud-tasks(云端环境)而非本地 worktree。对 workspace 型产品(Yoda),CC 的实现是一份可逐条对照的工程清单。
研究问题
- CC worktree 的完整生命周期(创建/复用/退出/清理)和资源共享策略?
- 「worktree 状态」如何随会话持久化、resume 后如何恢复?
- Codex 有没有 worktree 支持?没有的话并行隔离靠什么?
各 Agent 设计与实现
Claude Code
以下行号均出自 CC 重构源码 src_2026-03-31/utils/worktree.ts(架构参考;线上行为以 docs 为准)。
三层入口 [一手源码] [一手文档]:
- CLI:
claude --worktree <name>(缺省名生成bright-running-fox式 slug),可配--tmux直接 exec 进 tmux 会话(execIntoTmuxWorktree,worktree.ts:1180-1519;iTerm2 下自动用-CCcontrol mode)。name 支持 PR 引用:#1234或 GitHub PR URL → fetchpull/N/head→ worktree 名pr-N(parsePRReference,:633-651;docsworktrees.md:55-59)。 - 会话中工具:
EnterWorktree(创建/复用并 chdir 进去,同时清掉依赖 cwd 的系统提示词与 CLAUDE.md 缓存——clearSystemPromptSections()/clearMemoryFileCaches(),tools/EnterWorktreeTool/EnterWorktreeTool.ts:98-102)与ExitWorktree(action: keep|remove+discard_changes,tools/ExitWorktreeTool/ExitWorktreeTool.ts:30-40)。 - subagent 隔离:AgentTool 的
isolation: "worktree"参数(与cwd互斥)为子 agent 建临时 worktree(tools/AgentTool/AgentTool.tsx:99-100,590-592);自定义 subagent 可在 frontmatter 写死isolation: worktree(docsworktrees.md:79-83)。
布局与命名:worktree 在 <repoRoot>/.claude/worktrees/<slug>,分支 worktree-<slug>;嵌套 slug(user/feature)扁平化为 user+feature,注释解释了 git ref D/F 冲突与父 worktree 删除连坐两个原因(:204-227)。slug 经过严格 allowlist 校验防路径穿越(validateWorktreeSlug,:66-87)。基分支默认 origin/<defaultBranch>(fresh),settings worktree.baseRef: "head" 可改为本地 HEAD(docs worktrees.md:43-53)。
性能工程(全是注释里写明的实测数字)[一手源码]:复用路径直接读 .git 指针文件取 HEAD SHA,省 ~15ms 子进程(:243-255);origin/<branch> 本地已有就跳过 fetch(大仓 fetch 烧 6-8 秒,:278-301);git worktree add -B(非 -b)顺带复位孤儿分支,省一次 branch -D(:326-328);.worktreeinclude 匹配用 ls-files --directory 折叠全忽略目录,「~500k entries/~7s 降到 ~hundreds/~100ms」(:410-417)。
资源共享:.worktreeinclude(.gitignore 语法)把 .env 类 gitignored 文件复制进新 worktree(copyWorktreeIncludeFiles,:391-504);settings.worktree.symlinkDirectories 软链 node_modules 等大目录防磁盘膨胀(:102-138,580-585);settings.worktree.sparsePaths 走 sparse-checkout(失败则整体 tear down 防「空 worktree 被当成功复用」,:336-366);settings.local.json 复制传播、core.hooksPath 指回主仓(含 husky prepare 脚本会重置共享配置的对抗处理,:510-623)。
状态持久化与 resume [一手源码]:worktree 会话状态作为 type: 'worktree-state' 条目写进 transcript(utils/sessionStorage.ts:818-821,读取在 :1198);语义是三态——「undefined = 从未碰过(不写),null = 已退出 worktree,object = 正在 worktree 中」(:541-542 注释);--resume 时 restoreWorktreeSession 恢复(worktree.ts:162-169),saveWorktreeState 的 docstring 写明「Record the session's worktree state for --resume」(sessionStorage.ts:2884-2890)。
清理(fail-closed) [一手源码]:交互退出时无改动自动删、有改动弹 keep/remove 对话框(docs worktrees.md:87-93;-p 模式不清理)。后台扫描只清匹配临时 slug 模式的 worktree(agent-a<7hex>、wf_<...>、bridge-*、job-*,精确正则防误伤用户命名,EPHEMERAL_WORKTREE_PATTERNS,:1030-1041),且超过 30 天(cleanupPeriodDays)、git status --porcelain -uno 干净、无未推送 commit 三条全过才删,任何 git 命令失败一律跳过(cleanupStaleAgentWorktrees,:1043-1136)。
非 git VCS:配置 WorktreeCreate/WorktreeRemove hook 后整体替换 git 实现(hook 读 stdin 的 name、stdout 输出目录路径),hook 模式下 .worktreeinclude 不生效(:715-728;docs worktrees.md:131-154)。
Desktop 与会话内切换:desktop 应用「creates a worktree for every new session automatically」(docs worktrees.md:11)——worktree 隔离在 GUI 形态下是默认而非可选;CLI 会话内还能用 EnterWorktree 直接切到 .claude/worktrees/ 下另一个已存在的 worktree,原 worktree 原样留盘(docs worktrees.md:35)。worktree 模式本身已无开关:曾经的 GrowthBook flag tengu_worktree_mode 因首启缓存竞态吞掉 --worktree 而被移除,现在无条件启用(utils/worktreeModeEnabled.ts:1-12 注释引 issue #27044)[一手源码]——一个「feature flag 的缓存语义反噬功能」的真实案例。
Codex CLI
没有 worktree 管理功能 [一手源码-缺失证据]。在 codex-rs @ b89ce9a 全仓 grep worktree,命中全部是「识别当前目录是否为 git worktree」类的只读检测:git-utils/src/info.rs:743-772(通过 .git 文件指针解析 worktrees/ 目录定位主仓,「Handles worktrees via filesystem inspection」)、core/src/config/mod.rs:1007(项目信任判定提到 worktree)、TUI 的 diff/resume 对 worktree 路径的兼容。没有任何创建/删除/切换 worktree 的代码路径,docs 目录也无 worktree 文档。
并行隔离的替代答案:cloud-tasks crate——把任务提交到云端环境执行(cloud-tasks/src/lib.rs 依赖 codex_cloud_tasks_client::TaskStatus,配 env_detect/new_task/scrollable_diff 模块在 TUI 内选环境、建任务、看 diff),本地仓库不被并行任务触碰 [一手源码]。也即 Codex 的模型是「本地单会话 + 云端多任务」,CC 是「本地多 worktree 多会话」。(ChatGPT Codex 网页产品的容器隔离属云端实现,本仓库无源码,[推断])
这个缺位是设计选择而非疏漏的旁证:Codex 对 git 边界非常敏感——exec 默认拒绝在非 git 目录运行(exec/src/cli.rs:26-28 的 --skip-git-repo-check 即其逃生门),git-utils 专门写了不调 git 子进程的 worktree 主仓解析(info.rs:743「Handles worktrees via filesystem inspection without invoking」);它完全有能力感知 worktree,只是把「创建与编排 worktree」留给了上层(用户/harness/云端)[推断]。
差异矩阵
| 维度 | Claude Code | Codex CLI |
|---|---|---|
| worktree 创建 | --worktree flag / EnterWorktree 工具 / subagent isolation | 无 [一手源码-缺失] |
| 目录/分支约定 | .claude/worktrees/<slug> / worktree-<slug>(嵌套扁平化为 +) | 不适用 |
| 基分支策略 | 默认 origin/HEAD(fresh),可设 baseRef: head;支持 PR 引用 | 不适用 |
| 资源共享 | .worktreeinclude 复制 + symlinkDirectories 软链 + sparsePaths | 不适用 |
| 状态持久化 | transcript worktree-state 条目,--resume 恢复(三态语义) | 不适用 |
| 自动清理 | fail-closed:仅临时 slug 模式 + 30 天 + 无未提交/未推送 | 不适用 |
| 非 git VCS | WorktreeCreate/WorktreeRemove hook 整体替换 | 不适用 |
| 并行隔离模型 | 本地多 worktree(CLI/desktop 每会话一个) | 云端容器任务(cloud-tasks);本地仅 worktree 检测 |
| subagent 文件隔离 | createAgentWorktree(不动全局状态,挂主仓 canonical root) | 无对应概念 |
最小复现
# CC:两个并行隔离会话
claude --worktree feature-auth # 终端 1
claude --worktree bugfix-123 # 终端 2
git worktree list # 可见 .claude/worktrees/ 下两个挂载
# CC:基于 PR 的 worktree
claude --worktree "#1234" # → .claude/worktrees/pr-1234
# CC:资源共享配置
cat > .worktreeinclude <<'EOF'
.env
.env.local
EOF
# settings.json: {"worktree": {"symlinkDirectories": ["node_modules"]}}
# CC:subagent worktree 隔离(会话内自然语言即可触发)
claude
> 用 worktrees 隔离你的 agents,并行重构这三个模块
# CC:观察 transcript 里的 worktree-state 条目
grep -rh '"type":"worktree-state"' ~/.claude/projects/ | head -1
# {"type":"worktree-state","worktreeSession":{"worktreePath":"...","worktreeBranch":"worktree-...",...}}
# Codex:验证无 worktree 子命令
codex worktree 2>&1 | head -1
# error: unrecognized subcommand 'worktree'Harness 接入建议(Yoda 实践)
- Yoda 已自建 worktree-per-task(
src/main/core/projects/worktrees/worktree-service.ts,分支前缀默认yoda,.yoda.json的preservePatterns等价于 CC 的.worktreeinclude,yoda/agents/workflows/worktrees.md)。CC 这份实现可直接抄三件事:fail-closed 清理三条件(status 干净 + 无未推送 + 超龄,且只清自家命名模式)、slug allowlist 校验(路径穿越防护,validateWorktreeSlug的注释就是威胁模型文档)、symlinkDirectories(Yoda 目前 preservePatterns 是复制语义,node_modules 应改软链)。 - 冲突规避:Yoda 在自己的 worktree 里 spawn
claude时,要防止用户再触发 CC 的EnterWorktree造成嵌套——CC 自己用findCanonicalGitRoot把 agent worktree 强制归位主仓(worktree.ts:921-926注释),Yoda 可在.claude/settings.local.json(Yoda 已往 worktree 写该文件,providers.md)里用权限规则禁掉 EnterWorktree,或接受嵌套但把.claude/worktrees/加进 Yoda 的清理扫描。 - Codex 任务无需额外隔离动作:它不会自己开 worktree,Yoda 的 task worktree 即最终隔离边界;但要注意 Codex 默认拒绝在非 git 目录运行(
--skip-git-repo-check),Yoda worktree 天然是 git 目录,无碍。 .worktreeinclude与.yoda.json#preservePatterns语义重叠:长期建议 Yoda 读取并合并.worktreeinclude,让同仓的 CC 用户和 Yoda 用户共享一份「需要带进 worktree 的文件」清单。
失效条件
- CC 重构源码滞后线上 ~2 个月:worktree.ts 的行为细节(如 ephemeral 模式列表、30 天阈值默认)需对照最新 docs/changelog 回归
-
worktree.baseRef当前只接受"fresh"|"head"(docs 明示非任意 ref);若放开任意 ref,基分支策略段落需更新 - Codex 若引入本地并行/worktree 能力(关注 codex-rs 新 crate 与 cloud-tasks 演进),本章核心反差结论作废
- CC desktop「每个新会话自动建 worktree」(docs
worktrees.md:11)若改默认,并行模型描述需调整
参考资料
- CC 源码(重构):
src_2026-03-31/utils/worktree.ts(全生命周期)、tools/EnterWorktreeTool/、tools/ExitWorktreeTool/、tools/AgentTool/AgentTool.tsx:99、utils/sessionStorage.ts:818-821,2884-2890、utils/worktreeModeEnabled.ts - CC 文档:
claude-code-docs/docs/worktrees.md(--worktree/.worktreeinclude/清理/非 git VCS 全量) - Codex 源码:
codex-rs/git-utils/src/info.rs:743-772(仅检测)、cloud-tasks/src/lib.rs(@ b89ce9a) - Yoda:
yoda/agents/workflows/worktrees.md、yoda/agents/integrations/providers.md - 交叉章节:
chapters/orchestration/(subagent/teams 与 worktree 的配合)、chapters/workflow/code-review.md(评审跑在 task worktree)