リライトを任せたサブエージェントが、2週間前の本文を土台に黙々と作業していました。
原因はClaude Codeのisolation: worktreeです。worktreeはコミット済みの内容から作られるので、手元の未コミットの変更は届きません。
私はこの仕様で2回事故っています。1回目は記事の巻き戻し寸前、2回目は保存したはずの下書きが本体に残りませんでした。
worktreeは並列開発の定番ですが、任せる作業を選ばないと静かに壊れます。2件の事故と、同じ穴に落ちないための手順をまとめました。
この記事でわかること
- Claude Codeのworktreeに引き継がれるもの・引き継がれないもの
- 実際に起きた2件の事故と、気づいたきっかけ
- worktreeを使う作業と使わない作業の分け方
- git worktreeの一覧・削除と、分岐してしまったときの戻し方
PARTS LIST /目次
Claude Codeのworktreeは「コミット済みの世界」で動く
Claude Codeのworktreeは、コミット済みの内容だけでできた別の作業フォルダです。手元で編集中のファイルは、その世界に存在しません。
事故の話の前に、この前提をそろえておきます。仕組みは単純なのに、使っている最中は忘れがちなところです。私も2回忘れました。
動作を確認した環境は、Claude Code 2.1.310とGit 2.50.1(macOS)です。公式ドキュメントの記述は2026年11月5日時点のものです。
isolation: worktreeとは?サブエージェント専用の作業場所
isolation: worktreeとは、サブエージェントを一時的なgit worktreeの中で動かす設定です。公式ドキュメントは「リポジトリの分離されたコピー」と説明しています。
指定する場所は2つあります。
- カスタムサブエージェントの定義ファイル(
.claude/agents/配下)のフロントマターにisolation: worktreeと書く - メインのClaudeがAgentツールで委任するときに、
isolation: "worktree"を付ける
私が事故ったのは2つ目です。「並列で動かすなら隔離しておくか」くらいの軽い気持ちで付けていました。
worktreeは.claude/worktrees/名前/に作られ、ブランチ名はworktree-名前です。サブエージェントが何も変更しなければ、worktreeは自動で消えます。
土台はリモートのmain|baseRefのfreshとhead
新しいworktreeの土台は、設定worktree.baseRefで決まります。既定値は"fresh"です。
worktree.baseRefの2つの値(公式ドキュメントより)
"head"にしたい場合は、設定ファイルに次のように書きます。
{
"worktree": {
"baseRef": "head"
}
}
注意したいのは、既定の"fresh"だとpushしていないコミットすら入らない点です。手元でコミットしただけでは足りません。
引き継がれない3つ:未コミット・未追跡・.env
worktreeは追跡されているファイルだけをチェックアウトします。手元にあっても、次の3つは新しいworktreeに入りません。
- 未コミットの変更:編集中のファイル、取得したばかりの生成物
- 未追跡のファイル:まだ
git addしていない新規ファイル - gitignoreされたファイル:
.envやnode_modules、認証情報のJSONなど
1つ目はbaseRefを"head"にしても入りません。コードの並列開発なら、困るのは3つ目の.envくらいです。ところが、リポジトリの実ファイルを読み書きする作業では、1つ目が致命傷になります。
事故1:リライトの土台が2週間前の本文になった
1件目は、ブログ記事のリライトで起きました。サブエージェントは指示どおり丁寧に働いていたのに、土台にしたファイルが古かったのです。
この事故の怖いところは、エラーが1つも出ない点でした。古いファイルも、ファイルとしては正しく読めてしまいます。
最新の本文を取ってからサブエージェントに任せた
ブログ記事1本のリライトを、自作のリライト用スキルからサブエージェントに任せました。当時のブログはWordPressで、記事の本文をローカルのHTMLに書き出してから編集する流れです。
リライトの前に、WordPressから最新の本文を取り直して、ローカルのHTMLを更新しました。このHTMLはgit管理下にあり、更新はコミット前です。そのままサブエージェントをisolation: worktree付きで起動しました。手順としては、最新を取ってから任せたので、正しく動くに違いないと考えていました。
実際には、サブエージェントが開いたHTMLは、2週間ほど前にコミットした古い版でした。取り直した最新の本文は、本体のフォルダにしかありません。
サブエージェントの報告で食い違いに気づいた
発覚のきっかけは、サブエージェント自身の報告です。編集の途中で「本文の書き方が、取得済みの内容と食い違っている」と返してきました。

