Skip to content

Merged-worktree cleanup skips worktrees whose branch was renamed #16559

Description

@elmarbeckmann

Summary

The "Delete merged worktrees" cleanup rule never removes a worktree when the thread's branch is renamed after T3 Code creates it. A common case is an agent that renames the generated t3code/... branch to a ticket branch name before it opens the PR.

Steps to reproduce

  1. Turn on Settings → Storage cleanup → Delete merged worktrees.
  2. Start a thread in a new worktree. T3 Code creates a branch such as t3code/revert-login-screen.
  3. In the worktree, rename the branch, for example git branch -m feature/ABC-123-remove-login-theme.
  4. Open a PR from the renamed branch and merge it into the default branch.
  5. Leave the thread idle and wait for the storage cleanup sweep.

Expected result

The cleanup sweep removes the worktree, because its PR is merged and its commits are in the default branch.

Actual result

The worktree stays. StorageCleanup.cleanWorktrees runs and exits with success, but it removes nothing.

Cause

The thread projection keeps the original branch name (thread.branch = "t3code/revert-login-screen"). It does not update after the rename. cleanWorktrees then exits early on this check:

const status = yield* git.statusDetailsLocal(worktreePath);
if (!status.isRepo || status.branch !== thread.branch || status.hasWorkingTreeChanges) return;

The same mismatch also makes gitManager.branchPullRequest look up the PR for the old branch name. That lookup cannot find the merged PR either.

Suggested fix

Update thread.branch when the branch checked out in the thread's worktree changes. Or, in cleanup, use the branch that is checked out in the worktree when it differs from the recorded branch.

Environment

  • T3 Code 0.0.46-nightly.20261005.2702
  • macOS

Activity

  1. juliusmarminge commented on Oct 6, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Confirmed. Delete merged worktrees skips a worktree when its branch is renamed after T3 records it. The sweep finishes successfully and removes nothing.

    thread.branch is written when the worktree is created and when T3 renames its own temporary branch. A later git branch -m in the worktree updates HEAD, and local status reports that new name (symbolic-ref --short HEAD). Cleanup bails out first:

    const status = yield* git.statusDetailsLocal(worktreePath);
    if (!status.isRepo || status.branch !== thread.branch || status.hasWorkingTreeChanges)
      return;

    The same check runs again on the final status. The merged-PR lookup also uses the recorded name (gitManager.branchPullRequest({ branch: thread.branch })), so it looks for refs/heads/<old> and refs/remotes/<remote>/<old>, neither of which exists after the rename.

    V2 never adopts the checkout. After a turn, RunFinalizationObserver refreshes status and returns when thread.branch !== local.refName instead of updating the thread. The client helper that would sync a drifted branch (resolveLiveThreadBranchUpdate) is skipped for server threads. That follow behavior used to live in V1 CheckpointReactor (#5159); it was not ported.

    The equality check should stay. It is what prevents cleanup from deleting a worktree that was switched onto a different, already-merged branch. The fix is to adopt the checked-out branch when the worktree belongs to exactly one thread, then let the existing guard and PR lookup run against that name.

    Not the same as #14742 / #14847 (squash merges; that PR still keys the PR read on thread.branch) or #15146 / #15208 (settled-thread eligibility). #4831 was the PR-badge symptom of this stale branch name.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions