<!-- title: worktree 并行扇出批量跑任务 -->

## 概述

本教程聚焦 Claude Code 的 **worktree 并行扇出**能力：用 `claude -w` 为每个任务创建一个 git worktree 隔离副本，配合 `-p` 无头模式让多个 Claude Code 实例同时开工，最后把成果合并回主干。它直接命中"批量任务"自动化的核心痛点——串行跑十个任务要等一下午，并行跑只要最慢那个的时间。适合已经会用 `claude -p` 跑单任务、想把它扩成可调度、可隔离、可合并的批量执行器的开发者与运维工程师。

## 前置条件

- 已安装 Claude Code CLI，能跑通 `claude -p "hello"`（前置轮次已完成首跑）
- 工作目录是一个 **git 仓库**（worktree 依赖 git；非 git VCS 需额外 hook，文末会讲）
- 掌握基础 shell：变量、循环、后台进程 `&` 与 `wait`
- 可选：`xargs`（系统自带）或 `parallel`（`apt install parallel` / `brew install parallel`）做并发限流

---

## 正文

### 第 1 步：理解 worktree 隔离为什么是并行的前提

直接在同一个目录里开两个 `claude -p` 跑不同任务，会撞车：两个实例都改 `src/` 下的文件，后写的覆盖先写的，git 暂存区乱成一团。串行执行（一个跑完再跑下一个）能避免冲突，但十个任务就要排队，浪费时间。

**git worktree** 解决的就是这个矛盾：它是同一个仓库的"另一份检出"，有自己独立的工作目录和分支，但共享 `.git` 历史和远程。把每个 Claude Code 会话关进各自的 worktree，A 在改 `src/auth`，B 在改 `src/billing`，磁盘上物理隔离，互不踩脚，而合并时又因为共享同一个 `.git` 而极其方便。

一句话记住核心：**worktree 管文件隔离，subagent/agent team 管任务分工**。本教程聚焦前者——把文件隔离做成可并行调度的批量管道。

### 第 2 步：用 `--worktree` 起跑第一个隔离会话

`--worktree`（短写 `-w`）是入口。传一个名字，Claude Code 会在仓库根下的 `.claude/worktrees/<名字>/` 创建一份新检出，并在分支 `worktree-<名字>` 上启动会话：

```bash
claude --worktree feature-auth
# 等价于 claude -w feature-auth
```

**预期结果**：当前终端进入一个全新工作目录（实际是 `.claude/worktrees/feature-auth/`），分支显示为 `worktree-feature-auth`。这里做的任何修改都不会影响你的主检出。

在**另一个终端**用不同名字再开一个：

```bash
claude --worktree bugfix-123
```

现在你有两个物理隔离的会话，可同时干活。省略名字时 Claude 会自动生成一个（如 `bright-running-fox`）。

**首次使用提示**：第一次在某个目录用 `--worktree` 交互式启动前，要先在该目录跑一次 `claude` 接受工作区信任对话框；否则 `--worktree` 会报错并提示你先跑 `claude`。但**非交互的 `-p` 会跳过信任检查**，所以 `claude -p --worktree xxx` 无需此步骤——这对自动化至关重要。

**常见问题**：worktree 内容会以"未跟踪文件"形式出现在主检出的 `git status` 里。把 `.claude/worktrees/` 加进 `.gitignore` 即可：

```text
# .gitignore
.claude/worktrees/
```

### 第 3 步：配置基准分支与环境文件

**基准分支（baseRef）**。默认情况下，新 worktree 从 `origin/HEAD`（远程默认分支）拉取，保证起点干净。如果你想让 worktree 带上本地未推送的提交或在途的功能分支状态（比如让子代理在你的半成品上继续干活），把基准改成本地 `HEAD`：

```json
// .claude/settings.json
{
  "worktree": {
    "baseRef": "head"
  }
}
```

该字段只接受 `"fresh"`（默认，从 `origin/HEAD`）或 `"head"`（从本地 `HEAD`），不接受任意 git ref。想从某个 PR 拉基准，直接传 PR 号：

```bash
claude --worktree "#1234"
# 会在 .claude/worktrees/pr-1234 创建，基准为 pull/1234/head
```

**复制 gitignored 文件（.worktreeinclude）**。worktree 是全新检出，主仓库里那些没纳入版本控制的文件（`.env`、`.env.local`、`config/secrets.json`）默认不会出现，跑测试就会因为缺配置而报错。在项目根新建 `.worktreeinclude`，用 `.gitignore` 语法声明要自动拷贝的文件：

```text
# .worktreeinclude
.env
.env.local
config/secrets.json
```

