A hand-written pre-push delegate with this command's own lines is adopted, a copy that drifted from the binary's text is reported by hooks --identity and refused by no-stale-hook-pins, and a probe can push an empty range through the hooks git runs - #207
Conversation
…pted, a copy that drifted from the binary's text is reported by hooks --identity and refused by no-stale-hook-pins, and a probe can push an empty range through the hooks git runs Thirteen consumer trees carried the pre-push delegate by hand before `hooks --install` existed, ten byte-identical and three wrapped at a different word, none with the marker the command writes, and one superproject kept a script whose only job was to notice when a copy drifted. `--adopt` compares an unmarked file's effective lines, the shebang and every line that is not a comment with continuations joined and whitespace collapsed, against the text the command would write: equal lines are rewritten with the marker and reported as adopted, and lines that differ are refused with a unified diff of the two, because a hook that does something else is somebody's decision. `--check` reports each of the four files and whether core.hooksPath points git at them, and writes nothing. The delegate is now a hook declaration. `pins::declarations` reads it from the directory core.hooksPath names, under the id `pre-push` and the manager `git`, with a body that says whether its effective lines are the ones this binary writes for prek or pre-commit. `hooks --identity` reports a copy that is not as `drifted`, a fourth finding beside forked, pinned apart and absent, and waivable like them, because a fleet whose every copy agrees can still be a fleet on an older release's text and the forked finding would call that agreement. `no-stale-hook-pins` reads the same file through the same reader and refuses a drifted copy at pre-push; a hand-written copy with the same lines passes with a note naming `--adopt`. `[[probe]]` takes `push = "empty"`. Instead of `<runner> run <id>` the probe makes a throwaway bare remote under `<owner>/<repo>.git`, brings it to the worktree's tip with a push that skips the hooks, and pushes to it again through the hooks git runs, named on the command line with -c so nothing is added to the repository's config. Measured 2026-09-20 on git 2.55.0, an up-to-date push starts the pre-push hook with the remote on argv and nothing on stdin, so the delegate is what runs and the destination is what it judges; `refuses` and `allows` therefore name destinations rather than files, and the six verdicts and `expect` apply as they do to a runner probe. A tree with no delegate reports the push as accepted, which is the state the delegate exists to end. This repository runs lefthook and installs no delegate, so the probe lives in tests/probe_cli.rs as a fixture rather than in its own policy/hooks.toml. Closes #199
|
Warning Review limit reachedNext included review available in 59 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (9)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
❌ Your patch status has failed because the patch coverage (93.43%) is below the target coverage (100.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #207 +/- ##
==========================================
+ Coverage 93.63% 93.74% +0.10%
==========================================
Files 44 44
Lines 17057 17561 +504
==========================================
+ Hits 15971 16462 +491
- Misses 1086 1099 +13 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Closes #199.
What is now true
hooks --install --adoptand--check. An unmarked file in the hooksdirectory is compared with the text the command would write by its effective
lines: the shebang and every line that is not a comment, a line ending in
\joined to the next, whitespace runs collapsed. That is exactly the difference
between the thirteen hand-written copies and the written text (ten
byte-identical, three wrapped at a different word on the last command).
Equal lines: the file is rewritten with the marker and reported
adopted.Different lines: exit 2 with a unified diff, file untouched. Without
--adoptthe existing refusal stands and now names
--adopt.--checkwrites nothingand reports each of the four files (absent / written by this command and
matching / written by this command and not matching / hand-written and
adoptable / hand-written and different, with the diff) plus whether
core.hooksPathpoints at the directory; exit 0 only when all four match andgit runs them.
The delegate is a hook declaration.
pins::declarationsreads<core.hooksPath or .githooks>/pre-pushas idpre-push, managergit,with a body naming the runner whose written text it matches (or that it
matches neither) and a fingerprint of the effective lines.
hooks --identitygains a fourth finding,
drifted, reported per repository and waivable likethe others; it exists because a fleet whose copies all agree can still be a
fleet on an older release's text, which
forkedwould call agreement.no-stale-hook-pinsreads the same file throughhooks::delegateandrefuses a drifted copy (exit 1) at the stage it runs; a hand-written copy with
the same lines passes with a note naming
--adopt.[[probe]]withpush = "empty". The probe makes a bare remote under<owner>/<repo>.git, seeds it to the worktree's tip with--no-verify, thenpushes
HEAD:refs/heads/probeto it again through the hooks git runs, namingthe remote with
-cso nothing is added to the repository's config. Measuredon git 2.55.0: an up-to-date push starts the pre-push hook with the remote on
argv and nothing on stdin, so the delegate is what runs and the destination is
what it judges.
refusesandallowstherefore name destinations(
owner/repo) rather than file contents;pathandstagebesidepusharerefused at load, as is any
pushvalue but"empty". The six verdicts andexpectapply unchanged. A tree with no delegate reports the push asACCEPTED, which is the finding.
This repository runs lefthook and installs no delegate, so the probe is a
tests/probe_cli.rsfixture rather than an entry in its ownpolicy/hooks.toml.Tests
tests/hooks_install_cli.rs: adopt of the fleet's verbatim hand-writtentext; a drifted copy refused with the diff and untouched; no
--adoptstillrefused;
--checkstates and exit codes;--adopt --checkis a usage error.tests/hooks_identity_cli.rs: two installed copies agree and a drifted oneis
drifted; a hand-written copy agrees with an installed one; the delegateis read from where
core.hooksPathpoints;driftedis waivable.tests/hook_pins_cli.rs: a matching delegate passes, a drifted one isrefused at exit 1; a hand-written copy passes with the adopt note.
tests/probe_cli.rs: the empty-range push reaches the delegate andprevent-public-push(demonstrated); no delegate means ACCEPTED; a refusalfrom elsewhere (no
upholdon PATH) is not the guard; the three load-timerefusals; a runner probe without
pathis refused.effective_lines,unified_diff, the fingerprint andis_destination.cargo test: 917 passed, 0 failed.cargo clippy --all-targets -- -D warnings,cargo run -- check,cargo run -- scanandbuild_reference.py --checkallclean.