AI Coding 时代,Git Worktree 为什么突然变成刚需

从 Git 原理、AI agent 并行任务、hotfix、PR review、命令用法和常见坑出发,讲清 git worktree 解决的真实问题。

一句话结论

git worktree 是 Git 自带的能力,不是 AI Coding 工具发明的新东西。

它解决的问题也不是“怎么创建分支”,而是更具体的一件事:同一个仓库,能不能同时展开多个互不干扰的工作现场

以前我们常说“开个分支做需求”。但分支只是 Git 历史上的一个指针,它不会给你第二个工作目录。你在一个目录里切分支,文件、依赖、编辑器状态、未提交改动都会跟着变化。

worktree 多给你的是一个真实目录:

repo/                 # 主工作区
repo-hotfix/          # hotfix 分支的工作区
repo-ai-refactor/     # AI 重构实验的工作区
repo-review-pr-123/   # PR review 的工作区

这些目录不是几份完全独立的 clone。它们共享同一个 Git 仓库的对象数据和历史记录,但每个目录有自己的文件现场、HEAD、index 和当前 checkout。

所以 worktree 最适合的不是“单线程写代码”,而是:

  • 当前工作不能被打断;
  • 需要快速切到 hotfix;
  • 想同时 review 几个分支;
  • 想让 AI agent 并行尝试多个方案;
  • 想把一个高风险改动关在临时目录里,做完再决定要不要合并。

如果只记一句话:

branch 保存不同方向的历史,worktree 同时展开这些方向的现场。

先把 branch、checkout、worktree 分开

Git 里有几个概念很容易混在一起。

branch 是一个名字,指向某个 commit。比如 mainfeature/loginhotfix/payment-timeout

checkout 是把某个 branch 或 commit 变成当前工作目录里的文件状态。

worktree 是一个真实的工作目录。一个 Git 仓库可以有一个主 worktree,也可以有多个 linked worktree。linked worktree 看起来像另一份代码目录,但它背后仍然挂在同一个 Git 仓库上。

默认的 Git 使用方式大概是:

一个仓库
  -> 一个工作目录
  -> 同一时间 checkout 一个分支

用了 worktree 后变成:

一个仓库
  -> 多个工作目录
  -> 每个目录 checkout 不同分支或 commit

这就是它和普通分支的区别。

分支解决的是版本历史分叉;worktree 解决的是工作现场并行。

它和重新 clone 一份有什么区别

很多人在不知道 worktree 之前,会用多 clone 解决并行问题:

app/
app-copy/
app-hotfix/

这当然能用,但成本偏高。

多 clone 意味着每个目录都有一套 .git 对象库、远程信息、hooks、配置和引用。大仓库会占更多磁盘;同步远程分支、清理本地分支、保持配置一致也更烦。

worktree 更像“轻量多开”:

同一个 Git 仓库对象库
  -> 多个工作目录
  -> 每个工作目录有自己的 checkout 状态

它不是完全免费的。每个 worktree 仍然会有一份真实文件,也通常会有自己的依赖目录,比如 node_modules.venvtargetdist。但 Git 历史和对象数据不会完整复制一遍。

所以三种方式可以这样理解:

方式适合主要问题
切分支单任务、短切换未提交改动和编辑器上下文容易被打断
多 clone强隔离、偶发需求占空间,配置和远程状态容易分散
worktree多任务并行、AI 实验、hotfix、review需要管理目录、依赖和分支占用

为什么 AI Coding 特别适合 worktree

AI Coding 改变了开发节奏。

传统开发常常是一条线:我在一个分支上理解问题、改代码、跑测试、提交 PR。即使中途切换任务,切换频率也不会太夸张。

AI agent 的工作方式更像并行探索:

  • 同一个需求可以让 agent 尝试两种实现;
  • 一个后台任务可以继续修测试,前台人类继续写设计;
  • 一个 agent 可以做重构,另一个 agent 可以查 bug;
  • 一些尝试最后会被丢弃,只保留最好的方案。

如果这些都发生在同一个工作目录里,文件很快会互相污染。你会分不清哪个改动来自哪个任务,也很难只回滚其中一个方案。

worktree 给 AI agent 的价值正好在这里:每个任务一个目录,每个目录一份 diff,每个 diff 单独验收

例如:

git worktree add -b ai/fix-login ../app-ai-fix-login main
git worktree add -b ai/refactor-router ../app-ai-refactor-router main
git worktree add -b ai/try-new-ui ../app-ai-try-new-ui main

现在你可以把三个任务交给三个 agent,或者同一个 agent 分三轮做。每个目录都可以独立安装依赖、跑测试、看 diff、提交分支。

最后你不是面对一坨混在一起的改动,而是面对三个候选结果:

app-ai-fix-login       -> 只看登录修复
app-ai-refactor-router -> 只看路由重构
app-ai-try-new-ui      -> 只看新 UI 实验

这就是 AI Coding 时代 worktree 突然变重要的根本原因。

