]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'sb/submodule-helper-clone-regression-fix' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 2 May 2016 21:24:08 +0000 (14:24 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 2 May 2016 21:24:08 +0000 (14:24 -0700)
A partial rewrite of "git submodule" in the 2.7 timeframe changed
the way the gitdir: pointer in the submodules point at the real
repository location to use absolute paths by accident.  This has
been corrected.

* sb/submodule-helper-clone-regression-fix:
  submodule--helper, module_clone: catch fprintf failure
  submodule--helper: do not borrow absolute_path() result for too long
  submodule--helper, module_clone: always operate on absolute paths
  submodule--helper clone: create the submodule path just once
  submodule--helper: fix potential NULL-dereference
  recursive submodules: test for relative paths

1  2 
builtin/submodule--helper.c
t/t7400-submodule-basic.sh

index 5295b727d4609fa33a08c31b2d051ce3f98244fb,b3a60f56c345fce8dabc31826769ff879fbde931..3bea3aaa5029082198abab2b5a5dab838dbd6dec
@@@ -22,12 -22,17 +22,12 @@@ static int module_list_compute(int argc
                               struct module_list *list)
  {
        int i, result = 0;
 -      char *max_prefix, *ps_matched = NULL;
 -      int max_prefix_len;
 +      char *ps_matched = NULL;
        parse_pathspec(pathspec, 0,
                       PATHSPEC_PREFER_FULL |
                       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
                       prefix, argv);
  
 -      /* Find common prefix for all pathspec's */
 -      max_prefix = common_prefix(pathspec);
 -      max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
 -
        if (pathspec->nr)
                ps_matched = xcalloc(pathspec->nr, 1);
  
@@@ -37,9 -42,9 +37,9 @@@
        for (i = 0; i < active_nr; i++) {
                const struct cache_entry *ce = active_cache[i];
  
 -              if (!S_ISGITLINK(ce->ce_mode) ||
 -                  !match_pathspec(pathspec, ce->name, ce_namelen(ce),
 -                                  max_prefix_len, ps_matched, 1))
 +              if (!match_pathspec(pathspec, ce->name, ce_namelen(ce),
 +                                  0, ps_matched, 1) ||
 +                  !S_ISGITLINK(ce->ce_mode))
                        continue;
  
                ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
@@@ -52,6 -57,7 +52,6 @@@
                         */
                        i++;
        }
 -      free(max_prefix);
  
        if (ps_matched && report_path_error(ps_matched, pathspec, prefix))
                result = -1;
@@@ -147,11 -153,11 +147,11 @@@ static int clone_submodule(const char *
  
  static int module_clone(int argc, const char **argv, const char *prefix)
  {
-       const char *path = NULL, *name = NULL, *url = NULL;
+       const char *name = NULL, *url = NULL;
        const char *reference = NULL, *depth = NULL;
        int quiet = 0;
        FILE *submodule_dot_git;
-       char *sm_gitdir, *cwd, *p;
+       char *p, *path = NULL, *sm_gitdir;
        struct strbuf rel_path = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
  
        argc = parse_options(argc, argv, prefix, module_clone_options,
                             git_submodule_helper_usage, 0);
  
+       if (!path || !*path)
+               die(_("submodule--helper: unspecified or empty --path"));
        strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name);
-       sm_gitdir = strbuf_detach(&sb, NULL);
+       sm_gitdir = xstrdup(absolute_path(sb.buf));
+       strbuf_reset(&sb);
+       if (!is_absolute_path(path)) {
+               strbuf_addf(&sb, "%s/%s", get_git_work_tree(), path);
+               path = strbuf_detach(&sb, NULL);
+       } else
+               path = xstrdup(path);
  
        if (!file_exists(sm_gitdir)) {
                if (safe_create_leading_directories_const(sm_gitdir) < 0)
        }
  
        /* Write a .git file in the submodule to redirect to the superproject. */
-       if (safe_create_leading_directories_const(path) < 0)
-               die(_("could not create directory '%s'"), path);
-       if (path && *path)
-               strbuf_addf(&sb, "%s/.git", path);
-       else
-               strbuf_addstr(&sb, ".git");
+       strbuf_addf(&sb, "%s/.git", path);
        if (safe_create_leading_directories_const(sb.buf) < 0)
                die(_("could not create leading directories of '%s'"), sb.buf);
        submodule_dot_git = fopen(sb.buf, "w");
        if (!submodule_dot_git)
                die_errno(_("cannot open file '%s'"), sb.buf);
  
-       fprintf(submodule_dot_git, "gitdir: %s\n",
-               relative_path(sm_gitdir, path, &rel_path));
+       fprintf_or_die(submodule_dot_git, "gitdir: %s\n",
+                      relative_path(sm_gitdir, path, &rel_path));
        if (fclose(submodule_dot_git))
                die(_("could not close file %s"), sb.buf);
        strbuf_reset(&sb);
        strbuf_reset(&rel_path);
  
-       cwd = xgetcwd();
        /* Redirect the worktree of the submodule in the superproject's config */
-       if (!is_absolute_path(sm_gitdir)) {
-               strbuf_addf(&sb, "%s/%s", cwd, sm_gitdir);
-               free(sm_gitdir);
-               sm_gitdir = strbuf_detach(&sb, NULL);
-       }
-       strbuf_addf(&sb, "%s/%s", cwd, path);
        p = git_pathdup_submodule(path, "config");
        if (!p)
                die(_("could not get submodule directory for '%s'"), path);
        git_config_set_in_file(p, "core.worktree",
-                              relative_path(sb.buf, sm_gitdir, &rel_path));
+                              relative_path(path, sm_gitdir, &rel_path));
        strbuf_release(&sb);
        strbuf_release(&rel_path);
        free(sm_gitdir);
-       free(cwd);
+       free(path);
        free(p);
        return 0;
  }
index e1abd1923033617540c915af4372ba42936326d0,ea3fabbed87a6bd3e91f4d1d9a640411fd04b9d6..a41be3142e85112af7de1c2e865b7b2e261e7ebd
@@@ -816,6 -816,47 +816,47 @@@ test_expect_success 'submodule add --na
                git config submodule.repo_new.url >actual &&
                test_cmp expect actual
        )