取得したのは本体のフォルダ、サブエージェントが開いたのはworktreeのフォルダ。同じパスでも、中身は別物でした。
調べると、worktreeの中のHTMLだけが古いままでした。サブエージェントが違和感を報告してくれなければ、私は気づかなかったはずです。
アップロードが通っていたら本番が巻き戻っていた
実害は出ませんでした。WordPressへのアップロードが、worktree内の環境が足りずにたまたま失敗していたからです。
アップロードが通っていたら、本番の記事が約2週間前の状態に巻き戻っていました。しかも、リライト済みの見た目なので、すぐには気づけません。
worktreeの中にあるのは「少し前の正しいファイル」です。読み込みも編集も成功するので、ログを見ても異常は分かりません。生成物や取得結果をgit管理下に置いているリポジトリほど、ずれに気づきにくくなります。
事故2:保存したはずの下書きが本体に無い
2件目は向きが逆でした。古いファイルを読んだのではなく、新しく書いたファイルが本体に届かなかったのです。
1件目で「読む側」の怖さは学んだつもりでした。ところが、worktreeに「書く側」の落とし穴もあるとは考えていませんでした。
下書きがworktree側のファイルに書かれた
X(旧Twitter)のポスト案を作る自作スキルを、サブエージェントに任せたときの話です。スキルは、できたポスト案をリポジトリ内の下書きファイルに追記して保存します。
ポスト案は保存されていました。ただし保存先は、worktreeの中にある同じ名前のファイルです。本体の下書きファイルは更新されないままでした。
書き込みも本体に戻らない|相対パスの落とし穴
保存用のスクリプトは、リポジトリからの相対パスでファイルを書きます。worktreeの中で動けば、worktreeがリポジトリの根っこになります。
想定していた保存先
本体の下書きファイル
実際の保存先
worktreeの中(.claude/worktrees/名前/ 配下)の同じファイル
worktreeは作業フォルダごと分かれる仕組みです。書いたファイルは、マージかコピーをしない限り本体へ戻りません。コードの変更ならブランチとして残るので後から取り込めますが、スクリプトが追記したファイルは「どこかにある」状態で放置されがちです。
サブエージェントが変更を加えたworktreeは自動では消えません。とはいえ、消える前に本体へ取り込む作業は、人間がやる必要があります。
worktreeを使う作業・使わない作業の分け方
2件の事故から、worktreeに向く作業と向かない作業の境目が見えてきました。境目は「リポジトリの実ファイルそのものが目的かどうか」です。
並列で動かせる便利さは本物なので、全部やめるのはもったいない話です。私は今、作業の性質で使い分けています。
使ってよい:差分を見てから採否を決めるコード変更
worktreeが生きるのは、変更を差分で受け取って、取り込むかどうかを後で決める作業です。
- 新機能の試作や、うまくいくか分からないリファクタリング
- 同じファイルを触らない、複数のバグ修正の並列実行
- 本体を汚したくない実験的な変更
どれも、結果をブランチとして受け取り、レビューしてからマージする流れです。土台が最新のmainでも困りません。
使わない:実ファイルを土台にする・更新する作業
逆に、リポジトリにあるファイルを読み書きすること自体が目的の作業では、worktreeを使いません。私の事故は2件ともこちらでした。
- 直前に取得・生成した未コミットのファイルを読んで編集する(事故1)
- スクリプトがリポジトリ内のファイルへ追記・保存する(事故2)
- 本番へのアップロードやデプロイまで一気に進める
3つ目は特に危険です。古い土台で作ったものが、そのまま本番に出ます。
迷ったときの判断フロー
迷ったら、次の順で確かめます。上から順に答えるだけで、worktreeを使うかどうかが決まります。
flowchart TD
A["サブエージェントに任せる作業"] --> B{"未コミットのファイルを<br>読む必要がある?"}
B -->|"はい"| C{"先にコミットしてよい?"}
C -->|"はい"| D["コミット(必要ならpush)<br>してからworktree"]
C -->|"いいえ"| E["worktreeを使わない"]
B -->|"いいえ"| F{"結果をファイルに<br>保存・追記する?"}
F -->|"はい"| E
F -->|"いいえ"| G{"差分を見てから<br>取り込みたい?"}
G -->|"はい"| H["worktreeを使う"]
G -->|"いいえ"| E
迷ったら使わない側に倒します。worktreeを使わなくても作業は進みますが、古い土台で作った成果物は戻すのに手間がかかります。
git worktreeをClaude Codeで安全に使う4つの手順
worktreeを使うと決めたら、次の4つの手順で事故を防ぎます。手順の1つ目さえ守れば、私の2件の事故は両方とも起きませんでした。
残りの3つは、作業が終わってからの後片付けです。git worktreeの基本的な使い方も、ここでまとめて押さえます。
委任する前にコミットする
step
1必要な変更をコミットする
サブエージェントに読ませたいファイルは、委任の前にコミットします。git statusで未コミットの変更が残っていないかを確かめてから任せます。
step
2既定のfreshならpushまでする
baseRefが既定の"fresh"なら、土台はリモートのmainです。コミットだけでは届かないので、pushまで済ませるか、baseRefを"head"に変えます。
git status
git add -A && git commit -m "リライト前の最新本文"
git push
.worktreeincludeで.envを持ち込む
step
3持ち込むファイルを.worktreeincludeに書く
.envなどのgitignoreされたファイルは、リポジトリの根っこに.worktreeincludeを置けばworktreeへコピーされます。書き方は.gitignoreと同じです。
.env
.env.local
config/secrets.json
コピーされるのは、パターンに一致し、かつgitignoreされているファイルだけです。追跡済みのファイルが二重にコピーされることはありません。未コミットの変更を持ち込む手段ではない点は覚えておきます。
終わったら差分を確かめて本体に取り込む
step
4worktreeの差分を確かめてから取り込む
サブエージェントの作業が終わったら、worktree側に何が残っているかを確かめます。git -Cを使えば、フォルダを移動せずにworktreeの状態を見られます。
git -C .claude/worktrees/名前 status
git -C .claude/worktrees/名前 diff
コミット済みの変更はブランチworktree-名前に残るので、確認してからマージします。未コミットのまま残ったファイルは、次の「戻し方」の手順で取り込みます。
git worktreeの一覧と削除|list・remove・prune
worktreeの後片付けは、次の3つのコマンドで足ります。
git worktreeの後片付けに使うコマンド
git worktree removeは、未コミットの変更が残っていると削除を拒みます。ここで--forceを付ける前に、残っている変更が本体に取り込み済みかを確かめます。仕組みの詳しい話は、次の記事で図解しています。
分岐してしまったときの戻し方
worktreeで作業させてから「本体にない」と気づいた場合でも、worktreeを消す前なら取り戻せます。先にworktreeを消すと、未コミットの変更はそこで失われます。
手順は「見つける」「取り込む」「消す」の順です。この順番を崩さないことが、いちばんの安全策です。
worktree側にだけある変更を見つける
まずgit worktree listで、残っているworktreeを確かめます。続けて、各worktreeのstatusで、未コミットの変更と未追跡のファイルを洗い出します。
git worktree list
git -C .claude/worktrees/名前 status --short
事故2のような追記型のファイルは、本体の同じファイルと見比べます。diffコマンドで、worktree側にだけある行が分かります(ファイル名は比べたいファイルに置き換えます)。
diff ファイル名 .claude/worktrees/名前/ファイル名
本体へ取り込んでからworktreeを消す
見つけた変更は、本体へ取り込んでから削除します。変更の種類によって、取り込み方を変えます。
変更の種類ごとの取り込み方
未コミットの編集をパッチで移す場合は、次のようにします。
git -C .claude/worktrees/名前 diff > /tmp/worktree.patch
git apply /tmp/worktree.patch
git worktree remove .claude/worktrees/名前
追記型のファイルを丸ごと上書きコピーしないよう注意します。本体側にも、その後に追記された行があるかもしれません。
よくある質問
Claude Codeのworktreeとサブエージェントについて、よく聞かれる質問をまとめました。引き継がれるものと後片付けの方法が、質問の中心です。細かい手順は各見出しの本文もあわせて確認してください。
Q1. Claude Codeのworktreeに未コミットの変更は引き継がれますか?
A1. 引き継がれません。worktreeは追跡されているファイルをコミットから取り出して作られます。worktree.baseRefを"head"にしても、入るのは未pushのコミットまでです。
Q2. isolation: worktreeのサブエージェントは、どのブランチから作業を始めますか?
A2. 既定ではリモートのデフォルトブランチ(通常はmain)からです。親セッションのHEADではありません。手元のHEADから始めたい場合はworktree.baseRefを"head"にします。
Q3. .envをworktreeで使うにはどうしますか?
A3. リポジトリの根っこに.worktreeincludeを置き、.envと書きます。書き方は.gitignoreと同じで、パターンに一致し、かつgitignoreされているファイルだけがコピーされます。
Q4. サブエージェントのworktreeは自動で削除されますか?
A4. サブエージェントが何も変更しなかった場合は、自動で削除されます。変更が残っている場合は残るので、差分を確かめて本体へ取り込んでからgit worktree removeで消します。
Q5. git worktreeを削除するコマンドは?
A5. git worktree remove パスです。未コミットの変更があると止まるので、取り込み済みかを確かめてから進めます。フォルダを手で消してしまった場合は、git worktree pruneで管理情報を掃除します。
Q6. worktreeを使わないほうがいいのはどんな作業ですか?
A6. リポジトリの実ファイルを読む・書くこと自体が目的の作業です。直前に取得した未コミットのファイルを編集する作業や、スクリプトがファイルへ追記する作業では、worktreeを使わずに本体のフォルダで動かします。
worktreeに任せる前の3つの確認まとめ
2件の事故は、どちらもworktreeの仕様どおりの動きでした。バグではないので、仕様を知っていれば避けられます。
【worktreeに任せる前の3つの確認】
- 読ませたいファイルはコミット済みか(既定のfreshならpush済みか)
- 作業の結果を、リポジトリ内のファイルへ保存・追記しないか
- 終わったあと、worktreeの差分を確かめて本体へ取り込む段取りがあるか
今の私は、事前の取得や生成をしてから委任する作業では、worktreeを使っていません。記事のリライトも下書きの保存も、本体のフォルダで動かしています。
worktreeは並列で回せる分、ずれた結果も並列で生まれます。便利さとずれのリスクを、作業ごとに天秤にかけるのが今のところの落としどころです。サブエージェントそのものの使い方は、こちらにまとめています。
本体に取り込み忘れた変更が残っていないか、各worktreeの status を見ておくと安心です。
続きを追う:X(@Tom_Java_Tech) / RSS
途中経過は、また書きます。



