t1800: add hook output stream tests

Lack of test coverage in this area led to some regressions while converting the remaining hooks to the newer hook.[ch] API. Add some tests to verify hooks write to the expected output streams. Suggested-by: Patrick Steinhardt <ps@pks.im> Suggested-by: Junio C Hamano <gitster@pobox.com> 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 c9ef360403e0f64a5d4c70f66a9b25f02a98fda6
1 file changed +137
t/t1800-hook.sh
+137
@@ -184,4 +184,141 @@ test_expect_success 'stdin to hooks' '
184 test_cmp expect actual
185 '
186
187 +check_stdout_separate_from_stderr () {
188 + for hook in "$@"
189 + do
190 + # Ensure hook's stdout is only in stdout, not stderr
191 + test_grep "Hook $hook stdout" stdout.actual || return 1
192 + test_grep ! "Hook $hook stdout" stderr.actual || return 1
193 +
194 + # Ensure hook's stderr is only in stderr, not stdout
195 + test_grep "Hook $hook stderr" stderr.actual || return 1
196 + test_grep ! "Hook $hook stderr" stdout.actual || return 1
197 + done
198 +}
199 +
200 +check_stdout_merged_to_stderr () {
201 + for hook in "$@"
202 + do
203 + # Ensure hook's stdout is only in stderr, not stdout
204 + test_grep "Hook $hook stdout" stderr.actual || return 1
205 + test_grep ! "Hook $hook stdout" stdout.actual || return 1
206 +
207 + # Ensure hook's stderr is only in stderr, not stdout
208 + test_grep "Hook $hook stderr" stderr.actual || return 1
209 + test_grep ! "Hook $hook stderr" stdout.actual || return 1
210 + done
211 +}
212 +
213 +setup_hooks () {
214 + for hook in "$@"
215 + do
216 + test_hook $hook <<-EOF
217 + echo >&1 Hook $hook stdout
218 + echo >&2 Hook $hook stderr
219 + EOF
220 + done
221 +}
222 +
223 +test_expect_success 'client hooks: pre-push expects separate stdout and stderr' '
224 + test_when_finished "rm -f stdout.actual stderr.actual" &&
225 + git init --bare remote &&
226 + git remote add origin remote &&
227 + test_commit A &&
228 + setup_hooks pre-push &&
229 + git push origin HEAD:main >stdout.actual 2>stderr.actual &&
230 + check_stdout_separate_from_stderr pre-push
231 +'
232 +
233 +test_expect_success 'client hooks: commit hooks expect stdout redirected to stderr' '
234 + hooks="pre-commit prepare-commit-msg \
235 + commit-msg post-commit \
236 + reference-transaction" &&
237 + setup_hooks $hooks &&
238 + test_when_finished "rm -f stdout.actual stderr.actual" &&
239 + git checkout -B main &&
240 + git checkout -b branch-a &&
241 + test_commit commit-on-branch-a &&
242 + git commit --allow-empty -m "Test" >stdout.actual 2>stderr.actual &&
243 + check_stdout_merged_to_stderr $hooks
244 +'
245 +
246 +test_expect_success 'client hooks: checkout hooks expect stdout redirected to stderr' '
247 + setup_hooks post-checkout reference-transaction &&
248 + test_when_finished "rm -f stdout.actual stderr.actual" &&
249 + git checkout -b new-branch main >stdout.actual 2>stderr.actual &&
250 + check_stdout_merged_to_stderr post-checkout reference-transaction
251 +'
252 +
253 +test_expect_success 'client hooks: merge hooks expect stdout redirected to stderr' '
254 + setup_hooks pre-merge-commit post-merge reference-transaction &&
255 + test_when_finished "rm -f stdout.actual stderr.actual" &&
256 + test_commit new-branch-commit &&
257 + git merge --no-ff branch-a >stdout.actual 2>stderr.actual &&
258 + check_stdout_merged_to_stderr pre-merge-commit post-merge reference-transaction
259 +'
260 +
261 +test_expect_success 'client hooks: post-rewrite hooks expect stdout redirected to stderr' '
262 + setup_hooks post-rewrite reference-transaction &&
263 + test_when_finished "rm -f stdout.actual stderr.actual" &&
264 + git commit --amend --allow-empty --no-edit >stdout.actual 2>stderr.actual &&
265 + check_stdout_merged_to_stderr post-rewrite reference-transaction
266 +'
267 +
268 +test_expect_success 'client hooks: applypatch hooks expect stdout redirected to stderr' '
269 + setup_hooks applypatch-msg pre-applypatch post-applypatch &&
270 + test_when_finished "rm -f stdout.actual stderr.actual" &&
271 + git checkout -b branch-b main &&
272 + test_commit branch-b &&
273 + git format-patch -1 --stdout >patch &&
274 + git checkout -b branch-c main &&
275 + git am patch >stdout.actual 2>stderr.actual &&
276 + check_stdout_merged_to_stderr applypatch-msg pre-applypatch post-applypatch
277 +'
278 +
279 +test_expect_success 'client hooks: rebase hooks expect stdout redirected to stderr' '
280 + setup_hooks pre-rebase &&
281 + test_when_finished "rm -f stdout.actual stderr.actual" &&
282 + git checkout -b branch-d main &&
283 + test_commit branch-d &&
284 + git checkout main &&
285 + test_commit diverge-main &&
286 + git checkout branch-d &&
287 + git rebase main >stdout.actual 2>stderr.actual &&
288 + check_stdout_merged_to_stderr pre-rebase
289 +'
290 +
291 +test_expect_success 'client hooks: post-index-change expects stdout redirected to stderr' '
292 + setup_hooks post-index-change &&
293 + test_when_finished "rm -f stdout.actual stderr.actual" &&
294 + oid=$(git hash-object -w --stdin </dev/null) &&
295 + git update-index --add --cacheinfo 100644 $oid new-file \
296 + >stdout.actual 2>stderr.actual &&
297 + check_stdout_merged_to_stderr post-index-change
298 +'
299 +
300 +test_expect_success 'server hooks expect stdout redirected to stderr' '
301 + test_when_finished "rm -f stdout.actual stderr.actual" &&
302 + git init --bare remote-server &&
303 + git remote add origin-server remote-server &&
304 + cd remote-server &&
305 + setup_hooks pre-receive update post-receive post-update &&
306 + cd .. &&
307 + git push origin-server HEAD:new-branch >stdout.actual 2>stderr.actual &&
308 + check_stdout_merged_to_stderr pre-receive update post-receive post-update
309 +'
310 +
311 +test_expect_success 'server push-to-checkout hook expects stdout redirected to stderr' '
312 + test_when_finished "rm -f stdout.actual stderr.actual" &&
313 + git init server &&
314 + git -C server checkout -b main &&
315 + test_config -C server receive.denyCurrentBranch updateInstead &&
316 + git remote add origin-server-2 server &&
317 + cd server &&
318 + setup_hooks push-to-checkout &&
319 + cd .. &&
320 + git push origin-server-2 HEAD:main >stdout.actual 2>stderr.actual &&
321 + check_stdout_merged_to_stderr push-to-checkout
322 +'
323 +
324 test_done