git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v2] hook: allow hooks to disable stdout_to_stderr

From
Jeff King <peff@peff.net>
Date
Jan 14, 2026, 17:19 UTC
Message-ID
<20260114171929.GC885771@coredump.intra.peff.net>
In-Reply-To
<20260114170849.GB885771@coredump.intra.peff.net>
On Wed, Jan 14, 2026 at 12:08:49PM -0500, Jeff King wrote:
Show 15 quoted lines
> I looked at what feed_receive_hook_cb() is doing and...it's kind of
> horrifying. It arbitrarily sends 500 lines, and then yields to the
> caller to pump stderr (assuming ungroup=0). So:
> 
>   1. It is assuming that 500 lines of input won't fill up the pipe
>      buffer and block. Even if we compute the size of 500 lines we're
>      sending, we don't know if the caller has cleared anything from the
>      pipe in the last call. There might be zero bytes available!
> 
>   2. After 500 lines we'll go back to the caller, which will then
>      poll(). But if there's nothing to read on stderr, it will wait for
>      the 100ms timeout. So if you have, say, 501 lines to send, then
>      there will be a pointless 100ms pause in the middle.
> 
> So here's an example hook setup that will deadlock due to (1):
And just for fun, here's an example that shows problem (2):

-- >8 -- rm -rf repo git init repo cd repo git commit --allow-empty -m foo git init --bare dst.git

cat >dst.git/hooks/pre-receive <<\EOF #!/bin/sh # We don't even need to do anything interesting here! Git # will send us 500 lines, then block waiting for stderr which # we'll never send, and then send us another batch of 500. cat >/dev/null EOF chmod +x dst.git/hooks/pre-receive

# Now do a moderate push of 500 branches. seq --format='create refs/heads/small-%g HEAD' 500 | git update-ref --stdin time git push -q dst.git refs/heads/small-*

# And compare with one that sends just one more. seq --format='create refs/heads/large-%g HEAD' 501 | git update-ref --stdin time git push -q dst.git refs/heads/large-* -- >8 --

The second push always takes 100ms more! If we run the server side under strace by replacing the final line with this:

  git push -q --receive-pack='strace -T git-receive-pack' dst.git refs/heads/large-*
we can see the stall here as we write to the hook:
  write(4, "00000000000000000000000000000000"..., 51393) = 51393 <0.000011>
  poll([{fd=5, events=POLLIN|POLLHUP}], 1, 100) = 0 (Timeout) <0.100506>
  write(4, "00000000000000000000000000000000"..., 102) = 102 <0.000057>

That would likewise be solved by using ungroup=1 (in which case we do not poll, but just call the feed function immediately again) or by using a real poll() loop (which would see immediately that the hook is ready for more input, rather than hitting the 100ms timeout).

-Peff
Previous: Jeff KingNext: Adrian Ratiu
Message 16 of 30 in “hook: make stdout_to_stderr optional”
  1. hook: make stdout_to_stderr optionalAdrian Ratiu, Jan 13, 2026
  2. Patrick SteinhardtJan 13, 2026
  3. Adrian RatiuJan 13, 2026
  4. Junio C HamanoJan 13, 2026
  5. Junio C HamanoJan 13, 2026
  6. Adrian RatiuJan 13, 2026
  7. Junio C HamanoJan 13, 2026
  8. Adrian RatiuJan 13, 2026
  9. Adrian RatiuJan 13, 2026
  10. hook: allow hooks to disable stdout_to_stderrAdrian Ratiu, Jan 13, 2026
  11. Jeff KingJan 14, 2026
  12. Adrian RatiuJan 14, 2026
  13. Adrian RatiuJan 14, 2026
  14. Kristoffer HaugsbakkJan 14, 2026
  15. Jeff KingJan 14, 2026
  16. Jeff KingJan 14, 2026
  17. Adrian RatiuJan 14, 2026
  18. Kristoffer HaugsbakkJan 14, 2026
  19. 0/2 Fix two hook conversion regressionsAdrian Ratiu, Jan 14, 2026
  20. 2/2 hook: make ungroup opt-out instead of opt-inAdrian Ratiu, Jan 14, 2026
  21. Jeff KingJan 14, 2026
  22. Adrian RatiuJan 14, 2026
  23. Kristoffer HaugsbakkJan 18, 2026
  24. 1/2 hook: allow hooks to disable stdout_to_stderrAdrian Ratiu, Jan 14, 2026
  25. Junio C HamanoJan 15, 2026
  26. Adrian RatiuJan 15, 2026
  27. Junio C HamanoJan 15, 2026
  28. Adrian RatiuJan 15, 2026
  29. Junio C HamanoJan 15, 2026
  30. Adrian RatiuJan 15, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.