Skip to content

feat(list): flag a branch checked out in more than one worktree - #3606

Merged
max-sixty merged 2 commits into
mainfrom
branch-in-status-flag
Jul 26, 2026
Merged

feat(list): flag a branch checked out in more than one worktree#3606
max-sixty merged 2 commits into
mainfrom
branch-in-status-flag

Conversation

@max-sixty

@max-sixty max-sixty commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Problem

Follow-up to #3480. That PR made a duplicated branch checkout (git worktree add --force <path> <branch>) visible at resolution time: worktree_for_branch warns once per branch, then resolves to whichever worktree git lists first. wt list said nothing about it. Two rows named feature, and no column that explains why.

The nearest thing to a signal was accidental. A force-added duplicate usually lands off-template, since the original holds the template path, so it picks up for the location mismatch — while the worktree at the template path, the one wt actually resolves to, carried no flag at all. Exactly backwards from what's useful.

The framing from the request: a worktree in the wrong location gets a status flag; a worktree sharing its branch should get one too.

Solution

now covers both, on every worktree of the duplicated branch, resolved one included. Which worktree wt picks is git's listing order, so singling out the shadowed rows would imply a legitimacy the ordering doesn't carry.

@ main           ^|                                      |     .                    05a4a45d  16h   Initial commit
+ feature       ⚑_                                             ../repo.feature      05a4a45d  16h   Initial commit
+ feature       ⚑_                                             ../repo.feature-dup  05a4a45d  16h   Initial commit

This started as a seventh glyph () and collapsed onto in the second commit. The Status column is a dense alphabet the reader has to learn, and the two states say one thing: this worktree's place in the branch ⇔ worktree map is irregular. Off-template path and branch-claimed-twice are both instances. The table already distinguishes them without a glyph — a repeated Branch cell is the duplicate, an odd Path cell the mismatch — so the flag only has to say "not a rendering glitch, look at the Path column". Sharing the glyph means sharing its dim-yellow styling, since the codebase treats a symbol's color as part of its identity; #3480's warning remains the loud channel, firing the moment any command resolves the branch.

The Path column comes along. It previously appeared only for a location mismatch, on the reasoning that the path is otherwise redundant with the branch. A duplicate inverts that: the branch name no longer identifies the row, and the path is the only thing telling the two apart. The layout flag is renamed from has_branch_worktree_mismatch to path_is_informative to say what it now means.

The data model keeps the distinction. JSON has no cardinality budget, and reporting a duplicate that sits at the template path as branch_worktree_mismatch would be false — its path does match. Schema 1's worktree.state names the cause ("duplicate_branch"), schema 2 gets its own worktree.duplicate_branch bool beside branch_mismatch, matching that schema's one-fact-per-field shape. The priority between the two states now decides only which cause JSON reports.

Detection is one pass over the worktree list (duplicated_branches, next to #3480's worktree_paths_for_branch), in memory, pre-skeleton, no git calls.

Testing

  • test_worktree_paths_for_branch_detects_duplicates gains the set form and a detached-HEAD worktree, which has no branch to duplicate.
  • test_metadata_worktree_state_priority covers the two states' ordering and both yielding to /.
  • test_list_duplicate_branch snapshots the table above, showing both flagged rows and the Path column earning its place.
  • test_list_duplicate_branch_json asserts both schemas flag exactly the two duplicated rows.

The flag only fires on a state no prior test sets up, so the only snapshot churn is the help pages and the schema-2 envelope's new field.

This was written by Claude Code on behalf of max

max-sixty and others added 2 commits July 25, 2026 14:22
`git worktree add --force` can put one branch in two worktrees, and #3480
made the resulting ambiguity visible only at resolution time: a command that
looks the branch up warns once, then picks whichever worktree git lists
first. `wt list` showed nothing, so the two identical `feature` rows read as
a rendering glitch.

Both rows now carry `⧉` in the Status column's worktree-state position,
ranked above the informational `⚑` mismatch flag (a force-added duplicate
usually sits off-template too) and below `⊟`/`⊞`. The Path column, which
previously appeared only for a location mismatch, now also appears for a
duplicate: with the branch name repeated, the path is the only thing telling
the rows apart.

JSON reports it in both schemas: schema 1 as a `worktree.state` value,
schema 2 as its own `worktree.duplicate_branch` flag alongside
`branch_mismatch`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A seventh glyph in the worktree-state position bought little: the Status
column is a dense alphabet the reader has to learn, and a duplicated branch
is rare. Both states say one thing — this worktree's place in the branch ⇔
worktree map is irregular — and the table already tells them apart, since a
repeated Branch cell is the duplicate and an odd Path cell the mismatch.

`⚑` now covers both, at its existing dim-yellow styling (a symbol's color is
part of its identity, so sharing the glyph means sharing the color). The
worktree-state alphabet is back to six.

The data model keeps the distinction: JSON has no cardinality budget, and
reporting a duplicate sitting at the template path as
`branch_worktree_mismatch` would be false — its path does match. Schema 1's
`worktree.state` still names the cause, schema 2 keeps its own
`duplicate_branch` bool, and the priority between the two ⚑ states now
decides only which cause JSON reports.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@max-sixty
max-sixty marked this pull request as ready for review July 26, 2026 12:23
@max-sixty
max-sixty merged commit 04d8d58 into main Jul 26, 2026
40 checks passed
@max-sixty
max-sixty deleted the branch-in-status-flag branch July 26, 2026 14:16
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.

2 participants