Skip to content

fix(n): delete real branch on env destroy for slash-named worktrees#170

Open
jason10lee wants to merge 3 commits into
mainfrom
fix/n-env-destroy-branch-cleanup
Open

fix(n): delete real branch on env destroy for slash-named worktrees#170
jason10lee wants to merge 3 commits into
mainfrom
fix/n-env-destroy-branch-cleanup

Conversation

@jason10lee
Copy link
Copy Markdown
Contributor

@jason10lee jason10lee commented May 30, 2026

All Submissions:

Changes proposed in this Pull Request:

Completes the deferred follow-up noted in #152: n env destroy now removes the local git branch for slash-named monorepo worktrees, not just the worktree directory.

  • Previously the mount-derived safe form (feat-foo) was passed to worktree.sh remove, whose final git branch -D feat-foo no-op'd against the real feat/foo ref — leaving branches dangling across create/destroy cycles.
  • The destroy loop now resolves the real branch via the existing resolve_unsanitized_branch helper (the same one n env list already uses for display) and passes it to worktree.sh remove only when the directory → branch mapping is unambiguous: the live branch must sanitize back to the bound directory and be the only local branch that does. Any retargeted or ambiguous case falls back to the safe form, which still removes the bound directory (the real ref may then orphan — strictly better than deleting the wrong branch).
  • No worktree.sh change: it already re-sanitizes the branch arg for the directory path while deleting the ref by the raw name, so passing the real branch fixes deletion without affecting directory resolution.

A note on sanitize collisions

Branch sanitization (tr '/' '-') is many-to-one: feat/foo-bar and feat-foo/bar both map to the directory feat-foo-bar. Resolving the branch from live git state (rather than persisted metadata) means a worktree retargeted via git checkout to a colliding branch could otherwise hand the wrong ref to git branch -D and force-delete it. The "exactly one local branch maps to this directory" guard closes that hole: on a collision there are ≥2 matches, so destroy falls back to the safe form and deletes nothing by the real path (no wrong-branch deletion; the refs simply orphan). The fully robust fix — persisting the original branch at env-creation time so retargeting is irrelevant — lands with the metadata approach in #154; this PR is the lighter interim that is safe in every case.

How to test the changes in this Pull Request:

  1. n env create orphan-test --worktree newspack-plugin:fix/some-slash-branch --up
  2. n env destroy orphan-test
  3. git branch --list 'fix/some-slash-branch' → empty (previously the branch survived as a dangling ref).
  4. Retarget case: create an env, git checkout a different (non-colliding) branch inside the worktree dir, then destroy — the bound directory is still removed; the real branch is left untouched (falls back to safe form).
  5. Collision case: with two local branches that sanitize to the same directory name (e.g. feat/foo-bar and feat-foo/bar), destroy falls back to the safe form and deletes neither by the real path — the directory is still removed and no wrong branch is force-deleted.

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable? — n and bin/env.sh have no automated test suite; verified via worktree.sh add/remove cycles (safe-form removal reproduces the orphan; real-form removal via the guard clears the branch) plus guard-decision checks for the common (one match → delete) and collision (two matches → safe fallback, nothing deleted) cases.
  • Have you successfully run tests with your changes locally?

@jason10lee jason10lee self-assigned this May 30, 2026
@jason10lee jason10lee marked this pull request as ready for review May 31, 2026 00:42
@jason10lee jason10lee requested a review from a team as a code owner May 31, 2026 00:42
@jason10lee jason10lee requested a review from Copilot June 2, 2026 01:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants