AIコーディングエージェントに複数の作業を同時に任せたい場面があります。

たとえば、片方ではUIを直し、もう片方ではテストを直す。あるいは、A案とB案を別々に試す。こういうとき、同じ作業ディレクトリで同時に編集させると、未コミット変更やブランチ切り替え、同じファイルの編集が絡んでかなり危なっかしくなります。

そこで使えるのが git worktree です。

この記事では、1つのローカルリポジトリから複数の作業ディレクトリを作り、feature/new-feature-afeature/new-feature-b を別々に進める流れを、実際のコマンドと結果で確認します。

1つの.gitをmain、feature A、feature Bの3つのworktreeが共有している図

git worktree とは

git worktree は、1つのGitリポジトリに複数の作業ディレクトリを紐づける機能です。

普通は1つのリポジトリに1つの作業ディレクトリがあり、その中で git switchgit checkout を使ってブランチを切り替えます。

一方、git worktree を使うと、ブランチごとに作業ディレクトリそのものを分けられます。

  • /tmp/worktree-demomain
  • /tmp/worktree-demo-afeature/new-feature-a
  • /tmp/worktree-demo-bfeature/new-feature-b

というように、別々の場所で別々のブランチを同時に開けます。

git checkout との違い

git checkoutgit switch は、今いる作業ディレクトリの中身を別ブランチへ切り替える操作です。

作業途中の変更があると、切り替え時に止められたり、stashやコミットが必要になったりします。

git worktree は、ブランチを切り替えるのではなく、作業ディレクトリを増やします。なので、main の作業場所を残したまま、A用、B用の作業場所を別に用意できます。

AIエージェントに並列で頼む場合は、この差がかなり大きいです。

検証用リポジトリを作る

今回はブログ本体のリポジトリではなく、/tmp に捨てリポジトリを作って試します。

cd /tmp
mkdir worktree-demo
cd worktree-demo
git init -b main
printf '# worktree demo\n' > README.md
git add README.md
git -c user.name='Demo User' -c user.email='[email protected]' commit -m 'initial commit'

ここまでで main ブランチに最初のコミットが1つある状態になります。

2つのworktreeを作る

次に、main から2つの作業ディレクトリを作ります。

git worktree add ../worktree-demo-a -b feature/new-feature-a main
git worktree add ../worktree-demo-b -b feature/new-feature-b main
git worktree list

検証時の git worktree list はこうなりました。

/private/tmp/worktree-demo    76f5917 [main]
/private/tmp/worktree-demo-a  76f5917 [feature/new-feature-a]
/private/tmp/worktree-demo-b  76f5917 [feature/new-feature-b]

git worktree listで3つのworktreeが表示されているターミナル画面

同じリポジトリから、3つの作業ディレクトリが見えています。

GUIクライアントのForkで見ると、同じリポジトリ内に mainfeature/new-feature-afeature/new-feature-b が並んで見えます。この時点では、まだ3つとも最初のコミットを指しています。

Forkでmain、feature/new-feature-a、feature/new-feature-bが同じ初期コミットを指している画面

A側のworktreeで作業する

まずA側へ移動します。

cd /tmp/worktree-demo-a
git branch --show-current

出力はこうです。

feature/new-feature-a

このworktreeでは feature/new-feature-a がチェックアウトされています。ここでA用のファイルを追加してコミットします。

printf 'feature A note\n' > feature-a.txt
git add feature-a.txt
git -c user.name='Demo User' -c user.email='[email protected]' commit -m 'add feature A note'

B側のworktreeで作業する

次にB側へ移動します。

cd /tmp/worktree-demo-b
git branch --show-current

出力はこうです。

feature/new-feature-b

B側では別ファイルを追加してコミットします。

printf 'feature B note\n' > feature-b.txt
git add feature-b.txt
git -c user.name='Demo User' -c user.email='[email protected]' commit -m 'add feature B note'

この時点で、AとBは別々の作業ディレクトリ、別々のブランチ、別々のコミットとして進んでいます。

元のmain worktreeからどう見えるか

元の main worktreeに戻って確認します。

cd /tmp/worktree-demo
git branch --list

検証時の出力です。

+ feature/new-feature-a
+ feature/new-feature-b
* main

+ が付いているブランチは、別のworktreeでチェックアウト中です。つまり、feature/new-feature-afeature/new-feature-b は、今この main の作業ディレクトリではなく、別ディレクトリ側で開かれています。

履歴も見てみます。

git log --oneline --graph --decorate --all

出力はこうなりました。

* 1a0b4cb (feature/new-feature-b) add feature B note
| * 693dc6f (feature/new-feature-a) add feature A note
|/  
* 76f5917 (HEAD -> main) initial commit

feature Aとfeature Bのコミットがmainから分岐しているgit logのターミナル画面

feature/new-feature-afeature/new-feature-b に、それぞれ別のコミットが乗っています。

一方で、main の作業ツリーは変わっていません。

git status --short

この出力は空でした。ファイル一覧も README.md のみです。A側で作った feature-a.txt や、B側で作った feature-b.txt は、main には入っていません。

mainからfeature/new-feature-aとfeature/new-feature-bが分岐しているコミット図

