git@vger.kernel.org mailing list mirror (one of many)
 help / Atom feed
From: Stefan Beller <sbeller@google.com>
To: szeder.dev@gmail.com, email@benjaminfuchs.de,
	git@vger.kernel.org, sandals@crustytoothpaste.net,
	ville.skytta@iki.fi
Cc: Stefan Beller <sbeller@google.com>
Subject: [PATCHv3] rev-parse: add --show-superproject-working-tree
Date: Wed,  8 Mar 2017 11:20:37 -0800
Message-ID: <20170308192037.21847-1-sbeller@google.com> (raw)
In-Reply-To: <xmqq60jk488v.fsf@gitster.mtv.corp.google.com>

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.

Signed-off-by: Stefan Beller <sbeller@google.com>
---
> Looks more or less right but invoke "ls-files -z" and reading the \0
> delimited output would be easier;

done

> otherwise you would have to worry
> about c-unquoting the pathname when the submodule is bound at a path
> with funny character (like a double-quote) in it.
 
paths from "rev-parse" (like "--git-dir", "--show-toplevel", etc.) already
are excempt from quoting rules, apparently.

  $ git rev-parse --show-toplevel
/usr/local/google/home/sbeller/OSS/git/t/trash directory.t1500-rev-parse


interdiff to v2:
  #diff --git a/submodule.c b/submodule.c
  #index 06473d3646..bb405653fd 100644
  #--- a/submodule.c
  #+++ b/submodule.c
  #@@ -1543,7 +1543,8 @@ const char *get_superproject_working_tree(void)
  # 	argv_array_pop(&cp.env_array);
  # 
  # 	argv_array_pushl(&cp.args, "--literal-pathspecs", "-C", "..",
  #-			"ls-files", "--stage", "--full-name", "--", subpath, NULL);
  #+			"ls-files", "-z", "--stage", "--full-name", "--",
  #+			subpath, NULL);
  # 	strbuf_reset(&sb);
  # 
  # 	cp.no_stdin = 1;
  #@@ -1564,13 +1565,12 @@ const char *get_superproject_working_tree(void)
  # 
  # 		/*
  # 		 * There is a superproject having this repo as a submodule.
  #-		 * The format is <mode> SP <hash> SP <stage> TAB <full name> LF,
  #-		 * First remove LF, then skip up to \t.
  #+		 * The format is <mode> SP <hash> SP <stage> TAB <full name> \0,
  #+		 * We're only interested in the name after the tab.
  # 		 */
  #-		strbuf_rtrim(&sb);
  # 		super_sub = strchr(sb.buf, '\t') + 1;
  #+		super_sub_len = sb.buf + sb.len - super_sub - 1;
  # 
  #-		super_sub_len = sb.buf + sb.len - super_sub;
  # 		if (super_sub_len > cwd_len ||
  # 		    strcmp(&cwd[cwd_len - super_sub_len], super_sub))
  # 			die (_("BUG: returned path string doesn't match cwd?"));
  #@@ -1579,7 +1579,6 @@ const char *get_superproject_working_tree(void)
  # 		super_wt[cwd_len - super_sub_len] = '\0';
  # 
  # 		ret = real_path(super_wt);
  #-
  # 		free(super_wt);
  # 	}
  # 	strbuf_release(&sb);
  
  Thanks,
  Stefan
  

 Documentation/git-rev-parse.txt |  5 +++
 builtin/rev-parse.c             |  7 ++++
 submodule.c                     | 82 +++++++++++++++++++++++++++++++++++++++++
 submodule.h                     |  8 ++++
 t/t1500-rev-parse.sh            | 14 +++++++
 5 files changed, 116 insertions(+)

diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 91c02b8c85..b841bad7c7 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -261,6 +261,11 @@ print a message to stderr and exit with nonzero status.
 --show-toplevel::
 	Show the absolute path of the top-level directory.
 
+--show-superproject-working-tree
+	Show the absolute path of the top-level directory of
+	the superproject. A superproject is a repository that records
+	this repository as a submodule.
+
 --shared-index-path::
 	Show the path to the shared index file in split index mode, or
 	empty if not in split-index mode.
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..bb405653fd 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1514,3 +1514,85 @@ void absorb_git_dir_into_superproject(const char *prefix,
 		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;
+}
diff --git a/submodule.h b/submodule.h
index 05ab674f06..c8a0c9cb29 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(void);
+
 #endif
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 9ed8b8ccba..03d3c7f6d6 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -116,4 +116,18 @@ test_expect_success 'git-path inside sub-dir' '
 	test_cmp expect actual
 '
 
