Merge branch 'ap/clone-into-empty'
authorJunio C Hamano <gitster@pobox.com>
Sun, 18 Jan 2009 07:05:54 +0000 (23:05 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 18 Jan 2009 07:05:54 +0000 (23:05 -0800)
* ap/clone-into-empty:
Allow cloning to an existing empty directory
add is_dot_or_dotdot inline function

builtin-clone.c
builtin-count-objects.c
builtin-fsck.c
builtin-prune.c
builtin-rerere.c
dir.c
dir.h
entry.c
remote.c
t/t5601-clone.sh
transport.c
index f1a1a0c36591d1936088a180e3c0a8ca5e7b0757..f7e5a7b0a060c15432162fefc2e0ff89baf451b0 100644 (file)
@@ -357,6 +357,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        struct stat buf;
        const char *repo_name, *repo, *work_tree, *git_dir;
        char *path, *dir;
+       int dest_exists;
        const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
        struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
        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)
                dir = guess_dir_name(repo_name, is_bundle, option_bare);
        strip_trailing_slashes(dir);
 
-       if (!stat(dir, &buf))
-               die("destination directory '%s' already exists.", dir);
+       dest_exists = !stat(dir, &buf);
+       if (dest_exists && !is_empty_dir(dir))
+               die("destination path '%s' already exists and is not "
+                       "an empty directory.", dir);
 
        strbuf_addf(&reflog_msg, "clone: from %s", repo);
 
@@ -431,7 +434,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                if (safe_create_leading_directories_const(work_tree) < 0)
                        die("could not create leading directories of '%s': %s",
                                        work_tree, strerror(errno));
-               if (mkdir(work_tree, 0755))
+               if (!dest_exists && mkdir(work_tree, 0755))
                        die("could not create work tree dir '%s': %s.",
                                        work_tree, strerror(errno));
                set_git_work_tree(work_tree);
index ab35b65b073e9bc089fcc96f295ca3bc457c992a..62fd1f0961a29cc81032d20b3fe37fcc91293407 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include "cache.h"
+#include "dir.h"
 #include "builtin.h"
 #include "parse-options.h"
 
@@ -21,9 +22,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
                const char *cp;
                int bad = 0;
 
