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

[PATCH v2 01/10] run-command: add stdin callback for parallelization

From
Adrian Ratiu <adrian.ratiu@collabora.com>
Date
Oct 17, 2025, 14:15 UTC
Message-ID
<20251017141544.1538542-2-adrian.ratiu@collabora.com>
In-Reply-To
<20251017141544.1538542-1-adrian.ratiu@collabora.com>
From: Emily Shaffer <emilyshaffer@google.com>

If a user of the run_processes_parallel() API wants to pipe a large amount of information to the stdin of each parallel command, that data could exceed the pipe buffer of the process's stdin and can be too big to store in-memory via strbuf & friends or to slurp to a file.

Generally this is solved by repeatedly writing to child_process.in between calls to start_command() and finish_command(). For a specific pre-existing example of this, see transport.c:run_pre_push_hook().

This adds a generic callback API to run_processes_parallel() to do exactly that in a unified manner, similar to the existing callback APIs, which can then be used by hooks.h to convert the remaining hooks to the new, simpler parallel interface.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
---
 run-command.c               | 82 +++++++++++++++++++++++++++++++++----
 run-command.h               | 22 ++++++++++
 t/helper/test-run-command.c | 52 ++++++++++++++++++++++-
 t/t0061-run-command.sh      | 31 ++++++++++++++
 4 files changed, 178 insertions(+), 9 deletions(-)
diff --git a/run-command.c b/run-command.c
index ed9575bd6a..5bc6db5bb1 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1652,6 +1652,44 @@ static int pp_start_one(struct parallel_processes *pp,
 	return 0;
 }
 
+static void pp_buffer_stdin(struct parallel_processes *pp,
+			    const struct run_process_parallel_opts *opts)
+{
+	/* Buffer stdin for each pipe. */
+	for (ssize_t i = 0; i < opts->processes; i++) {
+		struct child_process *proc = &pp->children[i].process;
+		int ret;
+
+		if (pp->children[i].state != GIT_CP_WORKING || proc->in <= 0)
+			continue;
+
+		/*
+		 * child input is provided via path_to_stdin when the feed_pipe cb is
+		 * missing, so we just signal an EOF.
+		 */
+		if (!opts->feed_pipe) {
+			close(proc->in);
+			proc->in = 0;
+			continue;
+		}
+
+		/**
+		 * Feed the pipe:
+		 *   ret < 0 means error
+		 *   ret == 0 means there is more data to be fed
+		 *   ret > 0 means feeding finished
+		 */
+		ret = opts->feed_pipe(proc->in, opts->data, pp->children[i].data);
+		if (ret < 0)
+			die_errno("feed_pipe");
+
+		if (ret) {
+			close(proc->in);
+			proc->in = 0;
+		}
+	}
+}
+
 static void pp_buffer_stderr(struct parallel_processes *pp,
 			     const struct run_process_parallel_opts *opts,
 			     int output_timeout)
@@ -1722,6 +1760,7 @@ static int pp_collect_finished(struct parallel_processes *pp,
 		pp->children[i].state = GIT_CP_FREE;
 		if (pp->pfd)
 			pp->pfd[i].fd = -1;
+		pp->children[i].process.in = 0;
 		child_process_init(&pp->children[i].process);
 
 		if (opts->ungroup) {
@@ -1756,6 +1795,32 @@ static int pp_collect_finished(struct parallel_processes *pp,
 	return result;
 }
 
+static void pp_handle_child_IO(struct parallel_processes *pp,
+				const struct run_process_parallel_opts *opts,
+				int output_timeout)
+{
+	/*
+	 * First push input, if any (it might no-op), to child tasks to avoid them blocking
+	 * after input. This also prevents deadlocks when ungrouping below, if a child blocks
+	 * while the parent also waits for them to finish.
+	 */
+	pp_buffer_stdin(pp, opts);
+
+	if (opts->ungroup) {
+		for (size_t i = 0; i < opts->processes; i++) {
+			int child_ready_for_cleanup =
+				pp->children[i].state == GIT_CP_WORKING &&
+				pp->children[i].process.in == 0;
+
+			if (child_ready_for_cleanup)
+				pp->children[i].state = GIT_CP_WAIT_CLEANUP;
+		}
+	} else {
+		pp_buffer_stderr(pp, opts, output_timeout);
+		pp_output(pp);
+	}
+}
+
 void run_processes_parallel(const struct run_process_parallel_opts *opts)
 {
 	int i, code;
@@ -1775,6 +1840,13 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
 					   "max:%"PRIuMAX,
 					   (uintmax_t)opts->processes);
 
+	/*
+	 * Child tasks might receive input via stdin, terminating early (or not), so
+	 * ignore the default SIGPIPE which gets handled by each feed_pipe_fn which
+	 * actually writes the data to children stdin fds.
+	 */
+	sigchain_push(SIGPIPE, SIG_IGN);
+
 	pp_init(&pp, opts, &pp_sig);
 	while (1) {
 		for (i = 0;
@@ -1792,13 +1864,7 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
 		}
 		if (!pp.nr_processes)
 			break;
-		if (opts->ungroup) {
-			for (size_t i = 0; i < opts->processes; i++)
-				pp.children[i].state = GIT_CP_WAIT_CLEANUP;
-		} else {
-			pp_buffer_stderr(&pp, opts, output_timeout);
-			pp_output(&pp);
-		}
+		pp_handle_child_IO(&pp, opts, output_timeout);
 		code = pp_collect_finished(&pp, opts);
 		if (code) {
 			pp.shutdown = 1;
@@ -1809,6 +1875,8 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
 
 	pp_cleanup(&pp, opts);
 
+	sigchain_pop(SIGPIPE);
+
 	if (do_trace2)
 		trace2_region_leave(tr2_category, tr2_label, NULL);
 }
diff --git a/run-command.h b/run-command.h
index 0df25e445f..e536ed7544 100644
--- a/run-command.h
+++ b/run-command.h
@@ -420,6 +420,22 @@ typedef int (*start_failure_fn)(struct strbuf *out,
 				void *pp_cb,
 				void *pp_task_cb);
 
+/**
+ * This callback is repeatedly called on every child process who requests
+ * start_command() to create a pipe by setting child_process.in < 0.
+ *
+ * pp_cb is the callback cookie as passed into run_processes_parallel, and
+ * pp_task_cb is the callback cookie as passed into get_next_task_fn.
+ * The contents of 'send' will be read into the pipe and passed to the pipe.
+ *
+ * Returns < 0 for error
+ * Returns == 0 when there is more data to be fed (will be called again)
+ * Returns > 0 when finished (child closed fd or no more data to be fed)
+ */
+typedef int (*feed_pipe_fn)(int child_in,
+				void *pp_cb,
+				void *pp_task_cb);
+
 /**
  * This callback is called on every child process that finished processing.
  *
@@ -473,6 +489,12 @@ struct run_process_parallel_opts
 	 */
 	start_failure_fn start_failure;
 
+	/*
+	 * feed_pipe: see feed_pipe_fn() above. This can be NULL to omit any
+	 * special handling.
+	 */
+	feed_pipe_fn feed_pipe;
+
 	/**
 	 * task_finished: See task_finished_fn() above. This can be
 	 * NULL to omit any special handling.
diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c
index 3719f23cc2..dfdb03b3ab 100644
--- a/t/helper/test-run-command.c
+++ b/t/helper/test-run-command.c
@@ -23,19 +23,26 @@ static int number_callbacks;
 static int parallel_next(struct child_process *cp,
 			 struct strbuf *err,
 			 void *cb,
-			 void **task_cb UNUSED)
+			 void **task_cb)
 {
 	struct child_process *d = cb;
 	if (number_callbacks >= 4)
 		return 0;
 
 	strvec_pushv(&cp->args, d->args.v);
+	cp->in = d->in;
+	cp->no_stdin = d->no_stdin;
 	if (err)
 		strbuf_addstr(err, "preloaded output of a child\n");
 	else
 		fprintf(stderr, "preloaded output of a child\n");
 
 	number_callbacks++;
+
+	/* test_stdin callback will use this to count remaining lines */
+	*task_cb = xmalloc(sizeof(int));
+	*(int*)(*task_cb) = 2;
+
 	return 1;
 }
 
@@ -54,15 +61,48 @@ static int no_job(struct child_process *cp UNUSED,
 static int task_finished(int result UNUSED,
 			 struct strbuf *err,
 			 void *pp_cb UNUSED,
-			 void *pp_task_cb UNUSED)
+			 void *pp_task_cb)
 {
 	if (err)
 		strbuf_addstr(err, "asking for a quick stop\n");
 	else
 		fprintf(stderr, "asking for a quick stop\n");
+	if (pp_task_cb)
+		FREE_AND_NULL(pp_task_cb);
 	return 1;
 }
 
+static int task_finished_quiet(int result UNUSED,
+			       struct strbuf *err UNUSED,
+			       void *pp_cb UNUSED,
+			       void *pp_task_cb)
+{
+	if (pp_task_cb)
+		FREE_AND_NULL(pp_task_cb);
+	return 0;
+}
+
+static int test_stdin_pipe_feed(int hook_stdin_fd, void *cb UNUSED, void *task_cb)
+{
+	int *lines_remaining = task_cb;
+
+	if (*lines_remaining) {
+		struct strbuf buf = STRBUF_INIT;
+		strbuf_addf(&buf, "sample stdin %d\n", --(*lines_remaining));
+		if (write_in_full(hook_stdin_fd, buf.buf, buf.len) < 0) {
+			if (errno == EPIPE) {
+				/* child closed stdin, nothing more to do */
+				strbuf_release(&buf);
+				return 1;
+			}
+			die_errno("write");
+		}
+		strbuf_release(&buf);
+	}
+
+	return !(*lines_remaining);
+}
+
 struct testsuite {
 	struct string_list tests, failed;
 	int next;
@@ -157,6 +197,7 @@ static int testsuite(int argc, const char **argv)
 	struct run_process_parallel_opts opts = {
 		.get_next_task = next_test,
 		.start_failure = test_failed,
+		.feed_pipe = test_stdin_pipe_feed,
 		.task_finished = test_finished,
 		.data = &suite,
 	};
@@ -460,12 +501,19 @@ int cmd__run_command(int argc, const char **argv)
 
 	if (!strcmp(argv[1], "run-command-parallel")) {
 		opts.get_next_task = parallel_next;
+		opts.task_finished = task_finished_quiet;
 	} else if (!strcmp(argv[1], "run-command-abort")) {
 		opts.get_next_task = parallel_next;
 		opts.task_finished = task_finished;
 	} else if (!strcmp(argv[1], "run-command-no-jobs")) {
 		opts.get_next_task = no_job;
 		opts.task_finished = task_finished;
+	} else if (!strcmp(argv[1], "run-command-stdin")) {
+		proc.in = -1;
+		proc.no_stdin = 0;
+		opts.get_next_task = parallel_next;
+		opts.task_finished = task_finished_quiet;
+		opts.feed_pipe = test_stdin_pipe_feed;
 	} else {
 		ret = 1;
 		fprintf(stderr, "check usage\n");
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index 76d4936a87..2f77fde0d9 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -164,6 +164,37 @@ test_expect_success 'run_command runs ungrouped in parallel with more tasks than
 	test_line_count = 4 err
 '
 
+test_expect_success 'run_command listens to stdin' '
+	cat >expect <<-\EOF &&
+	preloaded output of a child
+	listening for stdin:
+	sample stdin 1
+	sample stdin 0
+	preloaded output of a child
+	listening for stdin:
+	sample stdin 1
+	sample stdin 0
+	preloaded output of a child
+	listening for stdin:
+	sample stdin 1
+	sample stdin 0
+	preloaded output of a child
+	listening for stdin:
+	sample stdin 1
+	sample stdin 0
+	EOF
+
+	write_script stdin-script <<-\EOF &&
+	echo "listening for stdin:"
+	while read line
+	do
+		echo "$line"
+	done
+	EOF
+	test-tool run-command run-command-stdin 2 ./stdin-script 2>actual &&
+	test_cmp expect actual
+'
+
 cat >expect <<-EOF
 preloaded output of a child
 asking for a quick stop
-- 
2.49.1
Previous: Adrian RatiuNext: Patrick Steinhardt
Message 45 of 187 in “Convert remaining hooks to hook.h”
  1. 00/10 Convert remaining hooks to hook.hAdrian Ratiu, Sep 25, 2025
  2. 01/10 run-command: add stdin callback for parallelizationAdrian Ratiu, Sep 25, 2025
  3. Patrick SteinhardtOct 2, 2025
  4. Junio C HamanoOct 2, 2025
  5. Adrian RatiuOct 6, 2025
  6. Adrian RatiuOct 6, 2025
  7. Adrian RatiuOct 14, 2025
  8. 02/10 hook: provide stdin via callbackAdrian Ratiu, Sep 25, 2025
  9. Junio C HamanoSep 25, 2025
  10. Adrian RatiuSep 26, 2025
  11. Emily ShafferOct 10, 2025
  12. Adrian RatiuOct 13, 2025
  13. 03/10 hook: convert 'post-rewrite' hook in sequencer.c to hook.hAdrian Ratiu, Sep 25, 2025
  14. Junio C HamanoSep 25, 2025
  15. Adrian RatiuSep 26, 2025
  16. Phillip WoodSep 26, 2025
  17. Adrian RatiuSep 26, 2025
  18. Phillip WoodSep 29, 2025
  19. Junio C HamanoSep 26, 2025
  20. Adrian RatiuSep 29, 2025
  21. Patrick SteinhardtOct 2, 2025
  22. Adrian RatiuOct 8, 2025
  23. 04/10 transport: convert pre-push hook to hook.hAdrian Ratiu, Sep 25, 2025
  24. D. Ben KnobleSep 25, 2025
  25. Adrian RatiuSep 26, 2025
  26. Phillip WoodSep 26, 2025
  27. Adrian RatiuSep 29, 2025
  28. 05/10 reference-transaction: use hook.h to run hooksAdrian Ratiu, Sep 25, 2025
  29. Junio C HamanoSep 25, 2025
  30. Adrian RatiuSep 26, 2025
  31. Patrick SteinhardtOct 2, 2025
  32. Adrian RatiuOct 8, 2025
  33. 06/10 run-command: allow capturing of collated outputAdrian Ratiu, Sep 25, 2025
  34. Junio C HamanoSep 25, 2025
  35. Adrian RatiuSep 26, 2025
  36. 07/10 hooks: allow callers to capture outputAdrian Ratiu, Sep 25, 2025
  37. 08/10 receive-pack: convert 'update' hook to hook.hAdrian Ratiu, Sep 25, 2025
  38. Junio C HamanoSep 25, 2025
  39. Emily ShafferOct 10, 2025
  40. Adrian RatiuOct 17, 2025
  41. 09/10 post-update: use hook.h libraryAdrian Ratiu, Sep 25, 2025
  42. 10/10 receive-pack: convert receive hooks to hook.hAdrian Ratiu, Sep 25, 2025
  43. Emily ShafferOct 10, 2025
  44. 00/10 Convert remaining hooks to hook.hAdrian Ratiu, Oct 17, 2025
  45. 01/10 run-command: add stdin callback for parallelizationAdrian Ratiu, Oct 17, 2025
  46. Patrick SteinhardtOct 21, 2025
  47. 02/10 hook: provide stdin via callbackAdrian Ratiu, Oct 17, 2025
  48. Patrick SteinhardtOct 21, 2025
  49. Patrick SteinhardtOct 21, 2025
  50. Adrian RatiuOct 21, 2025
  51. 03/10 hook: convert 'post-rewrite' hook in sequencer.c to hook APIAdrian Ratiu, Oct 17, 2025
  52. Patrick SteinhardtOct 21, 2025
  53. Adrian RatiuOct 21, 2025
  54. 04/10 transport: convert pre-push to hook APIAdrian Ratiu, Oct 17, 2025
  55. Patrick SteinhardtOct 21, 2025
  56. Adrian RatiuOct 21, 2025
  57. 06/10 hook: allow overriding the ungroup optionAdrian Ratiu, Oct 17, 2025
  58. 05/10 reference-transaction: use hook API instead of run-commandAdrian Ratiu, Oct 17, 2025
  59. 07/10 run-command: allow capturing of collated outputAdrian Ratiu, Oct 17, 2025
  60. Patrick SteinhardtOct 21, 2025
  61. Adrian RatiuOct 21, 2025
  62. 08/10 hooks: allow callers to capture outputAdrian Ratiu, Oct 17, 2025
  63. 09/10 receive-pack: convert update hooks to new APIAdrian Ratiu, Oct 17, 2025
  64. Kristoffer HaugsbakkOct 28, 2025
  65. 10/10 receive-pack: convert receive hooks to hook APIAdrian Ratiu, Oct 17, 2025
  66. Patrick SteinhardtOct 21, 2025
  67. Kristoffer HaugsbakkOct 28, 2025
  68. Adrian RatiuOct 29, 2025
  69. Kristoffer HaugsbakkOct 29, 2025
  70. Junio C HamanoNov 15, 2025
  71. Adrian RatiuNov 17, 2025
  72. Patrick SteinhardtOct 21, 2025
  73. Adrian RatiuOct 21, 2025
  74. 00/10 Convert remaining hooks to hook.hAdrian Ratiu, Nov 24, 2025
  75. 01/10 run-command: add stdin callback for parallelizationAdrian Ratiu, Nov 24, 2025
  76. Junio C HamanoNov 25, 2025
  77. Adrian RatiuNov 27, 2025
  78. 02/10 hook: provide stdin via callbackAdrian Ratiu, Nov 24, 2025
  79. Adrian RatiuNov 29, 2025
  80. Junio C HamanoNov 29, 2025
  81. Adrian RatiuDec 1, 2025
  82. 03/10 hook: convert 'post-rewrite' hook in sequencer.c to hook APIAdrian Ratiu, Nov 24, 2025
  83. 04/10 transport: convert pre-push to hook APIAdrian Ratiu, Nov 24, 2025
  84. Junio C HamanoNov 24, 2025
  85. Adrian RatiuNov 27, 2025
  86. 05/10 reference-transaction: use hook API instead of run-commandAdrian Ratiu, Nov 24, 2025
  87. 06/10 hook: allow overriding the ungroup optionAdrian Ratiu, Nov 24, 2025
  88. 09/10 receive-pack: convert update hooks to new APIAdrian Ratiu, Nov 24, 2025
  89. 08/10 hooks: allow callers to capture outputAdrian Ratiu, Nov 24, 2025
  90. 07/10 run-command: allow capturing of collated outputAdrian Ratiu, Nov 24, 2025
  91. 10/10 receive-pack: convert receive hooks to hook APIAdrian Ratiu, Nov 24, 2025
  92. 00/11 Convert remaining hooks to hook.hAdrian Ratiu, Dec 4, 2025
  93. 01/11 run-command: add first helper for pp child statesAdrian Ratiu, Dec 4, 2025
  94. 03/11 hook: provide stdin via callbackAdrian Ratiu, Dec 4, 2025
  95. Patrick SteinhardtDec 16, 2025
  96. 02/11 run-command: add stdin callback for parallelizationAdrian Ratiu, Dec 4, 2025
  97. 04/11 hook: convert 'post-rewrite' hook in sequencer.c to hook APIAdrian Ratiu, Dec 4, 2025
  98. 05/11 transport: convert pre-push to hook APIAdrian Ratiu, Dec 4, 2025
  99. Patrick SteinhardtDec 16, 2025
  100. Adrian RatiuDec 16, 2025
  101. Patrick SteinhardtDec 16, 2025
  102. Junio C HamanoDec 17, 2025
  103. 07/11 hook: allow overriding the ungroup optionAdrian Ratiu, Dec 4, 2025
  104. 06/11 reference-transaction: use hook API instead of run-commandAdrian Ratiu, Dec 4, 2025
  105. 08/11 run-command: allow capturing of collated outputAdrian Ratiu, Dec 4, 2025
  106. 09/11 hooks: allow callers to capture outputAdrian Ratiu, Dec 4, 2025
  107. 10/11 receive-pack: convert update hooks to new APIAdrian Ratiu, Dec 4, 2025
  108. Patrick SteinhardtDec 16, 2025
  109. Adrian RatiuDec 16, 2025
  110. 11/11 receive-pack: convert receive hooks to hook APIAdrian Ratiu, Dec 4, 2025
  111. 00/11 Convert remaining hooks to hook.hAdrian Ratiu, Dec 18, 2025
  112. 01/11 run-command: add first helper for pp child statesAdrian Ratiu, Dec 18, 2025
  113. 02/11 run-command: add stdin callback for parallelizationAdrian Ratiu, Dec 18, 2025
  114. 03/11 hook: provide stdin via callbackAdrian Ratiu, Dec 18, 2025
  115. 04/11 hook: convert 'post-rewrite' hook in sequencer.c to hook APIAdrian Ratiu, Dec 18, 2025
  116. 05/11 transport: convert pre-push to hook APIAdrian Ratiu, Dec 18, 2025
  117. 06/11 reference-transaction: use hook API instead of run-commandAdrian Ratiu, Dec 18, 2025
  118. 07/11 hook: allow overriding the ungroup optionAdrian Ratiu, Dec 18, 2025
  119. 08/11 run-command: allow capturing of collated outputAdrian Ratiu, Dec 18, 2025
  120. 09/11 hooks: allow callers to capture outputAdrian Ratiu, Dec 18, 2025
  121. 10/11 receive-pack: convert update hooks to new APIAdrian Ratiu, Dec 18, 2025
  122. 11/11 receive-pack: convert receive hooks to hook APIAdrian Ratiu, Dec 18, 2025
  123. Patrick SteinhardtDec 19, 2025
  124. Adrian RatiuDec 20, 2025
  125. 00/11 Convert remaining hooks to hook.hAdrian Ratiu, Dec 26, 2025
  126. 01/11 run-command: add first helper for pp child statesAdrian Ratiu, Dec 26, 2025
  127. 02/11 run-command: add stdin callback for parallelizationAdrian Ratiu, Dec 26, 2025
  128. 03/11 hook: provide stdin via callbackAdrian Ratiu, Dec 26, 2025
  129. 04/11 hook: convert 'post-rewrite' hook in sequencer.c to hook APIAdrian Ratiu, Dec 26, 2025
  130. 05/11 transport: convert pre-push to hook APIAdrian Ratiu, Dec 26, 2025
  131. 06/11 reference-transaction: use hook API instead of run-commandAdrian Ratiu, Dec 26, 2025
  132. SZEDER GáborJan 18, 2026
  133. Adrian RatiuJan 18, 2026
  134. 07/11 hook: allow overriding the ungroup optionAdrian Ratiu, Dec 26, 2025
  135. 08/11 run-command: allow capturing of collated outputAdrian Ratiu, Dec 26, 2025
  136. 09/11 hooks: allow callers to capture outputAdrian Ratiu, Dec 26, 2025
  137. 10/11 receive-pack: convert update hooks to new APIAdrian Ratiu, Dec 26, 2025
  138. 11/11 receive-pack: convert receive hooks to hook APIAdrian Ratiu, Dec 26, 2025
  139. Junio C HamanoDec 28, 2025
  140. Adrian RatiuJan 5, 2026
  141. Patrick SteinhardtJan 5, 2026
  142. 00/12 Convert remaining hooks to hook.hAdrian Ratiu, Jan 21, 2026
  143. 01/12 t1800: add hook output stream testsAdrian Ratiu, Jan 21, 2026
  144. Junio C HamanoJan 21, 2026
  145. Adrian RatiuJan 22, 2026
  146. 02/12 run-command: add first helper for pp child statesAdrian Ratiu, Jan 21, 2026
  147. Junio C HamanoJan 21, 2026
  148. Adrian RatiuJan 22, 2026
  149. 03/12 run-command: add stdin callback for parallelizationAdrian Ratiu, Jan 21, 2026
  150. 05/12 hook: convert 'post-rewrite' hook in sequencer.c to hook APIAdrian Ratiu, Jan 21, 2026
  151. 04/12 hook: provide stdin via callbackAdrian Ratiu, Jan 21, 2026
  152. 07/12 transport: convert pre-push to hook APIAdrian Ratiu, Jan 21, 2026
  153. 08/12 reference-transaction: use hook API instead of run-commandAdrian Ratiu, Jan 21, 2026
  154. 09/12 hook: add jobs optionAdrian Ratiu, Jan 21, 2026
  155. 10/12 run-command: poll child stdin in addition to stdoutAdrian Ratiu, Jan 21, 2026
  156. Kristoffer HaugsbakkJan 21, 2026
  157. Adrian RatiuJan 22, 2026
  158. Junio C HamanoJan 21, 2026
  159. Adrian RatiuJan 22, 2026
  160. Junio C HamanoJan 22, 2026
  161. Emily ShafferJan 26, 2026
  162. Junio C HamanoJan 27, 2026
  163. Adrian RatiuJan 27, 2026
  164. 11/12 receive-pack: convert update hooks to new APIAdrian Ratiu, Jan 21, 2026
  165. Kristoffer HaugsbakkJan 21, 2026
  166. Adrian RatiuJan 22, 2026
  167. Emily ShafferJan 27, 2026
  168. Adrian RatiuJan 27, 2026
  169. 12/12 receive-pack: convert receive hooks to hook APIAdrian Ratiu, Jan 21, 2026
  170. 06/12 hook: allow separate std[out|err] streamsAdrian Ratiu, Jan 21, 2026
  171. Patrick SteinhardtJan 23, 2026
  172. Adrian RatiuJan 23, 2026
  173. 00/12 Convert remaining hooks to hook.hAdrian Ratiu, Jan 28, 2026
  174. 01/12 t1800: add hook output stream testsAdrian Ratiu, Jan 28, 2026
  175. 02/12 run-command: add helper for pp child statesAdrian Ratiu, Jan 28, 2026
  176. 03/12 run-command: add stdin callback for parallelizationAdrian Ratiu, Jan 28, 2026
  177. 05/12 hook: convert 'post-rewrite' hook in sequencer.c to hook APIAdrian Ratiu, Jan 28, 2026
  178. 04/12 hook: provide stdin via callbackAdrian Ratiu, Jan 28, 2026
  179. 07/12 transport: convert pre-push to hook APIAdrian Ratiu, Jan 28, 2026
  180. 09/12 hook: add jobs optionAdrian Ratiu, Jan 28, 2026
  181. 08/12 reference-transaction: use hook API instead of run-commandAdrian Ratiu, Jan 28, 2026
  182. 10/12 run-command: poll child input in addition to outputAdrian Ratiu, Jan 28, 2026
  183. 06/12 hook: allow separate std[out|err] streamsAdrian Ratiu, Jan 28, 2026
  184. Chris DarrochFeb 2, 2026
  185. Junio C HamanoFeb 2, 2026
  186. 11/12 receive-pack: convert update hooks to new APIAdrian Ratiu, Jan 28, 2026
  187. 12/12 receive-pack: convert receive hooks to hook APIAdrian Ratiu, Jan 28, 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.