@matheusbsbs / matheus-bagliano / commits / 55892d2398
Fork 0

Allow cloning to an existing empty directory

The die() message updated accordingly. The previous behaviour was to only allow cloning when the destination directory doesn't exist. [jc: added trivial tests] Signed-off-by: Alexander Potashev <aspotashev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Alexander Potashev committed Jan 11, 2009 at 15:19 UTC 55892d23981917aefdb387ad7d0429f90cbd446a
4 files changed +46 -3
builtin-clone.c
+6 -3
@@ -357,6 +357,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
357 struct stat buf;
358 const char *repo_name, *repo, *work_tree, *git_dir;
359 char *path, *dir;
360 + int dest_exists;
361 const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
362 struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
363 struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
@@ -406,8 +407,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
407 dir = guess_dir_name(repo_name, is_bundle, option_bare);
408 strip_trailing_slashes(dir);
409
409 - if (!stat(dir, &buf))
410 - die("destination directory '%s' already exists.", dir);
410 + dest_exists = !stat(dir, &buf);
411 + if (dest_exists && !is_empty_dir(dir))
412 + die("destination path '%s' already exists and is not "
413 + "an empty directory.", dir);
414
415 strbuf_addf(&reflog_msg, "clone: from %s", repo);
416
@@ -431,7 +434,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
434 if (safe_create_leading_directories_const(work_tree) < 0)
435 die("could not create leading directories of '%s': %s",
436 work_tree, strerror(errno));
434 - if (mkdir(work_tree, 0755))
437 + if (!dest_exists && mkdir(work_tree, 0755))
438 die("could not create work tree dir '%s': %s.",
439 work_tree, strerror(errno));
440 set_git_work_tree(work_tree);
dir.c
+19
@@ -777,6 +777,25 @@ int is_inside_dir(const char *dir)
777 return get_relative_cwd(buffer, sizeof(buffer), dir) != NULL;
778 }
779
780 +int is_empty_dir(const char *path)
781 +{
782 + DIR *dir = opendir(path);
783 + struct dirent *e;
784 + int ret = 1;
785 +
786 + if (!dir)
787 + return 0;
788 +
789 + while ((e = readdir(dir)) != NULL)
790 + if (!is_dot_or_dotdot(e->d_name)) {
791 + ret = 0;
792 + break;
793 + }
794 +
795 + closedir(dir);
796 + return ret;
797 +}
798 +
799 int remove_dir_recursively(struct strbuf *path, int only_empty)
800 {
801 DIR *dir = opendir(path->buf);
dir.h
+2
@@ -84,6 +84,8 @@ static inline int is_dot_or_dotdot(const char *name)
84 (name[1] == '.' && name[2] == '\0')));
85 }
86
87 +extern int is_empty_dir(const char *dir);
88 +
89 extern void setup_standard_excludes(struct dir_struct *dir);
90 extern int remove_dir_recursively(struct strbuf *path, int only_empty);
91
t/t5601-clone.sh
+19
@@ -125,4 +125,23 @@ test_expect_success 'clone to destination with extra trailing /' '
125
126 '
127
128 +test_expect_success 'clone to an existing empty directory' '
129 + mkdir target-3 &&
130 + git clone src target-3 &&
131 + T=$( cd target-3 && git rev-parse HEAD ) &&
132 + S=$( cd src && git rev-parse HEAD ) &&
133 + test "$T" = "$S"
134 +'
135 +
136 +test_expect_success 'clone to an existing non-empty directory' '
137 + mkdir target-4 &&
138 + >target-4/Fakefile &&
139 + test_must_fail git clone src target-4
140 +'
141 +
142 +test_expect_success 'clone to an existing path' '
143 + >target-5 &&
144 + test_must_fail git clone src target-5
145 +'
146 +
147 test_done