Skip to content

feat: wt list --porcelain + [unadopted] indicator#35

Open
bezhermoso wants to merge 8 commits intoblock:mainfrom
bezhermoso:list.porcelain
Open

feat: wt list --porcelain + [unadopted] indicator#35
bezhermoso wants to merge 8 commits intoblock:mainfrom
bezhermoso:list.porcelain

Conversation

@bezhermoso
Copy link
Copy Markdown
Contributor

@bezhermoso bezhermoso commented Mar 17, 2026

wt list --porcelain: machine-readable worktree metadata + new indicators

Summary

  • wt list --porcelain — augmented git worktree list --porcelain with wt-specific metadata lines
  • [unadopted] indicator — surfaces unadopted worktrees in wt list and wt switch picker
  • Bug fix — stale (deleted) worktrees no longer produce warnings and blank entries in the picker

--porcelain output

Passes through native git porcelain verbatim and appends wt.* lines per entry:

worktree /Users/me/Development/java
HEAD abc123def456
branch refs/heads/master
wt.active

worktree /Users/me/Development/java-worktrees/feature-foo
HEAD def456abc123
branch refs/heads/feature/foo
wt.adopted

worktree /Users/me/Development/java-worktrees/bugfix-bar
HEAD 789abc012345
branch refs/heads/bugfix/bar

With -v, adds status metadata (slower — runs git status per worktree):

worktree /Users/me/Development/java-worktrees/feature-foo
HEAD def456abc123
branch refs/heads/feature/foo
wt.adopted
wt.dirty
wt.ahead 3
Line Mode Meaning
wt.active always Target of WT_ACTIVE_WORKTREE symlink
wt.adopted always Managed by wt (adoption marker exists)
wt.dirty -v Uncommitted changes
wt.ahead N -v Commits ahead of upstream
wt.behind N -v Commits behind upstream

What --porcelain unlocks

The structured output makes wt data composable with unix tools and custom scripts. Examples:

Custom fzf worktree picker:

wt_fzf_switch() {
  local selected
  selected=$(
    wt list --porcelain | awk '
      /^worktree /  { path = substr($0, 10); flags = "" }
      /^branch /    { branch = $2; sub("refs/heads/", "", branch) }
      /^wt\.active/ { flags = flags " *" }
      /^wt\.adopted/{ flags = flags " ✓" }
      /^$/          { if (path != "") printf "%s\t(%s)%s\n", path, branch, flags }
    ' | fzf --with-nth=1.. --delimiter='\t' \
        --preview 'git -C {1} log --oneline -10'
  )
  [[ -n "$selected" ]] && wt switch "$(echo "$selected" | cut -f1)"
}

Shell completions that show adoption status:

_wt_complete_worktrees() {
  local branches=()
  while IFS= read -r line; do
    case "$line" in
      branch\ *) branches+=("${line#branch refs/heads/}") ;;
    esac
  done < <(wt list --porcelain)
  COMPREPLY=($(compgen -W "${branches[*]}" -- "${COMP_WORDS[COMP_CWORD]}"))
}

Scripted batch adoption:

# Adopt all unadopted worktrees
wt list --porcelain | awk '
  /^worktree / { path = substr($0, 10); adopted = 0 }
  /^wt\.adopted/ { adopted = 1 }
  /^$/ { if (path != "" && !adopted) print path }
' | while read -r wt; do
  wt adopt "$wt"
done

[unadopted] indicator in nice output

Worktrees not managed by wt now show [unadopted] in wt list and the wt switch picker. Color escalates based on severity:

  /Users/me/Development/java (master) [main]
  /Users/me/Development/java-wt/feature-foo (feature/foo) [unadopted]
* /Users/me/Development/java-wt/bugfix-bar (bugfix/bar) [linked] [unadopted]
  /Users/me/Development/java-wt/feature-baz (feature/baz)
  • Yellow [unadopted] — informational: worktree exists but isn't wt-managed
  • Red [unadopted] — when combined with [linked]: you're actively working in an unmanaged worktree

