Repository navigation
Conversation
…round post-merge Implements the hook rationalization from #1670. Every lifecycle event now has a symmetric pre- (blocking) / post- (background) pair: | Event | pre- (blocking) | post- (background) | |---------|-----------------|---------------------------| | start | pre-start | post-start | | switch | pre-switch | post-switch | | commit | pre-commit | post-commit (new) | | merge | pre-merge | post-merge (was blocking) | | remove | pre-remove | post-remove | Changes: - **Rename post-create → pre-start**: accepts both names for one release cycle. Deprecation warning when post-create found in config. Migration file generated via `wt config update`. CLI alias `wt hook post-create` still works. - **New post-commit hook**: fires in background after successful commit in `wt commit` and `wt merge`. Respects --no-verify. Useful for CI triggers, notifications, or background linting. - **post-merge → background**: was blocking with Warn strategy, now spawns in background like all other post-* hooks. Removes PostMerge exit code propagation. `--foreground` flag added for debugging. Ref #1670 Co-Authored-By: Claude <noreply@anthropic.com>
Update `after_long_help` in cli/mod.rs (primary source) and all synced docs/skills files to reflect the hook rationalization: - post-create → pre-start in all examples, tables, and section headers - Add post-commit section with description and example - Mark post-merge as non-blocking (background) in hook types table - Update merge pipeline order to show background hooks - Update cli/step.rs copy-ignored help text Co-Authored-By: Claude <noreply@anthropic.com>
…table handling - Add 23 unit tests for post-create deprecation (detection, migration, integration, snapshot) matching the coverage pattern of existing deprecations (select, commit-generation) - Fix merge_with to fold post_create into pre_start so hooks from unmigrated configs aren't silently dropped when merging with configs that use the new name - Filter empty [post-create] tables from deprecation detection, consistent with [select] handling Co-Authored-By: Claude <noreply@anthropic.com>
worktrunk-bot
approved these changes
Mar 23, 2026
Update test fixtures in approval_pty, config_update_pty, and shell_wrapper to use `pre-start` instead of `post-create`. Accept 12 updated PTY snapshots reflecting the new hook name in approval prompts and execution output. Co-Authored-By: Claude <noreply@anthropic.com>
worktrunk-bot
approved these changes
Mar 23, 2026
The help test was renamed to pre-start but the old snapshot file wasn't deleted. Co-Authored-By: Claude <noreply@anthropic.com>
worktrunk-bot
left a comment
Collaborator
There was a problem hiding this comment.
Two documentation gaps:
-
docs/content/merge.mdPipeline section (lines 61–71) needs updating. The hook.md cross-reference correctly sayspre-commit → post-commit (background) → pre-merge → pre-remove → post-remove + post-merge (background), but the merge.md Pipeline section — which that cross-reference links to — still describes the old behavior:- No mention of pre-commit/post-commit hooks in the pipeline steps
- Step 7 still describes post-merge as blocking ("Failures are logged but don't abort") instead of background
-
Stale comment in
src/commands/hooks.rs:37—"Running post-create user hook"should be"Running pre-start user hook".
Both are outside the diff, so offering as a follow-up commit rather than inline suggestions.
- Add commit step (pre-commit, commit, post-commit) to pipeline - Fix post-merge description: runs in background, not blocking - Fix stale comment referencing post-create in hooks.rs Co-Authored-By: Claude <noreply@anthropic.com>
- Add PostCommit to approval batch in `wt step commit` and `wt step squash` so post-commit hooks get user consent - Spawn post-commit hooks after squash commit, matching the direct commit path in CommitOptions::commit() Co-Authored-By: Claude <noreply@anthropic.com>
worktrunk-bot
approved these changes
Mar 23, 2026
The hook command name completer didn't recognize `post-create` in the command context, so `wt hook post-create <TAB>` returned no completions. Map it to `pre-start` for the duration of the deprecation period. Co-Authored-By: Claude <noreply@anthropic.com>
Move the repeated log path template from each post-* hook section into the intro paragraph. Each hook section now focuses on use cases rather than mechanics. Also remove redundant "Failure aborts" from pre-switch (already stated in intro). Co-Authored-By: Claude <noreply@anthropic.com>
max-sixty
added a commit
that referenced
this pull request
Mar 23, 2026
Adds a changelog entry for #1679 (hook rationalization) to the 0.31.0 release notes. Covers the rename, new hook, post-merge behavior change, and deprecation path. > _This was written by Claude Code on behalf of max-sixty_ Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Mar 24, 2026
10 tasks
max-sixty
added a commit
that referenced
this pull request
Sep 7, 2026
… its worktree (#4026) `wt merge` prints `◎ Running post-commit: …` and then spawns that pipeline into a path the removal has already emptied, so a `post-commit` hook can't be relied on to do what it says. Nothing reports this, and two doc lines promised the behavior that doesn't happen. `post-commit` is the only hook in the merge's background batch anchored on the feature worktree — `post-merge`, `post-switch` and `post-remove` all anchor on the destination. `HookAnnouncer` flushes every pending pipeline once at the end of the command, which is after `finish_after_merge` has removed that worktree. What the runner then finds depends on where the worktree lived, because the fast removal path renames it into `.git/wt/trash/` and leaves an empty placeholder at the original path (`changed_directory: true`, so the shell's `$PWD` stays valid), torn down a second later by the detached `sleep 1 && rmdir`. `run_pipeline` calls `Repository::at` on that placeholder, and git discovery walks up from it: - **Worktree outside the repo** (the default `../{{ repo }}.{{ branch }}`): no git ancestor, so the runner logs `failed to open repository for pipeline` to `.git/wt/logs/<branch>/<source>/post-commit/runner.log`, which nothing reads back. The hook doesn't run. - **Worktree nested inside the repo** (`worktree-path = "{{ repo_path }}/.worktrees/{{ branch | sanitize }}"`, one of the config page's own examples): discovery resolves to the **primary** worktree, `Repository::at` succeeds, and the steps do run — with their cwd set to the placeholder `rmdir` unlinks a moment later, and any `git` inside them resolving against the primary worktree. It's a regression, not a hook that never worked: #1679 added `post-commit` and it fired for five weeks, until #2457 collapsed the merge's two or three `◎ Running …` lines into one. That was a cosmetic change, and deferring the spawn to a single end-of-command flush moved it past the removal. Documented rather than fixed, deliberately. The commit `post-commit` would fire on is squashed and rebased before the merge lands; `pre-remove` already covers work that must finish in the feature worktree, blocking removal until it does; and spawning at commit time only narrows the window, since `git worktree remove` succeeds against a live cwd. `post-commit` still runs properly wherever the worktree survives — `--no-remove`, merging on the target branch, merging from the primary worktree — and on `wt step commit` / `wt step squash`. So this adds the explanation at the `HookAnnouncer` construction in `handle_merge`, and corrects what the docs claimed: - The merge pipeline's step 1 said "Post-commit hooks run in background" flatly. - The hook page said "During `wt merge`, hooks run in this order: pre-commit → post-commit → pre-merge → pre-remove → post-remove + post-merge" — wrong twice, since the `post-*` hooks don't run in sequence either (#4020 corrected that one row above). It now gives the blocking order, says the `post-*` hooks start together in the worktree each is anchored on, and points at `pre-remove` or `--no-remove`. - `test_merge_squash_combines_post_commit_…` said the merge "fires post-commit"; it announces it. Both it and its auto-commit sibling now say the announce line is all they pin. No behavior change. <details> <summary>Reproduction</summary> A scratch repo with a `post-commit` hook, a feature worktree with one commit and one uncommitted file, then `wt merge main --yes`. Every case prints `◎ Running post-commit: mark (user)`: | Layout | Flags | Outcome | |--------|-------|---------| | external (`../{{ repo }}.{{ branch }}`) | default (squash) | hook doesn't run | | external | `--no-squash` | hook doesn't run | | external | `--no-remove` | runs correctly | | nested (`{{ repo_path }}/.worktrees/{{ branch }}`) | default (squash) | runs in the doomed placeholder | The external removing cases leave this in `.git/wt/logs/feat/user/post-commit/runner.log`: ``` ✗ failed to open repository for pipeline fatal: not a git repository (or any of the parent directories): .git ``` The nested case leaves an empty `runner.log` and the hook's own output shows where it landed — `pwd` is the removed worktree's path, while `git rev-parse --show-toplevel` from inside it answers with the primary worktree: ``` cwd=/…/repo/.worktrees/feat toplevel=/private/…/repo ``` The commit itself is made in every case — `Changes to dirty.txt` reaches `main`. </details> > _This was written by Claude Code on behalf of max-sixty_ --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the hook rationalization from #1670, establishing a symmetric
pre-(blocking) /post-(background) pattern for every lifecycle event.Changes
Rename
post-create→pre-start: The old name suggested it ran after creation, but it actually runs beforepost-startas a blocking dependency step. Both names accepted for one release cycle — config deprecation detection, migration file generation,wt config updatesupport, and CLI alias all in place.merge_withfolds old-name hooks into new-name so cross-config combinations don't silently drop hooks.Add
post-commithook: New background hook firing after successful commits (including squash commits), completing the commit lifecycle pair. Included in approval batches forwt step commit,wt step squash, andwt merge.Change
post-mergeto background: Was blocking withWarnstrategy, now runs in background like all otherpost-hooks.--foregroundflag available for debugging.The hook table is now a clean symmetric grid:
pre-(blocking)post-(background)pre-startpost-startpre-switchpost-switchpre-commitpost-commitpre-mergepost-mergepre-removepost-removeTesting
868 lib + 483 bin + 1227 integration tests pass, all 13 lint checks pass. The deprecation has 23 dedicated unit tests covering detection at all three config scopes, migration, empty table filtering, cross-config merge safety, and integration with
wt config show/wt config update.Closes #1670