Merge branch 'mm/subprocess-handshake-fix'

The subprocess handshake during startup has been made gentler by using
packet_read_line_gently() instead of packet_read_line() to prevent the
parent Git process from dying abruptly when a configured subprocess
(e.g., a clean/smudge filter) fails to start.

* mm/subprocess-handshake-fix:
  sub-process: use gentle handshake to avoid die() on startup failure
This commit is contained in:
Junio C Hamano
2026-06-16 09:01:03 -07:00
2 changed files with 37 additions and 6 deletions

View File

@@ -132,17 +132,24 @@ static int handshake_version(struct child_process *process,
if (packet_flush_gently(process->in))
return error("Could not write flush packet");
if (!(line = packet_read_line(process->out, NULL)) ||
!skip_prefix(line, welcome_prefix, &p) ||
if (packet_read_line_gently(process->out, NULL, &line) < 0)
return error("could not read greeting from subprocess '%s'",
process->args.v[0]);
if (!line || !skip_prefix(line, welcome_prefix, &p) ||
strcmp(p, "-server"))
return error("Unexpected line '%s', expected %s-server",
line ? line : "<flush packet>", welcome_prefix);
if (!(line = packet_read_line(process->out, NULL)) ||
!skip_prefix(line, "version=", &p) ||
if (packet_read_line_gently(process->out, NULL, &line) < 0)
return error("could not read version from subprocess '%s'",
process->args.v[0]);
if (!line || !skip_prefix(line, "version=", &p) ||
strtol_i(p, 10, chosen_version))
return error("Unexpected line '%s', expected version",
line ? line : "<flush packet>");
if ((line = packet_read_line(process->out, NULL)))
if (packet_read_line_gently(process->out, NULL, &line) < 0)
return error("could not read version flush from subprocess '%s'",
process->args.v[0]);
if (line)
return error("Unexpected line '%s', expected flush", line);
/* Check to make sure that the version received is supported */
@@ -171,8 +178,15 @@ static int handshake_capabilities(struct child_process *process,
if (packet_flush_gently(process->in))
return error("Could not write flush packet");
while ((line = packet_read_line(process->out, NULL))) {
for (;;) {
const char *p;
int len = packet_read_line_gently(process->out, NULL, &line);
if (len < 0)
return error("could not read capabilities from subprocess '%s'",
process->args.v[0]);
if (!line)
break;
if (!skip_prefix(line, "capability=", &p))
continue;

View File

@@ -857,6 +857,23 @@ test_expect_success 'invalid process filter must fail (and not hang!)' '
)
'
test_expect_success 'missing process filter with space in path does not die' '
test_config_global filter.protocol.process "/non existent/tool" &&
test_config_global filter.protocol.required true &&
rm -rf repo &&
mkdir repo &&
(
cd repo &&
git init &&
echo "*.r filter=protocol" >.gitattributes &&
cp "$TEST_ROOT/test.o" test.r &&
test_must_fail git add . 2>git-stderr.log &&
test_grep "clean filter.*protocol.*failed" git-stderr.log
)
'
test_expect_success 'delayed checkout in process filter' '
test_config_global filter.a.process "test-tool rot13-filter --log=a.log clean smudge delay" &&
test_config_global filter.a.required true &&