同じチェックアウトで 2 つのコーディングエージェントを動かしてみると、ソフトウェアチームがなぜブランチを使うのかがすぐにわかります。片方がモジュールの名前を変えている最中に、もう片方はその変更が半分だけ入った状態でテストスイートを走らせます。片方は、もう片方が削除したばかりのファイルをステージします。どちらも間違ってはいません。ただ同じ机を共有しているだけです。
SuperDevSpace は、manager と複数の worker を 1 つのリポジトリで同時に動かします。この記事では、彼らを互いに切り離す仕組みである git worktree と、それを扱うときにアプリが守っている具体的なルールを説明します。
git worktree とは
git リポジトリには通常、作業ディレクトリが 1 つしかありません。git worktree を使うと、1 つのリポジトリに複数の作業ディレクトリを持たせられます。それぞれが自分のブランチをチェックアウトし、オブジェクトデータベースはすべて共有します。2 つ目のクローンも、履歴の 2 つ目のコピーもありません。新しい worktree にかかるのは、チェックアウト 1 つ分のファイルだけです。
どのリポジトリでも手で試せます。コマンドはどこでも同じで、違うのはシェルだけです。
macOS / Linux
git worktree add -b agent/frontend-demo ../myrepo-frontend
git worktree list
cd ../myrepo-frontend && git status
cd - && git worktree remove ../myrepo-frontendWindows (PowerShell)
git worktree add -b agent/frontend-demo ..\myrepo-frontend
git worktree list
cd ..\myrepo-frontend; git status
cd ..\myrepo; git worktree remove ..\myrepo-frontendworktree にはそれぞれ専用の HEAD、専用のインデックス、専用のファイルがあります。2 つのプロセスが 2 つの worktree で同時に編集・ビルド・テストをしても、互いの書きかけの変更は見えません。エージェントのチームに必要なのは、まさにこの性質です。
SuperDevSpace での使い方
ルールはシンプルで、どの organization でも同じです。
- manager はメインのチェックアウトで作業します。 計画し、レビューし、マージします。ブランチが合流する唯一の場所です。
- worker はそれぞれ専用のブランチに専用の worktree を持ちます。 manager が worker を採用すると、アプリがその worker のために
git worktree add -b <branch> <path>を実行します。ブランチ名は、あなたが名前を付けない限りagent/<worker 名>-<スタンプ>になります。 - worktree はアプリ自身のデータフォルダ、
worktrees/<organization>/<worker>の下に置かれ、リポジトリの中には決して作られません。プロジェクトフォルダがエージェントのディレクトリで散らかることはありません。 - ターンごとにコミットされます。 worker がターンを終えると、アプリはその worktree で変わったものをすべてコミットします(
agent(<name>): turn)。worker の作業が、コミットされていない作業ディレクトリにしか存在しないという状態は起きません。 - マージはスカッシュマージです。 manager が worker のレポートを受け入れると、ブランチは
git merge --squashで 1 つのコミットとしてあなたのラインに取り込まれます。コンフリクトした場合はマージを中止し、コンフリクトの途中で放り出すのではなく、次の操作のためにリポジトリをきれいな状態に戻します。 - リポジトリごとに git 操作は一度に 1 つ。 worktree のディレクトリがファイルを分離し、リポジトリごとのキューが git コマンドそのものを直列化します。2 つの worker が同時に作業を終えても、git のメタデータを奪い合うことはありません。
図をテキストで見る
gitGraph
commit id: "main"
branch agent/frontend
commit id: "frontend: ターン 1"
checkout main
branch agent/qa
commit id: "qa: ターン 1"
checkout agent/frontend
commit id: "frontend: ターン 2"
checkout main
merge agent/frontend id: "squash: frontend"
merge agent/qa id: "squash: qa"ボード上では、これが同時に進む複数のタスクとして見えます。タスクごとに担当の worker が違い、その下にはそれぞれ専用のブランチがあります。

実用にするための工夫
作ったばかりの worktree には、git が追跡しているファイルしかありません。プロジェクトを動かすにはたいてい足りません。node_modules、ローカルの .env、生成ファイルなどです。これを 2 つの仕組みで補っています。
リポジトリごとのセットアップスクリプト
リポジトリに .super/scripts/setup-worktree.sh があれば、アプリは worker が動き出す前に、新しい worktree の中でそれを実行します。SUPERDEV_MAIN_REPO にはメインのチェックアウトのパスが入ります。出力はリアルタイムで表示されるので、時間のかかるインストールでも状況がわかり、途中でキャンセルもできます。
#!/usr/bin/env bash
set -euo pipefail
# ローカルにしかないファイルをメインのチェックアウトからコピー
cp "$SUPERDEV_MAIN_REPO/.env" .env 2>/dev/null || true
# 依存関係をインストール(pnpm は共有ストアからリンクするので速い)
pnpm install --frozen-lockfileサブモジュール
git worktree add はサブモジュールを空のままにします。新しい worktree に .gitmodules があれば、アプリはその中で git submodule update --init --recursive を実行し、依存関係が黙って欠けたままビルドされることを防ぎます。
作業を失わない後片付け
worktree はたまっていきます。アプリは回収しますが、慎重です。
図をテキストで見る
flowchart TD
start["worker の作業が完了"] --> clean{"作業ツリーはクリーン?"}
clean -->|"いいえ"| keep["worktree を残す"]
clean -->|"はい"| merged{"ブランチはあなたのラインにマージ済み?"}
merged -->|"いいえ"| keep
merged -->|"はい"| remove["worktree を削除"]コミットされていない変更がある worktree や、まだあなたのラインに入っていない作業を含むブランチを持つ worktree は、そのまま残ります。消したフォルダは作り直せますが、失った作業は戻りません。ブランチにも同じ慎重さを適用しています。アプリは自分で作ったブランチを記録しており、触るのはそれだけです。
あなたにとって何が変わるか
worker がそれぞれ自分のブランチを持てば、「エージェントを 4 つ同時に動かす」は賭けではなくなります。次のことができます。
- 独立したタスクに分かれる指示を manager に出し、worker たちを並行して動かす
- どの worker の diff も、それを生んだ会話の隣で個別に読む
- ほかの worker を邪魔せずに、1 人の worker の変更だけを却下する
- チームが働いている間も、メインのチェックアウトを自分で使い続ける
人間のチームが使うのと同じ規律を、互いの足を踏みそうになっても教えてくれないエージェントに適用しているだけです。なぜこれを中心にアプリを丸ごと作ったのかは、最初の記事で書いています。
試してみる
14 日間のトライアルは Premium で、カード登録は不要です。SuperDevSpace をダウンロードして新しい organization をリポジトリに向け、manager が最初の worker を採用するたびに worktree が現れる様子を見てみてください。