fix(run): add post-commit and pre-rebase subcommands#858
Conversation
`hk install` (and `hk install --global`) writes hookcmds for nine git
events including `post-commit` and `pre-rebase`, but `hk run` only
shipped typed subcommand handlers for seven of them. The two events
without handlers fell through to the `other` catch-all, which works
but:
- hides them from `hk run --help`
- mixes their args into `HookOptions::files` (the positional
collector) instead of named arguments, so usage is opaque
- produces confusing clap errors when arg parsing goes sideways
Add dedicated `PostCommit` (no args) and `PreRebase` (upstream +
optional branch, matching git's hook spec) handlers so every event
listed in `DEFAULT_GLOBAL_EVENTS` has a named handler.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Greptile SummaryThis PR adds dedicated Confidence Score: 5/5Safe to merge — additive only, follows established patterns exactly, no logic changes to existing paths Both new handlers are small, pattern-matched implementations with no edge-case risk. The only change to existing code is adding two enum variants and two match arms in mod.rs. No existing behaviour is altered. No files require special attention Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["hk run <subcommand>"] --> B{Commands enum}
B --> C[CommitMsg]
B --> D[PostCheckout]
B --> E["PostCommit 🆕"]
B --> F[PostMerge]
B --> G[PostRewrite]
B --> H[PreCommit]
B --> I[PrePush]
B --> J["PreRebase 🆕"]
B --> K[PrepareCommitMsg]
B --> L[other catch-all]
E --> E1["hook_args = ''"]
J --> J1["hook_args = upstream [branch]"]
E1 --> Z[HookOptions::run]
J1 --> Z
C --> Z
D --> Z
F --> Z
G --> Z
H --> Z
I --> Z
K --> Z
L --> M["hook_args = ''"]
M --> Z
Reviews (2): Last reviewed commit: "[autofix.ci] apply automated fixes" | Re-trigger Greptile |
There was a problem hiding this comment.
Code Review
This pull request introduces support for the post-commit and pre-rebase Git hooks by adding the corresponding modules and CLI subcommands. The post-commit hook is implemented with empty arguments, while the pre-rebase hook handles upstream and optional branch parameters. Review feedback highlights a potential issue where flags passed before subcommands are ignored due to the current command dispatch pattern. Additionally, a suggestion was made to optimize the pre-rebase argument construction by moving the upstream string instead of cloning it.
| return match cmd { | ||
| Commands::CommitMsg(cmd) => cmd.run().await, | ||
| Commands::PostCheckout(cmd) => cmd.run().await, | ||
| Commands::PostCommit(cmd) => cmd.run().await, |
There was a problem hiding this comment.
Flags passed before the subcommand (e.g., hk run --all post-commit) are captured by the Run struct's hook field but are ignored when dispatching to a subcommand, as the subcommand's run method only uses its own hook options. This is an existing pattern in this file, but it affects the newly added subcommands as well. Consider merging the parent options into the subcommand's options or refactoring how flags are handled.
| let args = match &self.branch { | ||
| Some(b) => format!("{} {}", self.upstream, b), | ||
| None => self.upstream.clone(), | ||
| }; |
There was a problem hiding this comment.
Joining upstream and branch with a space in hook_args can be ambiguous if either value contains spaces (e.g., a branch name with a space). While branch names with spaces are rare, Git's pre-rebase hook provides them as separate arguments to preserve boundaries. If the downstream consumer of hook_args splits by space, this implementation might fail for complex ref names. Additionally, since run takes ownership of self, you can avoid the clone by moving self.upstream in the None case.
| let args = match &self.branch { | |
| Some(b) => format!("{} {}", self.upstream, b), | |
| None => self.upstream.clone(), | |
| }; | |
| let args = match self.branch { | |
| Some(b) => format!("{} {}", self.upstream, b), | |
| None => self.upstream, | |
| }; |
### 🐛 Bug Fixes - **(git)** skip untracked scan when HK_STASH_UNTRACKED=false by [@jdx](https://github.com/jdx) in [#861](#861) - **(run)** add post-commit and pre-rebase subcommands by [@jdx](https://github.com/jdx) in [#858](#858) ### 📚 Documentation - **(install)** recommend global hooks as primary setup path by [@jdx](https://github.com/jdx) in [#855](#855) - add cross-site announcement banner by [@jdx](https://github.com/jdx) in [#857](#857) - respect banner expires field by [@jdx](https://github.com/jdx) in [#862](#862) ### 🔍 Other Changes - vendor bats test helpers instead of git submodules by [@jdx](https://github.com/jdx) in [#859](#859) ### 📦️ Dependency Updates - bump communique to 1.0.3 by [@jdx](https://github.com/jdx) in [#863](#863) - update anthropics/claude-code-action digest to e58dfa5 by [@renovate[bot]](https://github.com/renovate[bot]) in [#864](#864) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk release bookkeeping only: version numbers, generated CLI/docs, and lockfile dependency bumps with no runtime logic changes. > > **Overview** > **Release prep for `v1.44.1`.** Updates `Cargo.toml`/`Cargo.lock` (including `libc`) and all version references in generated CLI docs (`docs/cli/*`, `hk.usage.kdl`). > > Refreshes documentation examples to reference the new `v1.44.1` Pkl package URLs and adds the `1.44.1` entry to `CHANGELOG.md`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d7637d4. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: mise-en-dev <[email protected]>
Summary
hk install(andhk install --global) writes hookcmds for nine git events, buthk runonly ships typed subcommand handlers for seven.post-commitandpre-rebasefell through to theothercatch-all, which works but:hk run --helpHookOptions::files(the positional collector) rather than named arguments, so usage is opaqueThis adds dedicated handlers so every event listed in `DEFAULT_GLOBAL_EVENTS` has a named handler, matching the pattern of the other seven hooks.
Changes
Test plan
Repro
Before this patch, a stale `--from-hook` hookcmd from a previous `hk install` + downgraded hk binary produced:
```
$ git rebase origin/main
Usage: hk run --from-ref <FROM_REF> [FILES]...
error: The pre-rebase hook refused to rebase.
```
With named handlers, the hookcmd parses cleanly regardless of hk version skew.
🤖 Generated with Claude Code
Note
Low Risk
Low risk: adds two new
hk runsubcommand handlers and only affects CLI parsing/dispatch for these hooks, without changing hook execution logic beyond howhook_argsis populated.Overview
hk runnow has dedicated subcommands forpost-commitandpre-rebase, so they appear in--helpand don’t fall through to the genericotherhandler.post-commitruns with emptyhook_args, andpre-rebaseadds typed<upstream> [branch]parsing and passes those values viahook_argsbefore invoking the corresponding hook.Reviewed by Cursor Bugbot for commit 55f5778. Bugbot is set up for automated code reviews on this repo. Configure here.