Signed-off-by: Stefan Beller <[email protected]>
---
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