Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
# Changelog

## 0.79.0

### Improved

- **`wt switch --no-cd -x <program>` runs the program in the worktree**: it started in the invoking directory, so a program meant for the new worktree had to be handed `{{ worktree_path }}`. `--no-cd` now governs only your shell — `wt switch feature --no-cd -x code -- .` opens the worktree in an editor and leaves your terminal put. (Breaking: a program that wanted the invoking directory needs an explicit `cd`.) Fixes [#4042](https://github.com/max-sixty/worktrunk/issues/4042). ([#4179](https://github.com/max-sixty/worktrunk/pull/4179), thanks @yajo for reporting)

- **The picker's preview tabs show which have content**: a tab's label is dim when that tab is empty for the selected row, and underlined when it's the active tab. Availability sat on the tab's number alone, so every inactive label read dim whatever the row held. ([#4174](https://github.com/max-sixty/worktrunk/pull/4174))

- **Messages name the destination, and end with the command to run**: without shell integration, `wt merge` and `wt remove` printed `Cannot change directory — shell integration not installed` and no path; the warning now names the worktree, as `wt switch` already did. "Cannot determine default branch" had four wordings, and three recovery hints put their command first rather than last. ([#4163](https://github.com/max-sixty/worktrunk/pull/4163), [#4155](https://github.com/max-sixty/worktrunk/pull/4155), thanks @blrain3 for reporting)

- **`/wt-switch-create` no longer stalls at Claude Code's path-entry dialog**: Claude Code confirms every entry outside `.claude/worktrees/`, which is every Worktrunk worktree, so a background session waited for someone to attach. The plugin now approves entry into a worktree at its `worktree-path` location, and reads a bare name as the repo or the branch. ([#4158](https://github.com/max-sixty/worktrunk/pull/4158), [#4159](https://github.com/max-sixty/worktrunk/pull/4159))

### Fixed

- **`wt merge` on a dirty worktree describes what it commits**: the generated message covered the branch's earlier commits and said nothing about the work the merge had just staged into the same commit. `wt step squash --dry-run` now stages into a temp index so its preview covers what the run would commit, as `wt step commit --dry-run` does. ([#4178](https://github.com/max-sixty/worktrunk/pull/4178))

- **Diff display config no longer changes what Worktrunk reads**: `color.ui = always` and `diff.external` reached the commit, squash, and summary prompts. Two settings could also hide a branch's changes from the integration check, so `wt remove` deleted the branch without `-D`: `diff.relative` when run from a subdirectory the changes sat outside, and `submodule.<name>.ignore` on a submodule bump. Every diff Worktrunk parses now runs plumbing, which ignores that configuration, and upgrading discards the cached answers. ([#4146](https://github.com/max-sixty/worktrunk/pull/4146), [#4147](https://github.com/max-sixty/worktrunk/pull/4147), [#4181](https://github.com/max-sixty/worktrunk/pull/4181))
Comment thread
worktrunk-bot marked this conversation as resolved.

- **`wt config update --output <path>` asks before overwriting**: it replaced whatever was there, so `--output ~/.config/worktrunk/config.toml` from a repo with a deprecated project config wiped the user config and reported success. It now prompts, takes `--yes`, and refuses the config being migrated. (Breaking: `--output` naming the config being migrated used to succeed unless the migration dropped `approved-commands`.) ([#4153](https://github.com/max-sixty/worktrunk/pull/4153))

- **A config save no longer rewrites the rest of your config**: declining a prompt, or setting the commit-generation command, rewrote the whole file — dropping values written at their default, and re-spelling hook pipelines with their comments. It also reloaded that file over the in-memory config, so `wt step commit --config-set 'commit.stage="none"'` staged everything once it had asked about commit generation. ([#4160](https://github.com/max-sixty/worktrunk/pull/4160), [#4156](https://github.com/max-sixty/worktrunk/pull/4156), [#4151](https://github.com/max-sixty/worktrunk/pull/4151))

- **Auto-staging names a wholly untracked directory once**: since 0.78.0 the warning expanded each one into its files, so `wt step commit`, `wt step squash`, and `wt merge` listed 300 paths for a directory of 300 new files. The listing also stops at ten rows, with a hint counting the rest. ([#4152](https://github.com/max-sixty/worktrunk/pull/4152), thanks @Duang777)

- **`wt merge --no-ff` and `wt step push --no-ff` sign their merge commit under `commit.gpgSign`**: they built it with `commit-tree`, which ignores that setting. `wt step rebase` and `wt merge` also pass `--no-update-refs`, so a rebase rewrites only its own worktree's branch. (Breaking: `rebase.updateRefs` no longer moves other local branches stacked in the rebased range.) ([#4146](https://github.com/max-sixty/worktrunk/pull/4146))

- **`wt step prune --min-age` guards branches with no reflog**: they got no age guard at all, so in a bare repository — where `core.logAllRefUpdates` defaults off — a branch that had just arrived at an integrated commit was pruned on the next run. Age now comes from the mtime of the file holding the ref. ([#4154](https://github.com/max-sixty/worktrunk/pull/4154))

- **The picker preview no longer drops a character**: the pane rendered one column wider than skim paints, so a wrapped line breaking flush against the right edge lost its last character mid-sentence. ([#4178](https://github.com/max-sixty/worktrunk/pull/4178))

- **`wt config plugins pi install` expands `~` in `$PI_CODING_AGENT_DIR`**: Pi expands it, so `PI_CODING_AGENT_DIR="~/x"` means a directory under home, where Worktrunk created a literal `~` directory under the current directory. ([#4151](https://github.com/max-sixty/worktrunk/pull/4151))

### Documentation

- **The picker demo shows the CI and summary columns filling in**: `alt-p` widens the rows, the cells land behind them, then it pages a diff, a PR's comment thread, and the PR itself. The homepage omnibus demo opens on the picker. [Docs](https://worktrunk.dev/switch/#interactive-picker) ([#4178](https://github.com/max-sixty/worktrunk/pull/4178))

- **The command pages got a sweep**: help text drops internals, deprecated behavior, and edge cases the command reports itself when they happen — `wt step diff`'s "How it works", the `wt hook --var` paragraph, and the `wt config state ci-status` page among them. Every config sample now renders the file it belongs in as its tab. ([#4157](https://github.com/max-sixty/worktrunk/pull/4157), [#4153](https://github.com/max-sixty/worktrunk/pull/4153), [#4173](https://github.com/max-sixty/worktrunk/pull/4173), [#4177](https://github.com/max-sixty/worktrunk/pull/4177))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

#4180 landed on main after the cut-from tip 75baa2cd3, so it is already an ancestor of this release commit and ships in 0.79.0 — but nothing here covers it. This is the release skill's step 12 case: the merge squashes onto whatever main tip exists at merge time, so the drift ships whether or not the changelog names it. Folding it in now costs a line; catching it at step 12 costs a follow-up squash PR and another pass over the coverage list.

Whether a Further-reading removal clears the bar for an entry is your call — the section it would join already covers doc-site sweeps of comparable weight. If it does:

Suggested change
- **The homepage and README drop "Further reading"**: the section listed five external links; the one about Worktrunk itself — @DevOpsToolbox's video — moves into Next steps, beside the other things to do after installing. ([#4180](https://github.com/max-sixty/worktrunk/pull/4180))

### Internal

- **Library API rework** (Breaking library API): `cargo-semver-checks` fails five lints — `BranchDiffSpec` swaps `revs`/`working_base` for `diff_base`, `UserConfig::save_to` gives way to the `ConfigEdit` mutations, `config::UnknownAnalysis` is gone, `Repository::prepare_diff` takes `from`/`to` in place of a revision list, and four diff helpers on `PreparedDiff` and `WorkingTree` go with it. ([#4146](https://github.com/max-sixty/worktrunk/pull/4146), [#4147](https://github.com/max-sixty/worktrunk/pull/4147), [#4160](https://github.com/max-sixty/worktrunk/pull/4160), [#4156](https://github.com/max-sixty/worktrunk/pull/4156))

- **The Nix flake's test sandbox gains `openssh`**, which the merge-signing test needs. ([#4168](https://github.com/max-sixty/worktrunk/pull/4168))

## 0.78.0

### Improved
Expand Down
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ No `get_*` — bare nouns follow Rust stdlib convention.

`Repository` caches read-only values via `Arc<RepoCache>` (cloning shares it). What is and isn't cached, the `list_worktrees()` post-mutation invariant, the two storage patterns, and the in-memory-`RepoCache`-vs-persistent-`sha_cache` decision (cheap-and-hot → in-memory get-or-create; expensive → disk; both → in-memory front over disk back): the `# Caching` section in `src/git/repository/mod.rs`.

**A change to what a cached value means bumps `CACHE_EPOCH`** (`src/cache.rs`). The persistent entries are keyed on SHA pairs with no TTL, so the key cannot see the generator's output: an entry written by an older `wt` keeps answering until its key recurs, and on a finished branch that is never. Moving the diffs onto plumbing is the worked example — it left `has-added-changes` entries saying an unmerged branch had no added changes, which is `wt remove` deleting it. So the question belongs to any change that alters what a cached read reports, not just to code inside `cache.rs`; ask it whenever a generator behind one of `sha_cache`'s kinds changes.

## Releases

Use the `release` skill (version bump, changelog, crates.io publish, GitHub release). It writes every changelog entry from the commits since the last tag, so other PRs leave `CHANGELOG.md` untouched; a PR that already carries an entry drops it rather than resolving a conflict on it.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ filterset = "test(/aur_pkgbuild/)"

[package]
name = "worktrunk"
version = "0.78.0"
version = "0.79.0"
edition = "2024"
rust-version = "1.97"
build = "build.rs"
Expand Down
3 changes: 2 additions & 1 deletion docs/src/content/docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Worktrunk stores repository state, caches, and logs under `.git/`:
| Location | Purpose | Created by |
|----------|---------|------------|
| `git config worktrunk.*` | Cached default branch, switch history, branch markers, custom variables | Various commands |
| `.git/wt/cache/{kind}/*.json` | Cached CI status, the largest PR/MR number seen (sizes the `wt list` CI column), and git command results (merge-tree, integration probes, diff stats, ancestry checks, ahead/behind counts, merge bases) | `wt list`, `wt merge`, `wt remove` |
| `.git/wt/cache/{kind}/*.json` | Cached CI status, the largest PR/MR number seen (sizes the `wt list` CI column), and git command results (merge-tree, integration probes, diff stats, ancestry checks, ahead/behind counts, merge bases), beside a stamp of what those results mean — a worktrunk that disagrees with it discards the tree | `wt list`, `wt merge`, `wt remove` |
| `.git/wt/cache/summary/{branch}/{hash}.json` | Cached LLM branch summaries, content-addressed by diff hash | `wt list --full`, `wt switch` (when `[list] summary = true`) |
| `.git/wt/cache/picker-preview/*.json` | Rendered preview panes for the interactive picker | `wt switch` |
| `.git/wt/logs/{branch}/**/*.log` | Background hook output (nested per branch) | Hooks, background `wt remove` |
Expand Down Expand Up @@ -213,6 +213,7 @@ A branch checked out in a second worktree is retained regardless, `-D` included.

- `wt merge` / `wt step push` — the target branch's checked-out worktree is updated to the merged commits, so a file those commits delete disappears from it, and an ignored file at a path they track is overwritten — the same result a `git merge` run in that worktree would produce. Uncommitted changes at paths the merge doesn't touch stay in place, staged or not; one at a path it does touch refuses the merge upfront, naming the file
- `wt remove` — also stops the removed worktree's `git fsmonitor--daemon` (under `core.fsmonitor=true`), and sweeps `.git/wt/trash/` entries older than 24 hours along with fsmonitor daemons whose worktree no longer exists
- any command reading a cache — discards the cached git-command results under `.git/wt/cache/` when they were written by a worktrunk that computed them differently, so a stale answer can't outlive the code that produced it. Cached CI status and LLM summaries are keyed on what they describe, so they are left alone
- `wt config state clear` — removes all worktrunk data from `.git/` (config keys, caches, markers, hints, variables, logs, stale trash)
- `wt config shell install` — replaces an existing fish or Nushell wrapper file whole, and removes one an older version installed at a previous location (fish `conf.d/wt.fish`, Nushell `<config-dir>/vendor/autoload/wt.nu`), printing each removal; [Files created](/shell-integration/#files-created) names the file each shell gets
- `wt config shell uninstall` — removes the lines that run `wt config shell init` from bash/zsh/PowerShell rc files, and deletes wrapper and completion files carrying worktrunk's content markers (fish `functions/`, `conf.d/`, and `completions/`; nushell `vendor/autoload`). Every removed line is printed
Expand Down
3 changes: 2 additions & 1 deletion plugins/worktrunk/skills/worktrunk/reference/faq.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion skills/worktrunk/reference/faq.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading