五个 Agent 工作区,worktrunk 实测

五个 Agent 工作区,worktrunk 实测

下午三点,最容易上头的事不是写代码,是同时开五个 AI 改一个项目。

五个窗口、五个分支、五次 git worktree add、五次 cd ../repo.feat。真正让人放弃并行的不是模型不够聪明,是目录切来切去。所以我今天装了一个专门管这件事的小工具:worktrunk,截至 11 月 4 日 10,672 star;当天我看到的 GitHub trending 第 3,这个排名事后没法复核。

先说清楚这篇测了什么、没测什么,免得标题比证据走得更远:

  • 测了 :建 5 个 worktree 的耗时;copy-ignored 复制一个 120MB 测试文件的时间和 df 差值;5 份普通复制的磁盘占用(df 实测 600MB);remove --foreground 删完的耗时(0.09s,43 个文件 / 120MB);一个 pre-start hook 的耗时。
  • 没测:五个 AI 真的跑完五个任务、冲突怎么解、rebase 怎么走、reflink 之后写入的块分裂、交互式 picker、LLM 生成 commit message。

所以下文里的「快」「慢」「省」,只对应上面被量过的那几个动作。

先把结论放在前面:它不会让 worktree 变快:建 5 个比原生 git 多花 0.34s,单个多约 0.07s(本次单次测量约 4 倍);但它把同一份 120MB 的复制,从「搬 120MB、0.20s」变成「共享磁盘块、0.02s」,df 上看不到明显新增占用。

两条实测 + 一条对照基线:

项目 原生 git / cp worktrunk
创建 5 个 worktree 0.11s 0.45s
复制 120MB 测试文件(单文件) 0.20s,df +122,916 KB 0.02s,df −32KB
5 份同内容目录的磁盘占用 600MB(df 实测,差 614,716 KB) 5 份 reflink 未测

测试环境:arm64 Mac,macOS 26.6.2,git 2.56.0,worktrunk v0.81.0。

一、它把三个命令压成一个,但没打算跑得更快

git worktree 本身不复杂:它让同一个仓库的不同分支,各自有一个独立目录,互不干扰。五个 AI 并行时,这是最干净的隔离方式,比来回 git stash 稳。

问题是原生命令的输入成本高。仓库 README 里给了一组对照:创建并启动 Claude,原生要这样:

bash 复制代码
git worktree add -b feat ../repo.feat && \
cd ../repo.feat && \
claude

worktrunk 是一行:

bash 复制代码
wt switch -c -x claude feat

清理也一样。原生要回到主仓库、删 worktree、删分支;worktrunk 是 wt remove。它把「分支名」当成 worktree 的地址,路径用模板自动算,所以你不用记住 ../repo.feat 这种位置。

这个项目的体量:10,672 star、388 fork(截至 11 月 4 日),MIT OR Apache-2.0,Rust 写的,release 包 6.4MB,解压后 wt 单文件 22MB。

二、worktree 便宜,是因为它不复制历史

很多人第一反应是「开五个目录,不如 clone 五份」。真 clone 五份,每份都带完整对象库;worktree 不是。

我拆开看了。主仓库的 .git 是 740KB,每建一个新 worktree,目录里只多一个 55 字节的 .git 文件:

javascript 复制代码
gitdir: /tmp/wt-demo/.git/worktrees/wt-demo.f1

它是个指针,真正的 commit、tree、blob 还放在主仓库里共享。所以我那个带 40 个源文件的新 worktree,在复制依赖之前只有 336KB。

这也是 worktrunk 值得存在的前提:worktree 本身已经足够便宜,缺的只是一个顺手的入口。如果底层是 clone,再怎么封装命令也救不回来。

三、五个工作区怎么摆

这一段是流程演示,不是任务实测:我建了五个工作区,每条命令会把对应 agent 接到当前终端,但我没有真在五个窗口里输入任务,也没有让它们跑完、制造冲突再解。五个 agent 分别做登录、接口、样式、测试、文档------这是分工设想,不是五个 PR 的结果:

bash 复制代码
wt switch -c -x claude fix-login
wt switch -c -x codex refactor-api
wt switch -c -x claude polish-css
wt switch -c -x codex add-tests
wt switch -c -x claude write-docs

-c 是新建分支,-x 是创建完直接执行命令。五个 agent 会各自进自己的目录、在不同分支上工作,文件层面不会互相覆盖;实际改代码的流程我这次没跑。

注意:这五条要在各自的终端里执行。-x 会接管当前终端,第一条跑起来后,同一个窗口里的后续命令不会继续执行。

