hook: allow separate std[out|err] streams

The hook API assumes that all hooks merge stdout to stderr. This assumption is proven wrong by pre-push: some of its users actually expect separate stdout and stderr streams and merging them will cause a regression. Therefore this adds a mechanism to allow pre-push to separate the streams, which will be used in the next commit. The mechanism is generic via struct run_hooks_opt just in case there are any more surprise exceptions like this. Reported-by: Chris Darroch <chrisd@apache.org> Suggested-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Adrian Ratiu committed Jan 28, 2026 at 23:39 UTC d816637f6c253e3829c4c6e817c7749b3a4f8bf4
2 files changed +11 -1
hook.c
+1 -1
@@ -81,7 +81,7 @@ static int pick_next_hook(struct child_process *cp,
81 cp->in = -1;
82 }
83
84 - cp->stdout_to_stderr = 1;
84 + cp->stdout_to_stderr = hook_cb->options->stdout_to_stderr;
85 cp->trace2_hook_name = hook_cb->hook_name;
86 cp->dir = hook_cb->options->dir;
87
hook.h
+10
@@ -34,6 +34,15 @@ struct run_hooks_opt
34 */
35 int *invoked_hook;
36
37 + /**
38 + * Send the hook's stdout to stderr.
39 + *
40 + * This is the default behavior for all hooks except pre-push,
41 + * which has separate stdout and stderr streams for backwards
42 + * compatibility reasons.
43 + */
44 + unsigned int stdout_to_stderr:1;
45 +
46 /**
47 * Path to file which should be piped to stdin for each hook.
48 */
@@ -80,6 +89,7 @@ struct run_hooks_opt
89 #define RUN_HOOKS_OPT_INIT { \
90 .env = STRVEC_INIT, \
91 .args = STRVEC_INIT, \
92 + .stdout_to_stderr = 1, \
93 }
94
95 struct hook_cb_data {