Merge branch 'nd/clone-linked-checkout' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 5 Nov 2015 20:18:07 +0000 (12:18 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 5 Nov 2015 20:18:08 +0000 (12:18 -0800)
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

1  2 
builtin/clone.c
path.c
diff --combined builtin/clone.c
index cc896e22d16bab5fc46e02c7f164e1e512aeca62,3e14491a340cdce70308b31cdf96612344644c15..9eaecd9a7cdb9ad6726626c96edd05d2d9305453
@@@ -294,9 -294,14 +294,14 @@@ static int add_one_reference(struct str
                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 +429,10 @@@ static void clone_local(const char *src
        } 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);
@@@ -1064,10 -1071,8 +1071,10 @@@ int cmd_clone(int argc, const char **ar
        transport_unlock_pack(transport);
        transport_disconnect(transport);
  
 -      if (option_dissociate)
 +      if (option_dissociate) {
 +              close_all_packs();
                dissociate_from_references();
 +      }
  
        junk_mode = JUNK_LEAVE_REPO;
        err = checkout();
diff --combined path.c
index 69265f42cec4cfb19f6651b0dc845d2ab744711d,a34613446230751380df4ee1921f3d0d8d749458..56317a66be27e933d94e815d41a8806d235adbb7
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -98,7 -98,7 +98,7 @@@ static const char *common_list[] = 
        NULL
  };
  
 -static void update_common_dir(struct strbuf *buf, int git_dir_len)
 +static void update_common_dir(struct strbuf *buf, int git_dir_len, const char *common_dir)
  {
        char *base = buf->buf + git_dir_len;
        const char **p;
                        path++;
                        is_dir = 1;
                }
 +
 +              if (!common_dir)
 +                      common_dir = get_git_common_dir();
 +
                if (is_dir && dir_prefix(base, path)) {
 -                      replace_dir(buf, git_dir_len, get_git_common_dir());
 +                      replace_dir(buf, git_dir_len, common_dir);
                        return;
                }
                if (!is_dir && !strcmp(base, path)) {
 -                      replace_dir(buf, git_dir_len, get_git_common_dir());
 +                      replace_dir(buf, git_dir_len, common_dir);
                        return;
                }
        }
@@@ -164,7 -160,7 +164,7 @@@ static void adjust_git_path(struct strb
        else if (git_db_env && dir_prefix(base, "objects"))
                replace_dir(buf, git_dir_len + 7, get_object_directory());
        else if (git_common_dir_env)
 -              update_common_dir(buf, git_dir_len);
 +              update_common_dir(buf, git_dir_len, NULL);
  }
  
  static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
@@@ -232,8 -228,6 +232,8 @@@ static void do_submodule_path(struct st
                              const char *fmt, va_list args)
  {
        const char *git_dir;
 +      struct strbuf git_submodule_common_dir = STRBUF_INIT;
 +      struct strbuf git_submodule_dir = STRBUF_INIT;
  
        strbuf_addstr(buf, path);
        if (buf->len && buf->buf[buf->len - 1] != '/')
                strbuf_addstr(buf, git_dir);
        }
        strbuf_addch(buf, '/');
 +      strbuf_addstr(&git_submodule_dir, buf->buf);
  
        strbuf_vaddf(buf, fmt, args);
 +
 +      if (get_common_dir_noenv(&git_submodule_common_dir, git_submodule_dir.buf))
 +              update_common_dir(buf, git_submodule_dir.len, git_submodule_common_dir.buf);
 +
        strbuf_cleanup_path(buf);
 +
 +      strbuf_release(&git_submodule_dir);
 +      strbuf_release(&git_submodule_common_dir);
  }
  
  char *git_pathdup_submodule(const char *path, const char *fmt, ...)
@@@ -445,18 -431,22 +445,22 @@@ const char *enter_repo(const char *path
                }
                if (!suffix[i])
                        return NULL;
-               gitfile = read_gitfile(used_path) ;
+               gitfile = read_gitfile(used_path);
                if (gitfile)
                        strcpy(used_path, gitfile);
                if (chdir(used_path))
                        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;
@@@ -690,11 -680,6 +694,11 @@@ const char *remove_leading_path(const c
   * normalized, any time "../" eats up to the prefix_len part,
   * prefix_len is reduced. In the end prefix_len is the remaining
   * prefix that has not been overridden by user pathspec.
 + *
 + * NEEDSWORK: This function doesn't perform normalization w.r.t. trailing '/'.
 + * For everything but the root folder itself, the normalized path should not
 + * end with a '/', then the callers need to be fixed up accordingly.
 + *
   */
  int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
  {