Merge branch 'sb/rev-parse-show-superproject-root'
authorJunio C Hamano <gitster@pobox.com>
Fri, 17 Mar 2017 20:50:25 +0000 (13:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 17 Mar 2017 20:50:25 +0000 (13:50 -0700)
From a working tree of a repository, a new option of "rev-parse"
lets you ask if the repository is used as a submodule of another
project, and where the root level of the working tree of that
project (i.e. your superproject) is.

* sb/rev-parse-show-superproject-root:
rev-parse: add --show-superproject-working-tree

1  2 
submodule.c
diff --combined submodule.c
index 0a2831d846d27e694ada4bc557a7d54a8bf2d8df,bb405653fd29686e25faf978a760b8e33d80dff3..3200b7bb2b2360c7efab86b680ed5d0cafa5e9d3
@@@ -1403,7 -1403,7 +1403,7 @@@ static void relocate_single_git_dir_int
                /* If it is an actual gitfile, it doesn't need migration. */
                return;
  
 -      real_old_git_dir = real_pathdup(old_git_dir);
 +      real_old_git_dir = real_pathdup(old_git_dir, 1);
  
        sub = submodule_from_path(null_sha1, path);
        if (!sub)
        new_git_dir = git_path("modules/%s", sub->name);
        if (safe_create_leading_directories_const(new_git_dir) < 0)
                die(_("could not create directory '%s'"), new_git_dir);
 -      real_new_git_dir = real_pathdup(new_git_dir);
 +      real_new_git_dir = real_pathdup(new_git_dir, 1);
  
        if (!prefix)
                prefix = get_super_prefix();
@@@ -1472,14 -1472,14 +1472,14 @@@ void absorb_git_dir_into_superproject(c
                new_git_dir = git_path("modules/%s", sub->name);
                if (safe_create_leading_directories_const(new_git_dir) < 0)
                        die(_("could not create directory '%s'"), new_git_dir);
 -              real_new_git_dir = real_pathdup(new_git_dir);
 +              real_new_git_dir = real_pathdup(new_git_dir, 1);
                connect_work_tree_and_git_dir(path, real_new_git_dir);
  
                free(real_new_git_dir);
        } else {
                /* Is it already absorbed into the superprojects git dir? */
 -              char *real_sub_git_dir = real_pathdup(sub_git_dir);
 -              char *real_common_git_dir = real_pathdup(get_git_common_dir());
 +              char *real_sub_git_dir = real_pathdup(sub_git_dir, 1);
 +              char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
  
                if (!starts_with(real_sub_git_dir, real_common_git_dir))
                        relocate_single_git_dir_into_superproject(prefix, path);
                strbuf_release(&sb);
        }
  }
+ const char *get_superproject_working_tree(void)
+ {
+       struct child_process cp = CHILD_PROCESS_INIT;
+       struct strbuf sb = STRBUF_INIT;
+       const char *one_up = real_path_if_valid("../");
+       const char *cwd = xgetcwd();
+       const char *ret = NULL;
+       const char *subpath;
+       int code;
+       ssize_t len;
+       if (!is_inside_work_tree())
+               /*
+                * FIXME:
+                * We might have a superproject, but it is harder
+                * to determine.
+                */
+               return NULL;
+       if (!one_up)
+               return NULL;
+       subpath = relative_path(cwd, one_up, &sb);
+       prepare_submodule_repo_env(&cp.env_array);
+       argv_array_pop(&cp.env_array);
+       argv_array_pushl(&cp.args, "--literal-pathspecs", "-C", "..",
+                       "ls-files", "-z", "--stage", "--full-name", "--",
+                       subpath, NULL);
+       strbuf_reset(&sb);
+       cp.no_stdin = 1;
+       cp.no_stderr = 1;
+       cp.out = -1;
+       cp.git_cmd = 1;
+       if (start_command(&cp))
+               die(_("could not start ls-files in .."));
+       len = strbuf_read(&sb, cp.out, PATH_MAX);
+       close(cp.out);
+       if (starts_with(sb.buf, "160000")) {
+               int super_sub_len;
+               int cwd_len = strlen(cwd);
+               char *super_sub, *super_wt;
+               /*
+                * There is a superproject having this repo as a submodule.
+                * The format is <mode> SP <hash> SP <stage> TAB <full name> \0,
+                * We're only interested in the name after the tab.
+                */
+               super_sub = strchr(sb.buf, '\t') + 1;
+               super_sub_len = sb.buf + sb.len - super_sub - 1;
+               if (super_sub_len > cwd_len ||
+                   strcmp(&cwd[cwd_len - super_sub_len], super_sub))
+                       die (_("BUG: returned path string doesn't match cwd?"));
+               super_wt = xstrdup(cwd);
+               super_wt[cwd_len - super_sub_len] = '\0';
+               ret = real_path(super_wt);
+               free(super_wt);
+       }
+       strbuf_release(&sb);
+       code = finish_command(&cp);
+       if (code == 128)
+               /* '../' is not a git repository */
+               return NULL;
+       if (code == 0 && len == 0)
+               /* There is an unrelated git repository at '../' */
+               return NULL;
+       if (code)
+               die(_("ls-tree returned unexpected return code %d"), code);
+       return ret;
+ }