Skip to content

Improve UI for branches and worktrees distinction - #24

Closed
max-sixty wants to merge 8 commits into
mainfrom
claude/clarify-branches-worktrees-ui-018Za1BmVQXN7ubpgQAc6Gsu
Closed

max-sixty wants to merge 8 commits into
mainfrom
claude/clarify-branches-worktrees-ui-018Za1BmVQXN7ubpgQAc6Gsu

Conversation

@max-sixty

Copy link
Copy Markdown
Owner

Introduces a type indicator column following git branch conventions:

  • @ for current worktree
  • ^ for primary/main worktree
    • for other worktrees
  • (space) for branches without worktrees

This makes it immediately clear which items are worktrees vs. branches when using wt list --branches, addressing UX clarity in mixed listings.

Implementation:

  • Added ColumnKind::Gutter as the first column (priority 0)
  • Fixed width of 2 characters (symbol + space)
  • Updated all snapshot tests to reflect new column
  • Gutter symbols determined by worktree status hierarchy

claude and others added 8 commits November 21, 2025 06:00
Introduces a type indicator column following git branch conventions:
- @ for current worktree
- ^ for primary/main worktree
- + for other worktrees
- (space) for branches without worktrees

This makes it immediately clear which items are worktrees vs. branches
when using `wt list --branches`, addressing UX clarity in mixed listings.

Implementation:
- Added ColumnKind::Gutter as the first column (priority 0)
- Fixed width of 2 characters (symbol + space)
- Updated all snapshot tests to reflect new column
- Gutter symbols determined by worktree status hierarchy
The list tests were using a separate snapshot settings function that
didn't include the environment variable redactions. This caused
WORKTRUNK_CONFIG_PATH and other temp paths to leak into snapshots.

Added the same redactions used in setup_snapshot_settings() to
list_snapshots::base_settings() to ensure consistent path redaction
across all test types.
…mVQXN7ubpgQAc6Gsu

Resolved snapshot conflicts by accepting our version (with gutter column).
Updated all snapshots to reflect the new gutter column that
distinguishes worktrees from branches using @ ^ + symbols.

All tests now passing (370 passed, 2 ignored).
The test existed but its snapshot was never committed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Two fixes:
1. Remove 2-space gap after gutter column - gutter content already
   includes spacing (symbol + 1 space = 2 chars total)
2. Fix test filter to use [TEST_CONFIG] instead of [TEST_TEMP]/...
   to match existing snapshot expectations

Updated all list snapshots to reflect the tighter gutter spacing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The main worktree is now correctly identified as the worktree on the
default branch (main/master), not simply the first worktree in the list.
This fixes bare repos where git returns worktrees in alphabetical order.

Also renames is_primary → is_main and primary → main_worktree throughout
for clarity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@max-sixty max-sixty closed this Nov 21, 2025
@max-sixty
max-sixty deleted the claude/clarify-branches-worktrees-ui-018Za1BmVQXN7ubpgQAc6Gsu branch November 21, 2025 08:26
max-sixty added a commit that referenced this pull request Sep 7, 2026
Seven fixes to `wt list` — three to how the table lays out, one to what
detached and prunable worktrees show, and three to the page that
documents it.

**The table**

A single 58-character branch name sized the Branch column for every row:
at 60 columns the table degenerated into a branch list with nine columns
hidden, and at 200 it still lost Message. Branch now sizes to
`min(longest, 32)` and elides with `…`, the way Message already does.
`--format=json` still carries the whole name.

`Remote⇅` in a repo with no remote held its blank seven columns open
while Message, Commit, Age and Path — each with something to say on
every row — were dropped for want of them. The empty-column penalty now
exceeds every base priority, and the allocation loop stops admitting
empty columns once a populated one has failed to fit. `Remote⇅` also
learns it is empty before any task reports: a repo with no remote has no
branch that can track one, read O(1) off the bulk config map.

Alignment now follows the value type consistently: text and reference
columns align left; the scalar `Age` column and its header align right;
split diff fields use two right-aligned halves with centered headers and
centered whole-field states such as loading or in-sync markers. Rows no
longer carry trailing padding, and the hidden-column footer wraps at the
terminal width. The progressive renderer documents and asserts the
corresponding terminal invariant: ordinary rows and the loading footer
occupy one physical row, while only the final summary may wrap.

The familiar `main↕` and `main…±` labels remain fixed across
repositories. This avoids adding default-branch-name plumbing or a `^`
fallback without changing the meaning of either column.

**Detached and prunable rows**

A detached worktree rendered as a bare hash under Branch, wearing `⚑` on
loan from `branch_worktree_mismatch` — which it was only flagged with
because a worktree with no branch has no branch-implied path to sit at.
It gets `⊘`, and stops claiming to be off-template, so `⚑` again means
only what it says. A prunable worktree showed four `·` loading glyphs
that never resolved: its directory is gone, so no task is ever spawned
for it and no cell is coming. Those cells render blank, leaving `⊟` in
Status as the row's whole story.

**The page**

<details>
<summary>Documentation corrections</summary>

- The summary footer counted hidden columns ("3 columns hidden") without
saying which, and the page never explained that the table drops columns
to fit. The footer now names them ("hidden: Path, Commit, Message"), and
a paragraph under `## Columns` covers the drop order, `[list] columns`,
and that `--format=json` shows everything.
- The JSON section documented deprecated schema 1 at 159 lines and nine
sub-tables while schema 2 — what a future release makes the default —
got 88 lines and one table. Schema 2 now carries the full reference
(envelope, item fields, a sub-table per object, the three value
vocabularies) and the worked `jq` recipes. Schema 1 keeps a paragraph,
the deprecation pointer, and a schema-1 → schema-2 mapping table
covering every field it documented.
- The CI-cache line pointed at `wt config state`, a group with no
default action; it names `wt config state cache`.
- `wt list statusline --format=json` was documented as "a one-entry
array in the `wt list --format=json` schema", which holds only under
schema 1. It emits the current schema — an array under 1, the envelope
under 2 — and the line now records why that surface stays silent about
an unset `[list] json-schema` while plain `wt list` nags: a prompt
consumer can't act on a warning drawn over its own line.
- The Status-symbols section documented every subcolumn except the
branch marker. Both JSON schemas gain an additive `marker` field, so the
value is readable without parsing it back out of `symbols`.

</details>

UX survey items: `#24`, `#34`, `#58`, `#89`, `#90`, `#92`, `#93`.

Reviewable files: `src/commands/list/**` (`layout.rs`, `columns.rs`,
`render.rs`, `progressive_table.rs`, `model/item.rs`, `mod.rs`,
`json_v2.rs`), the list section of `src/cli/mod.rs`,
`src/styling/line.rs`, and
`.claude/skills/writing-user-outputs/SKILL.md`. Generated mirrors and
snapshots are regenerated.

Original analysis:
https://claude.ai/code/session_01XAUYWFN9d9oh6jyoQiouHb

> _This was written by Codex on behalf of max-sixty_

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
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