它不是让 Git 更高级,而是让 agent 的试错半径变小。

最小命令:先学这几个就够

查看当前有哪些 worktree:

git worktree list

main 创建一个新分支,并放到同级目录:

git worktree add -b feature/search ../app-feature-search main

这个命令做了三件事:

  1. main 创建 feature/search
  2. 创建 ../app-feature-search 目录。
  3. 在这个目录 checkout feature/search

进入这个目录后,它就是一个正常 Git 工作区:

cd ../app-feature-search
git status
git add .
git commit -m "add search"

如果要 checkout 一个已经存在、但没有被别的 worktree 占用的分支:

git worktree add ../app-release release/1.2

如果只是想临时看某个 commit,不想创建分支:

git worktree add --detach ../app-debug abc1234

删除 worktree:

git worktree remove ../app-feature-search

如果你手动删了目录,Git 里可能还残留 worktree 管理信息,可以清理:

git worktree prune

日常够用的命令其实就这些:

git worktree list
git worktree add -b <new-branch> <path> <base>
git worktree add <path> <existing-branch>
git worktree add --detach <path> <commit>
git worktree remove <path>
git worktree prune

一个完整例子:不中断当前开发,修线上 hotfix

假设你正在 feature/billing-redesign 里改了一半:

git status

看到一堆未提交文件。

这时线上登录坏了,需要马上从 main 切 hotfix。

不用 stash,也不用 checkout 回 main。直接在当前仓库里执行:

git worktree add -b hotfix/login-timeout ../app-hotfix-login main

然后:

cd ../app-hotfix-login
# 修改代码
npm test
git add .
git commit -m "fix login timeout"
git push -u origin hotfix/login-timeout

hotfix 合并后,回到原仓库:

cd ../app
git worktree remove ../app-hotfix-login

原来 feature/billing-redesign 目录里的未提交改动、打开的编辑器、临时文件都没有被动过。

这就是 worktree 最朴素、也最强的价值:不用为了切任务而破坏当前现场

AI agent 的推荐工作流

如果把 worktree 用在 AI Coding,我更推荐一套固定流程。

1. 一个任务一个 worktree

不要让多个 agent 共用一个 worktree。共用之后,worktree 的隔离价值就没了。

推荐命名:

git worktree add -b ai/login-copy-fix ../app-ai-login-copy-fix main
git worktree add -b ai/router-refactor ../app-ai-router-refactor main
git worktree add -b ai/settings-redesign ../app-ai-settings-redesign main

分支名表达任务,目录名表达来源和用途。

2. worktree 放在项目同级,不要嵌进项目内部

推荐:

projects/
  app/
  app-ai-login-copy-fix/
  app-ai-router-refactor/

不推荐:

app/
  worktrees/
    app-ai-login-copy-fix/

嵌在项目内部容易让编辑器、构建工具、搜索工具、测试脚本误扫到另一个工作区。尤其是 monorepo,嵌套 worktree 会让很多工具产生很怪的边界问题。

3. 每个 worktree 独立验证

agent 做完以后,不要只看它说“完成了”。要在那个 worktree 里看:

git status
git diff
npm test
npm run lint

或者按项目语言换成对应命令:

pytest
cargo test
go test ./...
pnpm build

worktree 的价值不是让 agent “随便改”,而是让你能按任务粒度验收。

4. 好方案进分支,坏方案直接删

如果结果好:

git push -u origin ai/router-refactor

然后开 PR,或者 cherry-pick / merge 回主线。

如果结果不好:

git worktree remove ../app-ai-router-refactor
git branch -D ai/router-refactor

这比在同一个目录里手工撤销几十个文件干净得多。

worktree 不是 sandbox

这点非常重要。

worktree 只隔离 Git 工作目录,不隔离运行时资源。

它不能自动隔离:

  • 数据库;
  • 端口;
  • Redis、Kafka、Elasticsearch;
  • .env 里的凭证;
  • 浏览器登录态;
  • 系统文件访问权限;
  • 后台进程;
  • 网络访问。

所以多个 AI agent 同时在不同 worktree 里跑服务,仍然可能抢同一个端口:

app-ai-a -> npm run dev -> localhost:3000
app-ai-b -> npm run dev -> localhost:3000

也可能连到同一个开发数据库,互相改数据。

这就是 worktree 和 sandbox 的边界:

worktree 隔离代码现场
sandbox / container / dev env 隔离运行环境

更稳的做法是给每个 worktree 配自己的环境变量:

PORT=3001
DATABASE_URL=postgres://localhost/app_ai_login
REDIS_DB=2

如果风险更高,就配 Docker Compose project name、临时数据库、临时 bucket、临时 API token。不要以为用了 worktree,agent 就被关进安全沙箱了。

最常见的坑

1. 同一个分支不能同时被两个 worktree checkout

如果你在主目录已经 checkout 了 feature/a,再执行:

git worktree add ../app-a feature/a

Git 可能会报:

