* git hook question @ 2026-05-29 5:01 Wesley Schwengle 2026-05-29 5:21 ` Jeff King 0 siblings, 1 reply; 10+ messages in thread From: Wesley Schwengle @ 2026-05-29 5:01 UTC (permalink / raw) To: Git maillinglist Hello, I added the following to my gitconfig: hook.npm-test.event=pre-push hook.npm-test.command=npm run test This works well when I run `git hook run pre-push' but when using `git push' this breaks a little because it adds the remote and the location, as seen via `GIT_TRACE=1 git push origin': 00:46:53.714453 run-command.c:673 trace: run_command: 'npm run test' origin git@gitlab.com:waterkip/mything.git 00:46:53.714458 run-command.c:765 trace: start_command: /bin/sh -c 'npm run test "$@"' 'npm run test' origin git@gitlab.com:waterkip/mything.git I understand the why, normally pre-push gets `<local-ref> SP <local-object-name> SP <remote-ref> SP <remote-object-name> LF'. This has a similar feel, albeit a different syntax. The difference feels like a minor bug, but not one I'm worried about at this moment: you would expect it to get the same arguments/parameters as the regular pre-push hook. But I digress. My actual question is: Is there a way to tell the hook "Don't give me arguments, just run the plain command that is defined". I looked in `man 1 git-hook', but I was unable to find something that looks like it. Cheers, Wesley -- Wesley Schwengle ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: git hook question 2026-05-29 5:01 git hook question Wesley Schwengle @ 2026-05-29 5:21 ` Jeff King 2026-05-29 16:11 ` Wesley Schwengle 2026-06-01 5:33 ` Junio C Hamano 0 siblings, 2 replies; 10+ messages in thread From: Jeff King @ 2026-05-29 5:21 UTC (permalink / raw) To: Wesley Schwengle; +Cc: Git maillinglist On Fri, May 29, 2026 at 01:01:34AM -0400, Wesley Schwengle wrote: > I understand the why, normally pre-push gets `<local-ref> SP > <local-object-name> SP <remote-ref> SP <remote-object-name> LF'. This has a > similar feel, albeit a different syntax. The difference feels like a minor > bug, but not one I'm worried about at this moment: you would expect it to > get the same arguments/parameters as the regular pre-push hook. But I > digress. I think the "git hook" command is mostly intended for scripting, and the caller is expected to understand the context and provide the appropriate arguments. The hook command itself doesn't know about what a "pre-push" hook should look like. So not a bug, but definitely a gotcha that could perhaps be better explained in the documentation. > My actual question is: Is there a way to tell the hook "Don't give me > arguments, just run the plain command that is defined". I looked in `man 1 > git-hook', but I was unable to find something that looks like it. I don't think so; the command is expected to handle (or ignore) the arguments as appropriate. You could obviously write a wrapper script to handle that, but since hook commands are run with a shell you can inline it, like: git config hook.npm-test.command 'npm run test #' Git will paste together the shell command: npm run test # "$@" which then treats everything after the "#" as a comment. The more general form of this trick is to use a shell function, like: f() { your_cmd_here; }; f which would do what you want, but also let you access the arguments however you like. For example: f() { some_cmd "$1"; another_cmd "$2"; }; f would let you consider the arguments independently. But for your purposes, using "#" to ignore them is simpler to write. -Peff ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: git hook question 2026-05-29 5:21 ` Jeff King @ 2026-05-29 16:11 ` Wesley Schwengle 2026-05-29 16:22 ` Wesley ` (2 more replies) 2026-06-01 5:33 ` Junio C Hamano 1 sibling, 3 replies; 10+ messages in thread From: Wesley Schwengle @ 2026-05-29 16:11 UTC (permalink / raw) To: Jeff King; +Cc: Git maillinglist On 5/29/26 01:21, Jeff King wrote: > On Fri, May 29, 2026 at 01:01:34AM -0400, Wesley Schwengle wrote: > >> I understand the why, normally pre-push gets `<local-ref> SP >> <local-object-name> SP <remote-ref> SP <remote-object-name> LF'. This has a >> similar feel, albeit a different syntax. The difference feels like a minor >> bug, but not one I'm worried about at this moment: you would expect it to >> get the same arguments/parameters as the regular pre-push hook. But I >> digress. > > I think the "git hook" command is mostly intended for scripting, and the > caller is expected to understand the context and provide the appropriate > arguments. The hook command itself doesn't know about what a "pre-push" > hook should look like. > > So not a bug, but definitely a gotcha that could perhaps be better > explained in the documentation. I think the "normal" pre-push makes more sense than the one I'm seeing right now, but perhaps that's me. But I think that the docs would perhaps need an update to why this `remote url' are the arguments. Especially if you read `githooks(5)' it seems a little strange. >> My actual question is: Is there a way to tell the hook "Don't give me >> arguments, just run the plain command that is defined". I looked in `man 1 >> git-hook', but I was unable to find something that looks like it. > > I don't think so; the command is expected to handle (or ignore) the > arguments as appropriate. You could obviously write a wrapper script to > handle that, but since hook commands are run with a shell you can inline > it, like: > > git config hook.npm-test.command 'npm run test #' > > Git will paste together the shell command: > > npm run test # "$@" That doesn't work on my side: $ cat ~/.config/git/js.config && git config --get hook.npm-test.command && GIT_TRACE=1 git poh [hook "npm-test"] event = pre-push command = npm run test # enabled = true npm run test [snip, alias expansion] 11:49:46.746800 run-command.c:673 trace: run_command: git push origin HEAD 11:49:46.746811 run-command.c:765 trace: start_command: /home/wesleys/.local/libexec/git-core/git push origin HEAD 11:49:46.749640 git.c:502 trace: built-in: git push origin HEAD 11:49:46.752107 run-command.c:673 trace: run_command: unset GIT_PREFIX; ssh git@gitlab.com 'git-receive-pack '\''some/repo'\''' 11:49:46.752135 run-command.c:765 trace: start_command: /usr/bin/ssh git@gitlab.com 'git-receive-pack '\''some/repo'\''' 11:49:47.549946 run-command.c:1576 run_processes_parallel: preparing to run up to 1 tasks 11:49:47.549988 run-command.c:673 trace: run_command: 'npm run test' origin git@gitlab.com:some/repo 11:49:47.550012 run-command.c:765 trace: start_command: /bin/sh -c 'npm run test "$@"' 'npm run test' origin git@gitlab.com:some/repo > @skirbi/semtic@0.0.18 test > tap origin git@gitlab.com:some/repo No valid test files found matching "origin" "git@gitlab.com:some/repo" 11:49:48.145805 run-command.c:1604 run_processes_parallel: done error: failed to push some refs to 'gitlab.com:some/repo' > The more > general form of this trick is to use a shell function, like: > > f() { your_cmd_here; }; f Also seems to fail: [hook "npm-test"] event = pre-push command = git npm-test enabled = true [alias] npm-test = !f() { npm run test; }; f 11:53:14.678237 run-command.c:673 trace: run_command: 'f() { npm run test' origin git@gitlab.com:some/repo 11:53:14.678248 run-command.c:765 trace: start_command: /bin/sh -c 'f() { npm run test "$@"' 'f() { npm run test' origin git@gitlab.com:some/repo f() { npm run test: 1: Syntax error: end of file unexpected (expecting "}") The wrapper script seems the only viable solution. I do think it's a little annoying, because any linter, tester, thing that gets called by this infra now needs to add wrappers. Which means you either need to start making a githook repo for all the tests that you have. The following circles back a little to the first response. Tt kind of diverges from `git hook run pre-push' and how additional arguments are given on the command line with that invocation. Wrappers need to become aware on way it is called, either via hook or via a manual way, because of the `remote url' that gets added. Normal hooks get that info via their STDIN, wouldn't this also make sense for these type of hooks? It makes differentiation much easier. Cheers, Wesley -- Wesley Schwengle ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: git hook question 2026-05-29 16:11 ` Wesley Schwengle @ 2026-05-29 16:22 ` Wesley 2026-05-29 17:52 ` Ben Knoble 2026-05-29 19:23 ` Jeff King 2 siblings, 0 replies; 10+ messages in thread From: Wesley @ 2026-05-29 16:22 UTC (permalink / raw) To: Jeff King; +Cc: Git maillinglist On 5/29/26 12:11, Wesley Schwengle wrote: >> Git will paste together the shell command: >> >> npm run test # "$@" > > That doesn't work on my side: > > $ cat ~/.config/git/js.config && git config --get hook.npm-test.command > && GIT_TRACE=1 git poh > [hook "npm-test"] > event = pre-push > command = npm run test # > enabled = true > npm run test It does work with: `command = npm run test "#"' Small oversight. Cheers, Wesley -- Wesley Why not both? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: git hook question 2026-05-29 16:11 ` Wesley Schwengle 2026-05-29 16:22 ` Wesley @ 2026-05-29 17:52 ` Ben Knoble 2026-05-29 19:23 ` Jeff King 2 siblings, 0 replies; 10+ messages in thread From: Ben Knoble @ 2026-05-29 17:52 UTC (permalink / raw) To: Wesley Schwengle; +Cc: Jeff King, Git maillinglist > Le 29 mai 2026 à 12:17, Wesley Schwengle <wesleys@opperschaap.net> a écrit : > > On 5/29/26 01:21, Jeff King wrote: >>> On Fri, May 29, 2026 at 01:01:34AM -0400, Wesley Schwengle wrote: >>> I understand the why, normally pre-push gets `<local-ref> SP >>> <local-object-name> SP <remote-ref> SP <remote-object-name> LF'. This has a >>> similar feel, albeit a different syntax. The difference feels like a minor >>> bug, but not one I'm worried about at this moment: you would expect it to >>> get the same arguments/parameters as the regular pre-push hook. But I >>> digress. >> I think the "git hook" command is mostly intended for scripting, and the >> caller is expected to understand the context and provide the appropriate >> arguments. The hook command itself doesn't know about what a "pre-push" >> hook should look like. >> So not a bug, but definitely a gotcha that could perhaps be better >> explained in the documentation. > > I think the "normal" pre-push makes more sense than the one I'm seeing right now, but perhaps that's me. But I think that the docs would perhaps need an update to why this `remote url' are the arguments. Especially if you read `githooks(5)' it seems a little strange. The hooks manual says that the pre-push hook is invoked with 2 parameters (name and location of the destination). ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: git hook question 2026-05-29 16:11 ` Wesley Schwengle 2026-05-29 16:22 ` Wesley 2026-05-29 17:52 ` Ben Knoble @ 2026-05-29 19:23 ` Jeff King [not found] ` <4d938e1e-fdd3-42d6-a879-4d394ee8c00d@opperschaap.net> 2 siblings, 1 reply; 10+ messages in thread From: Jeff King @ 2026-05-29 19:23 UTC (permalink / raw) To: Wesley Schwengle; +Cc: Git maillinglist On Fri, May 29, 2026 at 12:11:59PM -0400, Wesley Schwengle wrote: > > git config hook.npm-test.command 'npm run test #' > > > > Git will paste together the shell command: > > > > npm run test # "$@" > > That doesn't work on my side: > > $ cat ~/.config/git/js.config && git config --get hook.npm-test.command && > GIT_TRACE=1 git poh > [hook "npm-test"] > event = pre-push > command = npm run test # > enabled = true The "#" is being eaten by the config parser as a comment, so the value is effectively the same as what you originally had. As you noticed, putting it in double-quotes fixes that, though I'd probably do the whole thing for readability like: command = "npm run test #" Which is also what "git config" would write with the command I showed above. > Also seems to fail: > > [hook "npm-test"] > event = pre-push > command = git npm-test > enabled = true > > [alias] > npm-test = !f() { npm run test; }; f This is also a config quoting problem. Both "#" and semicolon begin comments. Putting the whole thing in double-quotes works. > The following circles back a little to the first response. > > Tt kind of diverges from `git hook run pre-push' and how additional > arguments are given on the command line with that invocation. Wrappers need > to become aware on way it is called, either via hook or via a manual way, > because of the `remote url' that gets added. I don't think the hooks themselves should need to be aware. If somebody is calling "git hook run pre-push" without providing arguments, they are breaking the contract to the hooks. You can get away with it if you know your particular hooks do not care about those arguments, but in the general case, what should a pre-push hook that _does_ care about the remote name do when it doesn't get any arguments? It's an error. I guess there's a more fundamental question: why are you running "git hook" in the first place? If it is just to test out your hooks, that's fine. But to make the test more realistic, you may want to give it arguments (and stdin input) to match the specific hook you're testing. > Normal hooks get that info via their STDIN, wouldn't this also make sense > for these type of hooks? It makes differentiation much easier. Usually we pass fixed-size information via arguments, and arbitrary-sized information over stdin. In pre-push you have the joy of dealing with both. So your "npm run test" hook is also going to have its stdin hooked up to a pipe with the ref updates sent over it. That might be OK if it never reads from stdin, but it may also cause some surprises depending on what the "test" target runs under the hood. So whether you are getting input as arguments or over stdin, it's probably something the hook needs to deal with (or at least think about). -Peff ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <4d938e1e-fdd3-42d6-a879-4d394ee8c00d@opperschaap.net>]
* Re: git hook question [not found] ` <4d938e1e-fdd3-42d6-a879-4d394ee8c00d@opperschaap.net> @ 2026-05-29 21:00 ` Jeff King 2026-06-03 13:07 ` Adrian Ratiu 0 siblings, 1 reply; 10+ messages in thread From: Jeff King @ 2026-05-29 21:00 UTC (permalink / raw) To: Wesley Schwengle; +Cc: Adrian Ratiu, git [re-adding list cc; let's let everyone benefit from the discussion] On Fri, May 29, 2026 at 04:14:33PM -0400, Wesley Schwengle wrote: > > I don't think the hooks themselves should need to be aware. If somebody > > is calling "git hook run pre-push" without providing arguments, they are > > breaking the contract to the hooks. You can get away with it if you know > > your particular hooks do not care about those arguments, but in the > > general case, what should a pre-push hook that _does_ care about the > > remote name do when it doesn't get any arguments? It's an error. > > Are they? The manual says this: > > git hook run has been designed to make it easy for tools which wrap Git to > configure and execute hooks using the Git hook infrastructure. It is > possible to provide arguments and stdin via the command line, as well as > specifying parallel or series execution if the user has provided multiple > hooks. > > Assuming your wrapper wants to support a hook named > "mywrapper-start-tests", you can have your users specify their hooks like > so: > > [hook "setup-test-dashboard"] > event = mywrapper-start-tests > command = ~/mywrapper/setup-dashboard.py --tap > > Then, in your mywrapper tool, you can invoke any users' configured > hooks by running: > > git hook run --allow-unknown-hook-name mywrapper-start-tests \ > # providing something to stdin > --stdin some-tempfile-123 \ > # execute multiple hooks in parallel > --jobs 3 \ > # plus some arguments of your own... > -- \ > --testname bar \ > baz > > There is nothing about the contract of the hook, in fact, the way it is > written there isn't really a contract. This is a made-up hook, so it is up to the person defining mywrapper-start-tests to define that contract. And in this example, implicitly it takes whatever is in some-tempfile-123 on stdin, and --testname as an argument. What those mean would need to be communicated between the script invoking "git hook" and whoever is configuring hooks. I agree that is not made very clear in the documentation, though. > > So whether you are getting input as arguments or over stdin, it's > > probably something the hook needs to deal with (or at least think > > about). > > Right. I see where this is going. That means I think the examples in the > manual are incorrect, no, that's harsh, it could be stated more clearly in > git-hook(1). > > Examples like this: > > > [hook "linter"] > > event = pre-commit > > command = ~/bin/linter --cpp20 > > seem to indicate: Any script can be run as a hook, the fact it needs to > respect the native hook structure isn't mentioned. This is mentioned: That example is OK-ish, in the sense that pre-commit does not take any arguments or receive anything on stdin. So you really can invoke whatever program you like (though it needs to understand how to use Git commands to look at what is staged in the index). So the details of "~/bin/linter" are doing a lot of the heavy lifting here, which is left unsaid. But the later example that adds "event = pre-push" is actively misleading. How does the ~/bin/linter script even know in which context it's being run? In the real world you are more likely to invoke a script that is aware it is a Git hook and can react accordingly. So I suspect there is a lot of room for expanding the documentation and explaining some of these gotchas. +cc Adrian, who wrote these docs, for visibility. -Peff ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: git hook question 2026-05-29 21:00 ` Jeff King @ 2026-06-03 13:07 ` Adrian Ratiu 0 siblings, 0 replies; 10+ messages in thread From: Adrian Ratiu @ 2026-06-03 13:07 UTC (permalink / raw) To: Jeff King, Wesley Schwengle; +Cc: git On Fri, 29 May 2026, Jeff King <peff@peff.net> wrote: > [re-adding list cc; let's let everyone benefit from the discussion] > > On Fri, May 29, 2026 at 04:14:33PM -0400, Wesley Schwengle wrote: > >> > I don't think the hooks themselves should need to be aware. If somebody >> > is calling "git hook run pre-push" without providing arguments, they are >> > breaking the contract to the hooks. You can get away with it if you know >> > your particular hooks do not care about those arguments, but in the >> > general case, what should a pre-push hook that _does_ care about the >> > remote name do when it doesn't get any arguments? It's an error. >> >> Are they? The manual says this: >> >> git hook run has been designed to make it easy for tools which wrap Git to >> configure and execute hooks using the Git hook infrastructure. It is >> possible to provide arguments and stdin via the command line, as well as >> specifying parallel or series execution if the user has provided multiple >> hooks. >> >> Assuming your wrapper wants to support a hook named >> "mywrapper-start-tests", you can have your users specify their hooks like >> so: >> >> [hook "setup-test-dashboard"] >> event = mywrapper-start-tests >> command = ~/mywrapper/setup-dashboard.py --tap >> >> Then, in your mywrapper tool, you can invoke any users' configured >> hooks by running: >> >> git hook run --allow-unknown-hook-name mywrapper-start-tests \ >> # providing something to stdin >> --stdin some-tempfile-123 \ >> # execute multiple hooks in parallel >> --jobs 3 \ >> # plus some arguments of your own... >> -- \ >> --testname bar \ >> baz >> >> There is nothing about the contract of the hook, in fact, the way it is >> written there isn't really a contract. > > This is a made-up hook, so it is up to the person defining > mywrapper-start-tests to define that contract. And in this example, > implicitly it takes whatever is in some-tempfile-123 on stdin, and > --testname as an argument. What those mean would need to be communicated > between the script invoking "git hook" and whoever is configuring hooks. > > I agree that is not made very clear in the documentation, though. > >> > So whether you are getting input as arguments or over stdin, it's >> > probably something the hook needs to deal with (or at least think >> > about). >> >> Right. I see where this is going. That means I think the examples in the >> manual are incorrect, no, that's harsh, it could be stated more clearly in >> git-hook(1). >> >> Examples like this: >> >> > [hook "linter"] >> > event = pre-commit >> > command = ~/bin/linter --cpp20 >> >> seem to indicate: Any script can be run as a hook, the fact it needs to >> respect the native hook structure isn't mentioned. This is mentioned: > > That example is OK-ish, in the sense that pre-commit does not take any > arguments or receive anything on stdin. So you really can invoke > whatever program you like (though it needs to understand how to use Git > commands to look at what is staged in the index). So the details of > "~/bin/linter" are doing a lot of the heavy lifting here, which is left > unsaid. > > But the later example that adds "event = pre-push" is actively > misleading. How does the ~/bin/linter script even know in which context > it's being run? In the real world you are more likely to invoke a script > that is aware it is a Git hook and can react accordingly. > > So I suspect there is a lot of room for expanding the documentation and > explaining some of these gotchas. +cc Adrian, who wrote these docs, for > visibility. Yes, there is a lot of room for improvements everywhere, especially in the documentation. Patches are very much welcome to expand on or correct hook-related issues. :) BTW the git hook command is also just a very basic tool for testing, it needs much attention and more additions. It is obviously not feature-complete or bug-free. Some historical context for the curious: This area of work was blocked for almost a decade because people tried to find a perfect/complete solution in one go, with complex patch series reaching even 36-38 review iterations for a single series which went nowhere, was regressing, was hard to review, you get the idea. So I tried to enable a simplified incremental development approach, reusing existing APIs & mechanisms, to allow more people to contribute smaller patches which are also easier to review, test and so on. P.S: This also reminds me, I don't think it's documented anywhere that the proc-receive hook is not using hook.[ch], so it cannot be specified via configs yet like pre-receive and other similar server hooks. I actually have a collegue at Collabora working on converting proc-receive so we can remove some deprecated APIs and also clean up some external hook_exists() calls which are now redundant because they are handled by the unified hook.c implementation. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: git hook question 2026-05-29 5:21 ` Jeff King 2026-05-29 16:11 ` Wesley Schwengle @ 2026-06-01 5:33 ` Junio C Hamano 2026-06-01 5:55 ` Jeff King 1 sibling, 1 reply; 10+ messages in thread From: Junio C Hamano @ 2026-06-01 5:33 UTC (permalink / raw) To: Jeff King; +Cc: Wesley Schwengle, Git maillinglist Jeff King <peff@peff.net> writes: > I don't think so; the command is expected to handle (or ignore) the > arguments as appropriate. We should also caution that the command is expected to handle not just the arguments but its standard input. Not reading any and exiting may be a no-no for some hooks. And unlike command line arguments, there is no handy way to say "I do not care what the input is" (other than putting "cat >/dev/null;" in front of what you really want to do, that is). ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: git hook question 2026-06-01 5:33 ` Junio C Hamano @ 2026-06-01 5:55 ` Jeff King 0 siblings, 0 replies; 10+ messages in thread From: Jeff King @ 2026-06-01 5:55 UTC (permalink / raw) To: Junio C Hamano; +Cc: Wesley Schwengle, Git maillinglist On Mon, Jun 01, 2026 at 02:33:13PM +0900, Junio C Hamano wrote: > Jeff King <peff@peff.net> writes: > > > I don't think so; the command is expected to handle (or ignore) the > > arguments as appropriate. > > We should also caution that the command is expected to handle not > just the arguments but its standard input. Not reading any and > exiting may be a no-no for some hooks. Perhaps. I think we've tried to make Git resilient to hooks which do not read all of their input (by ignoring SIGPIPE). It may be a bug for a hook to ignore stdin, but depending on what the hook is trying to do, that information might or might not be relevant. I do think there is a gotcha for hooks that expect the stdin of their commands to be hooked up to a terminal to interact with the user. I certainly don't have any objection to calling more of this out in the docs, though. -Peff ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-06-03 13:07 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-29 5:01 git hook question Wesley Schwengle
2026-05-29 5:21 ` Jeff King
2026-05-29 16:11 ` Wesley Schwengle
2026-05-29 16:22 ` Wesley
2026-05-29 17:52 ` Ben Knoble
2026-05-29 19:23 ` Jeff King
[not found] ` <4d938e1e-fdd3-42d6-a879-4d394ee8c00d@opperschaap.net>
2026-05-29 21:00 ` Jeff King
2026-06-03 13:07 ` Adrian Ratiu
2026-06-01 5:33 ` Junio C Hamano
2026-06-01 5:55 ` Jeff King
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox