transport-helper: fix sync issue on crashes

When a remote helper crashes while pushing we should revert back to the state before the push, however, it's possible that `git fast-export` already finished its job, and therefore has exported the marks already. This creates a synchronization problem because from that moment on `git fast-{import,export}` will have marks that the remote helper is not aware of and all further commands fail (if those marks are referenced). The fix is to tell `git fast-export` to export to a temporary file, and only after the remote helper has finishes successfully, move to the final destination. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Felipe Contreras committed Apr 12, 2014 at 15:33 UTC 3994e64d77d644df0f290f8bf5210ff0cb0adde2
2 files changed +30 -3
t/t5801-remote-helpers.sh
+19 -1
@@ -220,6 +220,20 @@ test_expect_success 'push update refs failure' '
220 )
221 '
222
223 +clean_mark () {
224 + cut -f 2 -d ' ' "$1" |
225 + git cat-file --batch-check |
226 + grep commit |
227 + sort >$(basename "$1")
228 +}
229 +
230 +cmp_marks () {
231 + test_when_finished "rm -rf git.marks testgit.marks" &&
232 + clean_mark ".git/testgit/$1/git.marks" &&
233 + clean_mark ".git/testgit/$1/testgit.marks" &&
234 + test_cmp git.marks testgit.marks
235 +}
236 +
237 test_expect_success 'proper failure checks for fetching' '
238 (GIT_REMOTE_TESTGIT_FAILURE=1 &&
239 export GIT_REMOTE_TESTGIT_FAILURE &&
@@ -232,7 +246,11 @@ test_expect_success 'proper failure checks for fetching' '
246
247 test_expect_success 'proper failure checks for pushing' '
248 (cd local &&
235 - test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git push --all
249 + git checkout -b crash master &&
250 + echo crash >>file &&
251 + git commit -a -m crash &&
252 + test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git push --all &&
253 + cmp_marks origin
254 )
255 '
256
transport-helper.c
+11 -2
@@ -435,7 +435,7 @@ static int get_exporter(struct transport *transport,
435 fastexport->argv[argc++] = data->signed_tags ?
436 "--signed-tags=verbatim" : "--signed-tags=warn-strip";
437 if (data->export_marks) {
438 - strbuf_addf(&tmp, "--export-marks=%s", data->export_marks);
438 + strbuf_addf(&tmp, "--export-marks=%s.tmp", data->export_marks);
439 fastexport->argv[argc++] = strbuf_detach(&tmp, NULL);
440 }
441 if (data->import_marks) {
@@ -911,7 +911,16 @@ static int push_refs_with_export(struct transport *transport,
911
912 if (finish_command(&exporter))
913 die("Error while running fast-export");
914 - return push_update_refs_status(data, remote_refs, flags);
914 + if (push_update_refs_status(data, remote_refs, flags))
915 + return 1;
916 +
917 + if (data->export_marks) {
918 + strbuf_addf(&buf, "%s.tmp", data->export_marks);
919 + rename(buf.buf, data->export_marks);
920 + strbuf_release(&buf);
921 + }
922 +
923 + return 0;
924 }
925
926 static int push_refs(struct transport *transport,