メインコンテンツへスキップ
モジュール 2:マルチエージェント 6 / 6
中級 Session 12 ワークツリー 分離 Git

ワークツリー分離

タスクごとの git worktree を使用し、イベントストリームによる完全なコード分離を実現する。

2026年3月20日 15 分で読む

学ぶこと

2つのエージェントが同時に同じファイルを編集すると、一方が負けます。変更が上書きされるか、両方の変更がまとまって一貫性のないものになります。ワークツリー分離は、各エージェントに独自の完全な作業ディレクトリを与えることでこれを排除します。

このセッションが終わるまでに、以下のことを理解できるようになります:

  • 共有作業ディレクトリがマルチエージェントワークフローを破綻させる理由
  • git worktree がエージェントごとの分離を提供する方法
  • ワークツリーのライフサイクル:作成、作業、マージまたは破棄
  • ワークツリーの活動を監視するためのイベントストリーム
  • 未使用のワークツリーの自動クリーンアップ

問題

同じリポジトリで並列に作業する2つのエージェント:

AGENT A: Adding authentication       AGENT B: Adding logging
  Creates src/middleware/auth.ts        Creates src/middleware/logger.ts
  Modifies src/app.ts ←──── CONFLICT ────→ Modifies src/app.ts
  Modifies src/routes/index.ts          Modifies src/config.ts

両方が src/app.ts を変更します。分離がなければ、3つの結果が考えられます:

1. LAST WRITE WINS
   Agent A writes app.ts with auth import
   Agent B writes app.ts with logger import → auth import lost

2. READ-BEFORE-WRITE RACE
   Both read the same version of app.ts
   Both write based on that version → second write overwrites the first

3. MERGE CONFLICT
   Both stage changes → git conflict markers → manual resolution needed

どれも許容できません。根本原因:複数のエージェントが単一の作業ディレクトリを共有していること。

仕組み

Git Worktree:1つのリポジトリ、複数のディレクトリ

Git worktree は、同じリポジトリから追加の作業ディレクトリを作成します。それぞれが独自のブランチとファイルを持ちますが、git 履歴は共有されます。

MAIN REPOSITORY                  WORKTREE: AGENT A
/project/                        /project/.worktrees/agent-a/
  ├── .git/  ◀── shared ──▶       (branch: feat/auth)
  ├── src/                         ├── src/        ← independent copy
  ├── tests/                       ├── tests/
  └── package.json                 └── package.json

                                 WORKTREE: AGENT B
                                 /project/.worktrees/agent-b/
                                   (branch: feat/logging)
                                   ├── src/        ← independent copy
                                   ├── tests/
                                   └── package.json

エージェント A とエージェント B は両方とも src/app.ts を変更できます — それぞれが自分のブランチ上に独自のコピーを持っています。

ワークツリー分離によるエージェントのスポーン

親が分離付きで子をスポーンする場合、シーケンスは以下の通りです:

Parent Agent

    ├──▶ 1. CREATE   git worktree add .worktrees/task-42 -b task-42
    │                 → new directory + branch created (fast, uses hardlinks)

    ├──▶ 2. SET CWD  Child agent works in .worktrees/task-42/
    │                 Agent sees a normal project — doesn't know it's a worktree

    ├──▶ 3. WORK     Child reads, writes, tests — all local to worktree
    │                 No impact on main directory or other worktrees

    ├──▶ 4. COMPLETE  Child commits to branch task-42
    │                  Returns: { worktree_path, branch, files_changed }

    └──▶ 5. DECIDE    Parent merges branch → or discards worktree

子エージェントは特別な認識を必要としません。その視点からは、通常のディレクトリで作業しています。分離はワーカーにとって透過的です。

完全なライフサイクル

┌─────────────────────────────────────────────────────┐
│  CREATE                                              │
│    git worktree add <path> -b <branch>               │
│    Fast: hardlinks, not full copy                    │
│                      │                               │
│                      ▼                               │
│  WORK                                                │
│    Agent operates in worktree directory               │
│    All reads/writes isolated. Can run tests locally. │
│                      │                               │
│                      ▼                               │
│  EVALUATE                                            │
│    git diff --stat → changes exist?                  │
│               ┌──────┴──────┐                        │
│               ▼             ▼                        │
│  MERGE                  DISCARD                      │
│    Merge branch         Remove worktree              │
│    into main            Delete branch                │
│               └──────┬──────┘                        │
│                      ▼                               │
│  CLEANUP                                             │
│    git worktree prune                                │
│    Remove directory, clean git references            │
└─────────────────────────────────────────────────────┘

イベントストリーム:活動の監視

親はイベントを通じてワークツリーの活動を監視します。分離を壊すことなく:

Parent Agent (orchestrator)

    ├── AGENT A (worktree: feat/auth)
    │     ├── event: file_created  src/middleware/auth.ts
    │     ├── event: file_modified src/app.ts
    │     ├── event: test_run      3 passed, 0 failed
    │     └── event: task_complete files_changed: 3

    ├── AGENT B (worktree: feat/logging)
    │     ├── event: file_created  src/middleware/logger.ts
    │     ├── event: file_modified src/app.ts
    │     └── event: task_complete files_changed: 3

    └── MERGE DECISION
          Both modified src/app.ts on different branches.
          Git merge handles it if changes are on different lines.
          If conflict: parent resolves with full context of both tasks.

イベントは子から親への一方向のみ流れます。親は干渉することなく観察します — 子が作業中にワークツリーを変更すると一貫性が壊れます。

自動クリーンアップ

変更のないワークツリーは自動的にクリーンアップされます:

1. Worktree created for exploration task
2. Agent reads 20 files, concludes "no changes needed"
3. git diff --stat → empty
4. Automatic: git worktree remove + git branch -d
5. No branch, no directory, no mess

これにより、多くの並列エージェントを伴う長いセッションでのワークツリーの蓄積を防ぎます。

キーインサイト

ワークツリー分離は、真の並列開発を可能にするものです。フィーチャーブランチと同じ概念ですが、エージェントレベルで適用されます。

より深いインサイト:ワークツリーは調整モデルを変えます。分離がなければ、エージェントはリアルタイムで調整する必要があります(「app.ts に触らないで、編集中だから」)。分離があれば、エージェントは自由に作業し、コンフリクトはマージ時に一度だけ解決されます。これは悲観的ロックではなく楽観的並行性です — エージェントが互いをブロックしないため、よりスケールします。

実践例

2つのエージェントが並列で機能を実装し、マージする例:

STEP 1: Create worktrees
──────────────────────────────────
git worktree add .worktrees/auth -b feat/auth
git worktree add .worktrees/logging -b feat/logging

STEP 2: Agents work in parallel
──────────────────────────────────
Agent A (in .worktrees/auth/):
  Creates src/middleware/auth.ts
  Modifies src/app.ts:
    + import { authMiddleware } from './middleware/auth'
    + app.use(authMiddleware)
  Runs tests → pass
  Commits: "feat: add authentication middleware"

Agent B (in .worktrees/logging/):          ← simultaneous
  Creates src/middleware/logger.ts
  Modifies src/app.ts:
    + import { logger } from './middleware/logger'
    + app.use(logger)
  Runs tests → pass
  Commits: "feat: add request logging"

STEP 3: Merge results
──────────────────────────────────
git checkout main
git merge feat/auth      → clean merge
git merge feat/logging   → auto-merge (different lines of app.ts)
Final app.ts has BOTH imports. No manual conflict resolution.

STEP 4: Cleanup
──────────────────────────────────
git worktree remove .worktrees/auth
git worktree remove .worktrees/logging

マージコンフリクトの処理

変更が重なった場合、親エージェントがコンテキストを持って解決します:

Agent A adds line 15: app.use(authMiddleware)
Agent B adds line 15: app.use(logger)

Parent reads conflict → understands both intents → resolves:
  app.use(logger)          ← logger first (every request)
  app.use(authMiddleware)  ← auth second (validates credentials)

分離戦略の比較

No Isolation:   instant setup, zero safety → single agent only
Worktree:       fast setup (hardlinks), full file isolation → parallel agents
Full Clone:     slow (copies repo), full isolation → untrusted agents
Container:      slowest (OS-level), maximum isolation → untrusted code

Worktree hits the sweet spot: strong isolation with minimal overhead.

変更点

共有作業ディレクトリワークツリー分離
エージェントが互いを上書き各エージェントが独自のディレクトリを持つ
作業中のコンフリクトコンフリクトはマージ時に解決
ファイルアクセスの調整が必要エージェントが独立して作業
衝突回避のため逐次的真の並列実行
単一ブランチエージェントごとに1ブランチ

次のセッション

これでモジュール2:マルチエージェントシステムは完了です。タスクグラフ、バックグラウンドタスク、チームコミュニケーション、プロトコル、自律エージェント、ワークツリー分離を理解しました。

モジュール3では、Claude Code を設定し拡張するシステムに移ります。セッション13コントロールプロトコルから始まります。外部ツールが Claude Code に構造化されたコマンドを送信しレスポンスを受信する方法、IDE 統合やプログラマティック制御を可能にする仕組みについて学びます。