中途看进度:

bash 复制代码
wt list

收工:

bash 复制代码
wt merge -y fix-login
wt remove -y polish-css

-y 是跳过确认。这套流程里我实际只用到 switch、list、merge、remove 四个子命令,没有碰交互式 picker,也没有让 LLM 生成 commit message。

四、先泼冷水:创建比原生 git 多花 0.34 秒

我没有只看 README,直接建了个测试仓库:40 个源文件,外加一个 120MB 的单文件,放在 .gitignore 里冒充依赖目录,然后在同一台机器上各建 5 个 worktree。这个 120MB 不是真实 node_modules ,是我用 dd 生成的单个大文件;真实依赖是几万个小文件,复制耗时和 reflink 行为可能不一样,这点后面还会再说一次。

原生 git:

bash 复制代码
for i in 1 2 3 4 5; do git worktree add -q -b f$i ../wt-plain.f$i; done
# real 0.11

worktrunk:

bash 复制代码
for i in 1 2 3 4 5; do wt -C /tmp/wt-demo switch -c -y f$i; done
# real 0.45

5 个 worktree,0.11s 对 0.45s:绝对值多 0.34s,单个多约 0.07s。按这一次的单次测量算是 4.1 倍,但 0.1 秒量级受进程启动抖动影响很大,别把这个倍数当稳定值。我猜慢在进程启动和那 22MB 二进制上------这只是推测,我没做 profile,也没把启动时间和 git 操作拆开量。能确认的只有总耗时这一个数。

所以第一个反直觉的点是:就「创建 worktree」这一项,原生 git 赢,而且赢得很明显。

但它省的不是创建的那 0.34 秒,是你每天要重复打的那些字。我自己是一天大概十几次目录切换,每次三行命令;worktrunk 把它压成一行,而且 wt switch feat 可以从任何 worktree 直接跳过去,不用先回到主仓库。

还有一个安装成本要先说清楚:不装 shell integration,它没法替你 cd。我第一次跑的时候,每次创建完都跟一句:

复制代码
▲ Cannot change directory --- shell integration not installed

功能不受影响,但每次多一行警告,很烦。要解决得跑 wt config shell install,它会改你的 shell 配置。

五、它省的不是「复制得快」,是根本不搬字节

如果 worktrunk 只做命令缩写,它不值得写一篇文章。它真正解决的是并行 agent 的冷启动问题:每个新 worktree 都没有 node_modules、没有 target/、没有构建缓存,五个 agent 就是五次重新安装。

它提供了一个命令:wt step copy-ignored,把主 worktree 里被 gitignore 的文件复制过去。

测试对象要先交代:一个 120MB 的单文件,用 dd 生成,放在被 gitignore 的目录里。所以它输出 Copied 1 file,因为真的只有一个文件。真实 node_modules 是几万个小文件,这个差异我没测,结论只对「大文件」成立。

普通复制:

bash 复制代码
cp -R node_modules /tmp/wt-demo.f2/node_modules
# real 0.20
# df -k 差值:122,916 KB,约 120MB

worktrunk:

bash 复制代码
wt step copy-ignored --from main
# ✓ Copied 1 file · 120.0 MiB (reflinked, no extra disk)
# real 0.02
# df -k 差值:-32 KB

同一份 120MB:cp -R 花 0.20s、df 多出约 120MB;copy-ignored 花 0.02s、df 上没有可测的新增。差别不在「复制得快」,而在它根本不做字节复制------APFS 上走 clonefile,两个文件指向同一批磁盘块。顺带一提,macOS 上手写 cp -Rc 也能拿到同样的效果;worktrunk 省的是你记得去开 clone 这一步。

本次单次测量是 10 倍,但 0.02s 已经接近计时精度,把它当量级差看,别当稳定倍数。磁盘那头要小心说:df 差值是 −32KB,落在噪声里,所以准确的说法是本次测量没有观察到明显新增占用;它推不出精确的「0 字节」,更推不出「复制不花任何磁盘」。

能支持这个现象的是 APFS 的 copy-on-write:复制时共享同一批磁盘块,只有后续写入才分裂。worktrunk 在 macOS 上走 clonefile,Linux 的 btrfs / XFS 也支持 reflink。

普通复制那边我重新量了一次,这次是 df 读数而不是推算:5 个目录各 cp -R 一份 120MB,df -k /tmp 前后相差 614,716 KB,约 600MB。

