worktrunk
人之相识,贵在相知,人之相知,贵在知心。——孟子
三行命令变一行:worktrunk 把 git 里那个被埋没的功能挖了出来
一个被埋了很久的功能
git 里有个东西叫 worktree。
它的作用是:让同一个仓库同时在多个目录里被检出,各自在不同的分支上。你在 ~/repo 上待着不动,另开一个 ~/repo.feat 去做新功能,两边的改动互不干扰,共享同一份 .git。
这个功能在 git 里已经存在很多年了,一直不温不火。原因是大部分人的工作流里,切换分支就够了——反正你只有一双手,一次只能改一处。
然后 agent 来了。
一个能连续跑半小时不喊停的编码 agent,会让你产生一种很自然的念头:那我同时开五个呢?
项目地址:https://github.com/max-sixty/worktrunk
worktrunk 就是从这个念头开始的产品。它的描述只有一句:一个 git worktree 管理的 CLI,为并行 AI agent 工作流而设计。
五个 agent,五个目录,互不踩脚
文档把背景交代得很清楚:
像 Claude Code 和 Codex 这样的 agent,已经能长时间无人监督地处理任务,因此同时管理五到十个是可行的。而 git 原生的 worktree 功能,正好能给每个 agent 一个独立的工作目录,让它们不互相踩改动。
逻辑成立。但紧接着就是那句转折:
可 git worktree 的体验很笨重。
笨重到什么程度?文档举了个例子:哪怕只是开一个新工作区这么小的事,你都得把分支名打三遍。
先是 git worktree add -b feat ../repo.feat,然后 cd ../repo.feat。
打三遍不是修辞。-b 后面一次,路径里一次,cd 里再一次。而人是会打错的,尤其是在第五个窗口里。
它做的第一件事:把分支名变成地址
worktrunk 的核心设计只有一句话:工作区用分支名寻址,路径由可配置的模板算出来。
这句话听着平淡,实际是把一个「你需要记住路径」的系统,改成了一个「你只需要记住分支」的系统。
分支名你本来就要记,因为你要提交、要开 PR、要合并。路径不是——路径是机器该操心的事。
而且它留了个后门:接受分支名的命令,也接受该工作区所在的路径。你想用哪种都行。
这套「以名字为地址」的抽象,一个直接的后果就是命令变短了。下面这张对照表来自文档:
| 任务 | worktrunk | 原生 git |
|---|---|---|
| 切换工作区 | wt switch feat |
cd ../repo.feat |
| 建工作区并启动 Claude | wt switch -c -x claude feat |
三行命令 |
| 清理 | wt remove |
三行命令 |
| 带状态列出 | wt list |
git worktree list,只有路径 |
表格右列最扎眼的不是长度,是最后一行那四个字:只有路径。
一条命令里塞了四件事
wt switch -c -x claude feat 这一行值得单独拆开看。
它同时做了:建分支、建工作区、切过去、启动 Claude。
四个动作,一个命令,零次重复输入。而原生 git 那边是三行,还得你自己记得 && 串起来,不然中间某一步失败了你都不知道。
这个差别在一个 agent 上不明显,在五个 agent 上就是「愿不愿意再开一个」的分界线。
工具的复利不在单次节省的那三秒,在它降低了「再来一次」的心理成本。
并行之后,冒出来的四个新问题
开五个工作区很快乐,快乐完之后有四个麻烦:
端口冲突。 每个工作区都想起一个开发服务器,然后它们想占同一个端口。
缓存重复。 十个工作区,十份 node_modules,十份 target/,硬盘开始报警。
清理。 活干完了,工作区和分支还堆在那儿,一个一个删到手软。
总览。 五个工作区五个 agent,谁卡住了,谁跑完了,谁的 CI 挂了?
worktrunk 的「生活质量功能」几乎全在回答这四问。
端口:模板里有个 hash_port 过滤器,给每个工作区算一个唯一的端口。
缓存:这一步做得最漂亮——在 APFS、btrfs 和 XFS 上,十个工作区可以直接共享 target/、node_modules/ 这些目录,既不用重新构建,也不用真的复制。这靠的是写时复制,文件系统层面的能力。
清理:wt remove 一条命令,工作区和分支一起收掉。
总览:wt list 给每个分支列出 CI 状态,还有 AI 生成的摘要。
再加上 PR 直接检出——wt switch pr:123 跳到那个 PR 的分支——并行工作流该有的零件基本齐了。
那一屏 wt list,信息密度有点高
快速开始那一段的输出,值得看一眼:
1 | Branch Status HEAD± main↕ main…± Remote⇅ Commit Age Message |
@ 是当前所在的工作区,^ 是主分支。+ 表示有暂存的改动,↑1 表示领先 main 一个提交,⇡ 表示有没推的提交。
一行里塞了分支、状态、相对 HEAD 的增删、相对 main 的领先落后、相对远端的同步情况、提交号、时间、提交信息。
而且最后那行还告诉你:隐藏了 Path 列。
一个列表能自定义显示哪些列,说明作者自己每天都在用这个东西,而且被某一列挤得难受过。
合并:一条命令里做完六件事
wt merge main 的输出,是整份文档里我最喜欢的一段,因为它把「自动化」和「你看得见发生了什么」这两件事同时做到了:
先生成提交信息并提交改动,告诉你改了几个文件、加了多少行、有没有需要 squash。
然后合并到 main,如果不需要 rebase 就直说「不需要 rebase」。
然后打印被合并的提交、改动的文件、增删行数。
然后在后台移除工作区和分支,并说明为什么可以安全移除——因为它和 main 是同一个提交。
最后切回 main 的工作区。
这六步,每一步都有输出,每一步都说得清为什么。
对比一下某些「一条命令搞定一切」的工具:它也确实一条命令搞定了,但你不知道它干了什么,出事的时候也不知道从哪一步开始查。
自动化最难的从来不是省掉步骤,是省掉步骤之后还让人放心。
安装:一句装包,一句装 shell
1 | brew install worktrunk && wt config shell install |
两条命令,第二条是关键。
为什么要单独装 shell 集成?因为 wt switch 需要改变你当前 shell 的目录。一个普通子进程改了 cd,父进程是不知道的——这是 Unix 进程模型的基本事实,绕不过去。
所以它得往你的 shell 配置里注入一小段东西,让命令能在当前 shell 里执行。
这一句也解释了为什么它不能只是一个「下载了就能跑」的二进制。工具和 shell 的关系,比大多数 CLI 想象的要深。
第二种装法是 cargo,Arch 用 pacman,conda 和 pixi 也有社区维护的包。
Windows 上那个撞名的 wt
这一段是全文最诚实的技术细节之一。
wt 这个短名字在 Windows 上是 Windows Terminal 的命令。所以 winget 安装时,会额外把它装成 git-wt,避免冲突。
你要想直接用 wt,就得去设置里把 Windows Terminal 的别名关掉:设置 → 应用 → 高级应用设置 → 应用执行别名 → 关掉 Terminal 和 Terminal Preview。
给一个命令取一个两个字母的名字,代价是要跟操作系统抢命名权。
而它没打算抢,它打算共存——两个名字都给你。
顺带说一句,Windows 版本有免费的代码签名,由 SignPath 提供。
藏在注释里的两段话
这份文档有两个 HTML 注释,写到了一种少见的程度。
第一段在开头,说 crates.io 的徽章先注释掉了——因为 shields.io 被 crates.io 限流,渲染出来是「CRATES.IO: INVALID」,等上游修好再恢复。
第二段在文末,解释 star-history 图表为什么要带一个 sealed_token:GitHub 把 stargazer 数据限制给仓库管理员和协作者,而 star-history 的服务器两者都不是,所以不带 token 就只能渲染一个「GitHub restricted access」的占位图。那个 token 是细粒度的,只够到这个仓库;它必须有写权限,因为 GitHub 把写权限当作协作者身份的证明。密文公开是安全的,真正的风险是 star-history 解密后持有一份能推送到这个仓库的凭证,直到 2027 年 8 月 16 日过期——那天图表会悄悄退回占位图,没有别的信号。
这段话如果没人看,它就白写了。但它还是写了,而且写得比很多安全公告都清楚。
一个项目愿意在注释里解释「我们借出了一把有时限的钥匙,以及为什么必须借」,这种透明度不太常见。
顺便说,「最流行」是它自己说的
文档顶上有一段 2026 年 11 月的更新:worktrunk 在今年年初发布,很快就成了最流行的 git worktree 管理器,并补了一句「是用心做的,没有 slop」。
这是项目自述,读的时候心里有个数。
但同一段里有句话更有意思:请把任何摩擦告诉我,哪怕是很小的摩擦或者一句不够好的提示语;对我帮助最大的,是大家把他们察觉到的问题贴出来。
「哪怕是很小的摩擦」——这句话比任何功能列表都更能解释这个项目为什么长这样。wt list 会告诉你隐藏了哪些列,wt merge 会解释为什么不需要 rebase,wt switch 会把三个动作合成一个。这些都是被摩擦磨出来的。
贡献指南里还专门开了一个 issue 模板,标题是「Worktree 摩擦:」,然后问三件事:哪个 worktree 相关的任务还是很痛、你现在怎么绕过去、理想方案是什么。
把「痛」做成一个工单类型,这个思路挺狠。
许可
MIT 或 Apache-2.0,双许可。你可以按自己项目的需要选一个。
最后
回到开头那个被埋没的功能。
git worktree 一直都在,能力也一直够用。它缺的不是功能,是一层把「路径」翻译成「名字」的界面——而这层界面,因为 agent 并行这件事,突然变得值得做了。
所以这个工具真正的贡献不是发明了什么,是承认了一件很朴素的事:一个好功能如果每次用都要多打两遍分支名,那它就会被闲置十年。
降低摩擦这件事,听起来不像技术,更像手艺。但很多工具的命运,就是被这两三行命令决定的。