Forkで見ると、main から feature/new-feature-afeature/new-feature-b がそれぞれ1コミットずつ分岐していることも分かります。CLIの git log --graph --all と同じ内容を、GUI上で確認している形です。

Forkでfeature/new-feature-aとfeature/new-feature-bがmainから分岐している画面

Gitの情報は共有されている

作業ディレクトリは分かれていますが、Gitのオブジェクトや参照は共通のリポジトリ側にあります。

確認するには git rev-parse --git-common-dir を使えます。

cd /tmp/worktree-demo-a
git rev-parse --git-common-dir

cd /tmp/worktree-demo-b
git rev-parse --git-common-dir

どちらも次の場所を指していました。

/private/tmp/worktree-demo/.git

cloneを2つ作っているわけではなく、同じGitリポジトリに複数の作業ディレクトリをぶら下げている、という理解でよさそうです。

mainへ反映するには統合作業が必要

worktree側でコミットしても、自動で main に入るわけではありません。

feature/new-feature-afeature/new-feature-b の内容を main に入れるには、通常のブランチ運用と同じように、必要に応じて mergerebasecherry-pick などを使います。

git worktree は、あくまで作業場所を分ける機能です。

並列作業の置き場所は分けてくれますが、設計分割、レビュー、テスト、最終的な統合判断まで自動で解決してくれるわけではありません。

使い終わったworktreeを片付ける

使い終わったworktreeは、ディレクトリを手で消すのではなく、git worktree remove で片付けます。

cd /tmp/worktree-demo
git worktree remove ../worktree-demo-a
git worktree remove ../worktree-demo-b
git worktree list

ディレクトリを手動で削除すると、Git側に管理情報が残ることがあります。

管理情報だけが残った場合に git worktree prune を使うことがありますが、実行前に git worktree list で状態を確認しておくのが安全です。

Codexに任せる時の考え方

CodexなどのAIコーディングエージェントに並列で作業を任せる場合は、先に次を決めておくと事故が減ります。

  • worktree の作成場所
  • ブランチ名
  • どの作業をどのworktreeに任せるか
  • 触ってよいファイルやディレクトリ
  • 自動実行してよいコマンド
  • 禁止する操作

Codex session AとCodex session Bを別々のworktreeとブランチに割り当てる図

たとえばA側の作業を頼むなら、開始時に次のように書いておきます。

このタスクは git worktree を使って進めてください。
main worktree は触らず、/tmp/<project-name>/worktrees/<branch-name> に feature/<branch-name> ブランチの worktree を作成して作業してください。
担当範囲は feature A に関係するファイルだけです。feature B や無関係なファイルは編集しないでください。
作業前後に git status --short と git worktree list を確認してください。
git reset --hard、git clean、既存 worktree の削除、履歴改変、submodule 操作は私の許可なしに実行しないでください。
完了時は対象 worktree 内でコミットしてください。

ポイントは、worktreeを作ること自体ではなく、作業場所、ブランチ、担当範囲、禁止操作を明確にすることです。

AGENTS.mdに書くなら

毎回の指示に書くのが面倒なら、プロジェクトの AGENTS.md に運用ルールとして書いておく方法もあります。

たとえば、こんな内容です。

- 複数タスクを並列に進める場合は、必要に応じて `git worktree` を使ってよい。
- worktree はリポジトリ外の `/tmp/<project-name>/worktrees/<task-name>` 配下に作成する。
- 1つの worktree では1つのブランチだけを担当する。
- 作業前後に `git status --short``git worktree list` を確認する。
- 他の worktree や main worktree の未コミット変更を上書きしない。
- 既存 worktree の削除、`git worktree prune`、履歴改変、`git reset --hard``git clean`、submodule 操作はユーザーの明示許可なしに実行しない。

実際に追記するかどうかは、プロジェクトごとの運用判断です。

ただ、AIエージェントに何度も作業を頼むなら、「どこまで自動でやってよいか」「何は禁止か」を明文化しておく価値はあります。

注意点

git worktree は便利ですが、万能ではありません。

同じファイルを別々のworktreeで編集すれば、最後に統合するときには普通にコンフリクトします。

AIエージェントに並列で頼む場合も、「どのworktreeで、どのブランチを、どのファイル範囲で触るか」を先に決めておくのが大事です。

また、submoduleを含むリポジトリでは、worktreeごとのsubmodule初期化や更新状態など、追加の注意点が出ます。この記事では git worktree の基本とAI並列作業の導入に絞り、submoduleまわりは深掘りしません。

まとめ

git worktree を使うと、1つのリポジトリから複数の作業ディレクトリを作れます。

今回の検証では、main から feature/new-feature-afeature/new-feature-b のworktreeを作り、それぞれ別々にコミットできることを確認しました。

各コミットは元のリポジトリから見えますが、main の作業ツリーは勝手には変わりません。main へ反映するには、通常どおり統合作業が必要です。

AIエージェントに並列作業を任せるときは、worktreeで作業場所を分けたうえで、担当範囲と禁止操作まで明確にしておくのが現実的です。

GitHub Actions やデプロイ自動化まで広げるなら、GitHub CI/CD で VPS へ自動デプロイするまで も関連します。