bash 复制代码
dd if=/dev/zero of=base/pkg bs=1m count=120
df -k /tmp                     # before: 24,740,764 KB available
for i in 1 2 3 4 5; do cp -R base copies/c$i; done
df -k /tmp                     # after:  24,126,048 KB available
# 差 614,716 KB ≈ 600MB

reflink 这边我只测了一份,5 份 reflink 的占用我没测,按机制应该接近 0,但这句是推断不是数据。

这里有个必须说清楚的边界:只有在支持 CoW 的文件系统上才会共享块。 ext4 上它就是普通复制,该占多少占多少;而且 reflink 之后如果你往那个文件里写,块会分裂,占用会重新长出来。构建缓存本来就会被写,所以这项收益主要落在「第一次冷启动」和「只读依赖」上。

六、hook 不是摆设,但我量了它的代价

worktrunk 的另一块是生命周期 hook:创建前、创建后、提交前、合并前、删除前,各有 pre / post 两档。pre 阻塞,失败就中止;post 在后台跑,输出进日志。

我写了一个最简单的项目配置 .config/wt.toml:

toml 复制代码
pre-start = "echo hook-ran > hook-proof.txt && sleep 0.2"

然后建第 6 个 worktree:

bash 复制代码
wt -C /tmp/wt-demo switch -c -y f6
# ✓ Created branch f6 from main and worktree @ /tmp/wt-demo.f6
# real 0.36

新目录里确实出现了 hook-proof.txt,内容就是 hook-ran。0.36s 里包含我故意加的 0.2s sleep,剩下 0.16s 是创建加执行 hook 的成本。

这个机制的实际用法不是 echo,是:pre-start 装依赖、生成 .env,post-start 起 dev server,pre-merge 跑测试。它甚至给了一个 hash_port 模板过滤器,让每个 worktree 的 dev server 自动分到不同端口,不会五个 agent 抢 3000。

安全上有个细节值得知道:项目里的 hook 命令第一次跑要批准,批准记录存在 ~/.config/worktrunk/approvals.toml;命令改了要重新批。CI 里用 --yes 跳过。

七、wt list 是我最后留下的理由

真正让我决定不卸载的,不是创建,也不是 reflink,是 wt list。

六个 worktree 的状态被压成一张表:

csharp 复制代码
  Branch  Status      HEAD±     main↕    main...±    Remote⇅  Path           Commit    Age  Message
@ main        ^                                             .              7084621   now  init
+ f1          _                                             ../wt-demo.f1  7084621   now  init
+ f2          _                                             ../wt-demo.f2  7084621   now  init
+ f3          _                                             ../wt-demo.f3  7084621   now  init
+ f4          _                                             ../wt-demo.f4  7084621   now  init
+ f6          _                                             ../wt-demo.f6  7084621   now  init

HEAD± 是有没有未提交改动,main↕ 是领先/落后主分支多少,Remote⇅ 是远端同步状态。原生的 git worktree list 只给路径和 commit,剩下的要自己一个个进去 git status。

对一个同时开五个 agent 的人来说,这张表就是仪表盘:哪个分支改完了、哪个落后了、哪个还没提交,一眼看完,不用五个终端来回点。

删除也顺手。wt remove -y f5 一条命令同时处理 worktree 和分支;原生要三条命令,而且顺序错了会报错。

这里有个我一开始没注意的地方:remove 默认把删除放到后台执行,命令返回时删除未必已经做完。所以比耗时要显式加 --foreground,让它阻塞到删完再返回。我补测了这一档:删一个带 120MB 依赖的 worktree(43 个文件),wt remove -y --foreground f10 real 0.09s,输出 ✓ Removed f10 worktree & branch ... (43 files · 120.0 MiB),删完才返回。

原生三条命令走完要多久我没测,所以两边只比命令数量,不比时间。

merge 我测的是无冲突路径:

bash 复制代码
wt merge -y f4
# ○ Already up to date with f4 (no new commits, no rebase needed)

这条路径没产生新 commit,所以它只验证了命令能跑通,冲突和 rebase 场景我没测。

八、我踩到的两个报错

第一个:同一个分支名再建一次,它不会帮你切过去,而是直接拒绝。

arduino 复制代码
✗ Branch f1 already exists
↳ To switch to the existing branch, run without --create: wt switch f1

这个设计我认同。并行 agent 最怕的就是「以为开了新分支,其实还在旧分支上改」。-c 的语义是严格的创建,想复用要去掉 -c。

第二个:worktree 里有未提交改动,remove 会拦住。

arduino 复制代码
✗ Cannot remove worktree: f2 has uncommitted changes
   M src_1.txt