规则很安全：只有**同时被某模式匹配且确实被 gitignore**的文件才会被复制，已跟踪文件永远不会被重复。该机制对 `-w`、子代理 worktree、桌面端并行会话都生效。

### 第 4 步：用 `-p` 把单 worktree 变成无人值守任务

交互式 `-w` 适合人盯着看，批量执行要的是无人值守。组合 `-w` 与 `-p`：

```bash
claude -w task-add-logging -p \
  "给 src/ 下所有 service 模块统一加上结构化日志，不要改公开 API" \
  --output-format json \
  > logs/task-add-logging.json
```

**预期结果**：Claude Code 静默创建 worktree、完成任务、把结构化结果（含改动摘要、token 用量）以 JSON 写入日志文件，进程退出。期间主检出完全不受影响。

关键点速记：

- `-p` 跳过信任检查，无需事先交互式跑过；
- `-p` 创建的 worktree **不会自动清理**（没有退出提示），任务后要自己 `git worktree remove`；
- `--output-format json` 让结果可被脚本解析，便于汇总成功/失败。

### 第 5 步：并行扇出——让 N 个 worktree 同时跑

隔离和无人值守就绪后，并行只剩编排。下面给出三种由轻到重的写法。

**写法 A：bash 后台 + wait（最朴素，零依赖）**

```bash
for t in add-logging fix-leak refactor-api; do
  ( claude -w "task-$t" -p "完成任务：$t" \
      --output-format json > "logs/$t.json" 2> "logs/$t.err" ) &
done
wait   # 阻塞直到全部完成
echo "全部结束"
```

**写法 B：xargs -P（带并发上限，系统自带）**

`-P 3` 表示最多同时跑 3 个，超过的排队：

```bash
printf '%s\n' add-logging fix-leak refactor-api harden-auth \
| xargs -P 3 -I {} bash -c '
    claude -w "task-{}" -p "完成任务：{}" \
      --output-format json > "logs/{}.json" 2> "logs/{}.err" \
    && echo "OK {}" || echo "FAIL {}"
  '
```

**写法 C：GNU parallel（功能最全，支持失败重试、结果聚合）**

```bash
parallel --jobs 4 --results logs/ \
  'claude -w task-{1} -p "完成任务：{1}" --output-format json' \
  ::: add-logging fix-leak refactor-api harden-auth
```

`parallel` 会把每个任务的 stdout/stderr/exit code 分别落到 `logs/` 下结构化目录，方便事后审计。

**并发上限怎么定**：每个 `claude -p` 实例都消耗 API 并发与 token。经验值从 `min(4, CPU核数-2)` 起步，观察限流报错再调。并行不是越大越好——撞到 API 速率限制会集体失败。

**常见问题**：多个实例同时读写共享的 `~/.claude` 状态目录偶发竞争。把每个实例的日志严格隔离（每任务独立文件），并避免在任务里写共享文件即可。

### 第 6 步：合并与冲突处理

所有任务跑完后，成果在各自的 `worktree-<名字>` 分支上。因为共享同一个 `.git`，合并非常直接。先切回主检出，再逐个合并：

```bash
git checkout main
for t in add-logging fix-leak refactor-api; do
  if git merge --no-ff "worktree-task-$t" -m "merge: $t"; then
    echo "✅ 已合并 $t"
  else
    echo "⚠️  $t 冲突，已中止，留待人工"
    git merge --abort
  fi
done
```

冲突处理策略：

- **任务间文件不重叠**（理想情况）：全自动合并，零冲突。这是 worktree 并行的最大红利——只要任务划分时让各 worktree 改不同模块，合并近乎无痛。
- **重叠但可自动三方合并**：`git merge` 自己解决。
- **真冲突**：`git merge --abort` 回退，保留对应 worktree（`.claude/worktrees/task-<名字>/`）让人工进去解决，或交给另一个 `claude -p` 专门修冲突。

### 第 7 步：清理 worktree

`-p` 跑出来的 worktree 不自动清理，跑完一批会留下一堆。手动清理：

```bash
for t in add-logging fix-leak refactor-api; do
  git worktree remove --force ".claude/worktrees/task-$t"
  git branch -D "worktree-task-$t" 2>/dev/null || true
done
```

`--force` 用于强制删除有未提交改动的 worktree（确认不需要时才加）。运行中的 agent 会对其 worktree 执行 `git worktree lock`，防止并发清理误删；agent 结束后锁自动释放。

子代理与后台会话产生的 worktree 则有自动清扫机制：超过 `cleanupPeriodDays`（默认若干天）且无未提交改动/未跟踪文件/未推送提交的，会被自动回收；你用 `--worktree` 主动建的不会被这条规则动。

### 第 8 步（进阶）：子代理 worktree 隔离与非 git VCS