Fixes

  • Stale worktrees in picker: worktrees registered in git but with deleted directories no longer produce cd: No such file or directory warnings or blank entries in the wt switch picker. They are silently skipped, matching the existing behavior in wt list.

Test plan

  • 12 new unit tests for wt_list_porcelain() (wt.active, wt.adopted, wt.dirty, wt.ahead, verbose/non-verbose modes)
  • 7 new integration tests for wt list --porcelain (output format, color absence, flag combinations)
  • 5 new integration tests for [unadopted] indicator (adopted/unadopted/main/linked+unadopted)
  • All 256 existing tests continue to pass
  • Manual: run wt list --porcelain on a real repo with multiple worktrees
  • Manual: run wt list and verify [unadopted] appears on correct entries
  • Manual: run wt switch and verify picker shows [unadopted] badges

🤖 Generated with Claude Code

bezhermoso and others added 7 commits March 16, 2026 19:01
Adds a new library function that wraps `git worktree list --porcelain`
and appends wt-specific metadata lines per entry:
- wt.active — worktree is the WT_ACTIVE_WORKTREE symlink target
- wt.adopted — adoption marker exists
- wt.dirty, wt.ahead, wt.behind — with --verbose flag

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Ai-assisted: true
Exposes the augmented porcelain output via `wt list --porcelain`.
Combinable with -v for verbose metadata (dirty, ahead/behind).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Ai-assisted: true
Unit tests for wt_list_porcelain() covering wt.active, wt.adopted,
wt.dirty, wt.ahead indicators and verbose/non-verbose modes.
Integration tests for wt-list --porcelain flag including color code
absence check.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Ai-assisted: true
Non-adopted worktrees now show a yellow ? prefix and [unadopted] badge.
If the worktree is both linked and unadopted, the badge escalates to
red to signal that the active worktree is missing metadata/symlinks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Ai-assisted: true
Applies the same ? prefix and [unadopted] badge (yellow/red) to the
interactive worktree selection menu used by wt switch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Ai-assisted: true
Add missing guard on cd failure when iterating worktrees, matching the
existing pattern in wt-list. Stale worktree registrations (directory
removed but still in git's list) are now silently skipped instead of
producing a warning and a blank entry in the picker.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Ai-assisted: true
Only the * prefix for active/linked worktrees remains. The [unadopted]
badge is sufficient on its own.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Ai-assisted: true
@bezhermoso bezhermoso changed the title feat: wt list --porcelain + [unadopted] indicator feat: wt list --porcelain + [unadopted] indicator Mar 17, 2026
@bezhermoso bezhermoso marked this pull request as ready for review March 17, 2026 02:52
Copy link
Copy Markdown
Collaborator

@guodong-sq guodong-sq left a comment

Choose a reason for hiding this comment

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

this adds a new public --porcelain flag to wt list, but the bash/zsh completion definitions do not appear to advertise it yet. It would be good to update completions so the new flag is discoverable from both wt-list and unified wt list completion paths.

(same with the help text)

Comment thread lib/wt-choose Outdated
Comment thread bin/wt-list
Comment thread lib/wt-choose
- wt-list: validate WT_MAIN_REPO_ROOT exists and is a git repo before
  dispatching to porcelain mode, so porcelain no longer returns an
  empty successful listing when the config points at a non-repo.
- wt-choose: use pwd -P when deriving main_repo_abs so it compares
  equal to worktree entries (which also use pwd -P) when the configured
  path contains symlink components. Prevents the main repo from being
  mis-flagged as [unadopted].
- wt-choose: use wt_source helper to load wt-adopt.
- completions + help: expose --porcelain in bash/zsh completion and in
  wt help output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bezhermoso
Copy link
Copy Markdown
Contributor Author

Re: the completions + help text feedback on the review — added in 04e2c4d:

  • completion/wt.bash: _wt_list_complete for wt-list, and a list case in the unified wt completion.
  • completion/wt.zsh: _wt_list with _arguments covering -v/--verbose, --porcelain, -h/--help; registered for both standalone and unified entry points.
  • lib/wt-help: --porcelain listed under list and in the examples block.

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