git worktree 这个命令 2015 年就有了,比我用的任何 AI 编程工具都老。但它直到我开始用 AI 替我写代码,才真正显出价值:多个分支、多个人(或多只 Agent)能在同一份仓库历史里并行干活,各自有独立的工作目录,互不踩脚。
引子:你的 Agent 正在和你抢同一份工作目录
你大概率遇到过这个画面。
正在 main 上改功能,改到一半,突然想起有个线上 bug 要修。顺手开了个 AI Agent(Cursor、Claude Code、WorkBuddy 都行),让它「去把登录验证码失效的 bug 修了」。它很听话,直接在你当前目录里切到 fix 分支、改文件、跑测试。等你回过神,刚才那一半没提交的功能改动已经被它搅进去了。
更常见的另一种:想让两个 Agent 同时干活,一个重构旧模块,一个给新功能补测试。但它们都在同一个工作目录里,第二个一启动就把第一个的活儿冲掉。最后只能排队等,串行跑,一天被拉成三天。
这真不怪你,是「一个仓库只有一个工作目录」这个老设定在拖累。
worktree 到底是个啥
普通的 git checkout 是在同一个目录里切换分支,任何时候你只能看见一个分支的文件。
git worktree 反过来,给任意分支再开一个独立目录,多个目录挂在同一份 .git 历史上,各自有各自的文件状态。
~/code/
├── lumen/ # 主工作树,分支 main
│ └── .git/ # 唯一的 git 目录(对象数据库在这)
├── lumen-dashboard/ # 关联工作树,分支 feat/analytics-dashboard
└── lumen-login-fix/ # 关联工作树,分支 fix/login-captcha
三个目录共享同一份提交历史,都连着同一个 .git 对象数据库,但文件各是各的。你在 lumen-dashboard 里改 Dashboard.tsx,lumen 里的 Dashboard.tsx 纹丝不动。
用法和正常 checkout 没区别:改文件、commit、push 照常。区别在于你再也不用反复 checkout + stash 来「保存现场」了。
传统分支 vs worktree
过去想并行搞两件事,套路是这样的:
git stash # 先把当前活儿塞起来
git checkout fix # 切过去修 bug
... 修完 ...
git checkout feat # 切回来
git stash pop # 再把现场捞回来(祈祷没冲突)
生产 bug 一打进来,心流就碎了。stash 攒多了根本记不住哪坨对应哪件事,切错分支把代码提交到地方更是常事。
用 worktree,你直接为 bug 开个新目录,主目录啥都不动:
# 把已存在的分支挂成一个工作树
git worktree add ../lumen-login-fix fix/login-captcha
# 或者一步到位:新建分支 + 开工作树
git worktree add -b feat/analytics-dashboard ../lumen-dashboard
新目录生成在主项目同级的位置,checkout 到你指定的分支。之后每个目录里独立编辑、提交、push,主工作目录干净如初。
有个限制得先说清楚:同一个分支不能同时挂在两个 worktree 上,每个 worktree 必须 checkout 一个唯一分支。这反而逼出了「一个任务 = 一个分支 = 一个目录」的对应关系,脑子不容易乱。
AI 时代它才好用
下面这几条,是写给已经开始用 AI 写代码的你。
给每只 Agent 一个房间。 最直白的玩法:每个 AI 任务开一个工作树,把 Agent 关进那个目录跑。
git worktree add -b agent/dashboard ../lumen-dashboard
git worktree add -b agent/login-fix ../lumen-login-fix
Agent A 在 lumen-dashboard/ 里搭看板,Agent B 在 lumen-login-fix/ 里修登录验证码,主目录 lumen/ 留在 main,你随时 git diff 审阅两边,或者自己手写点不想让 Agent 碰的精细活。两个 Agent 用的是同一份 Git 历史,但文件系统互不干扰。A 把 Dashboard.tsx 改崩了,绝不会连累 B,更不会动你的主树。
主树始终是能发的状态。 Agent 跑起来经常吐一堆中间产物、临时脚本、调试日志。它在主目录里跑,你的 git status 就被污染,连「这棵树现在能不能发」都看不清。关进 worktree 后,主树一直是你亲手维护的干净状态,Agent 那边折腾成什么样都不影响你随时合代码、切分支、跑 CI。
你的 IDE 不被打断。 不少 Agent 会改 .vscode/、临时装依赖、甚至动 package.json。它在你正在用的目录里跑,编辑器就疯狂弹「文件已变更」,终端里 npm 进程互相打架。worktree 把这一切挪到另一个目录,IDE 稳如老狗,该干嘛干嘛。
实战:线上登录挂了,让 Agent 救火,你继续写看板。 初始布局就一个主树:
~/code/
└── lumen/ # 主工作树,main
你正在 lumen/ 里搭数据看板(还没提交),告警群炸了,登录验证码失效,用户进不来。开个修复工作树,把救火 Agent 丢进去:
cd ~/code/lumen
git worktree add -b fix/login-captcha ../lumen-login-fix
布局变成:
~/code/
├── lumen/ # 主工作树,main(你继续搭看板)
└── lumen-login-fix/ # Agent 在这里修登录验证码
接下来:让 Agent 在 lumen-login-fix/ 里定位、修复、跑测试;你自己在 lumen/ 里继续推进看板,完全不被打断;等 Agent 修完,你 cd 过去 git diff 验收,满意了回主树 git merge fix/login-captcha。
任务被中断时,你不再需要 stash 救命,只是开了个新房间。
操作速查
看当前有哪些工作树。 动手删之前先看清楚 Git 认得哪些:
git worktree list
输出类似:
/Users/you/code/lumen 66c16256 [main]
/Users/you/code/lumen-dashboard 0c8ba118 [feat/analytics-dashboard]
/Users/you/code/lumen-login-fix a16e4be2 [fix/login-captcha]
一眼能看出哪个分支挂在哪个目录,省得去复用已经被某个 worktree 占用的分支。
把工作树合并回主分支。 合并逻辑和普通 Git 一样,只是上下文更清楚,每个分支都住自己目录里:
# 1. 在 feature 工作树里改完、提交
# 2. 切回主工作树
cd ../lumen && git checkout main
# 3. 合并
git merge feat/analytics-dashboard
# 4. 解决冲突、push
每个 worktree 只服务于一个分支,你几乎不可能提交错分支,hotfix 打断 feature 时也不会丢现场。
删掉一个工作树。 用完就清:
git worktree remove ../lumen-dashboard
只删工作目录,分支还在。要求工作树是干净的(无未提交改动、无未跟踪文件),强删加 --force。主工作树不能被 remove。删之前务必在对应工作树里 git status 确认没有未提交改动,不然容易把 Agent 的劳动成果弄丢。
清理孤儿元数据。 手贱直接 rm -rf 删了工作树目录,Git 在 .git/worktrees/ 下还留着元数据,git worktree list 会标 missing。清掉这些僵尸记录:
git worktree prune
只清很久没用的,加过期时间:
git worktree prune --expire 7.days.ago
本地环境想一次清干净所有僵尸:git worktree prune --expire now。
带 Agent 跑的几个坑
- 同一个分支不能挂两个 worktree。给每个 Agent 单独开分支,命名区分一下,比如都加
agent/前缀。 - 启动 Agent 时把工作目录指对。很多 Agent 默认在当前目录干活,开错房间是最常见的翻车点。
- 依赖不共享。worktree 是独立目录,
node_modules、.venv默认不跟着走。要么软链过去,要么让 Agent 第一步先装依赖,别让它在空目录里瞎跑测试。 - 明确告诉 Agent 只动当前目录,别顺着相对路径去碰兄弟工作树或主树。
- Agent 干完你亲自 diff 看一眼再合。worktree 只解决隔离问题,AI 写的要不要进主干,决定权在你。
结语
我用了好几年 Git 才发现 worktree。在 AI 编程之前,它只是偶尔并行两个 feature 的小技巧;AI 编程普及之后,它成了多 Agent 并行开发的底子。谁先把它用顺,谁就能让好几只 Agent 同时给自己打工,主分支还一直干净、能发、能审。
顺序的简单活儿,普通分支切换够用。但凡你冒出「要能同时在两个地方」的念头,不管是两个 Agent 还是 Agent 加你自己,worktree 就是那个答案。去开个房间,把 Agent 关进去。