Note

git worktree とは?

stash と switch で行き来する代わりに、ブランチごとに作業フォルダを並べる。仕組み(.git の中身)と注意点を、動く図で整理した勉強の記録。

GitCLI

git worktree は、1 つのリポジトリから作業フォルダをいくつも取り出す機能です。ブランチを切り替える代わりに、ブランチごとにフォルダを並べて、同時に開いておけます。コマンドの使い方より先に「何が起きているのか」を、図で整理しました。

1なぜ調べたか

AI のコーディングエージェントを複数並べて動かす話になると、決まって worktree が出てきます。名前は知っていても、git stash で行き来するのと何が違うのか、フォルダを増やしてディスクは大丈夫なのか、説明できませんでした。

2リポジトリと作業ツリーは別のもの

まず、git には 2 つの層があります。リポジトリ(.git)は、全部のコミットとブランチを持つ「倉庫」。作業ツリーは、そこから 1 本のブランチを取り出してファイルとして並べた「作業台」です。どのブランチを取り出しているかは HEAD が指しています。

作業ツリーファイルを開いて編集する場所(ただのフォルダ)
app/HEAD → main
  • index.ts
  • app.ts
  • README.md
HEAD が指すブランチの中身を取り出している
リポジトリ(.git)全部のコミットとブランチを持っている。いつでも 1 つだけ

リポジトリ(.git)は全部のブランチの履歴を持っている。作業フォルダに出ているのは、そのうち HEAD が指す 1 本(main)の中身だけ。

Animation 1上が作業ツリー、下がリポジトリ。色はブランチ。ボタンで状態を切り替えると、どのフォルダがどのブランチを取り出しているかが変わる。

ふつうは倉庫 1 つに作業台 1 つ。だから別のブランチを触るには、作業台の上を片付けて並べ直す(switch)しかありません。worktree は、倉庫はそのままに作業台だけを増やす仕組みです。

3入れ替えるか、増やすか

この違いは、作業の途中に別のブランチを触りたくなったときにはっきり出ます。feature の途中で、急ぎの修正が入った場面です。

  1. 退避する→
  2. 切り替える→
  3. 直す→
  4. 戻す→
  5. 復元する
  6. 5 手
app/feature未コミットの変更作業中
退避場所(stash)空

feature で作業中。変更はまだコミットしていない。そこに急ぎの修正依頼が来る。

Animation 2同じ場面を 2 通りで。「再生」で 1 コマずつ進む。入れ替えるやり方は 5 手、増やすやり方は 3 手で、変更を逃がす必要もない。

4共有されるもの、worktree ごとのもの

では、作業台を増やしたとき何が 1 つで、何が別々なのか。ポイントは、HEAD(今いるブランチ)と index(ステージ)と手元のファイルだけが worktree ごとで、コミット・ブランチ・設定は全員で 1 つを使っていることです。

app/この worktree だけ
HEAD
main今いるブランチ
index
次のコミットに入れるもの
files
手元のファイル
app-hotfix/この worktree だけ
HEAD
hotfix今いるブランチ
index
次のコミットに入れるもの
files
app.ts を編集中
リポジトリ(.git)— 共有どの worktree から見ても同じ 1 つ
コミットobjects
c1c2c3
ブランチrefs
main → c3hotfix → c3
設定configuser.name など

上の 2 つはそれぞれの worktree だけが持つもの、下はリポジトリにあって全員で 1 つを使うもの。

Animation 3「次へ」で進む。片方の worktree でコミットすると、それは共有の倉庫に入り、もう片方からもすぐ見える。

倉庫を共有できるのは、増やしたフォルダの .git がフォルダではなく、本体の倉庫の場所を書いた 1 行のファイルだからです。

~/dev/app-hotfix
$ cat .git
gitdir: /Users/you/dev/app/.git/worktrees/app-hotfix
Code 1追加した worktree の .git の中身。本体の .git の中にある、このフォルダ用の管理場所を指している。

5同じブランチは 1 か所だけ

worktree には 1 つ制約があります。同じブランチを 2 つのフォルダで同時に開くことはできません。HEAD はフォルダごとにあっても、ブランチ自体は共有なので、 片方で進めるともう片方の作業台が置いていかれるからです。

app/HEAD → mainファイル: c3 の状態
app-2/HEAD → mainファイル: c3 の状態
リポジトリ(.git)

もし同じ main を 2 つのフォルダで開けたとする(実際には git が止める)。どちらも HEAD は main、ファイルは c3 の状態。

Animation 4「もし開けたら」を順に。コミットでブランチが進むと、もう片方のフォルダのファイルとずれる。

同じ内容を別のフォルダで見たいだけなら、ブランチではなくコミットを直接取り出します(git worktree add --detach ../app-peek main)。

6つまずきやすいところ

7どんなときに使うか

PR のレビュー自分の作業を止めずに、レビューするブランチを隣のフォルダで開いて動かす。
急ぎの修正feature の途中でも、main から hotfix を別フォルダに切って直す。stash は要らない。
重い処理の裏で片方のフォルダでテストやビルドを回したまま、もう片方で次の作業を進める。
AI エージェントを並列にエージェントごとにフォルダを渡せば、同じファイルを取り合わずに並行して書ける。

逆に、ブランチを 1 日に 1〜2 回切り替えるくらいなら switch で十分です。「行き来が多い」「止めたくない処理がある」ときに効きます。

8コマンド早見表

git worktree add <path> <branch>既にあるブランチを <path> に取り出す
git worktree add -b <new> <path> <start><start> から新しいブランチを作って取り出す
git worktree add --detach <path> <commit>ブランチなしで取り出す(見るだけのとき)
git worktree listフォルダとブランチの一覧
git worktree remove <path>フォルダと管理情報を消す。変更があると止まる(--force で強制)
git worktree prune手で消したフォルダの管理情報を片付ける
git worktree move <path> <new-path>フォルダを移す(mv だと繋がりが切れる)
git worktree lock <path>外付けディスクなど、一時的に見えなくても prune させない
Table 1git worktree のサブコマンド。<path> は作業フォルダの場所。
まとめ
  • git には、全部を持つリポジトリ(倉庫)と、1 本を取り出した作業ツリー(作業台)がある。
  • switch は作業台の中身を入れ替える。worktree は作業台を増やす。
  • 増やした作業台ごとに別なのは HEAD・index・ファイルだけ。コミットとブランチは共有。
  • だから同じブランチは 1 か所でしか開けない。