Claude Media
agent viewで.claude/worktreesが溜まる原因と掃除の手順

agent viewで.claude/worktreesが溜まる原因と掃除の手順

agent viewでセッションを削除しても.claude/worktrees/にディレクトリが残る原因と、git worktree listに出ない残骸も含めた掃除の手順を示します。

agent viewでセッションを削除しても、プロジェクトの.claude/worktrees/にディレクトリが残ることがあります。原因は、削除の操作によってはworktreeが意図的に残される、あるいはgitが認識しない状態でディスクに置き去りになるためです。

後者はgit worktree listにも出ません。git worktree removeだけでは片付かず、手で消す工程が要ります。worktreeのあるリポジトリで外部Gitクライアントの表示が崩れる場合は、git maintenanceのloose-*パックが原因の報告もあります。

なぜ削除したのに残るのか

agent viewでセッションを削除すると、Claudeがそのセッション用に作ったworktreeは原則として一緒に消えます。ただし「原則として」であり、消えない条件が公式に列挙されています。残骸が生まれる場面は次の6つです。

場面worktreeの扱いセッション行
別のセッションがそのworktreeを使用中、またはロック中worktreeの扱い残る(再度削除しても変わらない)セッション行not deletedと表示
未pushのコミットがあるworktreeの扱い残る(もう一度削除すると破棄)セッション行残る
gitがworktreeを認識しない(git worktree prune後など)worktreeの扱いディレクトリだけディスクに残るセッション行削除される
gitまたはWorktreeRemove hookが削除に失敗worktreeの扱い残る(原因がメッセージに出る)セッション行残る
claude rmで未コミットの変更があるworktreeの扱い残るセッション行残る
自分で作ったworktreeの中でセッションを始めたworktreeの扱いそのまま残るセッション行削除される

3行目が今回の主題です。セッションの行は消えるのに、ディレクトリは.claude/worktrees/に居座ります。git worktree listには載らないので、一覧を見ても存在に気づけません。

agent viewの削除を通らない経路でも、.claude/worktrees/は溜まります。claude -p --worktreeのような非対話実行には終了時の確認がないため、Claudeはそのworktreeを片付けません。作成時にかけたロックも、あとのセッションによるロック掃除で解かれるまで残ります。消すにはgit worktree removeを使い、ロックで拒否されたら先にgit worktree unlockを実行します。作成の起点や通常セッションの片付けはClaude Code Worktree実践ガイドにあります。

agent view自体の仕組みはClaude Codeのagent viewで扱っています。ここでは、削除の後に何が残り、どう片付けるかに絞ります。未pushのコミットが理由でclaude rmが止まる場合は、claude rmがunpushedコミットで止まる理由と、pushか破棄かの選び方が詳しいです。セッションが増えたときの探し方はCtrl+Fとn:フィルタでの名前検索にまとめています。

残骸を見つける — git worktree listと実ディレクトリの突き合わせ

まず、gitが把握しているworktreeを一覧します。プロジェクトのディレクトリで実行します。

git worktree list

出てくるのは、gitに登録済みのworktreeだけです。次に、実際に.claude/worktrees/にあるディレクトリと見比べます。

ls -1 .claude/worktrees/

lsにあってgit worktree listにない名前が、gitの認識から外れた残骸です。数が多いときは、次のように未登録のものだけを拾うと手間が減ります。

