AI 编程工具改变了写代码的节奏。以前一个人同时只能推进一条线,现在用 Claude Code 或者其他 AI agent 可以很自然地并发:一个任务交给 agent 跑着,自己再开一个 session 做另一件事。问题随之而来——两个任务如果在同一个工作目录里,文件系统是共享的,两个 agent 会互相踩脚。
这不是 AI 工具的问题,是 git 工作目录没有为"并发"设计。git worktree 才是。
事实上,Claude Code 官方文档里有一整页专门介绍 worktree 隔离:自定义 subagent 可以在 frontmatter 里写 isolation: worktree,每个子任务就会在自己的文件系统里工作,互不干扰。这个设计背后的 git 原语,就是本文要介绍的内容。
当然,worktree 不只是 AI agent 的基础设施。在没有 AI 的场景里,它也能让一类常见情况更顺滑:正在 feature 分支开发到一半,突然需要紧急修复线上 bug。用 stash 当然能解决,但 worktree 让你不必暂停手头的工作——hotfix 目录和 feature 目录同时都是活的,可以各自跑测试、开编辑器,互不干扰。
1. 核心概念
通常我们认为一个 git 仓库就是一个工作目录,配一套 .git 目录里的对象存储、索引(index)和 HEAD 引用。但这个绑定并非不可拆分。
git worktree 允许从同一个 .git 存储出发,创建多个独立的工作目录(linked worktrees)。每个工作目录有自己的 index 和 HEAD,因此可以各自检出不同的分支。它们共享提交历史和对象存储,但彼此的工作区完全独立,不会互相干扰。
第一次打开仓库的那个目录叫做 main worktree(主工作树)。之后用命令创建的每一个额外目录叫做 linked worktree(链接工作树)。两者在 git 操作层面是对等的——没有主从之分,只是一个有 .git 目录,另一个通过 .git 文件指向那个目录。
一个约束值得提前知道:同一个分支不能同时被两个 worktree 检出。这不是 bug,而是防止两个工作区同时修改同一分支造成冲突。如果需要在新 worktree 里基于某个分支工作,可以从它新建分支,或者用 --detach 以 detached HEAD 状态检出。
2. 基础用法
准备一个已有仓库,添加一个新的 worktree:
# 在 ../hotfix 目录创建新 worktree,基于 main 分支新建 hotfix/login
git worktree add ../hotfix -b hotfix/login main这条命令做了三件事:在 ../hotfix 路径创建目录,新建 hotfix/login 分支,并检出到那个目录。
如果分支已经存在,直接指定就好:
git worktree add ../review feature/new-api查看当前所有 worktree:
git worktree list输出大概是这样:
/home/alice/projects/myapp a3f1c28 [main]
/home/alice/projects/hotfix a3f1c28 [hotfix/login]
/home/alice/projects/review 9e2b441 [feature/new-api]修完 hotfix,不再需要那个 worktree 时:
git worktree remove ../hotfix这个命令会删除那个目录,同时清理 .git 里的 worktree 记录。但它有保护措施:如果目录里有未提交的修改,它会拒绝删除(可以加 --force 强制)。
如果目录已经被手动删除,只是 .git 里的记录还在,用 prune 清理:
git worktree prune3. 实际场景
线上紧急修复是最经典的使用场景。开发分支继续待着,新建 worktree 处理 hotfix,两边的文件系统完全分离,修完直接删 worktree,回去继续开发,什么都不用 stash。
# 开发分支工作中
cd ~/projects/myapp # feature/payment 分支
vim src/payment.ts # 修了一半
# 紧急 hotfix
git worktree add ~/projects/myapp-hotfix -b hotfix/crash main
cd ~/projects/myapp-hotfix
vim src/auth.ts # 修完
git commit -m "fix: auth crash"
git push origin hotfix/crash
# 在 GitHub/GitLab 上提 PR 合并到 main,或直接合并:
# git switch main && git merge hotfix/crash && git push
# 如果 feature 分支也需要这个修复,cherry-pick 过来
cd ~/projects/myapp
git cherry-pick hotfix/crash
# 清理 worktree(分支已合并,可以一并删除)
git worktree remove ~/projects/myapp-hotfix
git branch -d hotfix/crash同时跑多个命令也是常见场景。比如在 main 分支跑测试套件的同时,在 feature 分支继续开发,两个测试进程用的是不同的文件集,互不影响:
git worktree add /tmp/myapp-test main
cd /tmp/myapp-test && npm test & # 后台跑 main 的测试
cd ~/projects/myapp # 继续写 featureCode review 可以借助 worktree 避免污染自己的工作区。需要看一个同事的 PR 时:
git worktree add /tmp/review-pr42 origin/feature/their-branch
cd /tmp/review-pr42
# 看代码、跑一遍、测试
git worktree remove /tmp/review-pr424. 与 IDE 和工具的协作
worktree 在文件系统上是独立的目录,IDE 可以各自打开它们。VSCode 里可以同时打开两个窗口,一个指向主项目,一个指向 hotfix 目录,互不干扰。
如果配合 Zellij 或 tmux,可以给不同 worktree 分配不同的 session 或 tab,进一步减少来回切换的摩擦。比如主开发工作区一个 session,hotfix 工作区另一个 session,zellij attach hotfix 就能切过去。
一个小细节:linked worktree 的 .git 是一个文件(不是目录),内容类似 gitdir: /home/alice/projects/myapp/.git/worktrees/hotfix。这是 git 把多个工作区指回同一个对象存储的机制。知道这个可以避免误删那个 .git 文件。
CI/CD 流水线在某些场景里也会用 worktree。如果流水线需要同时构建两个分支,用 worktree 比克隆两次仓库快,因为对象不需要重新下载。
5. 常用命令速查
# 添加 worktree(新建分支)
git worktree add <path> -b <new-branch> <start-point>
# 添加 worktree(已有分支)
git worktree add <path> <existing-branch>
# 添加 worktree(detached HEAD)
git worktree add --detach <path> <commit>
# 列出所有 worktree
git worktree list
git worktree list --porcelain # 机器可读格式
# 移动 worktree 到新路径
git worktree move <old-path> <new-path>
# 删除 worktree
git worktree remove <path>
git worktree remove --force <path> # 强制,忽略未提交改动
# 清理失效记录
git worktree prune
git worktree prune --dry-run # 预览,不实际删除6. 总结
git worktree 把"分支"和"工作目录"的绑定关系解开了。这个解耦带来的直接变化是:多个任务可以在文件系统上同时存在,各自有独立的进程、编辑器和终端,而不是共用同一个工作目录、靠来回切换维持秩序。
最值得先试的场景是紧急 hotfix 和 PR review——一条命令创建,做完删掉,几乎没有心智负担。用熟了之后,worktree 会变成一个自然反应:需要隔离,就开一个目录。