AI エージェントを並列で動かす― git worktree で「作業場」を複数持つ

いよいよ最終回です。

3 体の AI エージェントに、同時に別々の機能を作らせたい。ログイン画面と、API と、バグ修正を、並行で進められたら一気に終わります。ところが、ここで壁にぶつかります。

手元の作業場 (フォルダ) は 1 つしかないので、ブランチを git switch で切り替えるたびにフォルダの中身が丸ごと書き換わる。3 体が同じフォルダを取り合って、上書き合戦が始まってしまいます。

これを解くのが git worktree です。第3回の「ブランチは 40 文字のしおり」と、第4回の「作業ファイルは 1 セットだけ」を思い出してください。

TL;DR

  • git worktree は「1 つの .git(履歴・オブジェクト) を共有したまま、作業場 (フォルダ) を複数持つ」仕組みです。
  • git clone を 3 回するより圧倒的に安い。重いオブジェクトの保管庫は 1 つのまま、軽い作業コピーだけが増えます (第3回の「中身は住所で共有」がそのまま効く)。
  • 鉄則は 1 つだけ。同じブランチを 2 つの作業場で同時に開けません(第3回の「ブランチ=1 つのポインタ」だから)。並列でやるなら、作業場ごとに別ブランチです。
  • AI エージェントの並列開発は「エージェント 1 体=worktree 1 個=ブランチ 1 本」。隔離して作らせ、PR で合流し、気に入らなければ丸ごと捨てる (第5回第6回)。

なぜ「作業場が 1 つ」だと困るのか

通常、1 つのリポジトリには作業ディレクトリ (フォルダ) が 1 つだけ付いています。

【通常】1つの .git に、作業フォルダは1つ my-repo/ ├─ .git/ ←履歴のすべて(オブジェクト・参照) └─ (main の作業ファイル) ←作業場は1セットだけ

第4回で見たとおり、手元で触れる実ファイルは常に 1 セットです。だから feature の中身を見たければ、main の作業を一旦どけて git switch feature するしかありません。その瞬間、フォルダの中のファイルが feature の内容に丸ごと入れ替わります。

main でバグを直しながら、同時に feature で新機能を書く」が、これだと物理的にできません。切り替えるたびに、目の前のファイルが別物になるからです。AI を 3 体並べても、全員が同じ 1 つのフォルダを奪い合うだけになります。

worktree がやること:.git を共有して作業場を増やす

git worktree は、1 つの .git(履歴とオブジェクトの保管庫) を共有したまま、作業場を複数のフォルダに展開する仕組みです。

flowchart TD DB[".git<br/>履歴・オブジェクトは1つだけ(共有)"] --> W1["作業場 main<br/>my-repo/"] DB --> W2["作業場 feat-A<br/>my-repo-feat-A/"] DB --> W3["作業場 feat-B<br/>my-repo-feat-B/"]

それぞれの作業場は、自分専用の HEAD(今どこにいるか)・index(ステージング)・作業ファイルを持ちます。一方で、コミットやブランチの実体が入った保管庫は、全部の作業場で 1 つを共有します。第4回の鎖でいうと、HEAD → から先 (どのブランチのどこにいるか) は各作業場で独立、コミット→ tree → blob の実体は全作業場で共有、というイメージです。

git clone を 3 回するより安い理由

同じことを git clone を 3 回して実現することもできます。でも、それは高くつきます。第3回で見た「中身から決まる住所 (content-addressable) で、同じ中身は 1 つしか持たない」が、ここで効いてくるからです。

git clone を 3 回git worktree を 3 つ
オブジェクトの保管庫3 つに複製 (容量 3 倍)1 つを共有 (増えない)
作業ファイル3 セット3 セット
履歴の共有バラバラ (別リポジトリ)即共有 (同じ保管庫)
一方のコミットを他方が見るpush / fetch が必要その場で見える

worktree は「重い保管庫は 1 つのまま、軽い作業コピーだけ増やす」。第3回で確かめた「容量を決めるのは枝の数ではなく中身の量」という原理の、自然な延長です。

基本コマンドと、たった 1 つの鉄則

使うコマンドは数えるほどです。

