並列で動かしていたエージェントの片方が、もう片方のコミットを巻き込んで push してしまったことがあります。
個人開発で複数のサイトとアプリを並行運用しているため、Antigravity 2.0 でエージェントを同時に何本も走らせたくなります。あるエージェントには記事の追加を、別のエージェントには依存更新を任せる、といった具合です。ところが両方を同じクローンの上で動かした結果、依存更新側がまだステージしていない記事ファイルまで git add -A で巻き込み、意図しない内容が main に乗りました。
幸いすぐ revert できましたが、原因を突き詰めると「作業領域を共有したまま並列実行した」という設計の問題でした。私自身、ここで一度痛い目を見てから分離を徹底しています。同じリポジトリで複数エージェントを安全に走らせるための設計を、実運用の判断とあわせて順にたどっていきます。
なぜ同じ作業ツリーで並走すると壊れるのか
git のリポジトリは、履歴を保持する .git ディレクトリと、いま編集しているファイルが置かれる作業ツリー、そして次のコミットに含める内容を記録するインデックス(ステージングエリア)で構成されています。問題は、このインデックスと作業ツリーがクローンに対して1つしかないことです。
並列エージェントが同じクローンを共有すると、次の3種類の衝突が起きます。
ひとつ目は index.lock の衝突です。git はインデックスを書き換える操作の間 .git/index.lock を作ります。エージェント A が commit している最中にエージェント B が add を始めると、B 側が Unable to create '.git/index.lock': File exists で失敗します。VM 上の自動実行では、この失敗が無音で握り潰されて「コミットしたつもりで何もしていない」状態になりがちです。
ふたつ目は作業ツリーの汚染です。エージェント A が編集中のファイルを、エージェント B のチェックアウトが上書きしたり、git checkout . で消したりします。
みっつ目はブランチの取り違えです。作業ツリーは常に1つのブランチしか指せません。A が feature ブランチに切り替えた瞬間、B も同じブランチの上で作業することになり、変更が混線します。
worktree でエージェントごとに作業領域を分ける
この3つはすべて「インデックスと作業ツリーを共有している」ことが根本原因です。git worktree は、1つの .git(履歴)を共有しながら、独立した作業ツリーとインデックスを複数持てる仕組みです。エージェント1本につき worktree を1つ割り当てれば、衝突の根を断てます。
# ベアではない通常クローンから、エージェント用 worktree を派生させる
REPO = " $HOME /repos/antigravitylab.net"
cd " $REPO "
# エージェントごとに専用ブランチ + 専用作業ツリーを作る
git worktree add "../wt-agent-articles" -b agent/articles origin/main
git worktree add "../wt-agent-deps" -b agent/deps origin/main
# それぞれの worktree は独立したインデックスを持つ
# ../wt-agent-articles … 記事追加エージェント専用
# ../wt-agent-deps … 依存更新エージェント専用
これで記事エージェントは ../wt-agent-articles の中だけで git add / git commit し、依存更新エージェントは ../wt-agent-deps の中だけで作業します。git add -A を打っても、巻き込む範囲はその worktree のファイルに限られます。冒頭の事故は、この分離があれば起きませんでした。
worktree は履歴を共有しているので、ディスク消費は作業ツリー分(数十 MB)だけで済みます。クローンを丸ごと2つ持つより軽量です。
Antigravity 2.0 の projects に worktree を載せる
Antigravity 2.0 は projects と worktree のサポートが入り、サイドバーで作業単位を切り替えられるようになりました。エージェント管制塔として複数エージェントを監督する設計では、この projects を「worktree 1つ = project 1つ = エージェント1本」という対応で割り当てると、画面上でも作業の独立性が見えるようになります。
私は次のレイアウトに落ち着いています。
~/repos/antigravitylab.net ← 統合・push を行う「親」クローン(人間が触る)
~/repos/wt-agent-articles ← project: 記事エージェント
~/repos/wt-agent-deps ← project: 依存更新エージェント
~/repos/wt-agent-i18n ← project: 翻訳整合エージェント
親クローンでは作業させず、各 worktree でエージェントが作った feature ブランチを、人間(または統合役のエージェント1本)が順番に main へ取り込みます。push の窓口を1か所に絞ることで、複数エージェントが同時に origin/main を奪い合う non-fast-forward の押し合いも避けられます。
後始末まで含めてライフサイクルを管理する
worktree は作るのは簡単ですが、消し忘れると git worktree list が散らかり、ディスクも食います。エージェントの仕事が終わったら、ブランチを取り込んでから worktree を畳む、という後始末をスクリプト化しておきます。
#!/usr/bin/env bash
# finish_worktree.sh <worktree-path> <branch>
# 取り込み済みの worktree を安全に畳む
set -euo pipefail
WT = " $1 " ; BR = " $2 "
REPO = " $HOME /repos/antigravitylab.net"
cd " $REPO "
# 1) 作業ツリーに未コミットの変更が残っていないか確認(残っていれば中断)
if [ -n "$( git -C " $WT " status --porcelain )" ]; then
echo "⚠️ $WT に未コミットの変更があります。畳むのを中止します。"
exit 1
fi
# 2) ブランチが main に取り込み済みか確認(未取り込みなら中断)
if ! git merge-base --is-ancestor " $BR " origin/main ; then
echo "⚠️ $BR はまだ origin/main に取り込まれていません。中止します。"
exit 1
fi
# 3) worktree を削除し、用済みブランチも消す
git worktree remove " $WT "
git branch -d " $BR "
git worktree prune
echo "✅ $WT を畳みました( $BR 削除済み)"
ポイントは、未コミットの変更が残っていないことと、ブランチが main の祖先になっている(取り込み済みである)ことを、削除前に必ず検査することです。git merge-base --is-ancestor は、取り込み済みなら終了コード0、未取り込みなら1を返します。これを通過しない worktree は畳まない、という規律を機械で守らせます。
どこまで並列にしてよいか
分離できたからといって無限に並列化してよいわけではありません。実運用で回している体感では、4 並列を超えたあたりから、push の取り込み待ち行列とレビューの目が追いつかなくなります。
並列数の上限は、エージェントの本数ではなく「人間(または統合役)が一定時間内に main へ安全に取り込める本数」で決めるのが現実的です。私は記事・依存・翻訳整合の3本+統合役1本の構成を基本線にしています。これ以上増やしたくなったら、並列を増やすより、各エージェントの担当範囲を太くするほうが破綻しにくいと感じています。
本番運用での落とし穴として、私自身が踏んだ注意点を3つ挙げておきます。
親クローンでうっかり作業してしまう取り違えです。エージェントには worktree のパスを絶対パスで渡し、親クローンでは git config --local receive.denyCurrentBranch refuse のような防御も併用すると、誤操作を早めに弾けます。
worktree の消し忘れです。畳み忘れた作業ツリーが20個ほど溜まると、git worktree list の確認に毎回数秒の無駄が乗り、ディスクも数百 MB 単位で食います。1日の終わりに後始末スクリプトをまとめて回す運用をお勧めします。
同名ブランチの再利用です。前回の agent/articles が残ったまま次回も同名で作ろうとすると失敗します。worktree 名・ブランチ名には日付や実行 ID を含め、衝突を避けるのが安全です。
アプリ開発で AdMob のレポート集計や App Store 向けの素材生成をエージェントに任せている私の体感では、並列を3〜4本に抑えて担当範囲を太くしたほうが、5本以上に薄く割るより全体の所要時間がむしろ約20%短くなりました。取り込み待ちの行列が短くなるためだと考えています。
並列エージェントの設計は、速さよりも「壊れないこと」を先に固めるほど、結果的に手戻りが減って速くなります。次に複数エージェントを走らせるときは、まず worktree でそれぞれの作業領域を分けるところから始めてみてください。