feat: add {{ hook_stdin }} for pre-push stdin forwarding#825
Conversation
There was a problem hiding this comment.
Code Review
This pull request enables the pre-push hook to capture standard input and expose it through the hook_stdin template variable. The changes include updating the PrePush execution logic to store stdin in the template context and adding a BATS test suite to verify the functionality with git references and git-lfs. I have no feedback to provide.
Greptile SummaryImplements Confidence Score: 5/5Safe to merge — the Rust implementation is correct and the only finding is a P2 test-portability concern in the LFS bats test. Both Rust changes are correct: Tera serialises on insert so there is no borrow/lifetime issue, the terminal guard is consistent with existing code, and post_rewrite now properly captures stdin for rebase/amend. The single P2 finding (missing test/hook_stdin.bats — specifically the Important Files Changed
Sequence DiagramsequenceDiagram
participant Git
participant hk as hk pre-push/post-rewrite
participant Tera as Template Engine
participant Step as Step Command
Git->>hk: invoke hook (ref data via stdin)
hk->>hk: is_terminal()?
alt stdin is a terminal (no pipe)
hk->>Tera: insert("hook_stdin", "")
else stdin is piped
hk->>hk: read_to_string(&mut input)
hk->>Tera: insert("hook_stdin", &input)
end
hk->>Tera: render step config (stdin = "{{ hook_stdin }}")
Tera-->>hk: rendered stdin string
hk->>Step: execute with rendered stdin piped in
Step-->>hk: exit code
hk-->>Git: exit code
Reviews (2): Last reviewed commit: "feat: add {{ hook_stdin }} for pre-push ..." | Re-trigger Greptile |
| self.hook.tctx.insert("hook_stdin", ""); | ||
| vec![] | ||
| } else { | ||
| let mut input = String::new(); | ||
| std::io::stdin().read_to_string(&mut input)?; | ||
| self.hook.tctx.insert("hook_stdin", &input); |
There was a problem hiding this comment.
hook_stdin not initialised for non-pre-push hooks
hook_args is always available — it's set to "" in every dedicated handler and in the mod.rs fallback (self.hook.tctx.insert("hook_args", "")). hook_stdin is only inserted here, so using {{ hook_stdin }} in any other hook (e.g. pre-commit) will cause a Tera template-rendering error rather than silently expanding to an empty string. Adding self.hook.tctx.insert("hook_stdin", ""); to mod.rs's fallback branch (and to the other dedicated handlers) would make the variable consistently available everywhere, matching the hook_args pattern.
There was a problem hiding this comment.
Good catch! After checking the git source code, only 3 hook types actually receive stdin via feed_pipe or path_to_stdin:
| Hook | Stdin format | Source |
|---|---|---|
| pre-push | <local-ref> <local-sha> <remote-ref> <remote-sha> per ref |
transport.c:1325 |
| post-rewrite (amend) | <old-sha> <new-sha> single line |
sequencer.c:1313 |
| post-rewrite (rebase) | <old-sha> <new-sha> per rewritten commit |
sequencer.c:5175 |
| reference-transaction | <old-oid> <new-oid> <ref-name> per ref |
refs.c:2614 |
All other hooks (pre-commit, commit-msg, prepare-commit-msg, post-checkout, post-merge, post-commit) receive no stdin.
Among git-lfs hooks, only pre-push reads stdin.
So rather than initializing hook_stdin to "" everywhere, let's only set it in pre_push.rs and post_rewrite.rs. {{ hook_stdin }} in any other hook will produce a Tera error, which is the correct behavior (the variable genuinely doesn't exist there).
reference-transaction can get a dedicated handler later if needed. I see it's currently not supported yet.
263212a to
d975c66
Compare
Hey again! Thank you very much for merging and releasing #807! It's been working great with almost all
git lfshooks. There's one I missed in my original PR:pre-push. While{{ hook_args }}solved positional argument forwarding,git lfs pre-pushalso needs stdin.gitpipes ref data through it so LFS knows which objects to upload.Currently, hk's
PrePushhandler consumes stdin for its own ref resolution, leaving nothing for step commands. This PR preserves the raw stdin as{{ hook_stdin }}so steps can pipe it via the existingstdinfield.The problem
git lfs pre-pushreceives ref data via stdin:refs/heads/main refs/heads/main
Without it,
git lfs pre-pushexits 0 silently and uploads nothing. The remote then rejects the push:After the fix
Steps to reproduce locally
Usage