Signed-off-by: Stefan Beller <sbel...@google.com>
---

Marking this as RFC as documentation and tests are missing.

 builtin/rev-parse.c |  7 +++++
 submodule.c         | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 submodule.h         |  8 +++++
 3 files changed, 102 insertions(+)

diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index e08677e559..2549643267 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -12,6 +12,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "split-index.h"
+#include "submodule.h"
 
 #define DO_REVS                1
 #define DO_NOREV       2
@@ -779,6 +780,12 @@ int cmd_rev_parse(int argc, const char **argv, const char 
*prefix)
                                        puts(work_tree);
                                continue;
                        }
+                       if (!strcmp(arg, "--show-superproject-working-tree")) {
+                               const char *superproject = 
get_superproject_working_tree();
+                               if (superproject)
+                                       puts(superproject);
+                               continue;
+                       }
                        if (!strcmp(arg, "--show-prefix")) {
                                if (prefix)
                                        puts(prefix);
diff --git a/submodule.c b/submodule.c
index 3b98766a6b..a63aef2c6b 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1514,3 +1514,90 @@ void absorb_git_dir_into_superproject(const char *prefix,
                strbuf_release(&sb);
        }
 }
+
+static int superproject_exists(void)
+{
+       struct child_process cp = CHILD_PROCESS_INIT;
+       struct strbuf sb = STRBUF_INIT;
+       struct strbuf buf = STRBUF_INIT;
+       const char *one_up = real_path_if_valid("../");
+       const char *dirname;
+       int code, has_superproject = 0;
+
+       if (!one_up)
+               /* At the root of the file system. */
+               return 0;
+
+       dirname = relative_path(xgetcwd(), 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-tree", "HEAD", "--", dirname, NULL);
+
+       cp.no_stdin = 1;
+       cp.no_stderr = 1;
+       cp.out = -1;
+       cp.git_cmd = 1;
+
+       if (start_command(&cp))
+               die(_("could not start ls-tree in .."));
+
+       strbuf_read(&buf, cp.out, 7);
+       close(cp.out);
+       if (starts_with(buf.buf, "160000"))
+               /* there is a superproject having this as a submodule */
+               has_superproject = 1;
+
+       code = finish_command(&cp);
+
+       if (code == 128)
+               /* not a git repository */
+               goto out;
+       if (code == 0 && !has_superproject)
+               /* there is an unrelated git repository */
+               goto out;
+
+       if (code)
+               die(_("ls-tree returned unexpected return code"));
+
+       return 1;
+
+out:
+       strbuf_release(&sb);
+
+       return 0;
+}
+
+const char *get_superproject_working_tree()
+{
+       struct child_process cp = CHILD_PROCESS_INIT;
+       struct strbuf sb = STRBUF_INIT;
+
+       if (!superproject_exists())
+               return NULL;
+
+       prepare_submodule_repo_env(&cp.env_array);
+       argv_array_pop(&cp.env_array);
+
+       argv_array_pushl(&cp.args, "-C", "..",
+                       "rev-parse", "--show-toplevel", NULL);
+
+       cp.no_stdin = 1;
+       cp.no_stderr = 1;
+       cp.out = -1;
+       cp.git_cmd = 1;
+
+       if (start_command(&cp))
+               die(_("could not start rev-parse in .."));
+
+       strbuf_reset(&sb);
+       strbuf_read(&sb, cp.out, PATH_MAX);
+
+       /* remove trailing new line */
+       strbuf_rtrim(&sb);
+
+       if (finish_command(&cp))
+               die(_("rev-parse died unexpectedly"));
+
+       return strbuf_detach(&sb, NULL);
+}
diff --git a/submodule.h b/submodule.h
index 05ab674f06..f207bb8d5f 100644
--- a/submodule.h
+++ b/submodule.h
@@ -93,4 +93,12 @@ extern void prepare_submodule_repo_env(struct argv_array 
*out);
 extern void absorb_git_dir_into_superproject(const char *prefix,
                                             const char *path,
                                             unsigned flags);
+
+/*
+ * Return the absolute path of the working tree of the superproject, which this
+ * project is a submodule of. If this repository is not a submodule of
+ * another repository, return NULL.
+ */
+extern const char *get_superproject_working_tree();
+
 #endif
-- 
2.12.0.189.g3bc53220cb.dirty

Reply via email to