rev-parse: add --show-superproject-working-tree
In some situations it is useful to know if the given repository is a submodule of another repository. Add the flag --show-superproject-working-tree to git-rev-parse to make it easy to find out if there is a superproject. When no superproject exists, the output will be empty. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Stefan Beller committed
Mar 8, 2017 at 15:07 UTC
bf0231c66140be5194ac76a4a9f79e949c588293
5 files changed
+117
Documentation/git-rev-parse.txt
+6
@@ -261,6 +261,12 @@ print a message to stderr and exit with nonzero status.
261
--show-toplevel::
262
Show the absolute path of the top-level directory.
263
264
+--show-superproject-working-tree
265
+ Show the absolute path of the root of the superproject's
266
+ working tree (if exists) that uses the current repository as
267
+ its submodule. Outputs nothing if the current repository is
268
+ not used as a submodule by any project.
269
+
270
--shared-index-path::
271
Show the path to the shared index file in split index mode, or
272
empty if not in split-index mode.
builtin/rev-parse.c
+7
@@ -12,6 +12,7 @@
12
#include "diff.h"
13
#include "revision.h"
14
#include "split-index.h"
15
+#include "submodule.h"
16
17
#define DO_REVS 1
18
#define DO_NOREV 2
@@ -779,6 +780,12 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
780
puts(work_tree);
781
continue;
782
}
783
+ if (!strcmp(arg, "--show-superproject-working-tree")) {
784
+ const char *superproject = get_superproject_working_tree();
785
+ if (superproject)
786
+ puts(superproject);
787
+ continue;
788
+ }
789
if (!strcmp(arg, "--show-prefix")) {
790
if (prefix)
791
puts(prefix);
submodule.c
+82
@@ -1514,3 +1514,85 @@ void absorb_git_dir_into_superproject(const char *prefix,
1514
strbuf_release(&sb);
1515
}
1516
}
1517
+
1518
+const char *get_superproject_working_tree(void)
1519
+{
1520
+ struct child_process cp = CHILD_PROCESS_INIT;
1521
+ struct strbuf sb = STRBUF_INIT;
1522
+ const char *one_up = real_path_if_valid("../");
1523
+ const char *cwd = xgetcwd();
1524
+ const char *ret = NULL;
1525
+ const char *subpath;
1526
+ int code;
1527
+ ssize_t len;
1528
+
1529
+ if (!is_inside_work_tree())
1530
+ /*
1531
+ * FIXME:
1532
+ * We might have a superproject, but it is harder
1533
+ * to determine.
1534
+ */
1535
+ return NULL;
1536
+
1537
+ if (!one_up)
1538
+ return NULL;
1539
+
1540
+ subpath = relative_path(cwd, one_up, &sb);
1541
+
1542
+ prepare_submodule_repo_env(&cp.env_array);
1543
+ argv_array_pop(&cp.env_array);
1544
+
1545
+ argv_array_pushl(&cp.args, "--literal-pathspecs", "-C", "..",
1546
+ "ls-files", "-z", "--stage", "--full-name", "--",
1547
+ subpath, NULL);
1548
+ strbuf_reset(&sb);
1549
+
1550
+ cp.no_stdin = 1;
1551
+ cp.no_stderr = 1;
1552
+ cp.out = -1;
1553
+ cp.git_cmd = 1;
1554
+
1555
+ if (start_command(&cp))
1556
+ die(_("could not start ls-files in .."));
1557
+
1558
+ len = strbuf_read(&sb, cp.out, PATH_MAX);
1559
+ close(cp.out);
1560
+
1561
+ if (starts_with(sb.buf, "160000")) {
1562
+ int super_sub_len;
1563
+ int cwd_len = strlen(cwd);
1564
+ char *super_sub, *super_wt;
1565
+
1566
+ /*
1567
+ * There is a superproject having this repo as a submodule.
1568
+ * The format is <mode> SP <hash> SP <stage> TAB <full name> \0,
1569
+ * We're only interested in the name after the tab.
1570
+ */
1571
+ super_sub = strchr(sb.buf, '\t') + 1;
1572
+ super_sub_len = sb.buf + sb.len - super_sub - 1;
1573
+
1574
+ if (super_sub_len > cwd_len ||
1575
+ strcmp(&cwd[cwd_len - super_sub_len], super_sub))
1576
+ die (_("BUG: returned path string doesn't match cwd?"));
1577
+
1578
+ super_wt = xstrdup(cwd);
1579
+ super_wt[cwd_len - super_sub_len] = '\0';
1580
+
1581
+ ret = real_path(super_wt);
1582
+ free(super_wt);
1583
+ }
1584
+ strbuf_release(&sb);
1585
+
1586
+ code = finish_command(&cp);
1587
+
1588
+ if (code == 128)
1589
+ /* '../' is not a git repository */
1590
+ return NULL;
1591
+ if (code == 0 && len == 0)
1592
+ /* There is an unrelated git repository at '../' */
1593
+ return NULL;
1594
+ if (code)
1595
+ die(_("ls-tree returned unexpected return code %d"), code);
1596
+
1597
+ return ret;
1598
+}
submodule.h
+8
@@ -93,4 +93,12 @@ extern void prepare_submodule_repo_env(struct argv_array *out);
93
extern void absorb_git_dir_into_superproject(const char *prefix,
94
const char *path,
95
unsigned flags);
96
+
97
+/*
98
+ * Return the absolute path of the working tree of the superproject, which this
99
+ * project is a submodule of. If this repository is not a submodule of
100
+ * another repository, return NULL.
101
+ */
102
+extern const char *get_superproject_working_tree(void);
103
+
104
#endif
t/t1500-rev-parse.sh
+14
@@ -116,4 +116,18 @@ test_expect_success 'git-path inside sub-dir' '
116
test_cmp expect actual
117
'
118
119
+test_expect_success 'showing the superproject correctly' '
120
+ git rev-parse --show-superproject-working-tree >out &&
121
+ test_must_be_empty out &&
122
+
123
+ test_create_repo super &&
124
+ test_commit -C super test_commit &&
125
+ test_create_repo sub &&
126
+ test_commit -C sub test_commit &&
127
+ git -C super submodule add ../sub dir/sub &&
128
+ echo $(pwd)/super >expect &&
129
+ git -C super/dir/sub rev-parse --show-superproject-working-tree >out &&
130
+ test_cmp expect out
131
+'
132
+
133
test_done