Skip to content

Commit 0e1dd9f

Browse files
pks-tgitster
authored andcommitted
transport: don't ignore git-receive-pack(1) exit code on atomic push
When executing git-push(1) with the "--porcelain" flag, then we will print updated references in a machine-readable format that looks like this: To destination = refs/heads/noop:refs/heads/noop [up to date] ! refs/heads/rejected:refs/heads/rejected [rejected] (atomic push failed) ! refs/heads/noff:refs/heads/(off (non-fast-forward) Done The final "Done" stanza was introduced via 7755585 (git-push: make git push --porcelain print "Done", 2010-02-26), where it was printed "unless any errors have occurred". This behaviour was later changed via 7dcbeaa (send-pack: fix inconsistent porcelain output, 2020-04-17) such that the stanza will also be printed when there was an error with atomic pushes, which was previously inconsistent with non-atomic pushes. The fixup commit has introduced a new issue though. During atomic pushes it is expected that git-receive-pack(1) may exit early, and that causes us to receive an error on the client-side. We (seemingly) still want to print the "Done" stanza, but given that we only do so when the push has been successful we started to ignore the error code by the child process completely when doing an atomic push. We'd typically notice this case because the refs would have their error message set. But there is an edge case when pushing refs succeeds, but git-receive-pack(1) exits with a non-zero exit code at a later point in time due to another error. An atomic git-push(1) would ignore that error code, and consequently it would return successfully and not print any error message at all. Now it is somewhat unclear what the correct fix is in this case, mostly because the exact format of the porcelain output of git-push(1) is not specified to its full extent. What is clear though is that ignoring the error code is definitely not the correct thing to do. Adapt the code such that we honor the error code and unconditionally print the "Done" stanza even when pushing refs has failed. This ensures that git-push(1) notices the error condition and exits with an error, but slightly changes the output format. This requires a change to t5504, where we previously didn't print "Done" at the end of the push. As said, it is hard to say what the correct behaviour is in this case. But two test cases further up we have another test that fails in a similar way, and that test expects a final "Done" stanza. So if nothing else this at least seems to make the behaviour more consistent with other error cases. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent abd2a39 commit 0e1dd9f

File tree

4 files changed

+34
-8
lines changed

4 files changed

+34
-8
lines changed

send-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ int send_pack(struct send_pack_args *args,
630630
reject_atomic_push(remote_refs, args->send_mirror);
631631
error("atomic push failed for ref %s. status: %d",
632632
ref->name, ref->status);
633-
ret = args->porcelain ? 0 : -1;
633+
ret = -1;
634634
goto out;
635635
}
636636
/* else fallthrough */

t/t5504-fetch-receive-strict.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ test_expect_success 'push with receive.fsckobjects' '
105105
cat >exp <<-EOF &&
106106
To dst
107107
! refs/heads/main:refs/heads/test [remote rejected] (unpacker error)
108+
Done
108109
EOF
109110
test_must_fail git push --porcelain dst main:refs/heads/test >act &&
110111
test_cmp exp act

t/t5543-atomic-push.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,34 @@ test_expect_success 'atomic push reports (reject by non-ff)' '
281281
test_cmp expect actual
282282
'
283283

284+
test_expect_success 'atomic push reports exit code failure' '
285+
write_script receive-pack-wrapper <<-\EOF &&
286+
git-receive-pack "$@"
287+
exit 1
288+
EOF
289+
test_must_fail git -C workbench push --atomic \
290+
--receive-pack="${SQ}$(pwd)${SQ}/receive-pack-wrapper" \
291+
up HEAD:refs/heads/no-conflict 2>err &&
292+
cat >expect <<-EOF &&
293+
To ../upstream
294+
* [new branch] HEAD -> no-conflict
295+
error: failed to push some refs to ${SQ}../upstream${SQ}
296+
EOF
297+
test_cmp expect err
298+
'
299+
300+
test_expect_success 'atomic push reports exit code failure with porcelain' '
301+
write_script receive-pack-wrapper <<-\EOF &&
302+
git-receive-pack "$@"
303+
exit 1
304+
EOF
305+
test_must_fail git -C workbench push --atomic --porcelain \
306+
--receive-pack="${SQ}$(pwd)${SQ}/receive-pack-wrapper" \
307+
up HEAD:refs/heads/no-conflict-porcelain 2>err &&
308+
cat >expect <<-EOF &&
309+
error: failed to push some refs to ${SQ}../upstream${SQ}
310+
EOF
311+
test_cmp expect err
312+
'
313+
284314
test_done

transport.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -918,12 +918,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
918918

919919
close(data->fd[1]);
920920
close(data->fd[0]);
921-
/*
922-
* Atomic push may abort the connection early and close the pipe,
923-
* which may cause an error for `finish_connect()`. Ignore this error
924-
* for atomic git-push.
925-
*/
926-
if (ret || args.atomic)
921+
if (ret)
927922
finish_connect(data->conn);
928923
else
929924
ret = finish_connect(data->conn);
@@ -1488,7 +1483,7 @@ int transport_push(struct repository *r,
14881483
transport_update_tracking_ref(transport->remote, ref, verbose);
14891484
}
14901485

1491-
if (porcelain && !push_ret)
1486+
if (porcelain)
14921487
puts("Done");
14931488
else if (!quiet && !ret && !transport_refs_pushed(remote_refs))
14941489
/* stable plumbing output; do not modify or localize */

0 commit comments

Comments
 (0)