Skip to content

Commit 6aacb7d

Browse files
peffgitster
authored andcommitted
clone: clean up directory after transport_fetch_refs() failure
git-clone started respecting errors from the transport subsystem in aab179d (builtin/clone.c: don't ignore transport_fetch_refs() errors, 2020-12-03). However, that commit didn't handle the cleanup of the filesystem quite right. The cleanup of the directory that cmd_clone() creates is done by an atexit() handler, which we control with a flag. It starts as JUNK_LEAVE_NONE ("clean up everything"), then progresses to JUNK_LEAVE_REPO when we know we have a valid repo but not working tree, and then finally JUNK_LEAVE_ALL when we have a successful checkout. Most errors cause us to die(), which then triggers the handler to do the right thing based on how far into cmd_clone() we got. But the checks added by aab179d instead set the "err" variable and then jump to a new "cleanup" label, which then returns our non-zero status. However, the code after the cleanup label includes setting the flag to JUNK_LEAVE_ALL, and so we accidentally leave the repository and working tree in place. One obvious option to fix this is to reorder the end of the function to set the flag first, before cleanup code, and put the label between them. But we can observe another small bug: the error return from transport_fetch_refs() is generally "-1", and we propagate that to the return value of cmd_clone(), which ultimately becomes the exit code of the process. And we try to avoid transmitting negative values via exit codes (only the low 8 bits are passed along as an unsigned value, though in practice for "-1" this at least retains the property that it's non-zero). Instead, let's just die(). That makes us consistent with rest of the code in the function. It does add a new "fatal:" line to the output, but I'd argue that's a good thing: - in the rare case that the transport code didn't say anything, now the user gets _some_ error message - even if the transport code said something like "error: ssh died of signal 9", it's nice to also say "fatal" to indicate that we considered that to be a show-stopper. Triggering this in the test suite turns out to be surprisingly difficult. Almost every error we'd encounter, including ones deep inside the transport code, cause us to just die() right there! However, one way is to put a fake wrapper around git-upload-pack that sends the complete packfile but exits with a failure code. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 94f6e3e commit 6aacb7d

File tree

2 files changed

+11
-7
lines changed

2 files changed

+11
-7
lines changed

builtin/clone.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,9 +1294,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
12941294
}
12951295

12961296
if (!is_local && !complete_refs_before_fetch) {
1297-
err = transport_fetch_refs(transport, mapped_refs);
1298-
if (err)
1299-
goto cleanup;
1297+
if (transport_fetch_refs(transport, mapped_refs))
1298+
die(_("remote transport reported error"));
13001299
}
13011300

13021301
remote_head = find_ref_by_name(refs, "HEAD");
@@ -1343,9 +1342,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
13431342
if (is_local)
13441343
clone_local(path, git_dir);
13451344
else if (refs && complete_refs_before_fetch) {
1346-
err = transport_fetch_refs(transport, mapped_refs);
1347-
if (err)
1348-
goto cleanup;
1345+
if (transport_fetch_refs(transport, mapped_refs))
1346+
die(_("remote transport reported error"));
13491347
}
13501348

13511349
update_remote_refs(refs, mapped_refs, remote_head_points_at,
@@ -1373,7 +1371,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
13731371
junk_mode = JUNK_LEAVE_REPO;
13741372
err = checkout(submodule_progress);
13751373

1376-
cleanup:
13771374
free(remote_name);
13781375
strbuf_release(&reflog_msg);
13791376
strbuf_release(&branch_top);

t/t5600-clone-fail-cleanup.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,11 @@ test_expect_success 'failed clone into empty leaves directory (separate, wt)' '
9797
test_dir_is_empty empty-wt
9898
'
9999

100+
test_expect_success 'transport failure cleans up directory' '
101+
test_must_fail git clone --no-local \
102+
-u "f() { git-upload-pack \"\$@\"; return 1; }; f" \
103+
foo broken-clone &&
104+
test_path_is_missing broken-clone
105+
'
106+
100107
test_done

0 commit comments

Comments
 (0)