+test_expect_success 'showing the superproject correctly' '
+	git rev-parse --show-superproject-working-tree >out &&
+	test_must_be_empty out &&
+
+	test_create_repo super &&
+	test_commit -C super test_commit &&
+	test_create_repo sub &&
+	test_commit -C sub test_commit &&
+	git -C super submodule add ../sub dir/sub &&
+	echo $(pwd)/super >expect  &&
+	git -C super/dir/sub rev-parse --show-superproject-working-tree >out &&
+	test_cmp expect out
+'
+
 test_done
-- 
2.12.0.190.g6e60aba09d.dirty


  reply index

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-30 20:44 [PATCH 0/4] git-prompt.sh: Full patch for submodule indicator Benjamin Fuchs
2017-01-30 20:44 ` [PATCH 1/4] git-prompt.sh: add " Benjamin Fuchs
2017-01-30 23:48   ` Junio C Hamano
2017-01-31  0:10     ` Benjamin Fuchs
2017-01-31  3:11       ` Junio C Hamano
2017-02-06  4:23         ` Stefan Beller
2017-02-06  5:55           ` Jacob Keller
2017-02-06 10:13             ` Stefan Beller
2017-01-30 20:44 ` [PATCH 2/4] git-prompt.sh: rework of " Benjamin Fuchs
2017-01-30 20:44 ` [PATCH 4/4] git-prompt.sh: add tests for " Benjamin Fuchs
2017-01-31 18:32   ` SZEDER Gábor
2017-01-31 22:06     ` Junio C Hamano
2017-01-31 22:12       ` Stefan Beller
2017-03-07  3:45         ` [RFC PATCH] rev-parse: add --show-superproject-working-tree Stefan Beller
2017-03-07  5:13           ` Junio C Hamano
2017-03-07  7:16             ` Junio C Hamano
2017-03-07  7:23               ` Junio C Hamano
2017-03-07 18:44           ` Junio C Hamano
2017-03-07 20:40             ` Stefan Beller
2017-03-07 22:49               ` Junio C Hamano
2017-03-08  0:56                 ` [PATCHv2] " Stefan Beller
2017-03-08  1:30                   ` Junio C Hamano
2017-03-08  6:01                   ` Junio C Hamano
2017-03-08 19:20                     ` Stefan Beller [this message]
2017-03-08 22:28                       ` [PATCHv3] " Junio C Hamano
2017-03-08 23:07                         ` [PATCHv4] " Stefan Beller
2017-03-08 23:51                           ` Junio C Hamano
2017-03-17 22:28                           ` Jonathan Nieder
2017-03-17 22:51                             ` [PATCH] Documentation/git-worktree: use working tree for trees on the file system Stefan Beller
2017-03-17 22:55                               ` Jonathan Nieder
2017-03-17 23:04                                 ` Stefan Beller
2017-03-18 17:24                                   ` Junio C Hamano
2017-03-18  1:47                                 ` Junio C Hamano
2017-03-18  1:36                               ` Junio C Hamano
2017-03-20 17:29                                 ` Stefan Beller
2017-03-20 18:12                                   ` Junio C Hamano
2017-03-20 18:50                                     ` Jonathan Nieder
2017-03-20 19:22                                       ` [PATCH 0/2] use "working trees" instead of "worktree" in our API Stefan Beller
2017-03-20 19:22                                         ` [PATCH 1/2] git.c: introduce --working-tree superseding --work-tree Stefan Beller
2017-03-20 19:58                                           ` Jonathan Nieder
2017-03-20 19:22                                         ` [PATCH 2/2] revparse: introduce --is-inside-working-tree Stefan Beller
2017-03-20 20:00                                           ` Jonathan Nieder
2017-03-20 19:37                                         ` [PATCH 0/2] use "working trees" instead of "worktree" in our API Junio C Hamano
2017-03-21 10:37                                       ` [PATCH] Documentation/git-worktree: use working tree for trees on the file system Duy Nguyen
2017-03-21 15:48                                         ` Junio C Hamano
2017-03-23 17:06                                           ` Michael J Gruber
2017-03-23 17:55                                             ` Junio C Hamano
2017-03-25 12:07                                               ` Duy Nguyen
2017-04-07 13:59                                                 ` Michael J Gruber
2017-04-07 16:14                                                   ` Jacob Keller
2017-03-25 12:05                                           ` Duy Nguyen

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170308192037.21847-1-sbeller@google.com \
    --to=sbeller@google.com \
    --cc=email@benjaminfuchs.de \
    --cc=git@vger.kernel.org \
    --cc=sandals@crustytoothpaste.net \
    --cc=szeder.dev@gmail.com \
    --cc=ville.skytta@iki.fi \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

git@vger.kernel.org mailing list mirror (one of many)

Archives are clonable:
	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.org/gmane.comp.version-control.git

 note: .onion URLs require Tor: https://www.torproject.org/
       or Tor2web: https://www.tor2web.org/

AGPL code for this site: git clone https://public-inbox.org/ public-inbox