Codex 里的 worktree 是个啥
从 Git 的多工作目录讲到 Codex 的任务调度:worktree 负责隔离施工现场,Agent 系统负责协调并行开发。
使用 git worktree 是 Git 自带的功能。简单来说,它可以帮助开发者在同一个 Git 仓库下,同时展开多个真实的工作目录,让不同目录分别处在不同分支上,从而并行开发多个功能或修复多个 bug。
我一开始的直觉是:一个 repo = 一个项目目录 = 一个当前分支。这个直觉并没有完全错。对于普通 Git 使用方式来说,一个项目目录里确实通常只能 checkout 一个分支。比如:
cd squady-app
git checkout dev
这时:
squady-app/
当前分支:dev
如果再切到另一个分支:
git checkout fix/profile-create
这个目录里的文件状态就会变成 fix/profile-create 对应的样子。
所以普通 Git 像是:一本书,一次只能摊开一页。
而 git worktree 打破的不是“一个目录只能一个分支”这个限制。它没有让同一个目录同时处在多个分支上。它是换了一种办法:不在同一个目录里硬塞多个分支,而是让同一个 Git 仓库挂出多个真实工作目录,每个目录各自 checkout 一个分支。就像「盗贼的极意」开发出了书签能力。
原本一次只能翻开一本书的一页,也就是一个项目目录只能 checkout 一个分支。但有了 worktree,就像给不同页面夹了书签,可以让多个“能力”同时维持展开。
比如你执行:
git worktree add ../squady-app-fix-profile-delete fix/profile-delete
git worktree add ../squady-app-fix-draft-clear fix/draft-clear
就相当于:
盗贼的极意: 主仓库 squady-app
书签 A: squady-app-fix-profile-delete
书签 B: squady-app-fix-draft-clear
于是你会得到:
squady-app/ 当前分支:dev
squady-app-fix-profile-delete/ 当前分支:fix/profile-delete
squady-app-fix-draft-clear/ 当前分支:fix/draft-clear
每个目录都像一本“被书签维持展开”的页面。
这几个目录不是虚拟目录,也不是 VS Code workspace 的显示效果,而是真实存在的文件夹。只是它们背后仍然属于同一个 Git 仓库体系,很多 Git 数据是共享的,比如:
- commits
- branches
- tags
- objects
- remotes
- origin/main 或 origin/master
所以我现在更愿意把它理解成:同一个 Git 仓库宇宙,多个现实工作现场。
这和直接 clone 多份项目有点像,但又不完全一样。如果直接在不同路径下 clone 三份仓库,也可以并行开发:
squady-app-copy-a
squady-app-copy-b
squady-app-copy-c
但这相当于造了多个独立的 Git 宇宙。每一份都有自己的 .git,各自的 branch、commit、remote tracking 状态可能不一致。一个仓库里的提交,另一个仓库不一定马上知道,通常需要 push、fetch、pull 或 patch 才能互通。
而 worktree 的不同在于:多个工作目录仍然挂在同一个 Git 仓库体系下。
在一个 worktree 里提交的 commit,其他 worktree 通常也能在 Git 层面看到。比如:
cd ../squady-app-fix-profile-delete
git commit -m "fix: update profile after deleting trace"
然后回到主目录:
cd ../squady-app
git log --all --oneline
通常也能看到这个 commit。这有点像 Git 里的局域网:大家不在同一个房间里工作,但都在同一个仓库宇宙里。
不过这里有一个关键限制:worktree 共享的是 Git 仓库级数据,不是实时共享未提交的文件修改。
如果某个 worktree 里的改动还没有 commit,其他分支和其他开发者默认是看不到的。Git 本身不会突然变得热心,跳出来提醒你:“喂,另一个 worktree 也在改这个文件。”Git 更像是事后裁判。出了冲突,通常到 merge / rebase 的时候才处理。而 multi-agent system 更像是提前雷达。还没真正撞上之前,它可以通过额外的调度和 diff 分析,告诉你哪里可能撞车。
所以我可以这样记:
- Git: 事后裁判,出了冲突才处理
- Multi-agent system: 提前雷达,还没打就告诉你哪里可能撞车
- overlap: 雷达扫描出的危险施工区域
这里的 overlap 文件,不是 Git 或 worktree 提供的某种特殊文件,也不是一种配置文件。更准确地说,它是多个 agent / 多个分支的 diff 集合做比较后得到的结果。
比如:
Agent A 修改了: cache.ts, profile.service.ts
Agent B 修改了: cache.ts, feed.service.ts
那么 cache.ts 就是 overlap 文件,因为两个任务都改到了它。但 overlap 不等于一定冲突。它只是说明:多个任务在同一块区域施工,未来有撞车风险。
如果两个 agent 改的是同一个文件的不同区域,也许不会产生 Git merge conflict。但如果它们改的是同一个函数、同一段逻辑,冲突概率就会上升。更麻烦的是,有些时候 Git 层面不会冲突,但语义上会冲突。比如一个 agent 改了缓存结构,另一个 agent 还在按旧缓存结构写调用代码。Git 可能沉默,运行时替它尖叫。
所以 worktree 只负责隔离,不负责分析。它只做一件事:给每个任务一个独立文件系统视图。
比如:
Agent A → worktree A → fix/profile-delete
Agent B → worktree B → fix/draft-clear
Agent C → worktree C → fix/feed-cache
它不会自动比较 A 和 B 的 diff,也不会自动分析谁和谁有潜在冲突。真正负责这些的是 Codex / opencode 这类 agent 系统,或者是你自己写的脚本、CI、IDE 插件。
也就是说:
- worktree 是代码隔离容器;
- Agent 系统是任务调度容器。
Codex / opencode 这类系统负责的是:任务怎么拆、哪个 agent 做哪个任务、上下文怎么给、进度怎么展示、diff 怎么汇总、什么时候让你 review。它更像“调度室”。
worktree 负责的是:代码在哪个目录、当前在哪个分支、这个 agent 的改动不要污染另一个 agent 的工作区。它更像“施工现场”。
这两个东西一结合,多 Agent 并行开发才真正成立。以 Codex 为例,Codex Desktop / Codex app 大概就是把这套流程产品化了。你在 UI 里开一个任务,它可以帮你准备对应的 worktree,让这个任务在独立分支和独立目录里运行。多个 thread 可以并行推进,各自有自己的上下文、diff 和任务记录。
如果我自己用 CLI 手动做,流程大概是:
git worktree add -b fix/profile-delete ../squady-app-fix-profile-delete
cd ../squady-app-fix-profile-delete
codex
然后再开一个 terminal:
git worktree add -b fix/draft-clear ../squady-app-fix-draft-clear
cd ../squady-app-fix-draft-clear
codex
这时:
- 我自己 = 调度器
- terminal = 任务窗口
- codex = 执行 agent
- worktree = 代码隔离现场
- git merge = 最后结算机制
Codex Desktop 和 opencode 这类系统做的事情,就是把这些步骤往上包装一层。它们不只是“能改代码”,更重要的是负责调度。所以它们是“调度室”。
Codex Desktop 的好处是,它会帮你隐藏很多路径、分支绑定和 session 管理,让你看起来像是在一个干净的项目界面里同时跑多个任务。但这并不意味着它不需要额外文件路径。不同任务如果要真正隔离,底层仍然需要独立 worktree,也就仍然会有额外工作目录。只是桌面端工具把这些目录藏起来或集中管理了,让用户不必手动处理。
如果自己使用 CLI,也能做到类似效果,只是要自己负责:创建 worktree、拆分任务、启动多个 Codex session、检查 diff、识别 overlap、处理冲突、合并分支、清理工作目录。这更透明,但也更依赖自己管理。
Desktop 适合把调度外包;CLI 适合把控制权握在自己手里。
最后,用念能力版总结一下:
| Git 概念 | 猎人比喻 |
|---|---|
| .git 主仓库 | 盗贼的极意这本书本体 |
| branch | 书里的不同能力页 |
| worktree | 书签固定住的一页 |
| working directory | 当前展开的战斗场地 |
| Codex agent | 被派去执行能力的人偶 / 分身 |
| merge | 把不同战果汇总回主线 |
但有一个限制:同一个本地分支通常不能被两个 worktree 同时 checkout。
也就是说:
squady-app/ dev
squady-app-another/ dev ❌ 通常不允许
Git 会拦你一下,像念能力的制约与誓约。所以更推荐给每个 agent 单独开分支:fix/recommendation-delete, fix/profile-create, fix/thread-floor-no-concurrency。
一句话总结:
worktree 就是给同一个 Git 仓库的不同分支夹书签,让它们同时以不同文件夹的形式展开。它不是突破了“一个目录只能一个分支”的限制。它是绕开了这个限制:不开同一个目录,直接开多个目录。而 Codex / opencode 这类系统,就是在这些目录之上,再加上一层任务调度、上下文管理和 diff 汇总。
团长点头,Git 沉默,Codex 被关进不同 worktree 里开始加班。
补充说明(关于 Opencode 生态)
我额外查了一下 opencode 的公开文档和生态页:opencode 的 custom tools 上下文里区分了 directory 和 worktree,生态页也列了 opencode-worktree、opencode-workspace 这类插件;其中一个 worktree 插件说明它会在仓库外创建独立 worktree、打开新的 OpenCode session,并支持多个 worktree 同时存在。这部分可以作为你文中“opencode 这类系统/插件生态也在围绕 worktree 做调度封装”的旁证,但我不建议在正文里写死“opencode 官方桌面端一定就是这样实现”,免得把工具生态和核心产品混成一锅版本号地狱。