Skip to content

fix(hooks): propagate Repository::at errors in pre-remove config resolution#2708

Merged
max-sixty merged 1 commit into
mainfrom
remove-config-fail-fast
May 11, 2026
Merged

fix(hooks): propagate Repository::at errors in pre-remove config resolution#2708
max-sixty merged 1 commit into
mainfrom
remove-config-fail-fast

Conversation

@max-sixty

Copy link
Copy Markdown
Owner

Each of the three pre-remove config-resolution call sites — the two approval helpers (main.rs::approve_remove, prune::approve_prune_hooks) and the executor (handlers::execute_pre_remove_hooks_if_needed) — used a match that incidentally swallowed Err(_) from Repository::at(wt_path) into the legitimate "no .config/wt.toml" fallback. Rewrite as two-step so Repository::at errors propagate; the fallback now fires only when the removed worktree has no project config.

The executor's inline comment notes why we propagate here rather than follow the UserConfig::load() silent-skip a few lines above: user config can be benignly malformed, but a path git no longer recognizes as a worktree is a different kind of failure.

Follows the same shape as the sibling fix in #2701, which replaced Repository::at(&primary_path).unwrap_or_else(|_| repo.clone()) with ? for the same reason.

merge.rs::collect_merge_commands already uses ? for its Repository::at(destination_path) (refactored in #2690), so it's untouched.

… config

Each of the three `pre-remove` config-resolution call sites — the two
approval helpers (`main.rs::approve_remove`, `prune::approve_prune_hooks`)
and the executor (`handlers::execute_pre_remove_hooks_if_needed`) — used
a `match` that incidentally swallowed `Err(_)` from `Repository::at(wt_path)`
into the legitimate "no .config/wt.toml" fallback. Rewrite as two-step
so `Repository::at` errors propagate; the fallback now fires only when
the removed worktree has no project config.

Matches the sibling fix in #2701 that replaced `Repository::at(&primary_path)
.unwrap_or_else(|_| repo.clone())` with `?` for the same reason.

Co-Authored-By: Claude <noreply@anthropic.com>
@max-sixty max-sixty merged commit cbe3727 into main May 11, 2026
34 checks passed
@max-sixty max-sixty deleted the remove-config-fail-fast branch May 11, 2026 18:18
max-sixty added a commit that referenced this pull request May 11, 2026
…ve/merge/prune (#2709)

## Summary

`wt remove`, `wt merge`, and `wt step prune` all approve `pre-remove`
against each removed worktree's own `.config/wt.toml` (with
primary-worktree fallback) plus `post-remove`/`post-switch` against the
primary's. The pattern was duplicated in three places — subtle enough
that #2701 had to fix it separately for prune after #2690 fixed it for
remove/merge, and #2708 then had to fix the `Repository::at`
`Err`-swallowing in three places independently. This consolidates the
three call sites into one shared helper, so the next fix-this-pattern PR
only has to touch one place.

## Changes

- `src/commands/project_config.rs` — new
`collect_remove_hook_commands(primary_repo, paths)`. Returns the
`Vec<ApprovableCommand>` for `pre-remove` (per-worktree, with primary
fallback) + `post-remove`/`post-switch` (primary), deduped by template.
Carries forward #2708's `Repository::at(wt_path)?` propagation.
- `src/main.rs::approve_remove` — replaced the per-worktree
`approve_or_skip` loop with a single-batch flow. `wt remove` switches
from N+1 prompts to one combined batch (strictly fewer prompts in
practice; approvals saved by the first prompt would have suppressed
later identical ones anyway).
- `src/commands/merge.rs::collect_merge_commands` —
`pre-remove`/`post-remove`/`post-switch` now come from the helper; merge
keeps its inline `pre-commit`/`post-commit`/`pre-merge`/`post-merge`
collection and bundles everything into the same `approve_command_batch`
call.
- `src/commands/step/prune.rs::approve_prune_hooks` — one-line helper
call. The "over-approval superset" exception remains in the local
docstring.
- `src/commands/hooks.rs` — the "Which `.config/wt.toml` a hook reads"
spec docstring now points at the shared helper.

The executor `output::handlers::execute_pre_remove_hooks_if_needed`
still has its own copy of the pattern (an executor-side, not
approval-side, concern) — left as-is.

## Test plan

- [x] `cargo run -- hook pre-merge --yes` — 3660 tests pass; clippy
clean.
- Existing `wt remove` / `wt merge` / `wt step prune` approval tests
cover both branches of the helper (per-worktree config vs primary
fallback).

Co-authored-by: Claude <noreply@anthropic.com>
@max-sixty max-sixty mentioned this pull request May 13, 2026
max-sixty added a commit that referenced this pull request May 13, 2026
Release v0.50.0.

Highlights:

- Experimental Azure DevOps support (#1256, thanks @mikeyroush; fixes
#1144 from @dlecan) — `wt switch pr:<N>`, `wt list --full`, and `wt
config show --full` recognize Azure DevOps via the `az` CLI.
- Experimental Gitea CI-status detection (#2702) on top of the Gitea
`pr:` shortcut (#1320, thanks @SjB).
- Hooks now resolve `.config/wt.toml` from the worktree they act on —
the primary-worktree fallback is gone, and `post-remove` reads the
removed worktree's config (snapshotted before removal). Approval prompts
collect hook commands from the same worktree. Breaking change for setups
that relied on the primary-worktree fallback; the changelog entry has
the recovery action. (#2690, #2703, #2714, #2717, #2701, #2708, #2727,
#2736, #2748)
- The `wt switch` picker's `alt-r` removal no longer runs unapproved
project hooks (#2746) — the picker's removal path is now routed through
`handle_remove_output` and consults the existing approval state
read-only.
- `wt config alias show` with no name lists every alias's full
definition (#2684, #2691); `wt --help` switches to a compact aliases
pointer (#2688).
- `wt list --branches` warm-run perf: SHA-keyed cache for `main↕` and
`Remote⇅` ahead/behind counts; shared push-remote URL and local-branch
scan (#2704, #2718, #2673).
- Claude Code plugin ships the `wt-switch-create` skill (#2737, thanks
@onetom for #2631).

See `CHANGELOG.md` for the full list (8 Improved, 5 Fixed, 5 Internal).

semver-checks reports breaking library-API changes (new enum variants
without `#[non_exhaustive]`, removed `Branch::github_push_url`, new
trait method on `RemoteRefProvider`), which mandates at minimum a minor
bump pre-1.0.
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