「3つのsubagentを並列で走らせれば3倍速いはず」——そう思って設計を投げた3本のTaskを一斉に走らせたら、実際はできあがったコミットの中身がどれも中途半端に混ざっていた。片方のsubagentがcheckoutしたブランチに、もう片方が気づかずcommitしていた。原因を追うと、3本とも同じworking directoryで作業していただけだった(そもそもそこを疑うべきだった)。
Claude CodeのAgent toolで複数のsubagentを並列起動するのは、読み取り専用の調査タスクなら気持ちよく速くなる。ただし、並列に走らせたsubagentがファイルを書き換えたりgit操作をしたりする場合は話が別で、同じディレクトリを共有させたまま走らせると再現しづらい壊れ方をする。この記事では、その壊れ方の仕組みと、isolationオプションによる分離・直列実行への切り替えという2つの回避策を整理する。
この記事で学べること
- 複数subagentが同一working directoryで
git checkout -Bやgit commitを実行すると何が起きるか - Agent toolの
isolation: 'worktree'オプションが何を分離してくれるか、そのぶん何にコストがかかるか - 「isolationを使うべきか、直列に倒すべきか」を毎回迷わず判断するための基準
前提条件
- Claude Code(Pro $20/月、Max $100〜200/月——正直、地味に効いてくる出費)でAgent toolを使い、複数subagentを並列起動したことがある、またはこれからやろうとしている
- 対象リポジトリがgit管理下にある
何が起きるのか:同じworktreeでの git 競合
まず起きている現象を具体的に言葉にしておく。並列起動したsubagentのうち2つが、isolationを指定せずに同じworking directoryへgit checkout -B feature/xのようなブランチ切り替えやgit commitを投げると、それぞれのgit操作は同じ.gitディレクトリの同じHEADを取り合う。片方が切り替えたブランチのまま、もう片方がステージングしてgit commitを打つと、コミットの中身に「自分が書いたはずのないファイル」や「意図しない差分」が混ざり込む。タイミングによっては再現したりしなかったりするので、原因がgit操作の競合だと気づくまでに時間を溶かしやすい。
working directoryは1つしかなく、HEADもステージングエリアも1つしかない。複数のsubagentを「同時に」走らせているつもりでも、gitから見ればどのsubagentの操作も同じ状態を奪い合っているだけだ。
isolation: 'worktree' で個別のworktreeに分離する
Agent toolにはisolationパラメータがあり、'worktree'を指定すると、そのsubagentは一時的なgit worktreeの中で作業する。worktreeはブランチごとに独立した作業ディレクトリを持てるgitの機能なので、subagentごとに別々のHEAD・別々のステージングエリアが用意され、上で説明したような取り合いが起きなくなる。
ただしタダではない。worktreeを新規に作ると、そのディレクトリには依存関係のインストール状態が引き継がれない(せっかく並列で速くしたいのに、そこで律儀にnpm installを待たされる)。実際、社内のスキル開発チームでも、git worktree add直後のworktreeに依存パッケージが入っておらず、担当のsubagentがその場でインストールコマンドを実行して回避する、という状況が起きていた。この反省を踏まえて、worktree作成直後にロックファイルがあるときだけ依存関係を決定論的に整備するステップを追加した経緯もある——つまりworktreeを切ること自体に、依存関係を作り直す時間的コストが乗ってくるということだ。
だから、ファイルを書き換えない・git操作もしない純粋な並列調査(複数の観点からコードを読ませる、複数箇所を並行でgrepさせる、といった読み取り専用タスク)にまでisolation: 'worktree'を使うと、得られる安全性に対してセットアップコストが見合わない。isolationは「必要な時に、必要な分だけ」使う機能だと考えたほうがいい。
isolationが要る場面・要らない場面
実務でいちいち悩まないために、判断基準を1つに絞っておく。「並列で走らせるsubagentが、ファイルを書き換えるか・git操作をする可能性があるか」だけを見ればいい。
| 並列subagentの作業内容 | isolationの要否 | 理由 |
|---|---|---|
| 読み取り専用の調査(コードリーディング、grep、設計の把握) | 不要 | working directoryの状態を変更しないので競合しようがない |
| ファイルの書き換えを伴う実装 | isolation: 'worktree'か直列化が必須 | 同じファイルへの同時書き込みは後勝ちで上書きされる |
git checkout / git commitなどのgit操作を伴う作業 | isolation: 'worktree'か直列化が必須 | HEAD・ステージングエリアの奪い合いでコミットが壊れる |
読み取り専用かどうかを最初に自問する。それだけで、無駄にworktreeを切ってセットアップ待ちになる事故と、逆にisolationを付け忘れてコミットを壊す事故の両方を避けられる。
対処法1: isolation: 'worktree' を指定する
書き込み・git操作を伴う並列作業なら、Agent tool呼び出しで明示的に指定する。
Agent({
description: "機能Aを実装",
prompt: "...",
isolation: "worktree"
})
これを並列で呼び出したsubagentそれぞれに指定すれば、各subagentは自分専用のworktreeでcheckout・commitを行い、他のsubagentのHEADと衝突しない。実装が終わったworktreeは、あとでマージするなり差分だけ取り出すなりすればいい(増えたworktreeをそのまま放置しがちなのは、また別の話)。
対処法2: そもそも並列化せず直列実行に倒す
isolationにはセットアップコストがあると書いたが、それでも「並列にする価値」自体がない場面もある。本数が少ない、あるいはタスク同士に依存関係がある場合は、素直に直列実行に倒したほうが安全なことが多い。
典型的なのは、複数のタスクが同じファイルの近い場所を触るケースだ。社内の開発では、2つの改善タスクが同じ2ファイルの近接した区間を書き換える計画になっていたため、「並列worktreeは非推奨」と明記して直列実行の順番に回したことがある。ファイルが分かれていない限り、worktreeを分けて並列にしたはずなのに、最終的にマージするときに同じ場所でコンフリクトするなら、最初から順番にやったほうが速い(並列にした分の時間、コンフリクト解消でそのまま溶ける)。
もう一つ、isolationを使っていても油断できない例がある。並行して走っていた別のworkflowとworktreeが衝突し、PR作成だけがワークフローの外に押し出されて手動リカバリになった、という記録が社内に残っている。isolationは「同一worktreeでの競合」を防いでくれるが、「複数のworkflow・複数のプロセスが同時にworktreeを作ろうとする」タイミング自体まで面倒を見てくれるわけではない。worktreeを継承した状態でうっかりコミット漏れの変更を残したまま次の作業に入ってしまい、あとから「これは前の作業の続きです」と明示コミットして土台を作り直した、という記録も残っている。isolationを指定していれば安心、ではなく、どのタイミングで誰がworktreeを作っているかは依然として見ておく必要がある。
判断に迷ったら、「isolationで守れるのは1つのworktree内の競合まで」と覚えておくとちょうどいい。並列度そのものを絞るという選択肢を、isolationの代わりではなく合わせ技として持っておくと事故が減る。
動作確認:自分の環境で再現してみる
信じてもらうより、自分の手元で確認したほうが早い。適当なgitリポジトリで次を試すと、working directoryの共有が何を引き起こすか体感できる。
# 1. 検証用のディレクトリを用意
mkdir git-race-demo && cd git-race-demo
git init
echo "base" > file.txt
git add file.txt
git commit -m "base commit"
# 2. ターミナルを2枚開き、片方で先にブランチを切る
git checkout -B feature/a
# 3. もう片方のターミナルで、file.txtを変更してからブランチを切り替える
echo "agent-b change" >> file.txt
git checkout -B feature/b # HEADがfeature/bに切り替わる
# 4. 最初のターミナルに戻ってcommitしてみる
git add -A
git commit -m "agent-a commit"
# 5. どのブランチに何がcommitされたか確認する
git log --oneline --all --graph
git show HEAD --stat
git commitを打った側は「自分がfeature/aにcommitした」つもりでも、実際には別ターミナルが切り替えたfeature/bに、自分が意図していなかった変更まで含めてcommitされているはずだ(git log --graphを見て「あれ、これ誰の変更?」と二度見することになる)。Claude CodeのAgent toolで複数subagentを並列起動してgit操作をさせるときも、同じworking directoryを共有していれば原理は同じで起きる。isolationを指定してから同じ手順をなぞると、今度はそれぞれ独立したworktreeの中でcommitが完結し、混ざらないことも合わせて確認できる。
注意点・Tips
- isolationは書き込み・git操作の有無で決める: 読み取り専用の並列調査には付けない。付けるとセットアップ待ちの分だけ遅くなる
- 直列化も立派な選択肢: 本数が少ない・タスク間に依存がある・同じファイルの近接箇所を触る、のいずれかに当てはまるなら、無理に並列にせず順番に実行したほうがトラブルが少ない
- isolationを指定しても、worktreeを作るタイミングの衝突までは防げない: 複数のworkflowやプロセスが同時にworktree作成を試みる場面では、別途リトライやロックの設計が要る
まとめ
Claude CodeのAgent toolで複数のsubagentを並列起動するとき、isolationを指定し忘れたまま同じworking directoryでgit操作をさせると、HEADとステージングエリアの奪い合いでコミットが壊れることがある。原因は単純で、working directoryもHEADも1つしかないのに、複数のsubagentが同時にそこへ書き込もうとするからだ。
自分の実装でも、並列化する前に「このsubagentたちはファイルを書き換えるか、git操作をするか」を自問してほしい。読み取り専用ならisolationは不要、書き込み・git操作を伴うならisolation: 'worktree'で分離するか、そもそも直列実行に倒す——このどちらかを選べば、同じ問題は避けられる(どちらも選ばずに「多分大丈夫だろう」で走らせるのだけは避けたい)。isolationは万能ではなく、あくまで1つのworktree内の競合を防ぐための道具だという前提を忘れずに使いたい。



