Release Notes
Improved
-
[list] columnscan force a column on past--full: Listing a column now overrides the--full/[list] summarypresets —columns = ["branch", "ci"]shows the CI column without--full. Hard data-source prerequisites still apply: a listedsummarywith no[commit.generation]command, orurlwith no template, stays hidden, since listing can't conjure data that isn't configured. (#3295) -
Alt-rin the picker refreshes the preview panes, not just the rows:Alt-rre-collected the rows but kept serving cached preview content, so editing a tracked file and refreshing still showed the pre-edit diff. It now clears the preview cache too, recomputing the working-tree / log / branch-diff / upstream / summary tabs and re-fetchingpr/comments. Unchanged branches re-read from the content-keyed on-disk cache, so only genuinely changed content pays a recompute. (#3293) -
A narrowed
wt listis now actually faster: A narrowed[list] columnsselection (e.g.["branch", "path"]) now runs only the git work its columns need. It previously ran every per-worktreegit status, diff, and ahead/behind walk regardless, then discarded the unselected results — so a trimmed view was no faster than the full table, and on a repo with many dirty worktrees that discarded work was the bulk of the wall-clock cost. (#3274, thanks @jtaby for reporting) -
Fewer duplicate git calls in
wt list --full: The two integration probes per row (the conflict bit formain-stateand the clean-merge tree for the integration column) issued a byte-identicalgit merge-tree, and the shared default-branch tip was peeled to its tree once per row. Both are now deduplicated through the in-memory cache, so each resolves once per run instead of once per worktree. (#3288, #3289) -
Picker
commentstab avoids redundant forge fetches: The picker'scommentspreview tab gained an on-disk cache keyed by the PR'supdatedAt(which rides for free on the CI fetch the picker already makes), so a repeatwt switchskips the per-rowgh pr view --json commentsfetch when the thread is unchanged and paints the tab instantly instead of showing "Loading comments…". The cache is also primed from thegh pr listcall the picker already makes, so the tab skips its own fetch even on a session's first open (including PRs with no comments). GitHub only. (#3294, #3299) -
Statusline width comes from
COLUMNS, not a parent-process walk:wt list statuslineused to spawn up to 10pscalls plussttyper render to recover a terminal width, because Claude Code piped the subprocess with no inherited TTY. Claude Code now setsCOLUMNS/LINESto the terminal dimensions before running the script (since v2.1.153), so the width comes straight from there — less a fixed 5-column margin for Claude Code's own UI — and theps/sttywalk is gone. On an older Claude Code that doesn't setCOLUMNS, the line renders untruncated rather than walking the process tree. (#3286, closes #2950)
Fixed
-
wt listdiff and ahead/behind columns use the upstream default tip: Themain↕(ahead/behind) andmain…±(diff) columns measured every branch against the local default-branch tip, so in a fork whose localmainlagged its upstream they reported inflated counts — one fork branch showed↑44and+∞ / -5Kwhen it was ~2 commits past the real upstream tip. They now diff against the same upstream-aware base the integration column already uses. (#3280) -
Integrated branches no longer flash
✗inwt list: A squash-merged branch whose default branch later re-edited the same lines showed✗(would-conflict), even thoughwt step pruneclassified it as⊂(fully integrated) and removed it. The list now ranks the integration verdict above the downstream conflict, matching prune; a genuinely un-integrated conflict still shows✗. (#3278) -
wt listdivergence-overflow marker uses one emphasis level: When an ahead/behind count overflows its digit budget, themain↕column's compactC/K/∞marker rendered the "behind" subcolumn as dim + bold (reading as bold red) instead of a clean one-level step. It now steps exactly one level — dim red → normal red — matching the "ahead" subcolumn, acrosswt listand the picker. (#3303) -
Branch deletion on removal is atomic:
wt removeand prune now delete a branch with a compare-and-swap (git update-ref -d <ref> <expected-sha>) against the SHA the integration check already read, closing the window where a branch whose tip moved in between (e.g. a hook landing a commit) could be deleted. Such a branch is now retained with a clear message and awt remove -D <branch>recovery hint. This also unifies the previously divergent safe-delete paths; explicit force-delete still usesgit branch -D. (#2903) -
wt listand picker Age/Message columns paint as soon as the commit batch lands: These columns carry no async task — their data arrives with the initialgit logbatch — but stayed on the·placeholder until some slower task happened to redraw the row, so the commit message lagged behind a cache-warm Summary preview. They now paint the moment the batch lands. (#3287) -
Picker
Alt-xremoval: no cursor flash,--prsrows preserved: Removing a row withAlt-xflashed the>pointer to the top of the list for a frame, and in--prsmode made the streamed PR/MR rows vanish until the nextAlt-r. Removal is now a synchronous in-place pool resync: the cursor lands on the row that slid up with no flash, and the PR/MR rows survive. (#3268, #3275) -
Removable rows stay gray when selected in the picker: A safe-to-delete worktree (integrated, or clean and even with the default branch) renders its row gray, but the gray vanished under the selection highlight — exactly when you're about to act on it. The gray now survives selection (selected row only;
wt listand unselected rows are unchanged). (#3267) -
Picker preview keeps its scroll when CI status arrives: Scrolling down a diff and waiting a couple of seconds snapped it back to the top when the live CI fetch landed and re-rendered the pane. The re-render is now precise — a tab re-runs only when its own content would actually change — so a CI update no longer throws away the scroll position of an unrelated tab. (#3292)
-
Picker summary tab dims when there's nothing to summarize: The summary preview tab (
5) stayed lit on a clean branch with no commits ahead, unlike the diff tabs (1/3/4), which dim once their diff is known empty. It now dims in concert with them once both the branch diff and working tree are known empty. (#3291) -
Picker default view keeps collect order: With no query typed, the
wt switchpicker reordered rows by where each name's last/falls, so slash-bearing branches (feature/…,perf/…) sank toward the bottom and intermixed with other row kinds. The default view now preserves collect order. (#3301) -
Picker branch-diff preview and summary use the upstream-aware base: Like the
wt listcolumns above, the picker's branch-diff preview pane and the LLM branch summary diffed against the raw local default branch, so a fork whose local default lagged upstream made them describe dozens of already-merged commits. They now use the same upstream-aware comparison base. (#3305) -
Picker comment previews render fenced code blocks cleanly: A fenced code block inside a PR/MR comment rendered as a garbled double gutter in the
wt switchcomments preview — alternating bar/no-bar lines with broken alignment. The code block now renders without the nested gutter. (#3306) -
First-run hints show the config path wt actually loads from: The picker's disabled-summary tab and the commit-generation setup prompt hardcoded
~/.config/worktrunk/config.toml, so a user with--config,WORKTRUNK_CONFIG_PATH, or a non-default$XDG_CONFIG_HOMEwas told to edit a file wt never reads. Both now show the resolved path. (#3290, #3298)
Internal
-vvtrace and profiler accuracy:trace.logis now purely human-readable, with the machine-parseable[wt-trace]fields living only intrace.jsonl; and the performance profile's cache analysis no longer reports stdin-driven commands (LLMclaude -pcalls,git patch-id) as duplicate re-runs, since their real input isn't captured in the command string. (#3296, #3297)
Install worktrunk 0.63.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/max-sixty/worktrunk/releases/download/v0.63.0/worktrunk-installer.sh | sh && wt config shell installInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/max-sixty/worktrunk/releases/download/v0.63.0/worktrunk-installer.ps1 | iex"; git-wt config shell installInstall prebuilt binaries via Homebrew
brew install worktrunk && wt config shell installDownload worktrunk 0.63.0
| File | Platform | Checksum |
|---|---|---|
| worktrunk-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| worktrunk-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| worktrunk-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| worktrunk-aarch64-unknown-linux-musl.tar.xz | ARM64 MUSL Linux | checksum |
| worktrunk-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
Install via Cargo
cargo install worktrunk && wt config shell installInstall via Winget (Windows)
winget install max-sixty.worktrunk && git-wt config shell installInstall via AUR (Arch Linux)
paru worktrunk-bin && wt config shell install