Skip to content

E2|Worktrees:并行隔离靠第二份 checkout,不靠再拧一档沙箱 ​

先别把两条 thread 当成两套 SandboxPolicy ​

C5 说并行 Goal 必须配 worktree。D5 的 worker 并行写同一句话。读到这里的人,容易去 B3 给每条 thread 配一个 danger-full-access 以外的政策,以为隔离完成了。

判断先说清楚:workspace-write 的边界是「当前 cwd 那棵树」。 两条 Session 若 cwd 相同,两次 apply_patch 抢同一组文件。Git worktree 才是第二份工作区:文件树分开,.git 元数据共享。沙箱政策不用变,变的是 thread 的 cwd。

文件树在哪台机器上,是另一件事:B6 的 environment。本机 local 和远程 exec-server 都还能再套 worktree;远程 session 上 TUI 禁止创建 managed worktree。标题里的 Local 指 checkout,不是 environment。

本仓库的实现是 codex-worktree,契约对齐桌面 App(WorktreeManager 注释,worktree/src/lib.rs:45-46)。产品页上的 .worktreeinclude、setup script、Automations 默认后台 worktree,有的只在闭源壳里;CLI/TUI 路径以 Git worktree + codex-thread.json 绑定为准。


1. Local checkout vs managed worktree ​

Local: 你打开仓库时的那份工作区。TUI 默认 cwd。人手改的文件、未提交的脏状态,都在这里。

Managed worktree: WorktreeManager::create 在绝对路径根下分配桶(默认 $CODEX_HOME/worktrees,settings.rs:12-44),对源仓库 git worktree add --detach --no-checkout,再 reset --hard 到所选 commit(lib.rs:61-138)。ManagedWorktree 记下 root / cwd / source_root / source_cwd / head_sha(:26-37)。cwd 保持相对仓库根的同一子路径,这样 monorepo 里你在 packages/foo 开 worktree,还是进 foo。

CLI 与桌面共用分配根,但 CLI 不启用自动清理(settings.rs:27-35)。桌面可配 worktree-auto-cleanup-enabled 和 keep-count(默认保留 15)。桶满了 allocate_worktree_root 失败(paths.rs:13-39)。

必须是 Git 仓库。不是 git 的项目,官方文档说自动化会直接打在项目目录上——那就没有第二份树,并行写会撞。feature worktrees 默认开(features/src/lib.rs:1255-1258)。

没有「第二份 checkout」会怎样?并行 Goal、后台自动化、D5 worker 全在你正在打字的工作区里 apply_patch。沙箱全部允许写 cwd,等于没有隔离。


2. 一个 worktree 一条 thread;创建有硬前提 ​

Git 元数据里写 codex-thread.json:owner_thread_id(metadata.rs:1-27)。bind_thread 原子写入,已被别人占用就失败(:49-80)。这是所有权,不是建议。两条 thread 不能「友好共用」同一 managed checkout。

TUI 创建前会挡(managed_worktree_creation.rs:42-67):

  • feature 关了
  • 源项目显式未信任
  • 远程 workspace / environment(worktree 只支持 本机 session)
  • 主 session 没空闲(有排队输入)
  • 已有一次创建在飞
  • 有活动的 background terminals 会挡住 /cd 一类切目录(:13-31)

做完 Git 工作,完成事件再检查源 session 是否还在、配置是否变了、新 worktree 是否可信(:213-263)。未信任的新树不会悄悄接着跑——B5 的信任闸按项目根,新 checkout 是新根。

--worktree 只给:新交互会话、codex fork(要显式 session id)、codex exec、codex exec fork。resume / review / 其它子命令直接 bail(cli/src/main.rs:2506-2524)。resume 进已有 session 的 cwd,不能半路改成另一棵树。


3. Handoff:产品是 Local ↔ Worktree,本仓库是「Git 做完再把 UI 接过去」 ​

桌面文档里的 Handoff 是把一条 thread 在 Local 和 Worktree 之间搬:Git 操作由壳完成,对话还是那条 thread。本仓库 TUI 模块注释说的 handoff 更窄:managed_worktree_creation.rs:1-4——阻塞的 Git 创建 在后台跑完,再丢事件回 TUI event loop,避免把 UI 卡死。ManagedWorktreeTransition 把你送进新 cwd 上的会话。

/new、/fork 会先弹出 checkout 选择(Local 还是新 worktree)(slash_dispatch.rs:184-186, 254-258)。/worktree 打开 managed worktree picker(:257-258,说明「start or continue a conversation in a new worktree」,slash_command.rs:101)。

这不是换沙箱,也不是 fork rollout(A2 的 fork 是新 thread id 拷历史)。worktree 可以 新会话 或 fork 历史后换 cwd。历史仍在 CODEX_HOME/sessions,变的是磁盘上的工作副本。

没有「创建与 UI 分离」会怎样?大仓库 git worktree add 卡死 TUI;或 Git 成功了但 thread 仍指向旧 cwd,模型继续改你的 Local。


4. .worktreeinclude 和 setup script:产品有,CLI crate 里没有拷贝逻辑 ​

官方桌面 worktree 文档还提到:哪些未跟踪文件要带进新树(.worktreeinclude 一类清单)、以及创建后跑 setup(装依赖)。codex-worktree 的 create 路径是 git worktree + hard reset,没有读 include 文件、没有跑 setup 的代码。 那些步骤在桌面壳或后续产品面;工程师在这个 git 树里能抄的是:隔离单位 = checkout,所有权 = codex-thread.json。

需要 node_modules 的项目,新 worktree 是干净 commit,不会自动带上 Local 的未跟踪构建产物。这是特性(干净)也是坑(要自己装)。不要指望 CLI WorktreeManager::create 帮你 npm install。

自动化默认走后台 worktree:同样是产品行为(E7),避免冲人手 Local。本仓库没有单独的「AutomationWorktree」类型,它还是 ManagedWorktree,只是创建者是调度器而不是 /worktree。


5. 和沙箱、Goal、子代理的关系 ​

机制隔离什么
PermissionProfile / SandboxPolicy这一次 exec/patch 能不能 写 cwd 外(B3)
Environment(B6)命令和文件发生在 哪台机器
Worktree这条 thread 的 cwd 是哪一份文件树
Goal完成条件挂在 thread 上(C5)
Subagent另一条 Thread,默认继承 同一个 cwd(D5)

子代理并行写,若不先把父会话(或子会话)放进 worktree,所有权规则只是 prompt。explorer 并行读可以共用 Local。Goal 两条并行 = 两 thread = 两 checkout。

远程 exec-server 上的 environment 不是 git worktree(B6)。TUI 已拒绝在远程 session 上建 managed worktree。换 environment 也不等于换 checkout:两台机器各写同一逻辑路径,仍可能打架。


6. 结语:带走一句话 ​

并行任务的隔离单位是 Git worktree 这份 checkout,不是第二套沙箱政策——Local 留给人手,managed 树绑死一条 thread;CLI/TUI 负责 git worktree 和 codex-thread.json,桌面文档里的 include/setup 不要当成这个 crate 已经实现的拷贝机。