**子代理隔离**。在自定义子代理的 frontmatter 里加一行，让该子代理每次都在独立 worktree 里跑，子代理结束后无改动则自动删除：

```yaml
---
name: refactor-agent
isolation: worktree
tools: Edit, Read, Bash
---
你是一个重构专家……
```

或直接在会话里说"use worktrees for your agents"。这把"任务分工"（subagent）和"文件隔离"（worktree）叠加，适合一个会话内并行派发多个改不同目录的子任务。

**非 git 版本控制**。worktree 默认用 git。SVN/Perforce/Mercurial 等需配置 `WorktreeCreate` / `WorktreeRemove` hook 接管创建与清理逻辑。注意：一旦用 hook 接管，`.worktreeinclude` 不再生效，本地配置文件的复制要写进 hook 脚本里。一个 SVN 示例：

```json
{
  "hooks": {
    "WorktreeCreate": [
      { "hooks": [ { "type": "command",
        "command": "bash -c 'NAME=$(jq -r .name); DIR=\"$HOME/.claude/worktrees/$NAME\"; svn checkout https://svn.example.com/repo/trunk \"$DIR\" >&2 && echo \"$DIR\"'"
      } ] }
    ]
  }
}
```

hook 从 stdin 读 worktree 名字，检出一个 SVN 工作副本，打印目录路径，Claude Code 就把它当作会话工作目录。

---

## 实战案例：一个可运行的并行批量执行器

下面这个 `fanout.sh` 把前面所有步骤串成一条完整管道：读任务清单 → 并行扇出（带并发上限）→ 收集结果 → 自动合并并清理、冲突保留。

任务清单 `tasks.txt`，每行 `<名字><TAB><提示词>`：

```text
add-logging	给 src/services/ 下每个 service 加结构化日志，不动公开 API
fix-leak	修复 src/db/pool.go 里的连接泄漏，补一个测试
refactor-api	把 src/api/handlers.go 里的回调改成 async/await 风格
harden-auth	给 src/auth/ 加输入校验，拒绝空 token
```

执行器 `fanout.sh`：

```bash
#!/usr/bin/env bash
# fanout.sh — worktree 并行批量执行器
# 用法: ./fanout.sh tasks.txt
set -euo pipefail

REPO_ROOT="$(git rev-parse --show-toplevel)"
cd "$REPO_ROOT"
WORKDIR=".claude/worktrees"
MAX_PARALLEL="${MAX_PARALLEL:-3}"
TASKS_FILE="${1:-tasks.txt}"
BASE_BRANCH="${BASE_BRANCH:-main}"

mkdir -p "$WORKDIR" logs

run_one() {
  local name="$1" prompt="$2"
  if claude -w "$name" -p "$prompt" --output-format json \
       > "logs/$name.json" 2> "logs/$name.err"; then
    echo "✅ $name 完成"
  else
    echo "❌ $name 失败（见 logs/$name.err）"
  fi
}

# —— 阶段一：并行扇出 ——
mapfile -t LINES < "$TASKS_FILE"
for line in "${LINES[@]}"; do
  [ -z "$line" ] && continue
  name="${line%%$'\t'*}"; prompt="${line#*$'\t'}"
  run_one "$name" "$prompt" &
  # 限流：达到并发上限就等一个槽位空出
  while [ "$(jobs -r | wc -l)" -ge "$MAX_PARALLEL" ]; do sleep 1; done
done
wait
echo "---- 全部任务结束，开始合并 ----"

# —— 阶段二：逐个合并 ——
git checkout "$BASE_BRANCH" 2>/dev/null || git checkout -b "$BASE_BRANCH"
for line in "${LINES[@]}"; do
  [ -z "$line" ] && continue
  name="${line%%$'\t'*}"
  branch="worktree-$name"
  wt="$WORKDIR/$name"

  # 无改动直接清掉
  if git diff --quiet "HEAD" "$branch" -- 2>/dev/null; then
    echo "⏭️  $name 无改动"
    git worktree remove --force "$wt" 2>/dev/null || true
    git branch -D "$branch" 2>/dev/null || true
    continue
  fi

  if git merge --no-ff "$branch" -m "merge: $name"; then
    echo "🔗 已合并 $branch"
    git worktree remove --force "$wt" 2>/dev/null || true
    git branch -D "$branch" 2>/dev/null || true
  else
    echo "⚠️  $branch 冲突，保留 worktree 待人工处理：$wt"
    git merge --abort
  fi
done

echo "---- 完成。成功合并的改动已在 $BASE_BRANCH ----"
```

**运行**：

```bash
chmod +x fanout.sh
MAX_PARALLEL=4 ./fanout.sh tasks.txt
```