git worktree add ../myrepo-feat-A -b feat-A # 別フォルダに feat-A を作って展開
git worktree list # 今ある作業場を一覧
git worktree move <old> <new> # 場所を移す(手で mv しない)
git worktree remove ../myrepo-feat-A # 使い終わったら削除
git worktree prune # 後始末(壊れた参照の掃除)

そして、鉄則はたった 1 つです。

同じブランチを、2 つの作業場で同時に開くことはできません (Git が拒否します)。

理由は第3回の「ブランチ=1 つのポインタ」です。1 つのしおりを 2 つの作業場が別々に動かしたら、どちらが正しいか決まらず矛盾します。だから、並列でやるなら作業場ごとに必ず別ブランチにする。これさえ守れば、worktree で迷うことはほとんどありません。

似た 3 つの操作は、目的で選び分けます。

やりたいこと使う道具なぜ
同じ作業場で別の歴史へ移るgit switch作業場は 1 つでよい。一番軽い
複数の作業を同時に並行したいgit worktree作業場を物理的に分離。保管庫は共有で安い
完全に独立した別環境がほしいgit clone保管庫ごと複製。独立するぶん重い

動かして確認:作業場を増やして「共有」を体感する

10 分ほどで、worktree の「作業場は複数・履歴は 1 つ」を体感できます。新しい使い捨てフォルダで試します。

cd ~/Desktop
mkdir wt-lab && cd wt-lab && git init -b main
printf 'main work\n' > app.txt
git add app.txt && git commit -m "init on main"
git worktree add ../wt-lab-featA -b feat-A # feat-A を別フォルダに展開
git worktree list # 2 つの作業場が並ぶ

AI に頼むなら

いまの main の作業場はそのまま残して。それとは別に、feat-A 用の作業場(フォルダ)をもう 1 つ作って、main と同時並行で feat-A の作業ができるようにして

この一言で、AI は git switch(同じ作業場を切り替える) ではなく git worktree add ../<フォルダ> -b feat-A を選びます。「main はそのまま」「別に」「もう 1 つ」「同時並行」という言葉が、作業場を切り替える操作ではなく、物理的に増やす操作を指し示します。

保管庫が共有されている証拠は、追加した作業場の .git を見ると分かります。

cat ../wt-lab-featA/.git
# → gitdir: .../wt-lab/.git/worktrees/wt-lab-featA

追加した作業場の .git は、フォルダではなくテキストファイルで、本体の保管庫を指しているだけです。保管庫を複製していない、決定的な証拠です。

両方の作業場で同時に作業しても、ぶつかりません。そして履歴は、push も fetch もせずに、その場で共有されています。

cd ~/Desktop/wt-lab && printf 'fix\n' >> app.txt && git commit -am "fix on main"
cd ~/Desktop/wt-lab-featA && printf 'new\n' > feature.txt && git add -A && git commit -m "feat on feat-A"
git log --oneline --all --graph # feat-A 側からでも main のコミットがそのまま見える

鉄則も体感しておきます。main をもう 1 つの作業場で開こうとすると、止められます。

cd ~/Desktop/wt-lab && git worktree add ../wt-lab-main2 main
# → fatal: 'main' is already checked out at '.../wt-lab'

最後は、合流するか、丸ごと捨てるかです。

cd ~/Desktop/wt-lab && git merge feat-A # 採用するなら合流
git worktree remove ../wt-lab-featA # 作業場を片付ける
git branch -d feat-A
cd ~/Desktop && rm -rf wt-lab wt-lab-featA # 実験はここで破棄

AI エージェントを並列で動かす

ここまで来れば、冒頭の「3 体の AI を同時に動かす」が素直に組めます。割り当てる単位は、1 タスク=1 ブランチ=1 worktree=1 エージェントです。

flowchart TD A1["AI 1"] --> W1["worktree A<br/>feat/login"] A2["AI 2"] --> W2["worktree B<br/>feat/api"] A3["AI 3"] --> W3["worktree C<br/>fix/bug-123"] W1 --> M["main へ PR で順番に合流"] W2 --> M W3 --> M

AI に頼むなら

ログイン画面・API・バグ修正の 3 つを並行で進めたい。機能ごとに別の作業場とブランチを用意して。ブランチ名は feat/login・feat/api・fix/bug-123 にして

