Claude Media
claude rmがunpushedコミットで止まる理由と、pushか破棄かの選び方

claude rmがunpushedコミットで止まる理由と、pushか破棄かの選び方

バックグラウンドセッションをclaude rmで消そうとしてworktreeが残るとき、止めている未pushのコミットの扱いと、pushして再実行するか--discard-unpushedで破棄するかの判断を示します。

claude rmでバックグラウンドセッションを消そうとすると、keptと表示されてセッションの行もworktreeも残ることがあります。理由が「リモートのどこにもないコミットがある」なら、Claude Codeがコミットを失わないように止めている状態で、故障ではありません。

先に結論です。コミットを残したいならworktreeのブランチをpushして、もう一度claude rmを実行します。捨ててよいなら、メッセージに印字された--discard-unpushed付きのコマンドをそのまま実行します。

表示されるメッセージの読み方

エラーリファレンスにある表示例は次の形です。IDやコミットの値は、実行のたびに違うものが印字されます。

kept 7c5dcf5d — its worktree is still at “/home/you/project/.claude/worktrees/fix-login”
  2 unpushed commits on “claude/fix-login”: a1b2c3d “Fix login flow” and 1 more. They exist on no remote, so deleting the worktree would lose them.
  push them and run 'claude rm 7c5dcf5d' again, or discard the worktree and its commits: claude rm 7c5dcf5d --discard-unpushed a1b2c3d000000000000000000000000000000000@0123456789abcdef0123456789abcdef

読むべき箇所は3つです。

  • 1行目のkept <id>は、セッションの行とworktreeを両方残したという宣言です。
  • 2行目は、対象のブランチと未pushのコミット数です。先頭のコミットだけ要約され、残りは「and 1 more」のように数だけが出ます。
  • 3行目は次の一手です。pushして再実行するか、--discard-unpushed付きのコマンドで破棄するかの2択になります。

コミットの要約を作れなかったときは、詳細行がThe worktree has unpushed commitsという一文に変わります。agent viewでは、セッションの行にnot deletedと出て、理由は同じです。

どのコミットが「未push」と数えられるのか

数えられ方は、思ったより細かく決まっています。

コミットの置き場所削除をブロックするか
リモートにある削除をブロックするかしない
originの既定ブランチのローカルコピーにあり、そのブランチをメインのチェックアウトで開いている削除をブロックするかしない
上記のどちらでもない削除をブロックするかする

2行目の条件には注意点があります。メインのチェックアウトとは、リポジトリのディレクトリそのものを指し、worktreeではありません。別のworktreeで既定ブランチを開いていても、この例外には当たりません。

つまり、ブランチをローカルの既定ブランチへマージ済みでも、メインのチェックアウトでそのブランチを開いていなければ止まります。

残すなら: pushかマージをして、もう一度消す

コミットを残したいときの手順です。まず、メッセージに出ていたworktreeのパスへ移ってブランチをpushします。

cd /home/you/project/.claude/worktrees/fix-login
git push -u origin claude/fix-login

pushが済めば、コミットはリモートにあるので削除の妨げになりません。セッションのIDで再実行します。IDを忘れたときは、claude agents --jsonで一覧を出して探せます。各セッションのIDは、~/.claude/jobs/の下にあるディレクトリ名と同じです。

claude rm 7c5dcf5d

pushの代わりに、そのコミットを既定ブランチへマージする手もあります。マージ先はメインのチェックアウトで開いている既定ブランチです。上の表の2行目の例外に当たるので、これでも通ります。

agent viewから消すなら、該当の行でCtrl+Xを2回押します。1回目は停止、2秒以内の2回目が削除です。

捨てるなら: --discard-unpushedで破棄する

コミットが不要なら、メッセージが印字したコマンドをそのまま実行します。

claude rm 7c5dcf5d --discard-unpushed \
  a1b2c3d000000000000000000000000000000000@0123456789abcdef0123456789abcdef

@の左はコミット、右はworktreeのIDです。手で組み立てず、拒否されたときの出力をコピーします。引数の値は、拒否のときに見せた状態と対応しているためです。

agent viewなら、同じ行でもう一度Ctrl+Xを2回押す操作が、破棄に当たります。

破棄で消えるもの、消えないもの

くらべる

--discard-unpushedの影響範囲

戻せない

消える

セッションの行、worktree、worktreeのブランチ、未pushのコミット、未コミットの変更。

手元に残る

残る

会話のトランスクリプト。claude --resumeから開き直せます。

消えるコミットはリモートにないので、後から取り戻す前提の仕組みがありません。ここは取り消せない操作です。実行前に、worktreeでgit logを見てコミットの中身を確かめてから決める進め方が安全です。

破棄の前に、消えるコミットを自分の目で見る

メッセージの要約は先頭の1件だけです。残りの中身は、worktreeに入ってgit logで確かめられます。リモート追跡ブランチと比べると、pushされていない分だけが出ます。

cd /home/you/project/.claude/worktrees/fix-login
git log --oneline --not --remotes

--not --remotesは「どのリモート追跡ブランチからも届かないコミット」に絞る指定です。出力がメッセージの件数と合っていれば、破棄で失うものはその一覧だけだと分かります。必要な行が混じっていたら、破棄せずpushに切り替えます。

差分の中身まで見たいときは、git diffで既定ブランチとの違いを確かめます。ただし、ここで出る内容はコミット済みの分に限られ、未コミットの変更はgit statusで別に見ます。破棄は両方をまとめて消します。

拒否の後でコミットが増えた場合

破棄で消えるのは、拒否のときに見せられた状態だけです。拒否から再実行までの間にworktreeへコミットが増えていたら、Claude Codeは再び残し、更新後の状態を表示します。見ないまま消してしまう事故を防ぐ作りです。

破棄しても消えないケースがある

別の完了済みセッションの記録が同じworktreeを指している場合は、再実行しても破棄されません。メッセージにその旨が出るので、先にコミットをpushしてからもう一度削除します。

ほかにも、keptで止まる理由は未pushのコミットだけではありません。見分けるには、メッセージが何と言っているかを読みます。

切り分け

kept と出たときの切り分け

  1. Qメッセージは未pushのコミットに触れているか?
    答えが次の問いへ

    このページの手順です。pushして再実行するか、--discard-unpushedを使います。

    答えがはい
  2. Q別の実行中セッションがそのworktreeを使っている、またはロックしているか?
    答えが次の問いへ

    再実行しても結果は変わりません。もう一方のセッションを閉じてから削除します。

    答えがはい
  3. QgitまたはWorktreeRemove hookが削除に失敗したと書かれているか?
    答えが次の問いへ

    原因が文面に出ています。条件を満たすときは--force-remove-worktreeが案内されます。

    答えがはい

未コミットの変更が理由

claude rmは未コミットの変更があるworktreeを残します。コミットするか、スタッシュしてから再実行します。

未コミットの変更は、経路で扱いが分かれます。agent viewで消すとworktreeごと未コミットの変更も消え、claude rmは残します。残したい変更があるときは、先にコミットします。溜まったworktreeを片付ける手順はagent viewで.claude/worktreesが溜まる原因と掃除の手順にまとめています。

使っているバージョンで挙動が違う

この拒否は、バージョンごとに表示と選択肢が変わってきました。

あゆみ

未pushのコミットで止まる挙動の変遷

  1. v2.1.248既定ブランチのローカルコピーを数えるようになった

    メインのチェックアウトで既定ブランチを開いていれば、そこへマージ済みのコミットは止まりません。それ以前は、リモートに届くまで拒否されました。

  2. v2.1.260ブランチ名とコミット数を表示し、破棄できるようになった

    それ以前のメッセージはworktree has commits that are not pushed anywhereの一文だけでした。再実行しても同じ拒否が返ります。

  3. v2.1.268コミットの要約が詳細行に移った

    それ以前は、要約がkeptの行に入っていました。要約できないときは、keptの行が前述の一文になっていました。

--discard-unpushedの対応バージョンはv2.1.260以降です。それ以前のバージョンでは、worktreeを自分でgit worktree remove --force <path>で消してから、claude rm <id>を再度実行する手順になります。まずclaude --versionで確認します。

起こさないための指示の置き方

バックグラウンドセッションは、あなたが画面を見ていない間にコミットを積みます。pushまで任せておけば、削除の段階で止まりません。例として、依頼文の中でpushまで指定する方法があります。

claude --bg "ログイン処理のバグを直して。完了したらブランチをoriginにpushして"

pushする運用を常に揃えたいなら、CLAUDE.mdに規約として書く手もあります。

## ブランチの扱い
- バックグラウンドで作業を終えたら、worktreeのブランチを必ずoriginへpushする
- pushできない事情があれば、作業を終える前に報告する

これは一例で、pushの権限がない環境では指示に従えません。権限の設定は、運用側で合わせてください。

セッションとworktreeの結びつき自体は、Claude Codeのagent viewとClaude Code Worktree実践ガイドにあります。

まとめ

kept ... unpushedは、Claude Codeがコミットの消失を避けて止めた状態です。残すならpush(またはメインのチェックアウトの既定ブランチへマージ)してから再実行し、捨てるなら拒否時に印字された--discard-unpushed付きのコマンドを使います。破棄の前にgit logで中身を見るのが安全な手順です。

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