git worktree — 並行作業の仕組み
書きかけを置いたまま急ぎの直しをしたい、Claude Code のセッションを2つ並べて同時に進めたい。そういうときに使うのが git worktree です。worktree は、同じリポジトリに「作業ツリー・ステージ・HEAD」の組をもう1つ増やすコマンドで、コミットとブランチは両方で共有します。この回では、となりのフォルダに作業ツリーを増やして行き来し、同じブランチを2か所で開けない理由、Claude Code が使う --detach の形、片づけるときの remove と --force の違いを見ます。
- 上のターミナルは、実際に打ったときと同じ出力です(Git は英語で答えます)。
cdでとなりのフォルダに入ると、プロンプトが~/memo-app-fix (fix)のように変わります - 下の中で起きていることは、コマンドの結果、Git の中の何が変わったかを図にしたものです。丸がコミット、黒い札がブランチ、ピンクの札が HEAD です
- 作業ツリーが2つあると、HEAD も2つ出ます。塗りのピンクの札が、いまターミナルがいる作業ツリーの HEAD、白地にピンク枠の
HEAD(memo-app-fix)がもう一方の作業ツリーの HEAD です - 3つの場所の見出しには、いま入っている作業ツリーの名前が「作業ツリー(memo-app-fix)」のように出ます
- 右の説明をスクロールして読み進めると、左のターミナルでコマンドが1つずつ打たれます。
→キーでも1つずつ進みます(←で1つ戻ります。スマホでは「次へ」ボタン)。最後まで進んでから→を押すと次の区間へ移ります。黄色く光っているのが、そのコマンドで変わった場所です
1. git worktree add — 作業ツリーをもう1つ増やす
ファイルは作業ツリー・ステージ・コミットの3つの場所にあり、HEAD は今乗っているブランチを指す付箋でした。ふだんのリポジトリには、この「作業ツリー・ステージ・HEAD」が1組しかありません。だから別のブランチで作業するには、git switch で HEAD を乗り換え、作業ツリーの中身を入れ替える必要がありました。
git worktree add は、この組をもう1つ増やします。増やした組は別のフォルダになり、その中では別の HEAD と別のステージが使われます。一方、コミットとブランチの付箋は1か所にしかなく、どちらの作業ツリーからも同じものが見えます。
| 作業ツリーごとに別々 | 両方で共有 |
|---|---|
| 作業ツリー(フォルダの中のファイル)・ステージ・HEAD(どのブランチに乗っているか) | コミット・ブランチの付箋(main・fix) |
次の区間で打つ git worktree add ../memo-app-fix -b fix の ../memo-app-fix は作るフォルダ(memo-app のとなり)、-b fix は「新しいブランチ fix を作って、そこに乗せる」という意味です。
worktree add — 作業ツリーをもう1つ増やす
mainで、todo.txtに「バターを買う」の書きかけがあります。ここで急ぎの直しを頼まれたとします。stash で退避する代わりに、作業ツリーをもう1つ増やします。$ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: todo.txt no changes added to commit (use "git add" and/or "git commit -a")となりのフォルダ
memo-app-fixに もう1つの作業ツリー ができ、新しいブランチfixがそこで開かれました。グラフには白地にピンク枠のHEAD(memo-app-fix)が増えています。塗りの HEAD が、いまターミナルがいるmemo-appの HEAD です。$ git worktree add ../memo-app-fix -b fix Preparing worktree (new branch 'fix') HEAD is now at e5c0a62 パンを追加このリポジトリの作業ツリーが1行ずつ出ます。左から、フォルダの場所・その作業ツリーの HEAD のコミット・乗っているブランチです。
$ git worktree list /Users/you/memo-app e5c0a62 [main] /Users/you/memo-app-fix e5c0a62 [fix]*は、いまいる作業ツリーが乗っているブランチです。fixの前の+は ほかの作業ツリーが乗っているブランチ の印です。$ git branch + fix * mainとなりのフォルダに入ると、プロンプトが
~/memo-app-fix (fix)になり、塗りの HEAD がfixに移りました。3つの場所もmemo-app-fixのものに切り替わっています。$ cd ../memo-app-fixこちらの
todo.txtに「バターを買う」はありません。作業ツリーとステージは作業ツリーごとに別々で、ここはパンを追加の中身から始まっています。$ cat todo.txt 牛乳を買う 卵を買う パンを買うfixでの用事を済ませます。$ echo "ジャムを買う" >> todo.txtfixの付箋だけがジャムを追加へ進みました。白枠のHEAD(memo-app)は、mainに乗ったままです。$ git commit -am "ジャムを追加" [fix bbe8599] ジャムを追加 1 file changed, 1 insertion(+)元のフォルダに戻ります。塗りの HEAD が
mainに戻り、3つの場所もmemo-appのものに戻りました。$ cd ../memo-app「バターを買う」の書きかけはそのまま残り、「ジャムを買う」は入っていません。もう一方の作業ツリーでコミットしても、こちらのファイルは変わりません。
$ cat todo.txt 牛乳を買う 卵を買う パンを買う バターを買うコミットとブランチは2つの作業ツリーで共有なので、
memo-appからもfixのジャムを追加が見えます。書きかけを片づけたら、ここでgit merge fixを打てば取り込めます。$ git log --oneline --all bbe8599 (fix) ジャムを追加 e5c0a62 (HEAD -> main) パンを追加 8b41d07 卵を追加 3f2a9c1 牛乳を追加
戻ったあとの todo.txt に、「ジャムを買う」は入っていませんでした。片方の作業ツリーでコミットしても、動くのはそのブランチの付箋だけで、もう片方のファイルには触りません。
git worktree list の各行は「フォルダの場所・HEAD のコミット・乗っているブランチ」です。1行目は、どの作業ツリーから打っても、最初からあったメインの作業ツリー(.git フォルダの本体がある方)です。
2. stash・switch との違い
書きかけがあるときに別のブランチで作業する方法は、ほかに 1-4 checkout の乗り換えと 1-7 stash の退避がありました。3つの違いは、書きかけをどこに置いたまま、別の作業をするかです。
| 方法 | 書きかけはどうなるか | 向いている場面 |
|---|---|---|
git switch fix | 作業ツリーに載せたまま乗り換える。上書きされるファイルがあると止まる | 書きかけが無いとき |
git stash → 乗り換え → git stash pop | 退避の棚にしまい、戻ってから作業ツリーに戻す | 短い用事を済ませて、すぐ戻るとき |
git worktree add | 元のフォルダに置いたまま。触らない | 2つの作業を並行して進めるとき |
worktree は作業ツリーそのものを増やすので、元のフォルダで開いているエディタや dev サーバーも止まりません。その代わり、追跡していないもの(node_modules など)は新しいフォルダに入らないので、入れ直しが要ります。
3. 同じブランチは2か所で開けない
作業ツリーを増やしても、1つのブランチに乗れるのは1つの作業ツリーだけです。fix を memo-app-fix で開いているあいだは、memo-app から fix に乗ることも、fix の付箋を剥がすこともできません。
同じブランチは2か所で開けない
fixを、となりのmemo-app-fixの作業ツリーで開きました。ターミナルがいるのは、mainに乗ったmemo-appのままです。$ git worktree add ../memo-app-fix -b fix Preparing worktree (new branch 'fix') HEAD is now at e5c0a62 パンを追加memo-appからfixに乗ろうとすると止まります。already used by worktree at '/Users/you/memo-app-fix'は「fixはmemo-app-fixの作業ツリーがもう使っている」という意味です。$ git switch fix fatal: 'fix' is already used by worktree at '/Users/you/memo-app-fix'fixを3つ目のフォルダで開こうとしても、同じ理由で止まります。1つのブランチに乗れる作業ツリーは1つだけ です。$ git worktree add ../memo-app-fix2 fix Preparing worktree (checking out 'fix') fatal: 'fix' is already used by worktree at '/Users/you/memo-app-fix'付箋を剥がすこともできません。
memo-app-fixの HEAD が乗っている付箋を剥がすと、その作業ツリーは乗る場所を失うからです。$ git branch -d fix error: cannot delete branch 'fix' used by worktree at '/Users/you/memo-app-fix'反対側からも試します。
memo-app-fixに入りました。$ cd ../memo-app-fix今度は
mainがmemo-appの作業ツリーに使われているので、同じように止まります。$ git switch main fatal: 'main' is already used by worktree at '/Users/you/memo-app'* fixがいまいる作業ツリーのブランチ、+ mainがもう一方の作業ツリーのブランチです。+の付いたブランチに乗りたいときは、それを使っている作業ツリーで別のブランチに移るか、その作業ツリーを消してからにします。$ git branch * fix + main
止める理由は、付箋が共有されていることにあります。かりに2つの作業ツリーが両方 fix に乗っていて、片方でコミットすると、もう片方から見てHEAD のコミットだけが勝手に進み、作業ツリーとステージが取り残された状態になります。付箋を剥がせないのも、乗っている作業ツリーが乗る場所を失わないためです。git branch で + の付いたブランチに止められたら、git worktree list で使っているフォルダを確かめます。
4. Claude Code の形 — git worktree add --detach
Claude Code の作業ログに出てくる git worktree add は、--detach を付けた形でした(10回)。--detach は、ブランチに乗らず、コミットを直接指す HEAD(1-4 の detached HEAD)で作業ツリーを作るオプションです。
ブランチに乗らないので、3 の「同じブランチは2か所で開けない」に引っかかりません。自分が main で作業していても、並行セッションは同じコミットから、ブランチを取り合わずに始められます。その代わり、作業が終わったら、ブランチの付箋を貼るか、main に取り込むかを決める必要があります。
Claude Code の形 — worktree add --detach
Claude Code の作業ログに出てくる形です。
--detachは、ブランチに乗らずにコミットe5c0a62を直接指す detached HEAD で作業ツリーを作ります。新しいブランチは増えていません。$ git worktree add --detach ../memo-app-wt Preparing worktree (detached HEAD e5c0a62) HEAD is now at e5c0a62 パンを追加(detached HEAD)は、この作業ツリーがどのブランチにも乗っていない印です。ブランチを使わないので、mainを開いている作業ツリーとブランチを取り合いません。$ git worktree list /Users/you/memo-app e5c0a62 [main] /Users/you/memo-app-wt e5c0a62 (detached HEAD)memo-app-wtに入ります。プロンプトの括弧には、ブランチ名の代わりにコミットの ID が出ます。$ cd ../memo-app-wt並行セッションでの作業です。
$ echo "ジャムを買う" >> todo.txt[detached HEAD bbe8599]は「ブランチに乗らずにコミットした」という意味です。進んだのはこの作業ツリーの HEAD だけで、ジャムを追加を指すブランチの付箋はまだありません。$ git commit -am "ジャムを追加" [detached HEAD bbe8599] ジャムを追加 1 file changed, 1 insertion(+)残したいコミットには付箋を貼ります。
git branch jamは、いまの HEAD の位置にjamを貼るだけで、HEAD は detached のままです。$ git branch jam元の
memo-appに戻ります。$ cd ../memo-appmainに取り込みます。mainはjamの祖先なので、付箋を前へずらすだけの fast-forward で済みました。$ git merge jam Updating e5c0a62..bbe8599 Fast-forward todo.txt | 1 + 1 file changed, 1 insertion(+)用が済んだ作業ツリーを消します。書きかけも追跡していないファイルも無いので、
--force無しで何も言わずに消えます。$ git worktree remove ../memo-app-wtjamはmainに取り込み済みなので、-dで剥がせます。$ git branch -d jam Deleted branch jam (was bbe8599).並行セッションの
ジャムを追加が、mainの歴史に入りました。$ git log --oneline -3 bbe8599 (HEAD -> main) ジャムを追加 e5c0a62 パンを追加 8b41d07 卵を追加
detached HEAD で作ったコミットを指しているのは、その作業ツリーの HEAD だけです。付箋を貼らずに作業ツリーを消すと、次の 5 で見るように辿れなくなります。なお、Claude Code は作業ツリーをリポジトリの中の .claude/worktrees/ などに作ることがありますが、場所が違うだけで仕組みは同じです(この教材の画面では、となりのフォルダに作っています)。
5. 片づける — git worktree remove と --force
用が済んだ作業ツリーは git worktree remove フォルダ で消します。消えるのはフォルダと、その作業ツリーの HEAD・ステージで、共有のコミットとブランチは残ります。ただし、コミットしていない変更や一度も add していないファイルがあると、何もせずに止まります。
worktree remove と --force
fix用の作業ツリーを、となりのmemo-app-fixに作ります。$ git worktree add ../memo-app-fix -b fix Preparing worktree (new branch 'fix') HEAD is now at e5c0a62 パンを追加memo-app-fixに入ります。$ cd ../memo-app-fix1行書き足します。
$ echo "ジャムを買う" >> todo.txtfixがジャムを追加へ進みました。$ git commit -am "ジャムを追加" [fix bbe8599] ジャムを追加 1 file changed, 1 insertion(+)もう1行書き足しますが、今度はコミットしません。これが 書きかけ として残ります。
$ echo "チーズを買う" >> todo.txtmemo-appに戻ります。memo-app-fixのフォルダには、「チーズを買う」の書きかけが残っています。$ cd ../memo-appgit worktree removeは止まります。contains modified or untracked files, use --force to delete itは「書きかけか追跡していないファイルがある。消すなら --force を付けて」という意味です。$ git worktree remove ../memo-app-fix fatal: '../memo-app-fix' contains modified or untracked files, use --force to delete it--forceを付けると、フォルダごと消えて白枠の HEAD もなくなりました。「チーズを買う」は一度もコミットもステージもしていないので、reflog でも取り戻せません。$ git worktree remove --force ../memo-app-fix残った作業ツリーは
memo-appだけです。$ git worktree list /Users/you/memo-app e5c0a62 [main]一方、コミット済みの
ジャムを追加は残っています。作業ツリーを消しても、ブランチの付箋fixは消えない からです。$ git log --oneline --all bbe8599 (fix) ジャムを追加 e5c0a62 (HEAD -> main) パンを追加 8b41d07 卵を追加 3f2a9c1 牛乳を追加fixをmainに取り込みます。付箋を前へずらすだけの fast-forward で済みました。$ git merge fix Updating e5c0a62..bbe8599 Fast-forward todo.txt | 1 + 1 file changed, 1 insertion(+)「ジャムを買う」は入り、「チーズを買う」はありません。
--forceで消えたのは、コミットしていなかった書きかけだけです。$ cat todo.txt 牛乳を買う 卵を買う パンを買う ジャムを買う
3-4 reflog は HEAD とブランチが指したコミットの記録なので、一度もコミットしていない書きかけは、reflog でも取り戻せません。コミット済みのものが残るかどうかは、付箋で決まります。
| 消した作業ツリーにあったもの | remove のあと |
|---|---|
ブランチ(fix)に積んだコミット | 残る。git merge fix で取り込める |
| detached HEAD で作り、付箋を貼っていないコミット | 辿れなくなる。指していた HEAD と、その動きの記録(reflog)が一緒に消えるため |
| コミットしていない変更・追跡していないファイル | --force のときだけ消える。付けなければ remove が止まる |
フォルダを rm -rf などで直接消すと、作業ツリーの記録が残って git worktree list に出続けます。そのときは git worktree prune で片づけます。
6. Claude Code が打つ worktree
Claude Code が打った Git のコマンド延べ約14,000回のうち、git worktree は204回でした。内訳は git worktree list が103回、git worktree remove --force が25回、git worktree add --detach が10回です。見るだけの list が約半分を占めます。
気をつけたいのは git worktree remove --force です。そのフォルダに書きかけが残っていれば、確認なしに消えます。許可する前に git -C ../memo-app-wt status(-C は「そのフォルダで打ったことにする」)で書きかけが無いかを見て、git log --oneline --all で残したいコミットに付箋があるかを確かめてください。
なお worktree はその PC の中だけの仕組みで、Windows のノート PC で増やした作業ツリーは Mac からは見えません。もう1台に渡したい作業は、ブランチにコミットして push します。
7. Claude Code の許可画面で見かけたら
この回で見たコマンドを、「何が消えうるか」で並べるとこうなります。
| コマンド | 何が起きるか | 消えうるもの |
|---|---|---|
git worktree list | 作業ツリーの一覧を見るだけ | なし |
git worktree add ../x -b fix / git worktree add --detach ../x | となりに作業ツリーを増やす。いまの作業ツリーには触らない | なし(使用中のブランチなら止まる) |
git worktree remove ../x | その作業ツリーのフォルダを消す。ブランチに積んだコミットは残る | 注意 detached HEAD で作って付箋を貼っていないコミットは辿れなくなる(書きかけや追跡していないファイルがあれば止まる) |
git worktree remove --force ../x | 書きかけがあっても、フォルダごと消す | その作業ツリーのコミットしていない変更(reflog でも戻らない。付箋の無い detached のコミットも辿れなくなる) |
見分け方は、remove に --force が付いているかどうかです。付いていなければ、書きかけがあるときは Git が止めてくれます。付いていたら、そのフォルダの git status を先に見てください。
まとめ
git worktree addは、同じリポジトリに作業ツリー・ステージ・HEAD の組をもう1つ増やす。コミットとブランチの付箋は共有git worktree add ../memo-app-fix -b fixで、となりのフォルダにfix用の作業ツリーができる。cdで行き来する- 片方でコミットしても、もう片方のファイルは変わらない。書きかけを置いたまま別の作業ができる
- 同じブランチは2か所で開けない。使用中のブランチは switch も
branch -dもできず、git branchでは+が付く - Claude Code の作業ログに出てくる
git worktree add --detachは、ブランチを取り合わずに作業ツリーを作る形。終わったら付箋を貼るか、main に取り込む git worktree removeは書きかけがあると止まる。--forceは書きかけごと消し、reflog でも戻らない。ブランチに積んだコミットは残る
これで「Git の中身が見える講座」はおしまいです。第1部では3つの場所と、ブランチと HEAD という付箋を、第2部では origin/main という GitHub の写しを見ました。第3部では歴史をつなぎ・書き換え・取り戻し、第4部ではそれを Claude Code のコマンドと許可画面に当てはめました。どのコマンドも、動かしているのは3つの場所と付箋のどれかです。許可画面に見慣れないコマンドが出たら、どの場所と付箋が動き、何が消えうるかを、この講座の図に当てはめてみてください。