この一言で、AI は git worktree add ../<フォルダ> -b feat/login のように、作業場とブランチを 3 つまとめて切り出します。あとは作業場ごとに 1 体ずつ AI を割り当てれば、上の図の並列開発がそのまま始まります。git switch(同じ作業場の切り替え) ではなく worktree を選ぶのは、「別の作業場で並行」と言葉にしているからです。

この形が効くのには理由があります。作業場が物理的に分かれているので、エージェント同士がファイルを上書きし合いません。保管庫は共有なので、ディスクも無駄になりません。依存物も混ざらないので、各作業場で独立にビルド・テストできます。そして、出来が気に入らなければ、git worktree removegit branch -D(第5回) でまるごと破棄して別案をやり直せる。main は一切汚れません。第3回からくり返してきた「AI に作らせて、気に入らなければ捨てる」が、いちばん活きる場面です。

Claude Code のような AI エージェントツールには、「エージェントごとに隔離した作業場を用意し、終わったら本流へ合流する」を自動でやる仕組みがあります。その土台が、まさにこの worktree です。仕組みを知っていれば、ツールが裏で何をしているのかが見えます。

実際の回し方は、第6回までの作法をそのままつなげるだけです。以下の ~/code/myrepo は説明用の例なので、自分のリポジトリのパスに読み替えてください。また git -C <パス> は、「そのフォルダに移動してから git を実行する」という書き方で、cd で行き来せずに別の作業場へコマンドを送れます。

cd ~/code/myrepo && git switch main && git pull # 母艦で main を最新化
git worktree add ../myrepo.worktrees/feat-login -b feat/login # 作業場を切り出す
# →このフォルダで AI に作業させる(依存物は各作業場で npm install 等)
git -C ../myrepo.worktrees/feat-login push -u origin feat/login
gh pr create --base main --head feat/login --fill # PR を出してレビュー
gh pr merge feat/login --squash --delete-branch # 採用して合流(第6回)
git worktree remove ../myrepo.worktrees/feat-login # 作業場を片付ける
git fetch --prune # 消えたリモートを掃除

並列で詰まらないコツは 2 つです。タスクはファイルやフォルダ単位で分けて割り当て、同じ箇所を 2 体に触らせないこと。そして依存物 (node_modules など) は作業場ごとに必要で共有されないので、第6回.gitignore で追跡の対象外にしておくことです。worktree が「物理的な衝突」を防ぎ、ブランチと PR が「論理的な合流」を秩序立てる。AI を増やすほど、この型が効いてきます。

AI に頼むなら

この feat-x の実験は気に入らなかった。作業場(フォルダ)も feat-x ブランチも、まるごと捨てて。マージしていないけど確認は要らない、強制的に消していい

この一言で、AI は git worktree remove で作業場を片付けてから、git branch -D feat-x でブランチを消します。worktree を消してもブランチは別物として残るので、両方を消すには 2 つの操作が要ります。「マージしていないけど確認は要らない」が、安全削除の -d ではなく強制削除の -D を選ばせます。

まとめ

第 7 回として、複数の作業場を同時に持つ git worktree を見ました。

  • git worktree は「1 つの .git を共有したまま、作業場を複数持つ」仕組み。重い保管庫は 1 つ、軽い作業コピーだけ増える。
  • 鉄則は「同じブランチを 2 つの作業場で同時に開けない」。並列なら作業場ごとに別ブランチ。
  • AI エージェントの並列開発は「1 タスク=1 ブランチ=1 worktree=1 エージェント」。隔離して作らせ、PR で合流し、ダメなら丸ごと捨てる。
  • Claude Code などが裏で使っているのも、この worktree。仕組みを知っていれば、ツールの動きが見える。

7 回をかけて、Git を内側から見てきました。中心にあったのは、第3回HEAD →ブランチ→コミット→ tree → blob という 1 本の鎖です。addcommit も、resetrebase も、PR も worktree も、結局はこの鎖のどこを、どこまで動かすかの違いでしかありませんでした。

そして、これは AI 時代だからこそ効く理解です。コマンドは AI に打たせればいい。けれど、何が起きているのかが頭の中で像を結んでいれば、「ここだけ取り消して」「別の作業場で並行して」と、的確に頼めます。手を動かす人から、仕組みを分かって指示できる人へ。その土台に、この鎖を置いておいてください。お疲れさまでした。