fatal: 'feature/a' is already used by worktree at ...

这是 Git 在保护你。

同一个 branch 指针如果被两个工作区同时移动,状态会非常危险。正确做法通常是新建一个分支,或者让其中一个 worktree 切到别的分支。

2. 依赖目录通常要重新安装

worktree 共享 Git 对象,不共享构建产物和依赖目录。

Node 项目常见情况是每个 worktree 都要有自己的 node_modules

cd ../app-ai-login-copy-fix
pnpm install

pnpm、Cargo、Go、uv 这类工具有全局缓存,实际成本会低很多。但工作目录里的依赖和构建输出仍然要按项目情况处理。

3. 被 .gitignore 忽略的本地文件不会凭空出现

很多项目依赖这些本地文件:

.env
.env.local
local.sqlite
certs/dev.pem

它们通常不进 Git,所以新 worktree 里默认没有。

这不是 Git 出错,而是 Git 正常工作。你需要用项目自己的方式生成或复制本地配置。对 AI agent 来说,这一点尤其重要:如果缺 .env,agent 可能跑不起来测试,或者误以为项目坏了。

更好的做法是准备模板:

.env.example
scripts/setup-dev-env.sh

让每个 worktree 都能从可审计的模板初始化,而不是复制一份藏着真实 token 的本机文件。

4. 手动删目录后要 prune

理想情况用:

git worktree remove ../app-ai-login-copy-fix

如果你已经手动 rm -rf 了目录,Git 可能还记得那个 worktree。此时用:

git worktree prune

这会清掉已经失效的 worktree 管理记录。

5. worktree 太多会制造认知负担

worktree 解决并行,不解决管理。

如果你同时开了十几个:

git worktree list

自己也会忘记哪个目录对应哪个任务。

我的习惯是让 worktree 短命:

  • hotfix 合并后删;
  • AI 实验验收后删;
  • PR review 结束后删;
  • 长期 release 分支才保留。

一套我会实际使用的目录规范

假设主项目叫 lumen

projects/
  lumen/
  lumen-ai-tokenizer-fix/
  lumen-ai-ui-redesign/
  lumen-hotfix-login/
  lumen-review-pr-481/
  lumen-release-1.4/

分支命名:

ai/tokenizer-fix
ai/ui-redesign
hotfix/login
review/pr-481
release/1.4

创建命令:

git worktree add -b ai/tokenizer-fix ../lumen-ai-tokenizer-fix main
git worktree add -b hotfix/login ../lumen-hotfix-login main
git worktree add ../lumen-release-1.4 release/1.4

清理命令:

git worktree list
git worktree remove ../lumen-ai-tokenizer-fix
git branch -D ai/tokenizer-fix
git worktree prune

这套规范的重点不是名字本身,而是让目录、分支、任务三者一一对应。以后看 git worktree list,一眼就知道哪个目录能删,哪个还在跑。

什么时候不该用 worktree

worktree 不是所有场景都必要。

如果你只是改一个小文件,几分钟内提交,普通分支就够。

如果你需要完全隔离依赖、系统包、数据库、网络和凭证,worktree 不够,需要 container、虚拟机、远程开发环境或 CI preview environment。

如果你的项目本身很大,每个 worktree 初始化依赖要几十分钟,也要控制数量。否则你只是把“切分支成本”变成了“维护多个环境的成本”。

如果团队还不熟悉 Git 基础,直接把 worktree 引入主流程也可能增加困惑。可以先从两个场景开始:hotfix 和 AI 实验。它们收益最明显,也最容易解释。

我对它的定位

git worktree 以前像一个偏高级的 Git 技巧。很多人知道 branch、stash、clone,但很少主动用 worktree。

AI Coding 把它推到了前台,因为 agent 让“同时做很多事”变成了日常需求。

人类开发者用 worktree,是为了减少上下文切换。

AI agent 用 worktree,是为了减少任务污染。

团队使用 worktree,是为了把实验、修复、review、release 变成可以并行验收的工作单元。

它不是替代 branch,也不是替代 sandbox,更不是替代代码审查。它只是把一个仓库从“单工作现场”扩展成“多工作现场”。

但这个变化很关键。

因为 AI Coding 的新问题不是“代码能不能生成”,而是“生成出来的多条路线,能不能被隔离、比较、验证和选择”。

worktree 正好提供了最小的一层工程基础设施。

自检清单

下次你想用 worktree 前,可以问自己五个问题:

  1. 这个任务会不会打断我当前目录里的工作现场?
  2. 我是不是想让 AI agent 做一个可以随时丢弃的实验?
  3. 我是不是需要同时看多个分支或 PR?
  4. 这个 worktree 有没有独立的端口、数据库和本地配置?
  5. 任务结束后,我准备 merge、push、cherry-pick,还是直接删除?

如果前三个问题有一个答案是“是”,worktree 很可能值得用。

如果第四个问题答不上来,就要小心:你隔离了代码,但还没有隔离运行环境。

资料