**预期结果**：屏幕滚动打印每个任务的 ✅/❌，最后打印合并结果。成功的分支并入 `main` 并清理 worktree；失败或冲突的 worktree 原地保留，你可在 `.claude/worktrees/<名字>/` 里继续处理。`logs/` 下留存每个任务的 JSON 结果与错误日志，便于审计与重跑。

**扩展点**：失败任务可在第二阶段加一段 `claude -w "$name" -p "修复 logs/$name.err 里的错误"` 做一轮自愈重试；想跨多个仓库批量操作，把 `REPO_ROOT` 换成遍历仓库列表的外层循环即可。

---

## Mermaid 流程图：并行扇出→隔离执行→合并

```mermaid
flowchart TD
    A[tasks.txt 任务清单] --> B[逐行读取任务]
    B --> C{并行扇出<br/>MAX_PARALLEL 限流}
    C --> W1[worktree-add-logging<br/>claude -w -p]
    C --> W2[worktree-fix-leak<br/>claude -w -p]
    C --> W3[worktree-refactor-api<br/>claude -w -p]
    C --> W4[worktree-harden-auth<br/>claude -w -p]
    W1 --> R1[logs/add-logging.json]
    W2 --> R2[logs/fix-leak.json]
    W3 --> R3[logs/refactor-api.json]
    W4 --> R4[logs/harden-auth.json]
    R1 --> M[wait 全部完成]
    R2 --> M
    R3 --> M
    R4 --> M
    M --> G{逐个合并到 main}
    G -->|无冲突| K[git merge + 清理 worktree]
    G -->|有冲突| H[保留 worktree 待人工/自愈重试]
    K --> DONE([main 已包含全部改动])
    H --> DONE
```

---

## 延伸阅读

- **Claude Code 官方文档 - Subagents & Agent Teams**：把"任务分工"叠在 worktree 的"文件隔离"之上，做会话内多代理协作。
- **Claude Code 官方文档 - Headless / `-p` 模式**：深入 `--output-format json`、streaming、exit code，把单任务做扎实后再扇出。
- **git worktree 官方手册**（`git-scm.com/docs/git-worktree`）：`add`/`remove`/`lock`/`prune` 的完整参数，自定义 worktree 布局时必读。
- **GNU parallel 教程**：当任务数过百、需要失败重试与结果聚合时，比 bash `&`+`wait` 更省心。

---

## 训练营适用性评估

- **适合的营型**：自动化运维营、DevOps/CI 提效营、AI 工程实战营。尤其适合"把 AI 编排进现有工程流水线"这类强调可重复、可审计、可回滚的主题。
- **不适合**：纯入门营（需先掌握 `claude -p` 与 git 基础）、单机小脚本营（并行收益不明显）。
- **建议教学时长**：2.5–3 小时。其中 30 分钟讲 worktree 隔离原理与配置，45 分钟带跑 `fanout.sh` 完整案例，45 分钟做并发上限调优与冲突处理演练，剩余时间留给学员用自己仓库实操。
- **前置关卡**：建议放在"print 模式结构化输出"（已覆盖）之后、"子代理团队编排"之前，承上启下——上接单任务无头执行，下接多代理任务分工。
- **验收标准**：学员能独立写出一份 `tasks.txt`，用 `fanout.sh` 在自己的真实仓库上并行完成 4 个互不冲突的任务并干净合并、清理，且能说清并发上限与冲突保留的取舍。

---

## 参考来源

1. [Run parallel sessions with worktrees — Claude Code Docs](https://code.claude.com/docs/en/worktrees) — 官方对 `--worktree`、`baseRef`、`.worktreeinclude`、子代理隔离、清理规则与 `WorktreeCreate`/`WorktreeRemove` hook 的权威说明。
2. [Introduction to Git Worktrees in Claude Code — Better Stack](https://betterstack.com/community/guides/ai/git-worktrees-claude/) — 三个功能并行实现的实操指南，含 worktree 管理技巧与已知问题排查。
3. [Practical Parallelism With Claude Code, Part 3: Automating Parallel](https://claydon.co/code/practical-parallelism-with-claude-code/part3/) — 从 tmux 手动编排到自动化并行任务分发的演进，脚本编排思路的来源。
4. [Git Worktrees + Claude Code: The 2026 Playbook](https://developersdigest.tech/blog/git-worktrees-claude-code-parallel-agents-guide) — 多 agent 同仓库并行时分支冲突与 stash 混乱的成因与 worktree 解法。
5. [git-worktree(1) Manual Page](https://git-scm.com/docs/git-worktree) — `git worktree add/remove/lock/prune` 完整命令参考，自定义 worktree 布局与清理的底层依据。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