for d in .claude/worktrees/*/; do
  p="$(cd "$d" && pwd -P)"
  git worktree list --porcelain | grep -qxF "worktree $p" \
    || echo "未登録: $p"
done

これは公式の手順ではなく、上の突き合わせを自動化した例です。pwd -Pで実パスにそろえるのは、gitがworktreeの行に実パスを出すためです。macOSの/tmpは/private/tmpへのリンクで、git worktree listは/private/tmp/...と表示します。

残骸の実物を見ると、なぜgit worktree removeが効かないかが分かります。検証用リポジトリにaliveとgoneの2つを作り、goneだけgitの管理情報を外した状態で取った出力です。

$ git worktree list
/private/tmp/demo                                b1f4df9 [main]
/private/tmp/demo/.claude/worktrees/alive        b1f4df9 [alive]
$ ls -1 .claude/worktrees/
alive
gone
$ cat .claude/worktrees/gone/.git
gitdir: /private/tmp/demo/.git/worktrees/gone
$ git -C .claude/worktrees/gone status
fatal: not a git repository: /private/tmp/demo/.git/worktrees/gone
$ git worktree remove --force .claude/worktrees/gone
fatal: '.claude/worktrees/gone' is not a working tree

残骸には、消えた管理情報を指す.gitファイルだけが残っています。gitから見れば作業ツリーではないため、--forceを付けても同じエラーになります。git branchにはgoneブランチがそのまま並んでいました。

掃除の手順 — 登録済みと未登録で分ける

登録済みのworktree

git worktree listに出るものは、gitの標準コマンドで消せます。

git worktree remove .claude/worktrees/<name>

未コミットの変更や未追跡ファイルがあるとgitが拒否します。中身を捨ててよいと確認できたときだけ、--forceを付けます。

git worktree remove --force .claude/worktrees/<name>

worktreeがロックされていて拒否されたら、先にgit worktree unlockを実行します。バックグラウンドで動作中のセッションが持つロックは実行中だけ保持されるため、中のセッションが生きていないかを先に確かめてください。

git worktree unlock .claude/worktrees/<name>
git worktree remove .claude/worktrees/<name>

gitが認識しないディレクトリ

git worktree listに出ないディレクトリには、git worktree removeは使えません。公式は「手で消す」としています。消す前に、次の順で見ます。

手順

未登録ディレクトリを消す前の3点

  1. 1

    中身を見る

    まだ必要な未コミットの作業が入っていないかを、ファイルの一覧で調べます。

  2. 2

    使用中かを見る

    実行中のセッションが、そのディレクトリを作業場所にしていないことを確かめます。

  3. 3

    パスを見る

    消す対象が.claude/worktrees/の直下にあることを確かめます。

3点が済んだら、通常のファイル削除で消します。gitやhookがworktreeを消せずに削除を拒否されたセッションは、ディレクトリを消してからもう一度削除すると行も消えます。

rm -rf .claude/worktrees/<name>

rm -rfは取り消せません。未登録の判定を誤ると、登録済みworktreeの中身を消しかねないので、直前の突き合わせを飛ばさないでください。

Windowsでは、もう一つ確かめておく点があります。worktreeの中にNTFSのジャンクションやディレクトリのシンボリックリンクがあると、リンク先のフォルダーは別の場所にある実体です。Claude Codeによる削除はリンクだけを消し、リンク先は残します(v2.1.205より前は、サブディレクトリの中にあるリンクでリンク先まで消えることがありました)。worktreesページの記述は、Claude Codeによる削除についてだけです。消す前にエクスプローラーなどで、中にリンクがないかを確かめてください。

ブランチは別に残る

worktreeを消しても、そのworktreeで作業していたブランチが自動で消えるとは限りません。公式も、claude rm --force-remove-worktreeはディレクトリだけを消し、ブランチはリポジトリに残ると説明しています。不要なブランチはgit branchで確認し、マージ済みかを見てからgit branch -dで削除します。

claude rmが返す拒否メッセージから逆引きする

claude rm <id>はバックグラウンドセッションとそのworktreeを削除するコマンドで、終了済みのセッションにも使えます。拒否されたときは、メッセージの中に次の一手がコマンド付きで出ます。値はメッセージが表示したものをそのまま渡します。v2.1.289のclaude rm --helpは、書式を次のように示します。

claude rm --help
Usage: claude rm <id> [--discard-unpushed <commit>@<worktree-id>] [--force-remove-worktree <worktree-id>]

--force-remove-worktreeの説明には、対象の条件が書かれています。リポジトリがworktreeとして登録していること、または削除に失敗した際に登録から外したことです。前者はgitに残っている場合、後者は削除途中で管理情報だけ消えた場合を指します。

拒否の理由出るコマンド消えるもの必要なバージョン
未pushのコミットがある出るコマンドclaude rm <id> --discard-unpushed消えるものworktree、ブランチ、コミット、未コミットの変更必要なバージョンv2.1.260以降
gitまたはhookがworktreeを消せない出るコマンドclaude rm <id> --force-remove-worktree <worktree-id>消えるものディレクトリだけ(ブランチは残る)必要なバージョンv2.1.268以降

--discard-unpushedは、拒否時に見せたコミットだけを破棄する仕組みです。その後にworktreeへコミットが増えていれば、再びworktreeを残して最新の状態を示します。--force-remove-worktreeは、次の3つを確認できたときにだけ提案されます。

  • .claude/worktrees/配下にある、リポジトリのリンク済みworktreeである
  • worktreeにも、チェックアウト済みのサブモジュールにも、追跡ファイルの未コミット変更がない
  • ほかのセッションの記録が、そのworktreeを指していない

サブモジュールの状態を確認できないとき(別のgitリポジトリに置き換わっているなど)は、この提案も出ません。サブモジュールの確認はv2.1.274以降の挙動です。

条件の1つ目は「リポジトリのリンク済みworktree」なので、WorktreeCreate hookが作ったgit管理外のディレクトリは--force-remove-worktreeの対象外です。agent viewで二度押しして削除すればWorktreeRemove hookが走り、hookがなければ削除は拒否されます。claude rmはセッションとworktreeを残します。いずれも通らなければ手で消します。提案されなければ、変更をコミットまたはstashする、ディレクトリを自分で消してからもう一度削除する、といった方法で対処します。

待てば消えるのか — 定期スイープの対象と限界

Claude Codeには、Claudeがサブエージェントやバックグラウンドセッション向けに作ったworktreeを定期的に掃除する仕組みがあります。cleanupPeriodDaysより古いものが対象で、既定は30日、最小は1です。

くらべる

30日たてば消えるのはどれか

スイープの対象

消える

Claudeがgitで作り、メタデータに印がある。作業が残っておらず、サブモジュールにも変更がない。cleanupPeriodDaysより古い。

待っても減らない

残る

変更・未追跡ファイル・未pushコミットがある。サブモジュールに変更があるか、検査できない。バックグラウンドに移していない--worktreeセッション(経過日数を問わない)。自分でgit worktree addしたもの。hookで作ったもの。

スイープの対象は、Claudeがgitで作った印をメタデータに持つworktreeだけです。gitの管理情報が消えた残骸はこの条件で確かめられないため、待つより手で消すほうが確実です。

保持期間を短くしたい場合は、settings.jsonに書きます。

{
  "cleanupPeriodDays": 7
}

この値はトランスクリプトの保持期間も兼ねます。worktreeを早く消すために値を下げると、古い会話の記録も同じ日数で削除されます。孤立したworktreeの自動削除にも同じ日数が使われますが、残されるworktreeの条件は変わりません。

溜めないための運用

溜まる量を減らすには、削除の前後で次を習慣にします。

手順

削除の前後の習慣

  1. 1

    成果を先にpushする

    agent viewの削除は、コミットしていない変更ごとworktreeを消します。未pushのコミットがあるときは、削除が止まります。

  2. 2

    警告メッセージを読む

    not deletedの行があれば理由を見ます。使用中のロックは、相手のセッションを閉じてから、もう一度削除します。

  3. 3

    週に一度突き合わせる

    git worktree listとls .claude/worktrees/を並べて、未登録の名前がないかを調べます。

worktreeを使いたくないリポジトリでは、worktree.bgIsolationを"none"にする選択肢もあります。バックグラウンドセッションが作業ツリーを直接編集するようになり、worktreeが作られません。並列で同じファイルを触るリスクを引き受ける設定なので、詳しくはworktree.bgIsolationの記事を参照してください。

Claudeに一覧の作成だけを任せる手もあります。CLAUDE.mdやプロンプトに次のように書くと、削除の実行と分けて確認できます。

.claude/worktrees/ の未登録ディレクトリを、git worktree list と突き合わせて
一覧にしてください。削除はせず、各ディレクトリの中身(git status 相当)も
報告してください。

削除そのものは、一覧を見た自分が実行します。rm -rfをClaudeの自動実行に任せると、突き合わせの誤りがそのまま消失につながります。

よくある質問

git worktree pruneを実行すれば解決しますか

git worktree pruneは、gitの管理情報から、ディレクトリがすでに存在しないworktreeの記録を消すコマンドです。ディレクトリ自体は消しません。公式が示すとおり、pruneの後にagent viewでセッションを削除すると、ディレクトリだけが残る典型例になります。

削除したセッションの会話は失われますか

失われません。会話のトランスクリプトは、削除しても保持期間内は手元に残り、claude --resumeから再開できます。agent viewでは/resumeと入力すると、削除したセッションも含む一覧から呼び戻せます(v2.1.212以降)。

worktreeの作成や削除をhookで差し替えている場合は

WorktreeRemove hookが失敗すると、worktreeとセッションが残り、hookの終了状況と標準エラー出力の冒頭がメッセージに出ます。hookの設計はWorktreeCreate/WorktreeRemove hookにまとめています。

この記事を共有:XはてブLinkedIn