Stacked on !233.
pre-receive on a require-signed repository forked a cat-file per
incoming commit and built one JSON message holding every raw commit. A
50k-commit first push forked 50k processes and held the history in memory
twice. One cat-file --batch now serves the push; each commit crosses the
socket as its own value and the daemon verifies it as it arrives.
Two hazards the streaming shape introduces, both tested:
- Object names are fed to git from their own goroutine. 4000 names is past a 64 KiB pipe, so writing them all before reading deadlocks.
- The subprocess runs under a cancelled-on-return context. Without it,
giving up part-way leaves git blocked on a pipe nobody reads and
Waitblocked on git.TestStreamIncomingCommitsCallbackErrorhangs rather than fails without it — I confirmed that by reverting the guard.
The daemon drains the stream to its end before answering even once a commit has failed: answering early would leave the hook writing into a socket nobody reads.
Closes #100
retargeted from retention-sweep to main: !233 merged
2026-09-04 15:58 UTC