Subject: Re: [PATCH v3 8/9] hook: introduce extensions.hookStdoutToStderr

From: Adrian Ratiu <[email-masked]>
Date: Wed, 18 Mar 2026 21:50:08 +0200

On Mon, 16 Mar 2026, Junio C Hamano <[email-masked]> wrote:
> Adrian Ratiu <[email-masked]> writes:
>
>> All hooks already redirect stdout to stderr with the exception of
>> pre-push which has a known user who depends on the separate stdout
>> versus stderr outputs (the git-lfs project).
>>
>> The pre-push behavior was a surprise which we found out about after
>> causing a regression for git-lfs. Notably, it might not be the only
>> exception (it's the one we know about). There might be more.
>>
>> This presents a challenge because stdout_to_stderr is required for
>> hook parallelization, so run-command can buffer and de-interleave
>> the hook outputs using ungroup=0, when hook.jobs > 1.
>>
>> Introduce an extension to enforce consistency: all hooks merge stdout
>> into stderr and can be safely parallelized. This provides a clean
>> separation and avoids breaking existing stdout vs stderr behavior.
>>
>> When this extension is disabled, the `hook.jobs` config has no
>> effect for pre-push, to prevent garbled (interleaved) parallel
>> output, so it runs sequentially like before.
>>
>> Alternatives I've considered to this extension include:
>> 1. Allowing pre-push to run in parallel with interleaved output.
>> 2. Always running pre-push sequentially (no parallel jobs for it).
>> 3. Making users (only git-lfs? maybe more?) fix their hooks to read
>>    stderr not stdout.
>>
>> Out of all these alternatives, I think this extension is the most
>> reasonable compromise, to not break existing users, allow pre-push
>> parallel jobs for those who need it (with correct outputs) and also
>> future-proofing in case there are any more exceptions to be added.
>
> Hmph, I am a bit surprised that this is not hook.<name>.stdoutToStderr
> controlled per hook process.

You may laugh at me, but making this a per hook process setting (or
per-event) didn't even occur to me until now. :)

I think we could do this and let the user decide if their hooks are safe
or not (i.e. do they expect output on stdout?)

Or even better:

Since we now default to jobs == 1, that already keeps backwards
compatibility  (initially in v1 I turned parallelism on by default,
using the number of cpus, so this extension was unavoidable).

Therefore if the user opts-in to parallelism (via config or -jN), we can
just document that output will go to stderr instead of stdout.

>
> If we already have consensus that giving output to stdout is a
> historical wart that we would rather want to fix, then this
> configuration is probably good enough.  It is certainly a much
> simpler approach, and there is no need to make finer-grained
> customization available when nobody wants it ;-).

Agreed. I don't think anybody (including myself) wants this extension
and if we do what I suggested above, we can drop it and don't even need
a hook.<name>.stdoutToStderr config.

Will drop this patch and the next one in the re-roll.

>
> We may also want to consider "fixing" it at Git 3.0 boundary, if
> that is the case, though?  I dunno.  I weren't following the
> discussion closely enough to tell myself.

There's only 1 known breaking hook, however now I'm convinced we don't
need to break backwards compatibility with my "even better" approach
suggested above.