-               if ((ent->d_name[0] == '.') &&
-                   (ent->d_name[1] == 0 ||
-                    ((ent->d_name[1] == '.') && (ent->d_name[2] == 0))))
+               if (is_dot_or_dotdot(ent->d_name))
                        continue;
                for (cp = ent->d_name; *cp; cp++) {
                        int ch = *cp;
index 5c4c77adaaba36693e304c27d1f171f8e7e9f151..aecc8280a0aedb37437ccce446f3382ccba08829 100644 (file)
@@ -10,6 +10,7 @@
 #include "tree-walk.h"
 #include "fsck.h"
 #include "parse-options.h"
+#include "dir.h"
 
 #define REACHABLE 0x0001
 #define SEEN      0x0002
@@ -395,19 +396,12 @@ static void fsck_dir(int i, char *path)
        while ((de = readdir(dir)) != NULL) {
                char name[100];
                unsigned char sha1[20];
-               int len = strlen(de->d_name);
 
-               switch (len) {
-               case 2:
-                       if (de->d_name[1] != '.')
-                               break;
-               case 1:
-                       if (de->d_name[0] != '.')
-                               break;
+               if (is_dot_or_dotdot(de->d_name))
                        continue;
-               case 38:
+               if (strlen(de->d_name) == 38) {
                        sprintf(name, "%02x", i);
-                       memcpy(name+2, de->d_name, len+1);
+                       memcpy(name+2, de->d_name, 39);
                        if (get_sha1_hex(name, sha1) < 0)
                                break;
                        add_sha1_list(sha1, DIRENT_SORT_HINT(de));
index 7b4ec80e62997fe70f53c92380cd4d66e80d62a0..545e9c1f9458ed936e2a99a208f75b70f368294c 100644 (file)
@@ -5,6 +5,7 @@
 #include "builtin.h"
 #include "reachable.h"
 #include "parse-options.h"
+#include "dir.h"
 
 static const char * const prune_usage[] = {
        "git prune [-n] [-v] [--expire <time>] [--] [<head>...]",
@@ -61,19 +62,12 @@ static int prune_dir(int i, char *path)
        while ((de = readdir(dir)) != NULL) {
                char name[100];
                unsigned char sha1[20];
-               int len = strlen(de->d_name);
 
-               switch (len) {
-               case 2:
-                       if (de->d_name[1] != '.')
-                               break;
-               case 1:
-                       if (de->d_name[0] != '.')
-                               break;
+               if (is_dot_or_dotdot(de->d_name))
                        continue;
-               case 38:
+               if (strlen(de->d_name) == 38) {
                        sprintf(name, "%02x", i);
-                       memcpy(name+2, de->d_name, len+1);
+                       memcpy(name+2, de->d_name, 39);
                        if (get_sha1_hex(name, sha1) < 0)
                                break;
 
index d4dec6b7156b081bf63933d4de6d0b62ab2212c8..bd8fc77a7a65a21a401f917b75d36883cda634ed 100644 (file)
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "dir.h"
 #include "string-list.h"
 #include "rerere.h"
 #include "xdiff/xdiff.h"
@@ -59,17 +60,15 @@ static void garbage_collect(struct string_list *rr)
        git_config(git_rerere_gc_config, NULL);
        dir = opendir(git_path("rr-cache"));
        while ((e = readdir(dir))) {
-               const char *name = e->d_name;
-               if (name[0] == '.' &&
-                   (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
+               if (is_dot_or_dotdot(e->d_name))
                        continue;
-               then = rerere_created_at(name);
+               then = rerere_created_at(e->d_name);
                if (!then)
                        continue;
-               cutoff = (has_resolution(name)
+               cutoff = (has_resolution(e->d_name)
                          ? cutoff_resolve : cutoff_noresolve);
                if (then < now - cutoff * 86400)
-                       string_list_append(name, &to_remove);
+                       string_list_append(e->d_name, &to_remove);
        }
        for (i = 0; i < to_remove.nr; i++)
                unlink_rr_item(to_remove.items[i].string);
diff --git a/dir.c b/dir.c
index 0131983dfbc143ce5dae77e067663bb2e7d5f126..7c598296a9e4997e153f4762b4a222328a6bd36b 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -585,10 +585,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
                        int len, dtype;
                        int exclude;
 
-                       if ((de->d_name[0] == '.') &&
-                           (de->d_name[1] == 0 ||
-                            !strcmp(de->d_name + 1, ".") ||
-                            !strcmp(de->d_name + 1, "git")))
+                       if (is_dot_or_dotdot(de->d_name) ||
+                            !strcmp(de->d_name, ".git"))
                                continue;
                        len = strlen(de->d_name);
                        /* Ignore overly long pathnames! */
@@ -779,6 +777,25 @@ int is_inside_dir(const char *dir)
        return get_relative_cwd(buffer, sizeof(buffer), dir) != NULL;
 }
 
+int is_empty_dir(const char *path)
+{
+       DIR *dir = opendir(path);
+       struct dirent *e;
+       int ret = 1;
+
+       if (!dir)
+               return 0;
+
+       while ((e = readdir(dir)) != NULL)
+               if (!is_dot_or_dotdot(e->d_name)) {
+                       ret = 0;
+                       break;
+               }
+
+       closedir(dir);
+       return ret;
+}
+
 int remove_dir_recursively(struct strbuf *path, int only_empty)
 {
        DIR *dir = opendir(path->buf);
@@ -793,10 +810,8 @@ int remove_dir_recursively(struct strbuf *path, int only_empty)
        len = path->len;
        while ((e = readdir(dir)) != NULL) {
                struct stat st;
-               if ((e->d_name[0] == '.') &&
-                   ((e->d_name[1] == 0) ||
-                    ((e->d_name[1] == '.') && e->d_name[2] == 0)))
-                       continue; /* "." and ".." */
+               if (is_dot_or_dotdot(e->d_name))
+                       continue;
 
                strbuf_setlen(path, len);
                strbuf_addstr(path, e->d_name);
diff --git a/dir.h b/dir.h
index 768425af0e7095a54edf161fe20400c4caf85b31..bdc2d47447c2ca406aac41d7a8382bf5928fbda8 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -77,6 +77,15 @@ extern int file_exists(const char *);
 extern char *get_relative_cwd(char *buffer, int size, const char *dir);
 extern int is_inside_dir(const char *dir);
 
+static inline int is_dot_or_dotdot(const char *name)
+{
+       return (name[0] == '.' &&
+               (name[1] == '\0' ||
+                (name[1] == '.' && name[2] == '\0')));
+}
+
+extern int is_empty_dir(const char *dir);
+
 extern void setup_standard_excludes(struct dir_struct *dir);
 extern int remove_dir_recursively(struct strbuf *path, int only_empty);
 
diff --git a/entry.c b/entry.c
index aa2ee46a84033585d8e07a585610c5a697af82c2..5f24816eb9fe9fa934889336f2dbcdc7bf006635 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "blob.h"
+#include "dir.h"
 
 static void create_directories(const char *path, const struct checkout *state)
 {
@@ -62,9 +63,7 @@ static void remove_subtree(const char *path)
        *name++ = '/';
        while ((de = readdir(dir)) != NULL) {
                struct stat st;
-               if ((de->d_name[0] == '.') &&
-                   ((de->d_name[1] == 0) ||
-                    ((de->d_name[1] == '.') && de->d_name[2] == 0)))
+               if (is_dot_or_dotdot(de->d_name))
                        continue;
                strcpy(name, de->d_name);
                if (lstat(pathbuf, &st))
index 570e11286ea295e825a23b1d5ed40c9fbd02be57..d7079c6dd871dc1b482d347d013438fe30cc0908 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -4,6 +4,7 @@
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
+#include "dir.h"
 
 static struct refspec s_tag_refspec = {
        0,
@@ -634,10 +635,7 @@ static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
 
 static int valid_remote_nick(const char *name)
 {
-       if (!name[0] || /* not empty */
-           (name[0] == '.' && /* not "." */
-            (!name[1] || /* not ".." */
-             (name[1] == '.' && !name[2]))))
+       if (!name[0] || is_dot_or_dotdot(name))
                return 0;
        return !strchr(name, '/'); /* no slash */
 }
index 78a3fa639c97b7dce054d89c74c67a855d0d7954..fe287d31fb98237b11ccc1d1209001dec3fb0a8e 100755 (executable)
@@ -125,4 +125,23 @@ test_expect_success 'clone to destination with extra trailing /' '
 
 '
 
+test_expect_success 'clone to an existing empty directory' '
+       mkdir target-3 &&
+       git clone src target-3 &&
+       T=$( cd target-3 && git rev-parse HEAD ) &&
+       S=$( cd src && git rev-parse HEAD ) &&
+       test "$T" = "$S"
+'
+
+test_expect_success 'clone to an existing non-empty directory' '
+       mkdir target-4 &&
+       >target-4/Fakefile &&
+       test_must_fail git clone src target-4
+'
+
+test_expect_success 'clone to an existing path' '
+       >target-5 &&
+       test_must_fail git clone src target-5
+'
+
 test_done
index 56831c57c5cf6500714c46c63581ca98662d58c3..9ad4a16c317b90770974aa5afbcf0986f4a5db91 100644 (file)
@@ -50,9 +50,7 @@ static int read_loose_refs(struct strbuf *path, int name_offset,
        memset (&list, 0, sizeof(list));
 
        while ((de = readdir(dir))) {
-               if (de->d_name[0] == '.' && (de->d_name[1] == '\0' ||
-                               (de->d_name[1] == '.' &&
-                                de->d_name[2] == '\0')))
+               if (is_dot_or_dotdot(de->d_name))
                        continue;
                ALLOC_GROW(list.entries, list.nr + 1, list.alloc);
                list.entries[list.nr++] = xstrdup(de->d_name);