↳ Commit or stash changes first, or to lose uncommitted changes, run wt remove --force f2

它没有替你决定「改动要不要丢」,而是把文件名列出来,要么 commit,要么显式 --force。对一个人管五个 agent 的场景,这个刹车比省下的那几个字值钱。

九、代价清单

我按自己会在意的顺序列:

  • 44MB 磁盘 :wt 和 git-wt 两个二进制各 22MB,release 压缩包 6.4MB。
  • shell integration 是可选项,但不装就没有自动 cd,而且每次多一行警告。
  • 创建更慢:五个 0.45s 对 0.11s,多 0.34s,单个约多 0.07s;4 倍是本次单次测量,别当稳定倍数。
  • reflink 有平台边界:APFS / btrfs / XFS 之外就是普通复制,该占多少占多少。
  • hook 有审批成本:项目配置第一次要人工点确认,团队协作时每个人都要点一次。
  • worktree 不是万能隔离 :数据库、写死的外部服务地址、共享缓存这些仓库外的东西还是共享的。端口可以靠 hash_port 在 hook 里分流,但 .env 里写死的连接串它管不了,五个 agent 照样会连到同一个 5432。

还有几项我没测,就不写结论:真实 node_modules 的复制、5 份 reflink 的总占用、交互式 picker、LLM 生成 commit message、merge 的冲突处理。

本文的终端输出在 worktrunk v0.81.0、macOS 26.6.2 上复现过(2026-11-04)。复现材料就是上面这些命令和环境:仓库 max-sixty/worktrunk,版本 v0.81.0,测试全在 /tmp 下,df -k 前后各取一次。没有跑分脚本,因为这些是一次性的手工对照,我不想把它包装成 benchmark。

十、什么时候值得装

你的情况 建议
只开 1 个 agent,偶尔切分支 不用,原生 git 够
同时开 3 个以上 agent 装,wt list 和 switch 省心
依赖/构建缓存很大,且在 APFS 值得试:本次 120MB 单文件实测接近零拷贝。真实 node_modules 我没测,先拿你最大的那个目录跑一次再决定
在 ext4 上,只想省磁盘 别指望,reflink 不生效
只想少打字,不在乎多 44MB 装,命令确实短
想要「创建更快」 别为这个装:创建比原生慢(五个多花 0.34s),它省的是输入和依赖复制,不是创建本身

最后留一个可以被反驳的判断:

worktrunk 的价值不在 worktree,而在于把「开一个新工作区」的成本压到接近 0。成本接近 0,你才会真的去开第二个、第三个 agent;在那之前,多数人所谓的并行,只是五个窗口切来切去。

如果你从来不并行跑 agent,这套东西对你就是负资产:多 44MB,多三个命令,多一层要记的配置。这话我认,也欢迎你拿自己的用法来反驳。

如果真按这个流程跑一天,画面大概是这样:五个 AI 各改各的,你在 wt list 里看谁改完了,然后 wt remove 收掉一个,磁盘不用为每份依赖再付 120MB。这一段是设想,不是我跑出来的------我验证的只有创建、复制、删除这几步,五个 agent 跑完一天会怎样,得你自己试。

相关推荐
qinglongcn41 分钟前
Plan 从 DAG 退回线性清单——一个引擎设计教训
agent·ai编程
yz_aiks1 小时前
WorkBuddy 怎么做网页小游戏:深海钓鱼游戏 43 次对话、301 积分从一句话做到发布(附手机横屏踩坑)
人工智能·html5·ai编程·小游戏·workbuddy
小碗细面3 小时前
Magpie 实战教程:一个本地网关,让 Claude Code 跑 Kimi、Codex 跑 DeepSeek
aigc·ai编程
濮水大叔3 小时前
AI Vibe Coding 实战(三):把 SMS 开发方案落成 Spec 文档
ai编程·claude·vibecoding
threerocks7 小时前
2027 年最赚钱的 AI 创业方向
aigc·openai·ai编程
ZzT8 小时前
AI-SDLC 实践 01|用好 Claude Code/Codex 提供的六种能力
ai编程·claude
梯度下降者8 小时前
3天时间,我使用 Cursor 开发了一个提示词生成器
ai编程·next.js·cursor·产品开发·提示词生成器
70后写java的老码农8 小时前
换模型只改三行配置:LangChain4j + Spring Boot 3.5 实战,一次分别接入 9 家模型服务
后端·ai编程
Rain的Java大神实战圈9 小时前
面试官让你把 LLM、RAG、Agent、MCP 串起来讲清楚,90% 的 Java 工程师当场露馅
ai编程