Merge branch 'nd/clone-linked-checkout'
authorJunio C Hamano <gitster@pobox.com>
Thu, 15 Oct 2015 22:43:39 +0000 (15:43 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 15 Oct 2015 22:43:40 +0000 (15:43 -0700)
It was not possible to use a repository-lookalike created by "git
worktree add" as a local source of "git clone".

* nd/clone-linked-checkout:
clone: better error when --reference is a linked checkout
clone: allow --local from a linked checkout
enter_repo: allow .git files in strict mode
enter_repo: avoid duplicating logic, use is_git_directory() instead
t0002: add test for enter_repo(), non-strict mode
path.c: delete an extra space

builtin/clone.c
path.c
t/t0002-gitfile.sh
t/t2025-worktree-add.sh
index 578da85254418a620d3c7c847af8eed6a3a29d58..3e14491a340cdce70308b31cdf96612344644c15 100644 (file)
@@ -294,9 +294,14 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
                char *ref_git_git = mkpathdup("%s/.git", ref_git);
                free(ref_git);
                ref_git = ref_git_git;
-       } else if (!is_directory(mkpath("%s/objects", ref_git)))
+       } else if (!is_directory(mkpath("%s/objects", ref_git))) {
+               struct strbuf sb = STRBUF_INIT;
+               if (get_common_dir(&sb, ref_git))
+                       die(_("reference repository '%s' as a linked checkout is not supported yet."),
+                           item->string);
                die(_("reference repository '%s' is not a local repository."),
                    item->string);
+       }
 
        if (!access(mkpath("%s/shallow", ref_git), F_OK))
                die(_("reference repository '%s' is shallow"), item->string);
@@ -424,8 +429,10 @@ static void clone_local(const char *src_repo, const char *dest_repo)
        } else {
                struct strbuf src = STRBUF_INIT;
                struct strbuf dest = STRBUF_INIT;
-               strbuf_addf(&src, "%s/objects", src_repo);
-               strbuf_addf(&dest, "%s/objects", dest_repo);
+               get_common_dir(&src, src_repo);
+               get_common_dir(&dest, dest_repo);
+               strbuf_addstr(&src, "/objects");
+               strbuf_addstr(&dest, "/objects");
                copy_or_link_directory(&src, &dest, src_repo, src.len);
                strbuf_release(&src);
                strbuf_release(&dest);
diff --git a/path.c b/path.c
index 5ec34905a39d6e74134dd3488145b9da44f61b55..62a2ae82ddfd3fc9213da0988e761985a5f177e4 100644 (file)
--- a/path.c
+++ b/path.c
@@ -668,11 +668,15 @@ const char *enter_repo(const char *path, int strict)
                        return NULL;
                path = validated_path;
        }
-       else if (chdir(path))
-               return NULL;
+       else {
+               const char *gitfile = read_gitfile(path);
+               if (gitfile)
+                       path = gitfile;
+               if (chdir(path))
+                       return NULL;
+       }
 
-       if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
-           validate_headref("HEAD") == 0) {
+       if (is_git_directory(".")) {
                set_git_dir(".");
                check_repository_format();
                return path;
index 9393322c3e7028ea7074d2b1ec50fbb293c6728f..9670e8cbe6cb9a9faa3519b0f11dc16713496188 100755 (executable)
@@ -116,4 +116,46 @@ test_expect_success 'setup_git_dir twice in subdir' '
        )
 '
 
+test_expect_success 'enter_repo non-strict mode' '
+       test_create_repo enter_repo &&
+       (
+               cd enter_repo &&
+               test_tick &&
+               test_commit foo &&
+               mv .git .realgit &&
+               echo "gitdir: .realgit" >.git
+       ) &&
+       git ls-remote enter_repo >actual &&
+       cat >expected <<-\EOF &&
+       946e985ab20de757ca5b872b16d64e92ff3803a9        HEAD
+       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/heads/master
+       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/tags/foo
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'enter_repo linked checkout' '
+       (
+               cd enter_repo &&
+               git worktree add  ../foo refs/tags/foo
+       ) &&
+       git ls-remote foo >actual &&
+       cat >expected <<-\EOF &&
+       946e985ab20de757ca5b872b16d64e92ff3803a9        HEAD
+       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/heads/master
+       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/tags/foo
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'enter_repo strict mode' '
+       git ls-remote --upload-pack="git upload-pack --strict" foo/.git >actual &&
+       cat >expected <<-\EOF &&
+       946e985ab20de757ca5b872b16d64e92ff3803a9        HEAD
+       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/heads/master
+       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/tags/foo
+       EOF
+       test_cmp expected actual
+'
+
 test_done
index 8267411a0ec129a67cde5381cfd79824471d8fd2..369417498946fcebb901d8593bb584f3767b1e67 100755 (executable)
@@ -193,4 +193,9 @@ test_expect_success '"add" -B/--detach mutually exclusive' '
        test_must_fail git worktree add -B poodle --detach bamboo master
 '
 
+test_expect_success 'local clone from linked checkout' '
+       git clone --local here here-clone &&
+       ( cd here-clone && git fsck )
+'
+
 test_done