git clone: don't clone into non-empty directory

When using git clone with --separate-git-dir realgitdir and
realgitdir already exists, it's content is destroyed.

So, make sure we don't clone into an existing non-empty directory.

When d45420c1 (clone: do not clean up directories we didn't create,
2018-01-02) tightened the clean-up procedure after a failed cloning
into an empty directory, it assumed that the existing directory
given is an empty one so it is OK to keep that directory, while
running the clean-up procedure that is designed to remove everything
in it (since there won't be any, anyway).  Check and make sure that
the $GIT_DIR is empty even cloning into an existing repository.

Signed-off-by: Ben Wijen <ben@wijen.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Ben Wijen 2020-07-10 10:47:32 +02:00 коммит произвёл Junio C Hamano
Родитель a08a83db2b
Коммит dfaa209a79
2 изменённых файлов: 13 добавлений и 3 удалений

Просмотреть файл

@ -946,7 +946,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int is_bundle = 0, is_local; int is_bundle = 0, is_local;
const char *repo_name, *repo, *work_tree, *git_dir; const char *repo_name, *repo, *work_tree, *git_dir;
char *path, *dir, *display_repo = NULL; char *path, *dir, *display_repo = NULL;
int dest_exists; int dest_exists, real_dest_exists = 0;
const struct ref *refs, *remote_head; const struct ref *refs, *remote_head;
const struct ref *remote_head_points_at; const struct ref *remote_head_points_at;
const struct ref *our_head_points_at; const struct ref *our_head_points_at;
@ -1021,6 +1021,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die(_("destination path '%s' already exists and is not " die(_("destination path '%s' already exists and is not "
"an empty directory."), dir); "an empty directory."), dir);
if (real_git_dir) {
real_dest_exists = path_exists(real_git_dir);
if (real_dest_exists && !is_empty_dir(real_git_dir))
die(_("repository path '%s' already exists and is not "
"an empty directory."), real_git_dir);
}
strbuf_addf(&reflog_msg, "clone: from %s", strbuf_addf(&reflog_msg, "clone: from %s",
display_repo ? display_repo : repo); display_repo ? display_repo : repo);
free(display_repo); free(display_repo);
@ -1057,7 +1065,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
} }
if (real_git_dir) { if (real_git_dir) {
if (path_exists(real_git_dir)) if (real_dest_exists)
junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL; junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
junk_git_dir = real_git_dir; junk_git_dir = real_git_dir;
} else { } else {

Просмотреть файл

@ -271,7 +271,9 @@ test_expect_success 'fetch from gitfile parent' '
test_expect_success 'clone separate gitdir where target already exists' ' test_expect_success 'clone separate gitdir where target already exists' '
rm -rf dst && rm -rf dst &&
test_must_fail git clone --separate-git-dir realgitdir src dst echo foo=bar >>realgitdir/config &&
test_must_fail git clone --separate-git-dir realgitdir src dst &&
grep foo=bar realgitdir/config
' '
test_expect_success 'clone --reference from original' ' test_expect_success 'clone --reference from original' '