mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
![Jeff King](/assets/img/avatar_default.png)
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>
110 lines
3 KiB
Bash
Executable file
110 lines
3 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# Copyright (C) 2006 Carl D. Worth <cworth@cworth.org>
|
|
#
|
|
|
|
test_description='test git clone to cleanup after failure
|
|
|
|
This test covers the fact that if git clone fails, it should remove
|
|
the directory it created, to avoid the user having to manually
|
|
remove the directory before attempting a clone again.
|
|
|
|
Unless the directory already exists, in which case we clean up only what we
|
|
wrote.
|
|
'
|
|
|
|
. ./test-lib.sh
|
|
|
|
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/
|
|
}
|
|
|
|
test_expect_success 'clone of non-existent source should fail' '
|
|
test_must_fail git clone foo bar
|
|
'
|
|
|
|
test_expect_success 'failed clone should not leave a directory' '
|
|
test_path_is_missing bar
|
|
'
|
|
|
|
test_expect_success 'create a repo to clone' '
|
|
test_create_repo foo
|
|
'
|
|
|
|
test_expect_success 'create objects in repo for later corruption' '
|
|
test_commit -C foo file &&
|
|
git -C foo checkout --detach &&
|
|
test_commit -C foo detached
|
|
'
|
|
|
|
# source repository given to git clone should be relative to the
|
|
# current path not to the target dir
|
|
test_expect_success 'clone of non-existent (relative to $PWD) source should fail' '
|
|
test_must_fail git clone ../foo baz
|
|
'
|
|
|
|
test_expect_success 'clone should work now that source exists' '
|
|
git clone foo bar
|
|
'
|
|
|
|
test_expect_success 'successful clone must leave the directory' '
|
|
test_path_is_dir bar
|
|
'
|
|
|
|
test_expect_success 'failed clone --separate-git-dir should not leave any directories' '
|
|
corrupt_repo &&
|
|
test_must_fail git clone --separate-git-dir gitdir foo worktree &&
|
|
test_path_is_missing gitdir &&
|
|
test_path_is_missing worktree
|
|
'
|
|
|
|
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
|
|
'
|
|
|
|
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
|
|
'
|
|
|
|
test_done
|