+ '
+ test_expect_success 'recursive relative submodules stay relative' '
+       test_when_finished "rm -rf super clone2 subsub sub3" &&
+       mkdir subsub &&
+       (
+               cd subsub &&
+               git init &&
+               >t &&
+               git add t &&
+               git commit -m "initial commit"
+       ) &&
+       mkdir sub3 &&
+       (
+               cd sub3 &&
+               git init &&
+               >t &&
+               git add t &&
+               git commit -m "initial commit" &&
+               git submodule add ../subsub dirdir/subsub &&
+               git commit -m "add submodule subsub"
+       ) &&
+       mkdir super &&
+       (
+               cd super &&
+               git init &&
+               >t &&
+               git add t &&
+               git commit -m "initial commit" &&
+               git submodule add ../sub3 &&
+               git commit -m "add submodule sub"
+       ) &&
+       git clone super clone2 &&
+       (
+               cd clone2 &&
+               git submodule update --init --recursive &&
+               echo "gitdir: ../.git/modules/sub3" >./sub3/.git_expect &&
+               echo "gitdir: ../../../.git/modules/sub3/modules/dirdir/subsub" >./sub3/dirdir/subsub/.git_expect
+       ) &&
+       test_cmp clone2/sub3/.git_expect clone2/sub3/.git &&
+       test_cmp clone2/sub3/dirdir/subsub/.git_expect clone2/sub3/dirdir/subsub/.git
  '
  
  test_expect_success 'submodule add with an existing name fails unless forced' '
@@@ -849,19 -890,6 +890,19 @@@ test_expect_success 'set up a second su
        git commit -m "submodule example2 added"
  '
  
 +test_expect_success 'submodule deinit works on repository without submodules' '
 +      test_when_finished "rm -rf newdirectory" &&
 +      mkdir newdirectory &&
 +      (
 +              cd newdirectory &&
 +              git init &&
 +              >file &&
 +              git add file &&
 +              git commit -m "repo should not be empty"
 +              git submodule deinit .
 +      )
 +'
 +
  test_expect_success 'submodule deinit should remove the whole submodule section from .git/config' '
        git config submodule.example.foo bar &&
        git config submodule.example2.frotz nitfol &&
@@@ -1012,30 -1040,5 +1053,30 @@@ test_expect_success 'submodule add clon
        )
  '
  
 +test_expect_success 'submodule helper list is not confused by common prefixes' '
 +      mkdir -p dir1/b &&
 +      (
 +              cd dir1/b &&
 +              git init &&
 +              echo hi >testfile2 &&
 +              git add . &&
 +              git commit -m "test1"
 +      ) &&
 +      mkdir -p dir2/b &&
 +      (
 +              cd dir2/b &&
 +              git init &&
 +              echo hello >testfile1 &&
 +              git add .  &&
 +              git commit -m "test2"
 +      ) &&
 +      git submodule add /dir1/b dir1/b &&
 +      git submodule add /dir2/b dir2/b &&
 +      git commit -m "first submodule commit" &&
 +      git submodule--helper list dir1/b |cut -c51- >actual &&
 +      echo "dir1/b" >expect &&
 +      test_cmp expect actual
 +'
 +
  
  test_done