2006-02-17 21:33:28 +00:00
|
|
|
#!/bin/sh
|
|
|
|
#
|
|
|
|
# Copyright (C) 2006 Carl D. Worth <cworth@cworth.org>
|
|
|
|
#
|
|
|
|
|
2008-09-03 08:59:29 +00:00
|
|
|
test_description='test git clone to cleanup after failure
|
2006-02-17 21:33:28 +00:00
|
|
|
|
2008-09-03 08:59:29 +00:00
|
|
|
This test covers the fact that if git clone fails, it should remove
|
2006-02-17 21:33:28 +00:00
|
|
|
the directory it created, to avoid the user having to manually
|
2018-01-02 21:11:39 +00:00
|
|
|
remove the directory before attempting a clone again.
|
|
|
|
|
|
|
|
Unless the directory already exists, in which case we clean up only what we
|
|
|
|
wrote.
|
|
|
|
'
|
2006-02-17 21:33:28 +00:00
|
|
|
|
2022-04-13 20:01:48 +00:00
|
|
|
TEST_PASSES_SANITIZE_LEAK=true
|
2006-02-17 21:33:28 +00:00
|
|
|
. ./test-lib.sh
|
|
|
|
|
2018-01-02 21:11:39 +00:00
|
|
|
corrupt_repo () {
|
|
|
|
test_when_finished "rmdir foo/.git/objects.bak" &&
|
|
|
|
mkdir foo/.git/objects.bak/ &&
|
|
|
|
test_when_finished "mv foo/.git/objects.bak/* foo/.git/objects/" &&
|
|
|
|
mv foo/.git/objects/* foo/.git/objects.bak/
|
|
|
|
}
|
|
|
|
|
2018-01-02 21:09:00 +00:00
|
|
|
test_expect_success 'clone of non-existent source should fail' '
|
|
|
|
test_must_fail git clone foo bar
|
|
|
|
'
|
2006-02-17 21:33:28 +00:00
|
|
|
|
2018-01-02 21:09:00 +00:00
|
|
|
test_expect_success 'failed clone should not leave a directory' '
|
|
|
|
test_path_is_missing bar
|
|
|
|
'
|
2006-02-17 21:33:28 +00:00
|
|
|
|
2018-01-02 21:09:00 +00:00
|
|
|
test_expect_success 'create a repo to clone' '
|
|
|
|
test_create_repo foo
|
|
|
|
'
|
2006-02-17 21:33:28 +00:00
|
|
|
|
2018-01-02 21:09:00 +00:00
|
|
|
test_expect_success 'create objects in repo for later corruption' '
|
t5600: provide detached HEAD for corruption failures
When checking how git-clone behaves when it fails, we stimulate some
failures by trying to do a clone from a local repository whose objects
have been removed. Because these clones use local optimizations, there's
a subtle dependency in how the corruption is handled on the sending
side.
If upload-pack does not show us the broken refs (which it does not
currently), then we see only HEAD (which is itself broken), and clone
that as a detached HEAD. When we try to write the ref, we notice that we
never got the object and bail.
But if upload-pack _does_ show us the broken refs (which it may in a
future patch), then we'll realize that HEAD is a symref and just write
that. You'd think we'd fail when writing out the refs themselves, but we
don't; we do a bulk write and skip the connectivity check because of our
--local optimizations. For the non-bare case, we do notice the problem
when we try to checkout. But for a bare repository, we unexpectedly
complete the clone successfully!
At first glance this may seem like a bug. But the whole point of those
local optimizations is to give up some safety for speed. If you want to
be careful, you should be using "--no-local", which would notice that
the pack did not transfer sufficient objects. We could do that in these
tests, but part of the point is for them to fail at specific moments
(and indeed, we have a later test that checks for transport failure).
However, we can make this less subtle and future-proof it against
changes on the upload-pack side by just having an explicit detached
HEAD in the corrupted repo. Now we'll fail as expected during the ref
write if any ref _or_ HEAD is corrupt, whether we're --bare or not.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-09-24 18:34:04 +00:00
|
|
|
test_commit -C foo file &&
|
|
|
|
git -C foo checkout --detach &&
|
|
|
|
test_commit -C foo detached
|
2018-01-02 21:09:00 +00:00
|
|
|
'
|
2006-02-17 21:33:28 +00:00
|
|
|
|
2008-09-03 08:59:29 +00:00
|
|
|
# source repository given to git clone should be relative to the
|
2006-10-14 12:02:51 +00:00
|
|
|
# current path not to the target dir
|
2018-01-02 21:09:00 +00:00
|
|
|
test_expect_success 'clone of non-existent (relative to $PWD) source should fail' '
|
|
|
|
test_must_fail git clone ../foo baz
|
|
|
|
'
|
2006-10-14 12:02:51 +00:00
|
|
|
|
2018-01-02 21:09:00 +00:00
|
|
|
test_expect_success 'clone should work now that source exists' '
|
|
|
|
git clone foo bar
|
|
|
|
'
|
2006-02-17 21:33:28 +00:00
|
|
|
|
2018-01-02 21:09:00 +00:00
|
|
|
test_expect_success 'successful clone must leave the directory' '
|
|
|
|
test_path_is_dir bar
|
|
|
|
'
|
2013-01-05 20:17:04 +00:00
|
|
|
|
|
|
|
test_expect_success 'failed clone --separate-git-dir should not leave any directories' '
|
2018-01-02 21:11:39 +00:00
|
|
|
corrupt_repo &&
|
2013-01-05 20:17:04 +00:00
|
|
|
test_must_fail git clone --separate-git-dir gitdir foo worktree &&
|
2018-01-02 21:09:00 +00:00
|
|
|
test_path_is_missing gitdir &&
|
|
|
|
test_path_is_missing worktree
|
2013-01-05 20:17:04 +00:00
|
|
|
'
|
2006-02-17 21:33:28 +00:00
|
|
|
|
2018-01-02 21:11:39 +00:00
|
|
|
test_expect_success 'failed clone into empty leaves directory (vanilla)' '
|
|
|
|
mkdir -p empty &&
|
|
|
|
corrupt_repo &&
|
|
|
|
test_must_fail git clone foo empty &&
|
|
|
|
test_dir_is_empty empty
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'failed clone into empty leaves directory (bare)' '
|
|
|
|
mkdir -p empty &&
|
|
|
|
corrupt_repo &&
|
|
|
|
test_must_fail git clone --bare foo empty &&
|
|
|
|
test_dir_is_empty empty
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'failed clone into empty leaves directory (separate)' '
|
|
|
|
mkdir -p empty-git empty-wt &&
|
|
|
|
corrupt_repo &&
|
|
|
|
test_must_fail git clone --separate-git-dir empty-git foo empty-wt &&
|
|
|
|
test_dir_is_empty empty-git &&
|
|
|
|
test_dir_is_empty empty-wt
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'failed clone into empty leaves directory (separate, git)' '
|
|
|
|
mkdir -p empty-git &&
|
|
|
|
corrupt_repo &&
|
|
|
|
test_must_fail git clone --separate-git-dir empty-git foo no-wt &&
|
|
|
|
test_dir_is_empty empty-git &&
|
|
|
|
test_path_is_missing no-wt
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'failed clone into empty leaves directory (separate, wt)' '
|
|
|
|
mkdir -p empty-wt &&
|
|
|
|
corrupt_repo &&
|
|
|
|
test_must_fail git clone --separate-git-dir no-git foo empty-wt &&
|
|
|
|
test_path_is_missing no-git &&
|
|
|
|
test_dir_is_empty empty-wt
|
|
|
|
'
|
|
|
|
|
clone: clean up directory after transport_fetch_refs() failure
git-clone started respecting errors from the transport subsystem in
aab179d937 (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 aab179d937 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 <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-05-19 11:17:15 +00:00
|
|
|
test_expect_success 'transport failure cleans up directory' '
|
|
|
|
test_must_fail git clone --no-local \
|
|
|
|
-u "f() { git-upload-pack \"\$@\"; return 1; }; f" \
|
|
|
|
foo broken-clone &&
|
|
|
|
test_path_is_missing broken-clone
|
|
|
|
'
|
|
|
|
|
2006-02-17 21:33:28 +00:00
|
|
|
test_done
|