GitワークツリーでAIコーディングエージェントを並列実行する方法
エージェントごとに専用のGitワークツリーを用意します。リポジトリの履歴を共有しつつ、自分のブランチを持つ別の作業ディレクトリです。git worktree addで作成し、その中でエージェントを起動し、作業が終わったらブランチをマージしてワークツリーを削除します。MAOのレイヤーは同じことをキャンバス上で行い、マージの前にチェックします。
- ワークツリーは、1つのリポジトリを共有しながら自分のブランチを持つ2つ目のチェックアウトです
- Gitは同じブランチを2つのワークツリーでチェックアウトすることを拒否します
- .envやnode_modulesなどの無視されたファイルは、新しいワークツリーにはありません
AIコーディングエージェントを互いの作業を上書きさせずに並列で動かすには、エージェントごとに専用のGitワークツリーを用意します。1つのリポジトリを共有しながら、自分のブランチを持つ別の作業ディレクトリです。git worktree add -b で作成し、その中でエージェント(Claude Code、Codex、Gemini CLIなど)を起動し、作業が終わったらブランチをマージしてワークツリーを削除します。MAOでは、レイヤーがこのワークツリーです。ナビゲーターから作成し、取り込む前にチェックが入ります。
Gitワークツリーとは?
ワークツリーは、同じリポジトリにつながった追加の作業ディレクトリで、それぞれが自分のブランチをチェックアウトしています。
Git自身のドキュメントによると、1つのリポジトリは複数の作業ツリーを持てるので、複数のブランチを同時にチェックアウトできます。git clone や git init が作ったチェックアウトがメインワークツリーで、追加したものはそれぞれリンクされたワークツリーです。リンクされたワークツリーは、HEAD やインデックスのようなワークツリーごとのファイルを除いて、すべてをリポジトリと共有します。
実際には、各ワークツリーが自分のファイル、自分のブランチ、自分のステージ済みの変更を持ち、コミット、ブランチ、オブジェクトストアは共有されます。あるワークツリーで作ったコミットは、pushやfetchなしで、ほかのすべてのワークツリーからすぐに見えます。
並列のコーディングエージェントに別々のワークツリーが必要なのはなぜ?
1つのチェックアウトにいるエージェントは、同じファイルを編集し、1つのブランチを共有するからです。
2つのエージェントが同じディレクトリで作業すると、一方の書きかけの変更がもう一方の出発点になり、テストの実行にはどちらも組み合わせるつもりのなかった編集が混ざり、1つのターミナルでの git switch がすべてのエージェントの足元のファイルを変えてしまいます。エージェントごとに1つのワークツリーを使えば、各エージェントは自分のブランチ上で自分のファイルを編集し、何を組み合わせるかはブランチのマージであなたが決めます。
エージェントごとにワークツリーを用意するには?
メインのチェックアウトから、エージェントごとに1つのワークツリーと新しいブランチを追加し、それぞれのフォルダでエージェントを起動します。
- メインのチェックアウトで、エージェントごとにワークツリーと新しいブランチを作成します。パスはフォルダの置き場所です。リポジトリと同じ階層に置くと、プロジェクトのファイルに混ざりません。
- プロジェクトの実行に必要な無視されたファイル(
.envなど)をコピーし、各ワークツリーで依存関係をインストールします。 - 各ワークツリーで、それぞれ専用のターミナルからエージェントを1つずつ起動します。
- 今あるワークツリーは、いつでも
git worktree listで確認できます。
git worktree add ../myapp-api -b agent/api
git worktree add ../myapp-tests -b agent/tests
cp .env ../myapp-api/
cp .env ../myapp-tests/
cd ../myapp-api && claude # agent 1
cd ../myapp-tests && claude # agent 2
git worktree listgit worktree list は、まずメインワークツリーを、続いてリンクされた各ワークツリーを、チェックアウト中のコミットとブランチとともに表示します。
/home/me/myapp d3d2dd1 [main]
/home/me/myapp-api d3d2dd1 [agent/api]
/home/me/myapp-tests d3d2dd1 [agent/tests]スクリプトでは、git worktree list --porcelain を使うと、Gitのバージョンが変わっても安定した形式で出力されます。すでにあるブランチをエージェントに渡すときは、-b を省きます(git worktree add ../myapp-fix fix/login)。
エージェントの作業をマージして片付けるには?
メインのチェックアウトでエージェントのブランチをマージし、ワークツリーを削除してからブランチを削除します。
- エージェントに、自分のブランチへ作業をコミットさせます。
- メインのチェックアウトで、ほかのブランチと同じようにマージします。
- ワークツリーを削除します。Gitが削除するのはクリーンなワークツリー、つまり追跡されていないファイルがなく、追跡中のファイルにも変更がないものだけです。
- マージ済みのブランチを削除します。ワークツリーがそのブランチをチェックアウトしている間、Gitはブランチの削除を拒否するので、先にワークツリーを削除します。
cd ../myapp
git merge agent/api
git merge agent/tests
git worktree remove ../myapp-api
git worktree remove ../myapp-tests
git branch -d agent/api agent/testsワークツリーに変更や追跡されていないファイルがあって git worktree remove が拒否した場合は、残したいものをコミットするか移動するか、--force を付けて破棄します。ワークツリーのフォルダを手で削除してしまった場合は、git worktree list がそれを prunable と表示し、git worktree prune が残った記録を削除します(git worktree prune -n は削除対象を表示するだけです)。
ワークツリーでよくある問題は?
問題のほとんどは、すでにチェックアウトされているブランチ、Gitが追跡しないファイル、そしてワークツリー同士がまだ共有しているものから生じます。
- 同じブランチを2回チェックアウトすることはできません。
git worktree addは、ほかのワークツリーがチェックアウト中のブランチを拒否し、ワークツリー内でのgit switchも同様です。メインのチェックアウトが使っているmainも対象になるので、ワークツリーをmainに切り替えるのではなく、メインのチェックアウトでマージします。エージェントごとに-bで新しいブランチを作ります。 - 無視されたファイルや追跡されていないファイルはコピーされません。 新しいワークツリーには、Gitが追跡しているファイルしかありません。
.env、node_modules、ビルド成果物、ローカル設定は、作られたチェックアウトに残るので、各ワークツリーでコピーするか再インストールします。 - 無視されたファイルは確認なしに削除されます。
git worktree removeを止めるのは、変更されたファイルか追跡されていないファイルだけです。コピーした無視対象の.envしかないワークツリーは、それごと削除されます(Git 2.56.0で確認)。 - ポートが衝突します。 各ワークツリーはプロジェクトの完全なコピーなので、2つのワークツリーで開発サーバーを起動すると、サーバーが2つ立ち上がります。両方が同じ固定ポートで待ち受けると、2つ目は起動に失敗します。ワークツリーごとに別のポートを設定します(たとえばそれぞれの
.envで)。 - フォルダを削除すると記録が残ります。
rmでワークツリーのディレクトリを消すと、git worktree pruneを実行するかGitが期限切れで消すまで、その記録がリポジトリに残ります。代わりにgit worktree removeを使います。 - サブモジュールのサポートは完全ではありません。 Gitのドキュメントは、複数のチェックアウトをまだ実験的な機能とし、サブモジュールのサポートは不完全で、スーパープロジェクトを複数チェックアウトすることは推奨しないとしています。サブモジュールを含むワークツリーの削除には
--forceが必要です。
Claude Codeは自分でワークツリーを作成できる?
できます。ワークツリー用のフラグで、ワークツリーとブランチを作成し、その中でセッションを開始します。
Claude Codeのドキュメントによると、claude --worktree feature-auth(または -w)は、リポジトリのルートにある .claude/worktrees/feature-auth/ にワークツリーを作り、worktree-feature-auth という新しいブランチに置きます。2つ目のターミナルで別の名前を付けてもう一度実行すると、2つ目の独立したセッションになります。同じページにある詳細は次のとおりです。
- 新しいワークツリーは、
worktree.baseRefの設定が"head"でない限り、リポジトリのデフォルトブランチから分岐します。 - プロジェクトのルートに置いた
.worktreeincludeファイル(.gitignoreと同じ書式)は、一致するGitの無視対象ファイル(.envなど)を新しいワークツリーごとにコピーします。 - 終了時、名前のないセッションのクリーンなワークツリーはブランチごと削除されます。変更やコミットがあるワークツリーでは、残すか削除するかを尋ねられます。
- フロントマターに
isolation: worktreeを持つカスタムサブエージェントは、常に専用の一時的なワークツリーで動きます。
ドキュメントでは、.claude/worktrees/ を .gitignore に加えて、これらのワークツリーがメインのチェックアウトで追跡されていないファイルとして表示されないようにすることも勧めています。
1つのチェックアウト、ワークツリー、クローン、MAOのレイヤーのどれがよい?
ワークツリーとレイヤーは、1つのリポジトリを共有しながら各エージェントに専用のファイルを与えます。クローンはより強く分離しますが、作業を共有するにはpushとfetchが必要です。
MAOのレイヤーはワークツリーをどう使う?
MAOのレイヤーは、自分のブランチと自分のキャンバスを持つGitワークツリーで、ナビゲーターから作成、切り替え、取り込みを行います。
- 作成。 ナビゲーターのレイヤーレールで New layer を選び、レイヤー名とブランチ名を入力します。Groundの配置を出発点としてコピーすることもできます。コピーされたノードは下書きとして始まり、権限をバイパスする起動オプションはコピーされません。
- 作業。 レールでレイヤーに切り替え、そこにエージェントを置きます。切り替えるとアクティブなキャンバスとワークツリーが変わりますが、何もマージされません。レイヤーのキャンバスはワークツリー内のファイルではなくMAO自身の状態に保存されるので、
git statusには表示されません。 - 報告。 レイヤー上のエージェントは、
mao layer statusで作業の進み具合を投稿できます。blockedまたはreviewにしたレイヤーは、要対応として示されます。 - 取り込み。 Groundに切り替え、レイヤーのメニューで Land… を選びます。MAOは衝突とコミットされていない変更をチェックし、マージまたはfast-forwardの前に取り込み先のブランチを表示します。ブランチのリセット、強制的な変更、作業のstashは一切行わず、チェック後にブランチが動いていれば取り込みを拒否します。
- アーカイブ。 取り込んだレイヤーは、Keep the layer をオンにしない限りアーカイブされます。アーカイブは元に戻せます。レイヤーを削除するコマンドはありません。
エージェントは自分のターミナルから、自分のレイヤーの状態を投稿します。オーケストレーターに指定されたエージェントは、さらにレイヤーの作成、取り込み、アーカイブ、復元を行い、新しいエージェントをレイヤーに置くこともできます。
mao layer status --state review --progress 3/5
mao layer land "api"
mao layer archive "api"
mao layer restore "api"よくある質問
使えません。git worktree add はほかのワークツリーがチェックアウト中のブランチを拒否し、ワークツリー内での git switch も拒否します。ワークツリーごとに -b で新しいブランチを作ります。
しません。新しいワークツリーにはGitが追跡しているファイルしかないので、.env や node_modules などの無視されたファイルは、ワークツリーごとにコピーするか再インストールする必要があります。Claude Codeの .worktreeinclude ファイルを使うと、Claude Codeが作るワークツリーにGitの無視対象ファイルをコピーできます。
違います。クローンは独自のブランチとオブジェクトを持つ別のリポジトリで、クローン同士はpushとfetchで作業をやり取りします。ワークツリーは1つのリポジトリを共有するので、あるワークツリーでのコミットはすぐにすべてのワークツリーから見えます。
Gitはそのワークツリーの記録を残し、git worktree list はそれをprunableと表示します。git worktree prune で記録を片付け、次からは git worktree remove を使います。
はい。MAOの各レイヤーは自分のブランチ上のGitワークツリーで、New layer を選んでブランチ名を入力すると作成されます。MAOが衝突とコミットされていない変更をチェックした後、キャンバスからGroundに取り込みます。
出典
- git-worktreeのドキュメント:メインワークツリーとリンクされたワークツリー、それらが共有するもの、
add -b、同じブランチの2回目のチェックアウトの拒否、listと--porcelain、removeと--force、prune、サブモジュールに関する注記。 - git-cloneのドキュメント:クローンは、元のリポジトリのリモート追跡ブランチを持つ新しいリポジトリであること。
- Claude Code:ワークツリーで並列セッションを実行する:
--worktree、.claude/worktrees/、worktree-で始まるブランチ名、worktree.baseRef、.worktreeinclude、終了時の片付け、サブエージェントのisolation: worktree。 - ワークツリーレイヤーを作成する:New layer、レイヤー名とブランチ名、Groundの配置のコピー。
- レイヤーをGroundに取り込む:取り込み前のチェック、Keep the layer、取り込み後のアーカイブ。
- レイヤーの状態を設定する、レイヤーを切り替える、レイヤーをアーカイブ・復元する:状態の種類、マージせずに切り替えること、アーカイブと復元。
- MAO 0.8.0のリリースノート:取り込み前のドライラン、リセット・強制・stashをしないこと、オーケストレーターによるレイヤー管理。
- MAO 0.5.20のリリースノート:レイヤーのキャンバスがワークツリーではなくMAOの状態に保存されること。
- このページのコマンドは、Linux上のGit 2.56.0でテスト用リポジトリを使って実行しました。
2026-10-28に確認。
ご質問は?Discordで質問するか、hello@miguer.comまでメールでお知らせください。