Skip to content

wt switch --create: detect/clean up orphan branch after a partial git worktree add failure #4108

Closed

Description

@technicalpickles

What happened

wt switch --create <branch> ran in an environment where a sandboxing layer blocks a handful of specific file writes (unrelated to worktrunk itself). The underlying git worktree add -b <branch> failed partway through populating the new worktree -- after the branch ref had already been created, before the worktree was usable:

fatal: Could not reset index file to revision 'HEAD'.
✗ Failed to create worktree for <branch> from base main

Retrying wt switch --create <branch> again then failed differently:

✗ Branch <branch> already exists
↳ To switch to the existing branch, run without --create: wt switch <branch>

Which is the actual fix, and it worked. So this isn't a "stuck" bug -- the tool already tells you the way out.

Suggestion

When git worktree add -b <branch> fails after the branch ref was created but before the worktree is usable, could wt switch --create detect that state and either:

  • clean up the orphan branch automatically before reporting the original failure, so a retry with --create just works, or
  • fall through to the no-create path itself when it detects the branch already exists in this specific "just created it in this same command" case

Either would remove the need to notice the second error is fallout from the first rather than a new conflict. Happy to provide more repro detail (this came up in an unusual sandboxed environment, so a from-scratch repro may need something less exotic to trigger the underlying git worktree add partial failure -- e.g. a read-only file that collides with something the checkout needs to write).

wt version: v0.76.0

Activity

  1. worktrunk-bot commented on Sep 14, 2026

    @worktrunk-bot
    Collaborator

    Reproduced, and #4109 has a fix — though not either of the two you proposed, for reasons worth putting on the record.

    The leftover doesn't need a sandbox. git worktree add -b writes the branch ref before it populates the worktree and unwinds only what it registered, so any failure in between strands the branch. A regular file where the worktree's leading directories would go is enough:

    $ git worktree add -b feat ../blocker/sub master
    Preparing worktree (new branch 'feat')
    fatal: could not create leading directories of '../blocker/sub/.git': Not a directory
    $ git branch
      feat
    * master
    

    Deleting the ref is the rollback #3984 removed: its did-we-create-it reasoning was wrong once and force-deleted a branch wt hadn't created, taking commits only that branch held. Falling through to the no-create path would make --create silently adopt an existing branch, which hides the real name collision the error exists for. What was actually missing is that the first failure said nothing about the branch, so the second error had to be decoded rather than read. #4109 names it there instead:

    ✗ Failed to create worktree for feature/auth from base main
     ┃ fatal: could not create leading directories
    ↳ Branch feature/auth was created before the failure, with no worktree; to delete it, run git branch -d -- feature/auth; to use it, run wt switch feature/auth
    

    That's a read-only check on the error path — nothing gets deleted, and both recoveries are one paste away. The regression test drives the whole path through wt rather than asserting the rendered string, and it fails with your original message verbatim when the detection is switched off. It still needs maintainer review before it lands.

    If the underlying git worktree add failure in your sandbox is itself worth chasing, wt -vv switch --create <branch> writes a diagnostic bundle with a trace.log of every git call and its output; the command prints the bundle's path and a ready-to-run gh gist create --web line.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions