claude-code - 💡(How to fix) Fix claude --worktree <existing-name> does not register worktree as session-managed; /exit → remove reports false success

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Two related bugs in the worktree lifecycle:

  1. claude --worktree <existing-name> (and claude --worktree <name> --resume <id>) does NOT register the worktree as session-managed. The session JSON at ~/.claude/sessions/<pid>.json is missing the worktree field that ExitWorktree's scope check requires.
  2. /exit → remove prints "Worktree removed. Uncommitted changes were discarded." even when the worktree is NOT actually removed. The success message is reported without verifying git worktree remove ran or succeeded.

Error Message

  1. The /exit → remove UI should verify git worktree remove succeeded before printing "Worktree removed." Print the actual error otherwise.

Root Cause

Teams using claude --worktree as the canonical entry point for isolated dev environments (per-branch Supabase + Doppler bindings, etc.) rely on /exit → remove to trigger cleanup. Today the success message gives false confidence that cleanup happened — operators don't realize they need to manually git worktree remove until they find stale entries piling up in git worktree list.

In my own checkout I have 8 prunable worktree entries that accumulated this way, plus the active worktree that just "remove"d but is still there.

Fix Action

Workaround

None on the user side. The session-state plumbing is in-memory and not influenceable via documented hook surface area (I verified this empirically — injecting worktree: {...} into ~/.claude/sessions/<pid>.json via a SessionStart hook had no effect).

Code Example

cd <main-repo>
   claude --worktree my-feature
   # WorktreeCreate hook fires, worktree created at .claude/worktrees/my-feature

---

cd <main-repo>
   claude --worktree my-feature --resume <prior-session-id>

---

{
     "pid": 45938,
     "sessionId": "2355cf12-c52f-4422-9b40-98eb9552b990",
     "cwd": "/Users/.../worktrees/up-skill",
     "startedAt": 1778600722769,
     "version": "2.1.139",
     "entrypoint": "cli",
     "kind": "interactive"
     // NO `worktree` field
   }
RAW_BUFFERClick to expand / collapse

Summary

Two related bugs in the worktree lifecycle:

  1. claude --worktree <existing-name> (and claude --worktree <name> --resume <id>) does NOT register the worktree as session-managed. The session JSON at ~/.claude/sessions/<pid>.json is missing the worktree field that ExitWorktree's scope check requires.
  2. /exit → remove prints "Worktree removed. Uncommitted changes were discarded." even when the worktree is NOT actually removed. The success message is reported without verifying git worktree remove ran or succeeded.

Environment

  • Claude Code version: 2.1.139
  • Platform: macOS (Darwin 25.4.0)
  • Shell: zsh

Reproduction

  1. Create a worktree via the documented hook path:
    cd <main-repo>
    claude --worktree my-feature
    # WorktreeCreate hook fires, worktree created at .claude/worktrees/my-feature
  2. Exit the session (/exit → keep) or just close the terminal.
  3. Re-launch into the existing worktree:
    cd <main-repo>
    claude --worktree my-feature --resume <prior-session-id>
  4. In the new session, run /exit and select remove.

Expected

  • Per docs, interactive --worktree sessions should support cleanup via the exit prompt.
  • "Worktree removed" should mean the worktree IS removed (git worktree list no longer shows it, directory deleted).

Actual

  • Message printed: "Worktree removed. Uncommitted changes were discarded."

  • git worktree list still shows the worktree.

  • The directory still exists on disk.

  • Session JSON shows no worktree field:

    {
      "pid": 45938,
      "sessionId": "2355cf12-c52f-4422-9b40-98eb9552b990",
      "cwd": "/Users/.../worktrees/up-skill",
      "startedAt": 1778600722769,
      "version": "2.1.139",
      "entrypoint": "cli",
      "kind": "interactive"
      // NO `worktree` field
    }

    (Compare to a session opened via EnterWorktree in-session, which presumably does have the worktree field — though I can't verify that path because EnterWorktree's scope correctly excludes pre-existing worktrees.)

Why this matters

Teams using claude --worktree as the canonical entry point for isolated dev environments (per-branch Supabase + Doppler bindings, etc.) rely on /exit → remove to trigger cleanup. Today the success message gives false confidence that cleanup happened — operators don't realize they need to manually git worktree remove until they find stale entries piling up in git worktree list.

In my own checkout I have 8 prunable worktree entries that accumulated this way, plus the active worktree that just "remove"d but is still there.

Related

  • #36205 — EnterWorktree ignores WorktreeCreate/WorktreeRemove hooks (open, unfixed)
  • #31969 — Enter/resume existing worktrees

Suggested fixes

  1. When --worktree <name> matches an existing worktree, register it on the session object (same in-memory state that EnterWorktree populates) so ExitWorktree's scope check accepts it.
  2. The /exit → remove UI should verify git worktree remove succeeded before printing "Worktree removed." Print the actual error otherwise.
  3. (Bonus) Document or add a hook output / SessionStart field that lets project hooks register a worktree as session-managed — useful for teams that bootstrap worktrees through their own scripts.

Workaround

None on the user side. The session-state plumbing is in-memory and not influenceable via documented hook surface area (I verified this empirically — injecting worktree: {...} into ~/.claude/sessions/<pid>.json via a SessionStart hook had no effect).

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING