Skip to content

feat(branch): reopen or refuse a branch name that already has a worktree - #178

Merged
baldurpan merged 3 commits into
mainfrom
feature/121-branch-reopen-existing-worktree
Oct 28, 2026
Merged

baldurpan merged 3 commits into
mainfrom
feature/121-branch-reopen-existing-worktree

Conversation

@baldurpan

Copy link
Copy Markdown
Contributor

Closes #121

Running worktree branch a second time for a name that already has a worktree used to fail inside git with a bare fatal: a branch named ... already exists, after the assign prompt had already run. The check now runs once the final name is known, before assignment, source resolution and creation.

  • Phase 1 — gitFindBranchCheckout finds the worktree a branch name is checked out in, from git worktree list --porcelain.
  • Phase 2 — branch reopens (interactive, after a confirm) or refuses (InvalidValueError, exit 2, invalid_value) for the four collision cases; docs, skill and context7.json updated.
  • No new error code; BranchDocument is unchanged.

Release note: minor, .changeset/branch-reopen-existing-worktree.md. Waiting on the release PR to ship.

Plan and ledger: #121. Owner check for the prompt on a real terminal: #177.

…121)

Add gitFindBranchCheckout, which reads `git worktree list --porcelain`
through parseWorktreeRecords and reports, for an exact branch-name match,
the path, whether the directory still exists, whether it sits under
<root>.worktrees/, and whether it is the current worktree. gitGetWorktrees
is unchanged.

Phase 1 of #121. Gate 1: pnpm check, pnpm typecheck, pnpm --filter docs
typecheck, pnpm build, pnpm test (1357 passed), pnpm docs:test (69 passed)
and the test-markers check all exit 0. Gate 2 (reviewer subagent): PASS
WITH NOTES after one loopback (type alias -> interface).
…ree (#121)

Before assignment, source resolution and creation, `branch` now looks the
final branch name up in `git worktree list --porcelain`:

- A worktree under <root>.worktrees/: on a terminal, ask and open it
  with the run's own open/agent/brief options (declining exits 1). A
  non-interactive run refuses with invalid_value (exit 2), naming the
  path and `worktree open <branch>`.
- The branch is checked out outside the worktrees directory, has a stale
  worktree record, or exists with no worktree: refuse with invalid_value
  in both modes, naming the path or the command to run.

Git's raw `fatal: a branch named ... already exists` no longer reaches
the user for these cases. The --json document and the error-code set are
unchanged. The docs page, the worktree skill and context7.json are updated.

Phase 2 of #121. Gate 1: pnpm check, pnpm typecheck, pnpm --filter docs
typecheck, pnpm build, pnpm test (1370 passed), pnpm docs:test (69 passed)
and the test-markers check all exit 0. Plan §8.1 was run against real git
with the built CLI: cases A-D exit 2 with no `fatal:`, and a fresh name
still creates its worktree. Gate 2 (reviewer subagent): PASS WITH NOTES
after one loopback, which pinned the lookup order and the edited-name check
in tests.
@baldurpan baldurpan mentioned this pull request Oct 28, 2026

@craig-o-curtis craig-o-curtis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving. I read the diff with CI green and did not rerun gates. The four collision states line up with the plan (D1–D4, D6). The check sits after the final name and before assignment, source and creation, and the tests cover each state plus the edited-name and --github orderings. This branch merges cleanly with #180, and #180's Jira tests stay safe under the new top-level gitFindBranchCheckout / gitGetLocalBranches defaults.

Non-blocking notes:

  1. The prompt doesn't mention the brief. src/commands/branch.ts:366: with --agent / --agent-file / --agent-stdin, a "y" to Open it instead? also starts an agent and delivers the brief in a tree that may already have one running. That is the exact risk D2 gives for refusing to open unasked. Consider saying so in the prompt when a brief is present (e.g. Open it and hand it the brief?). Or warn when hasLiveAgent is true for that tree.
  2. isCurrent is never read. src/lib/git.ts:334: gitFindBranchCheckout computes it (an extra git branch --show-current per run), but nothing in branch.ts uses it. Drop it, or keep it on purpose for a later caller.
  3. Misleading output line. A reopen with opener: none or --no-open prints Worktree created at <path> even though nothing was created. worktree open already does the same, so this is cosmetic and could be a follow-up.

@baldurpan
baldurpan merged commit 931cbf7 into main Oct 28, 2026
2 checks passed
@baldurpan
baldurpan deleted the feature/121-branch-reopen-existing-worktree branch October 28, 2026 15:25
craig-o-curtis added a commit that referenced this pull request Oct 28, 2026
Merging main brought in `run(): Promise<BranchDocument | undefined>` from
#178, and the Jira assign tests still read the result as a plain
`BranchDocument`, so `pnpm typecheck` failed with TS18048 and TS2769.
They now use `document?.`, as the other provider tests do, and the
`--json` keys test reads `Object.keys(document ?? {})`, so an undefined
result still fails it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

branch-reopen-existing-worktree

2 participants