用 Git Worktrees 跑并行 AI Agent:多个 Agent 同时改代码互不打架
适用场景
当你想同时让多个 AI agent 干活——一个修 bug、一个写新功能、一个重构——它们如果都在同一个工作目录里,会互相覆盖文件、抢着切分支、把对方改了一半的代码当成最新状态。git worktree 是这个问题的标准解法:一个仓库、多个工作区、各自独立的分支和文件系统状态。
适合:
- 想跑「双 agent 交叉检查」或「N 个 agent 并行攻不同模块」的人
- 长任务重构期间还想并行修紧急 bug,不想 stash 来回折腾
- 用 Claude Code / Codex 等终端 agent、习惯一个 agent 占一个终端的人
- 受够了
git stash/ 频繁切分支导致 agent 上下文错乱的开发者
为什么是 worktree,不是 clone 或 stash
| 方案 | 问题 |
|---|---|
| 同一目录切分支 | agent 跑到一半你切分支,它的文件状态全乱;两个 agent 抢分支 |
git stash | 临时切走再切回,agent 看到的代码状态不连续,容易误判 |
多次 git clone | 每个 clone 是独立仓库,分支/对象不共享,磁盘翻倍,push/pull 各管各 |
git worktree | 一个仓库共享 .git 对象,多个工作区各占一个目录、各在一个分支,互不干扰 |
worktree 共享同一份 .git(对象、refs、配置),所以磁盘开销小、分支全局可见,但每个工作区的文件系统状态和当前分支是独立的——正好是并行 agent 需要的隔离。
第一步:建工作区布局
推荐把主仓库和各 worktree 放在同级目录,命名带上任务语义:
# 假设主仓库在 ~/code/myapp(在 main 分支)
cd ~/code/myapp
# 为每个并行任务建一个 worktree + 新分支
git worktree add ../myapp-feature-auth -b feature/auth
git worktree add ../myapp-bugfix-payment -b bugfix/payment
git worktree add ../myapp-refactor-api -b refactor/api-client
# 查看所有 worktree
git worktree list
得到的目录结构:
~/code/
├── myapp/ # 主仓库,留在 main 做 review/合并
├── myapp-feature-auth/ # Agent A 在这里跑,feature/auth 分支
├── myapp-bugfix-payment/ # Agent B 在这里跑,bugfix/payment 分支
└── myapp-refactor-api/ # Agent C 在这里跑,refactor/api-client 分支
基于已有分支建 worktree(不新建分支):
git worktree add ../myapp-hotfix existing-branch
第二步:每个工作区开一个 agent
每个 worktree 是完整的工作目录,进去直接开 agent:
# 终端 1
cd ~/code/myapp-feature-auth && claude
# 终端 2
cd ~/code/myapp-bugfix-payment && claude
# 终端 3
cd ~/code/myapp-refactor-api && codex
每个 agent 看到的是自己分支的干净状态,改文件、跑测试、commit 全在自己的工作区,不会碰到别的 agent 的改动。
第三步:依赖与构建产物隔离(关键坑)
worktree 共享 .git,但不共享 node_modules / .venv / 构建缓存——这些是工作区本地的。两个注意点:
- 每个 worktree 要各自装依赖:
cd ~/code/myapp-feature-auth && pnpm install
cd ~/code/myapp-bugfix-payment && pnpm install
- 端口 / 数据库 / 缓存别撞车:如果多个 agent 各自起 dev server,端口要错开(如 3000 / 3001 / 3002);用本地数据库或 SQLite 的项目,确认各 worktree 不写同一个库文件。
本站经验(aiho.net):
@nuxt/content的 SQLite 内容库是 build 时生成的本地文件,两个 worktree 同时 build 会互相覆盖导致no such table。并行时要么错开 build,要么确认各自有独立的.data/.nuxt目录(worktree 天然隔离这些,因为它们不在 git 跟踪里)。
第四步:合并回主干
agent 在各自分支 commit 后,回主仓库走正常 review/merge:
cd ~/code/myapp # 主仓库,main 分支
git fetch # 如果 worktree 已 push 到远端
# 本地合并(worktree 的 commit 在共享 .git 里,本地直接可见)
git merge feature/auth
# 或更推荐:走 PR,让另一个 agent 或人 review
# 解决潜在冲突——并行改动重叠时这里会暴露
推荐:每个 worktree 的分支单独开 PR,用「一个 agent 写、另一个 agent 审 diff」的模式(见 终端 agent 工作流),人做最终 merge。
第五步:用完清理
# 删除某个 worktree(先确认改动已合并/push)
git worktree remove ../myapp-feature-auth
# 如果目录已手动删了,清理悬挂记录
git worktree prune
# 删掉已合并的分支
git branch -d feature/auth
常见踩坑
- 同一分支不能在两个 worktree 同时 checkout:git 会拒绝。每个 worktree 必须在不同分支——这正是隔离的保证。
- 忘了各装依赖:新 worktree 没有
node_modules,agent 一跑就报 module not found。建 worktree 后第一件事是装依赖。 - dev server 端口/数据库撞车:并行起服务要错开端口,共享本地库要小心写冲突(见第三步本站经验)。
- 改了
.git/config全局生效:worktree 共享配置,改 user.email、remote 等是全局的,别以为是本工作区私有。 - 路径写死:有些工具/脚本把绝对路径写死在配置里,换到 worktree 目录会失效,用相对路径或环境变量。
- agent 跨工作区找文件:给每个 agent 的项目记忆(CLAUDE.md 等)里写清「你只在当前目录工作,不要去别的路径」,避免它顺着文件系统乱翻。
- 删 worktree 前没合并:
git worktree remove会丢掉未提交的改动,删之前确认 commit 已 push 或合并。
进阶:脚本化批量开 worktree
#!/usr/bin/env bash
# spawn-agents.sh —— 一键为多个任务开 worktree + 装依赖
set -euo pipefail
tasks=("feature/auth" "bugfix/payment" "refactor/api-client")
for t in "${tasks[@]}"; do
dir="../myapp-${t//\//-}" # 把 / 换成 -
git worktree add "$dir" -b "$t"
( cd "$dir" && pnpm install )
echo "ready: $dir ($t)"
done
git worktree list
一句话总结
一仓库 → 多 worktree(各占一分支一目录)→ 每区一个 agent 并行干
→ 各装依赖、错开端口 → 分支开 PR → 人工 review + merge → 清理
worktree 把「并行 agent 互相打架」变成「并行 agent 互不可见」,这是多 agent 工作流最便宜也最可靠的隔离手段。