AI を並列で動かす前提は、独立した作業領域を切り分けること
目次
少し前に並列の話を書きました——大きなタスクを分割し、複数の agent に同時にばらまく、と。ですが尻尾を一つ残していました:複数の agent が同時にコードを編集するとき、何が彼らの衝突を防ぐのか?今回はそれを取り上げます。
まず私自身がぶつかった壁から。一つのセッションの中で AI が自分で起こす subagent——あれは実のところ問題ありません。自分で隔離の方法を考えてくれるので、あまり気にせずに済む。痛い目を見たのはもう一方です:私が手動で AI 端末をいくつも開き、同じプロジェクトを同時に編集させた。複数の手が同じ作業ディレクトリに伸びてきて、こちらが少し書き、あちらが少し書き、ファイルが互いに上書きされ、状態がぐちゃぐちゃになる——途中で、誰の作業もきれいに残っていないと気づくわけです。
欲しいもの、そして一つの境界
欲しいものは複雑ではありません。並列に動く何本かの手が、それぞれ自分の仕事をしながら、互いにぶつからずに同じプロジェクトを編集する。
ただ先に境界を引いておきます——すべての並列が隔離を必要とするわけではありません。何路かの agent を送り出すとき、一つはログを掘り、一つは原因を分析し、一つはドキュメントをめくる——これらはどれも読み取りだけなので、同じ作業領域に詰め込んでも何の問題もない。各々に一区画を切り出す必要はありません。本当に隔離が要るのは、ファイルを書き換える並列のほうです。読み取りは共有していい、書き込みは分けねばならない——これが以下のすべての出発点です。
回り道:まず 2 つ clone した
二つの AI に互いに干渉せず一つのプロジェクトを編集させるため、最初に手を伸ばしたのは一番素朴な手——物理的な隔離でした:プロジェクトを別々の二つのディレクトリに clone し、AI 一つにつき一部、井戸の水は河の水を犯さず。
きれいです、本当にきれい。ですがすぐに引っかかった:ディスクです。私のプロジェクトの多くは React フロントエンド + Python バックエンドの複合で、依存が山ほどある。一部 clone するだけで数 G になる。二部 clone すれば、ディスクがまるごと重複して食われる。さらに厄介なのは、この「二部開く」やり方を続けたい限り、その二部はずっとそこに居座って場所を占め、回収できないことです。
そこで git worktree に切り替えました。その利点はちょうどこの痛点に当たります:複数の作業ツリーが一つの .git を共有するので、リポジトリと履歴をまるごと何度も複製しない。しかも一時的——作業が終わって検証も済めば、すぐに回収できる。clone のように長く抱えておく必要がない。二つのやり方の隔離効果はほぼ同じ、ですが worktree はディスクを浪費しません。

二種類の並列——誰が worktree を開くか
実際に使うときは、二つの場面を区別しなければなりません。worktree の開き方が違うのです。
一つはセッション内の subagent 並列。これが一番手がかからない:AI に「並列で実行して」と一言告げるだけで、自分でタスクを分割し、隔離が要るときは自分で worktree を開く——いちいち指示しなくていい。
もう一つは私が手動で複数の端末を並列で開く場合。これは AI が既定では知りません——この瞬間、別の AI もこのディレクトリを触っていることを分かっていない。だから明確に伝える必要があります:「このプロジェクトのディレクトリはすでに別の AI が編集している。君は worktree のやり方で作業して。」この一言を指摘して初めて、メインの作業ツリーに直接手を出すのではなく、新しい worktree を作ってそこで作業します。
スムーズに回る流れ
隔離はあくまで第一歩で、作業はまだ回収しなければなりません。私の流れはおおむねこうです:
分割できるタスクの線で切る——前回と同じく、疎結合の部分を選び、各々を独立した worktree に送り込む。すべて終わったら、主控 agent が一つずつブランチに合わせ戻す。一つ合わせて一つ検証し、問題があればその場で直す。一区画が通ったら、その worktree を解放する。
万一二つの worktree が本当に同じファイルを触ってしまったら、主控 agent が出て merge する。ただ正直なところそれは稀です——タスクを分割するときにそもそも各ブロックをできる限り独立させている。二つのブロックが衝突するほど結合しているなら、そもそも二つのタスクに分けるべきではなかったのです。

踏んだ落とし穴と、防ぐべきもの
一番よくある落とし穴は、片付け忘れです。worktree を消し忘れると、そこに居座って場所を食う。ただこれは致命的ではない——機能はとっくに主幹に合わさっているので、失われるものはなく、名前の衝突も git 状態の混乱もない。せいぜい場所を取るだけです。
とはいえ「場所を取る」も手当てが要る。私はグローバルの軍規に一条書き込みました:worktree の作業が検証も merge も問題ないと確認できたら、片付ける。保険も足しました——解放する前に、その worktree の commits がすべて主幹に合わさっているか一度確かめる。手が早すぎて、まだ合わさっていない機能をまるごと払い落とさないように。強い AI はこの識別と後始末を自分でやれる。弱いほうは見落としがちで、そのときは私が見張るか、改めて主控 agent を呼んで処理させます。
今のところ、有用な worktree を誤って消したことは実際にはありません——片付ける前の「commits を確かめる」という一手が、おおむね歯止めになっています。ですが人が手で片付けると、その確認は消える。合わさっていない作業を失う可能性はある。そこは自分で気をつけるしかありません。
無理に使うな、だが一本の線は緩めない
worktree を万能薬扱いするのもよくない。単純なタスク、数ファイルの変更、一つの完結した機能とも言えないもの——そこで worktree を開くのは純粋に割に合わない。一つの作業領域で直して終わりにすればいい。
ただ緩めない線が一本あります:主幹で直接作業しない。どんな変更もまず新しいブランチで始め、検証して問題なければ、PR で主幹に合わせ戻す。worktree であれ単一ブランチであれ、どちらもこの線に奉仕している——主幹を常にきれいで信頼できる一部に保つために。
最後に、worktree そのものに話を戻します。誰かはこう鼻で笑うかもしれません:これは git が何年も前から持っている古い機能だろう、何を語ることがある、と。確かに古い機能です。ですが AI が並列で働くというこの新しい場面で、「複数の手が一つのプロジェクトを同時に編集する」という本物の問題を実際に解決し、かつての何倍もの働きをしている。老いた樹が新しい枝を伸ばした、とでも言いましょうか。
次回は少し毛色の違う話を取り上げたいと思います:AI はこれほど有能で、これほど多くの作業を肩代わりしてくれるのに、なぜ人は結局のところ疲れるのか?その間のどこで歯車が狂うのか。興味があればコメントで教えてください。
コメント