git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / code / Atom feed
* [RFC PATCH 0/4] git: remove --super-prefix
@ 2022-11-09  0:47 Glen Choo
  2022-11-09  0:47 ` [RFC PATCH 1/4] submodule--helper: teach --toplevel-cwd-prefix Glen Choo
                   ` (5 more replies)
  0 siblings, 6 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-09  0:47 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

*Note to maintainer*: See "Interactions with other series".

Given the work on ab/submodule-helper-prep-only, I'm sending this early
for feedback, and to see if I can avoid blocking Ævar's follow-up work.
This is pretty much done, but I haven't scrutinized the patches too
closely to see if all of the relevant paths are tested.

The main motivation behind this is the partial clone bug demonstrated by
the test in Patch 3/4, but instead of just fixing that one issue, I'd
prefer to get rid of this class of error once and for all.

= Description

When we introduced the internal-only "--super-prefix" in 74866d7579
(git: make super-prefix option, 2016-10-07), we specified that commands
must prefix paths by it, and pathspecs must be parsed relative to it.
That commit also includes safeguards to ensure that "--super-prefix" is
used correctly, namely:

- Only commands marked SUPPORT_SUPER_PREFIX can be invoked with
  "--super-prefix".
- The super prefix is propagated via the GIT_INTERNAL_SUPER_PREFIX env
  var, so a non-SUPPORT_SUPER_PREFIX command cannot be invoked by a
  SUPPORT_SUPER_PREFIX one.

However, its use is inconsistent, which is a strong reason to consider
using better-scoped flags instead. For example..

- Of the 4 commands that are SUPPORT_SUPER_PREFIX, only "read-tree" and
  "submodule--helper" do anything useful with it. "fsmonitor--daemon"
  has it to avoid the SUPPORT_SUPER_PREFIX warning [1].
  "checkout--worker" doesn't have a documented reason, but since it can
  be invoked by "read-tree", it's presumably also a workaround.
- "read-tree" and "submodule--helper" use different values for the super
  prefix; "read-tree" passes the path from the root of the
  superproject's tree to the submodule's gitlink, while
  "submodule--helper" passes the relative path of the original CWD to
  the submodule.
- "submodule--helper" doesn't use "--super-prefix" to parse pathspecs,
  only to display paths.

This series replaces the top-level "--super-prefix" with better-scoped,
per-command flags.

= Interactions with other series

As noted in the conversation starting at [2], the submodule--helper bits
in this series have substantial overlap with
ab/submodule-helper-prep-only and the work that series is prep for. I've
based this series off ab/submodule-helper-prep-only, since the
conversion of builtin/submodule--helper.c to use options parsing makes
patch 1 much easier to reason about.

Ævar: The patch of interest is 1/4, which removes the super prefix check
from submodule--helper. Hopefully you find this useful, I strongly
suspect that it will save time and churn for us to move this series
forward and to base your follow up work on this. But if this does end up
stalling, however, I'm happy to rebase this on top of your follow up
work.

= Patch summary

- Patch 1/4 introduces a "--toplevel-cwd-prefix" flag for "git
  submodule--helper" (replacing "--super-prefix" for "git
  submodule--helper").
- Patches 2-3/4 refactors "--submodule-prefix" for "git fetch" and
  reuses that implementation for "git read-tree" (replacing
  "--super-prefix" for "git read-tree").
- Patch 4 drops "--super-prefix" and a now-defunct fsmonitor test.

[1]: 53fcfbc84f (fsmonitor--daemon: allow --super-prefix argument, 2022-05-26)
[2]: https://lore.kernel.org/git/221104.86wn8bzeus.gmgdl@evledraar.gmail.com

Glen Choo (4):
  submodule--helper: teach --toplevel-cwd-prefix
  fetch: refactor --submodule-prefix
  read-tree: teach --submodule-prefix
  git: remove --super-prefix

 Documentation/fetch-options.txt    |  5 --
 Documentation/git.txt              |  7 +--
 builtin.h                          |  4 --
 builtin/fetch.c                    |  7 ++-
 builtin/read-tree.c                |  4 ++
 builtin/submodule--helper.c        | 52 ++++++++-----------
 cache.h                            |  2 -
 environment.c                      | 13 -----
 git.c                              | 40 +++-----------
 repository.c                       |  1 +
 repository.h                       |  9 +++-
 submodule.c                        | 83 ++++++++++++++++++------------
 submodule.h                        | 20 ++++++-
 t/t1001-read-tree-m-2way.sh        |  4 +-
 t/t5616-partial-clone.sh           | 43 ++++++++++++++++
 t/t7412-submodule-absorbgitdirs.sh | 13 ++++-
 t/t7527-builtin-fsmonitor.sh       | 50 ------------------
 unpack-trees.c                     | 32 ++++++------
 18 files changed, 187 insertions(+), 202 deletions(-)


base-commit: 69d94464e14de859ff56bcde7ebe0132201eceb9
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply	[flat|nested] 79+ messages in thread

* [RFC PATCH 1/4] submodule--helper: teach --toplevel-cwd-prefix
  2022-11-09  0:47 [RFC PATCH 0/4] git: remove --super-prefix Glen Choo
@ 2022-11-09  0:47 ` Glen Choo
  2022-11-09  2:37   ` Ævar Arnfjörð Bjarmason
  2022-11-09  0:47 ` [RFC PATCH 2/4] fetch: refactor --submodule-prefix Glen Choo
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-09  0:47 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

The top-level "--super-prefix" option (i.e. "git --super-prefix") is
overloaded:

- "git submodule--helper" passes the relative path between the top-level
  "git" process's cwd and the current repository
- "git read-tree" passes the path from the root of top-level
  superproject's tree to the the current repository.

In both cases, "--super-prefix" is only used to display meaningful paths
from the superproject to a nested submodule.

Let's address this overloading by breaking it up into its constituent
use cases. Teach "git submodule--helper" the "--toplevel-cwd-prefix"
option, which replaces its usage of "git --super-prefix". (A future
patch will address the "git read-tree" use case.) This value is only
used in builtin/submodule--helper.c, but it is stored in submodule.c,
since it may be needed by other builtins in the future.

When "--toplevel-cwd-prefix" is provided, paths to submodules in the
working tree should be prefixed by it when they are printed, making the
paths relative to the top-level process's cwd. This is the only way the
prefix is used in "git submodule--helper", and all of its subcommands
already conform to this behavior (even the ones that weren't marked
SUPPORT_SUPER_PREFIX) because they all use
get_submodule_displaypath() when printing paths to submodules. As such,
we can say that all of "git submodule--helper" supports (and should
continue to support) this flag, so we drop the constraint that
"--toplevel-cwd-prefix" is only allowed for certain subcommands.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/submodule--helper.c        | 52 +++++++++++++-----------------
 submodule.c                        | 26 ++++++++++++---
 submodule.h                        | 10 ++++++
 t/t7412-submodule-absorbgitdirs.sh | 13 ++++++--
 4 files changed, 64 insertions(+), 37 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c75e9e86b0..acb838e4d6 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -115,18 +115,18 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
 /* the result should be freed by the caller. */
 static char *get_submodule_displaypath(const char *path, const char *prefix)
 {
-	const char *super_prefix = get_super_prefix();
+	const char *toplevel_cwd_prefix = get_toplevel_cwd_prefix();
 
-	if (prefix && super_prefix) {
-		BUG("cannot have prefix '%s' and superprefix '%s'",
-		    prefix, super_prefix);
+	if (prefix && toplevel_cwd_prefix) {
+		BUG("cannot have prefix '%s' and toplevel_cwd_prefix '%s'",
+		    prefix, toplevel_cwd_prefix);
 	} else if (prefix) {
 		struct strbuf sb = STRBUF_INIT;
 		char *displaypath = xstrdup(relative_path(path, prefix, &sb));
 		strbuf_release(&sb);
 		return displaypath;
-	} else if (super_prefix) {
-		return xstrfmt("%s%s", super_prefix, path);
+	} else if (toplevel_cwd_prefix) {
+		return xstrfmt("%s%s", toplevel_cwd_prefix, path);
 	} else {
 		return xstrdup(path);
 	}
@@ -364,9 +364,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_pushl(&cpr.args, "--super-prefix", NULL);
+		strvec_pushl(&cpr.args, "submodule--helper",
+			     "--toplevel-cwd-prefix", NULL);
 		strvec_pushf(&cpr.args, "%s/", displaypath);
-		strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
+		strvec_pushl(&cpr.args, "foreach", "--recursive",
 			     NULL);
 
 		if (info->quiet)
@@ -682,10 +683,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushl(&cpr.args, "submodule--helper",
+			     "--toplevel-cwd-prefix", NULL);
 		strvec_pushf(&cpr.args, "%s/", displaypath);
-		strvec_pushl(&cpr.args, "submodule--helper", "status",
-			     "--recursive", NULL);
+		strvec_pushl(&cpr.args, "status", "--recursive", NULL);
 
 		if (flags & OPT_CACHED)
 			strvec_push(&cpr.args, "--cached");
@@ -1276,10 +1277,10 @@ static void sync_submodule(const char *path, const char *prefix,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushl(&cpr.args, "submodule--helper",
+			     "--toplevel-cwd-prefix", NULL);
 		strvec_pushf(&cpr.args, "%s/", displaypath);
-		strvec_pushl(&cpr.args, "submodule--helper", "sync",
-			     "--recursive", NULL);
+		strvec_pushl(&cpr.args, "sync", "--recursive", NULL);
 
 		if (flags & OPT_QUIET)
 			strvec_push(&cpr.args, "--quiet");
@@ -2438,11 +2439,12 @@ static void update_data_to_args(const struct update_data *update_data,
 {
 	enum submodule_update_type update_type = update_data->update_default;
 
+	strvec_push(args, "submodule--helper");
 	if (update_data->displaypath) {
-		strvec_push(args, "--super-prefix");
+		strvec_push(args, "--toplevel-cwd-prefix");
 		strvec_pushf(args, "%s/", update_data->displaypath);
 	}
-	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
+	strvec_pushl(args, "update", "--recursive", NULL);
 	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
 	if (update_data->quiet)
 		strvec_push(args, "--quiet");
@@ -3353,14 +3355,15 @@ static int module_add(int argc, const char **argv, const char *prefix)
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 {
-	const char *cmd = argv[0];
-	const char *subcmd;
 	parse_opt_subcommand_fn *fn = NULL;
 	const char *const usage[] = {
 		N_("git submodule--helper <command>"),
 		NULL
 	};
 	struct option options[] = {
+		OPT_CALLBACK_F(0, "toplevel-cwd-prefix", NULL, "path",
+			       "path from top level cwd to working tree root",
+			       0, option_parse_toplevel_cwd_prefix),
 		OPT_SUBCOMMAND("clone", &fn, module_clone),
 		OPT_SUBCOMMAND("add", &fn, module_add),
 		OPT_SUBCOMMAND("update", &fn, module_update),
@@ -3375,21 +3378,10 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 		OPT_SUBCOMMAND("set-url", &fn, module_set_url),
 		OPT_SUBCOMMAND("set-branch", &fn, module_set_branch),
 		OPT_SUBCOMMAND("create-branch", &fn, module_create_branch),
+
 		OPT_END()
 	};
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
-	subcmd = argv[0];
-
-	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
-	    strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") &&
-	    get_super_prefix())
-		/*
-		 * xstrfmt() rather than "%s %s" to keep the translated
-		 * string identical to git.c's.
-		 */
-		die(_("%s doesn't support --super-prefix"),
-		    xstrfmt("'%s %s'", cmd, subcmd));
 
 	return fn(argc, argv, prefix);
 }
diff --git a/submodule.c b/submodule.c
index 8fa2ad457b..a6db8c4bbe 100644
--- a/submodule.c
+++ b/submodule.c
@@ -28,6 +28,7 @@ static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
 static int initialized_fetch_ref_tips;
 static struct oid_array ref_tips_before_fetch;
 static struct oid_array ref_tips_after_fetch;
+static const char *toplevel_cwd_prefix;
 
 /*
  * Check if the .gitmodules file is unmerged. Parsing of the .gitmodules file
@@ -241,6 +242,21 @@ int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
 	return 0;
 }
 
+int option_parse_toplevel_cwd_prefix(const struct option *opt,
+				     const char *arg, int unset)
+{
+	if (arg)
+		toplevel_cwd_prefix = arg;
+	return 0;
+}
+
+const char *get_toplevel_cwd_prefix(void)
+{
+	if (!toplevel_cwd_prefix)
+		return "";
+	return toplevel_cwd_prefix;
+}
+
 /*
  * Determine if a submodule has been initialized at a given 'path'
  */
@@ -2298,7 +2314,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
 	real_new_git_dir = real_pathdup(new_gitdir.buf, 1);
 
 	fprintf(stderr, _("Migrating git directory of '%s%s' from\n'%s' to\n'%s'\n"),
-		get_super_prefix_or_empty(), path,
+		get_toplevel_cwd_prefix(), path,
 		real_old_git_dir, real_new_git_dir);
 
 	relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
@@ -2317,10 +2333,10 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
 	cp.dir = path;
 	cp.git_cmd = 1;
 	cp.no_stdin = 1;
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
-	strvec_pushl(&cp.args, "submodule--helper",
-		     "absorbgitdirs", NULL);
+	strvec_push(&cp.args, "submodule--helper");
+	strvec_pushf(&cp.args, "--toplevel-cwd-prefix=%s%s/",
+		     get_toplevel_cwd_prefix(), path);
+	strvec_pushl(&cp.args, "absorbgitdirs", NULL);
 	prepare_submodule_repo_env(&cp.env);
 	if (run_command(&cp))
 		die(_("could not recurse into submodule '%s'"), path);
diff --git a/submodule.h b/submodule.h
index b52a4ff1e7..436dbb2e11 100644
--- a/submodule.h
+++ b/submodule.h
@@ -54,6 +54,16 @@ int git_default_submodule_config(const char *var, const char *value, void *cb);
 struct option;
 int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
 						     const char *arg, int unset);
+int option_parse_toplevel_cwd_prefix(const struct option *opt,
+				   const char *arg, int unset);
+/*
+ * Return the relative path of the top-level process's cwd to the root of the
+ * working tree. When printing paths to submodules in the working tree, this
+ * value should be prepended to the path so that they appear relative to the
+ * top-level process's cwd instead of this process's cwd.
+ */
+const char *get_toplevel_cwd_prefix(void);
+
 int is_tree_submodule_active(struct repository *repo,
 			     const struct object_id *treeish_name,
 			     const char *path);
diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh
index 2859695c6d..a9efebc7ec 100755
--- a/t/t7412-submodule-absorbgitdirs.sh
+++ b/t/t7412-submodule-absorbgitdirs.sh
@@ -54,15 +54,24 @@ test_expect_success 'setup nested submodule' '
 '
 
 test_expect_success 'absorb the git dir in a nested submodule' '
+	# Touch the files so that they show up in git status
+	>expect.err &&
+	>actual.err &&
 	git status >expect.1 &&
 	git -C sub1/nested rev-parse HEAD >expect.2 &&
-	git submodule absorbgitdirs &&
+	git submodule absorbgitdirs 2>actual.err &&
 	test -f sub1/nested/.git &&
 	test -d .git/modules/sub1/modules/nested &&
 	git status >actual.1 &&
 	git -C sub1/nested rev-parse HEAD >actual.2 &&
 	test_cmp expect.1 actual.1 &&
-	test_cmp expect.2 actual.2
+	test_cmp expect.2 actual.2 &&
+	cat >expect.err <<-EOF &&
+	Migrating git directory of ${SQ}sub1/nested${SQ} from
+	${SQ}/Users/chooglen/Code/git/t/trash directory.t7412-submodule-absorbgitdirs/sub1/nested/.git${SQ} to
+	${SQ}/Users/chooglen/Code/git/t/trash directory.t7412-submodule-absorbgitdirs/.git/modules/sub1/modules/nested${SQ}
+	EOF
+	test_cmp expect.err actual.err
 '
 
 test_expect_success 're-setup nested submodule' '
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 2/4] fetch: refactor --submodule-prefix
  2022-11-09  0:47 [RFC PATCH 0/4] git: remove --super-prefix Glen Choo
  2022-11-09  0:47 ` [RFC PATCH 1/4] submodule--helper: teach --toplevel-cwd-prefix Glen Choo
@ 2022-11-09  0:47 ` Glen Choo
  2022-11-09  3:06   ` Ævar Arnfjörð Bjarmason
  2022-11-09  0:47 ` [RFC PATCH 3/4] read-tree: teach --submodule-prefix Glen Choo
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-09  0:47 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

Since "git fetch" learned to recurse into submodules [1], it has passed
"--submodule-prefix=<path from root of superproject tree to submodule>"
to print full paths to the submodules being fetched. This is the same
value as "--super-prefix"'s when calling "git read-tree
--recurse-submodules", as well as "git (grep|ls-files)
--recurse-submodules" before they were implemented in-process [2] [3],
(when they used repository.submodule_prefix to replace "--super-prefix).

Let's standardize the way we pass such prefixes. Having a per-command
"--submodule-prefix" is preferable to a top-level "--super-prefix",
since it gives us fine-grained control over which commands support it
and which don't, and we can preserve the effort-saving properties of the
top-level flag by sharing an implementation under the hood.

Refactor "git fetch" so that "--submodule-prefix" is stored in
repository.submodule_prefix, and create functions in submodule.h for
parsing and reading its value. Also, mark it with PARSE_OPT_HIDDEN and
drop it from our documentation. We will follow this pattern for "git
read-tree" in the next commit.

Since we've previously documented that repository.submodule_prefix is
only set for submodules, introduce repository.is_submodule for
distinguishing between the_repository and a submodule (although, this
turns out to be unused, since no caller uses repository.submodule_prefix
for that purpose).

[1] 7dce19d374 (fetch/pull: Add the --recurse-submodules option, 2010-11-12)
[2] 188dce131f (ls-files: use repository object, 2017-06-22)
[3] f9ee2fcdfa (grep: recurse in-process using 'struct repository', 2017-08-02)

Signed-off-by: Glen Choo <chooglen@google.com>
---
 Documentation/fetch-options.txt |  5 -----
 builtin/fetch.c                 |  7 +++----
 repository.c                    |  1 +
 repository.h                    |  9 +++++++--
 submodule.c                     | 35 +++++++++++++++++++++------------
 submodule.h                     | 12 +++++++++--
 6 files changed, 43 insertions(+), 26 deletions(-)

diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 622bd84768..20cbd2c291 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -241,11 +241,6 @@ endif::git-pull[]
 	linkgit:git-config[1].
 
 ifndef::git-pull[]
---submodule-prefix=<path>::
-	Prepend <path> to paths printed in informative messages
-	such as "Fetching submodule foo".  This option is used
-	internally when recursing over submodules.
-
 --recurse-submodules-default=[yes|on-demand]::
 	This option is used internally to temporarily provide a
 	non-negative default value for the --recurse-submodules
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b06e454cbd..78a46389ff 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -74,7 +74,6 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
 static struct strbuf default_rla = STRBUF_INIT;
 static struct transport *gtransport;
 static struct transport *gsecondary;
-static const char *submodule_prefix = "";
 static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
@@ -195,8 +194,9 @@ static struct option builtin_fetch_options[] = {
 	OPT_SET_INT_F(0, "refetch", &refetch,
 		      N_("re-fetch without negotiating common commits"),
 		      1, PARSE_OPT_NONEG),
-	{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
-		   N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
+	OPT_CALLBACK_F(0, "submodule-prefix", NULL, "path",
+			"path from top-level superproject root to current repo root",
+			PARSE_OPT_HIDDEN, option_parse_submodule_prefix),
 	OPT_CALLBACK_F(0, "recurse-submodules-default",
 		   &recurse_submodules_default, N_("on-demand"),
 		   N_("default for recursive fetching of submodules "
@@ -2297,7 +2297,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		add_options_to_argv(&options);
 		result = fetch_submodules(the_repository,
 					  &options,
-					  submodule_prefix,
 					  recurse_submodules,
 					  recurse_submodules_default,
 					  verbosity < 0,
diff --git a/repository.c b/repository.c
index 5d166b692c..1d454a0ac4 100644
--- a/repository.c
+++ b/repository.c
@@ -229,6 +229,7 @@ int repo_submodule_init(struct repository *subrepo,
 		}
 	}
 
+	subrepo->is_submodule = 1;
 	subrepo->submodule_prefix = xstrfmt("%s%s/",
 					    superproject->submodule_prefix ?
 					    superproject->submodule_prefix :
diff --git a/repository.h b/repository.h
index 24316ac944..1bc4afc2b6 100644
--- a/repository.h
+++ b/repository.h
@@ -119,10 +119,15 @@ struct repository {
 	 */
 	char *worktree;
 
+	/*
+	 * Whether this struct represents a submodule of this process's main
+	 * repository.
+	 */
+	int is_submodule;
+
 	/*
 	 * Path from the root of the top-level superproject down to this
-	 * repository.  This is only non-NULL if the repository is initialized
-	 * as a submodule of another repository.
+	 * repository.
 	 */
 	char *submodule_prefix;
 
diff --git a/submodule.c b/submodule.c
index a6db8c4bbe..d84345a0b4 100644
--- a/submodule.c
+++ b/submodule.c
@@ -257,6 +257,21 @@ const char *get_toplevel_cwd_prefix(void)
 	return toplevel_cwd_prefix;
 }
 
+int option_parse_submodule_prefix(const struct option *opt,
+				  const char *arg, int unset)
+{
+	if (arg)
+		the_repository->submodule_prefix = xstrdup(arg);
+	return 0;
+}
+
+const char *get_submodule_prefix(void)
+{
+	if (!the_repository->submodule_prefix)
+		return "";
+	return the_repository->submodule_prefix;
+}
+
 /*
  * Determine if a submodule has been initialized at a given 'path'
  */
@@ -1392,7 +1407,6 @@ struct submodule_parallel_fetch {
 	int changed_count;
 	struct strvec args;
 	struct repository *r;
-	const char *prefix;
 	int command_line_option;
 	int default_option;
 	int quiet;
@@ -1583,7 +1597,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
 		if (task->repo) {
 			if (!spf->quiet)
 				strbuf_addf(err, _("Fetching submodule %s%s\n"),
-					    spf->prefix, ce->name);
+					    get_submodule_prefix(), ce->name);
 
 			spf->index_count++;
 			return task;
@@ -1645,7 +1659,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
 		if (!spf->quiet)
 			strbuf_addf(err,
 				    _("Fetching submodule %s%s at commit %s\n"),
-				    spf->prefix, task->sub->path,
+				    get_submodule_prefix(), task->sub->path,
 				    find_unique_abbrev(cs_data->super_oid,
 						       DEFAULT_ABBREV));
 
@@ -1692,8 +1706,6 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
 		task = get_fetch_task_from_changed(spf, err);
 
 	if (task) {
-		struct strbuf submodule_prefix = STRBUF_INIT;
-
 		child_process_init(cp);
 		cp->dir = task->repo->gitdir;
 		prepare_submodule_repo_env_in_gitdir(&cp->env);
@@ -1705,13 +1717,11 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
 		strvec_push(&cp->args, task->default_argv);
 		strvec_push(&cp->args, "--submodule-prefix");
 
-		strbuf_addf(&submodule_prefix, "%s%s/",
-						spf->prefix,
-						task->sub->path);
-		strvec_push(&cp->args, submodule_prefix.buf);
+		strvec_pushf(&cp->args, "%s%s/",
+					get_submodule_prefix(),
+					task->sub->path);
 		*task_cb = task;
 
-		strbuf_release(&submodule_prefix);
 		string_list_insert(&spf->seen_submodule_names, task->sub->name);
 		return 1;
 	}
@@ -1723,7 +1733,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
 		spf->oid_fetch_tasks_nr--;
 
 		strbuf_addf(&submodule_prefix, "%s%s/",
-			    spf->prefix, task->sub->path);
+			    get_submodule_prefix(), task->sub->path);
 
 		child_process_init(cp);
 		prepare_submodule_repo_env_in_gitdir(&cp->env);
@@ -1829,7 +1839,7 @@ static int fetch_finish(int retvalue, struct strbuf *err,
 
 int fetch_submodules(struct repository *r,
 		     const struct strvec *options,
-		     const char *prefix, int command_line_option,
+		     int command_line_option,
 		     int default_option,
 		     int quiet, int max_parallel_jobs)
 {
@@ -1851,7 +1861,6 @@ int fetch_submodules(struct repository *r,
 	spf.command_line_option = command_line_option;
 	spf.default_option = default_option;
 	spf.quiet = quiet;
-	spf.prefix = prefix;
 
 	if (!r->worktree)
 		goto out;
diff --git a/submodule.h b/submodule.h
index 436dbb2e11..f2701c4869 100644
--- a/submodule.h
+++ b/submodule.h
@@ -55,7 +55,7 @@ struct option;
 int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
 						     const char *arg, int unset);
 int option_parse_toplevel_cwd_prefix(const struct option *opt,
-				   const char *arg, int unset);
+				     const char *arg, int unset);
 /*
  * Return the relative path of the top-level process's cwd to the root of the
  * working tree. When printing paths to submodules in the working tree, this
@@ -63,6 +63,15 @@ int option_parse_toplevel_cwd_prefix(const struct option *opt,
  * top-level process's cwd instead of this process's cwd.
  */
 const char *get_toplevel_cwd_prefix(void);
+int option_parse_submodule_prefix(const struct option *opt,
+				      const char *arg, int unset);
+/*
+ * Return the path from the root of the top-level superproject to root of this
+ * repository. When printing paths to submodules in a tree, this value should be
+ * prepended to the path so that they originate from the top-level
+ * superproject's tree instead of this repository's tree.
+ */
+const char *get_submodule_prefix(void);
 
 int is_tree_submodule_active(struct repository *repo,
 			     const struct object_id *treeish_name,
@@ -100,7 +109,6 @@ const struct submodule *submodule_from_ce(const struct cache_entry *ce);
 void check_for_new_submodule_commits(struct object_id *oid);
 int fetch_submodules(struct repository *r,
 		     const struct strvec *options,
-		     const char *prefix,
 		     int command_line_option,
 		     int default_option,
 		     int quiet, int max_parallel_jobs);
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 3/4] read-tree: teach --submodule-prefix
  2022-11-09  0:47 [RFC PATCH 0/4] git: remove --super-prefix Glen Choo
  2022-11-09  0:47 ` [RFC PATCH 1/4] submodule--helper: teach --toplevel-cwd-prefix Glen Choo
  2022-11-09  0:47 ` [RFC PATCH 2/4] fetch: refactor --submodule-prefix Glen Choo
@ 2022-11-09  0:47 ` Glen Choo
  2022-11-09  3:13   ` Ævar Arnfjörð Bjarmason
  2022-11-09  0:47 ` [RFC PATCH 4/4] git: remove --super-prefix Glen Choo
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-09  0:47 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

Following the precedent of previous commit, teach "git read-tree" the
"--submodule-prefix" flag, replacing its use of the global
"--super-prefix" flag.

This also fixes an existing bug where "git --super-prefix=<path>
read-tree" (typically invoked by "git restore") in a partial clone with
submodules could fail because we fetch promisor objects with "git
fetch", but "git fetch" doesn't support "--super-prefix".

Signed-off-by: Glen Choo <chooglen@google.com>
---
 builtin/read-tree.c         |  4 ++++
 submodule.c                 | 22 +++++++------------
 t/t1001-read-tree-m-2way.sh |  4 ++--
 t/t5616-partial-clone.sh    | 43 +++++++++++++++++++++++++++++++++++++
 unpack-trees.c              | 32 +++++++++++++--------------
 5 files changed, 73 insertions(+), 32 deletions(-)

diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index f4cbe460b9..7aedab6951 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -148,6 +148,10 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
 		OPT_CALLBACK_F(0, "recurse-submodules", NULL,
 			    "checkout", "control recursive updating of submodules",
 			    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
+		OPT_CALLBACK_F(0, "submodule-prefix", NULL, "path",
+			       "internal, path from root of top-level superproject tree to this repo",
+			       PARSE_OPT_HIDDEN, option_parse_submodule_prefix),
+
 		OPT__QUIET(&opts.quiet, N_("suppress feedback messages")),
 		OPT_END()
 	};
diff --git a/submodule.c b/submodule.c
index d84345a0b4..d3d6abc816 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2073,14 +2073,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)
 	strbuf_release(&config_path);
 }
 
-static const char *get_super_prefix_or_empty(void)
-{
-	const char *s = get_super_prefix();
-	if (!s)
-		s = "";
-	return s;
-}
-
 static int submodule_has_dirty_index(const struct submodule *sub)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2108,10 +2100,11 @@ static void submodule_reset_index(const char *path)
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	/* TODO: determine if this might overwright untracked files */
-	strvec_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
+	strvec_push(&cp.args, "read-tree");
+	strvec_pushf(&cp.args, "--submodule-prefix=%s%s/",
+		     get_submodule_prefix(), path);
+	strvec_pushl(&cp.args, "-u", "--reset", NULL);
 
 	strvec_push(&cp.args, empty_tree_oid_hex());
 
@@ -2191,9 +2184,10 @@ int submodule_move_head(const char *path,
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
-	strvec_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
+	strvec_push(&cp.args, "read-tree");
+	strvec_pushf(&cp.args, "--submodule-prefix=%s%s/",
+		     get_submodule_prefix(), path);
+	strvec_push(&cp.args, "--recurse-submodules");
 
 	if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
 		strvec_push(&cp.args, "-n");
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 516a6112fd..9cfba1a2af 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -366,11 +366,11 @@ test_expect_success 'a/b (untracked) vs a, plus c/d case test.' '
 	test -f a/b
 '
 
-test_expect_success 'read-tree supports the super-prefix' '
+test_expect_success 'read-tree supports --submodule-prefix' '
 	cat <<-EOF >expect &&
 		error: Updating '\''fictional/a'\'' would lose untracked files in it
 	EOF
-	test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual &&
+	test_must_fail git read-tree --submodule-prefix fictional/ -u -m "$treeH" "$treeM" 2>actual &&
 	test_cmp expect actual
 '
 
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 037941b95d..9bec57a047 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '
 	grep "loosen_unused_packed_objects/loosened:0" trace
 '
 
+test_expect_success 'setup src repo with submodules' '
+	test_config_global protocol.file.allow always &&
+
+	git init src-sub &&
+	git -C src-sub config uploadpack.allowfilter 1 &&
+	git -C src-sub config uploadpack.allowanysha1inwant 1 &&
+
+	# This blob must be missing in the subsequent commit.
+	echo foo >src-sub/file &&
+	git -C src-sub add file &&
+	git -C src-sub commit -m "submodule one" &&
+	SUB_ONE=$(git -C src-sub rev-parse HEAD) &&
+
+	echo bar >src-sub/file &&
+	git -C src-sub add file &&
+	git -C src-sub commit -m "submodule two" &&
+	SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
+
+	git init src-super &&
+	git -C src-super config uploadpack.allowfilter 1 &&
+	git -C src-super config uploadpack.allowanysha1inwant 1 &&
+	git -C src-super submodule add ../src-sub src-sub &&
+
+	git -C src-super/src-sub checkout $SUB_ONE &&
+	git -C src-super add src-sub &&
+	git -C src-super commit -m "superproject one" &&
+
+	git -C src-super/src-sub checkout $SUB_TWO &&
+	git -C src-super add src-sub &&
+	git -C src-super commit -m "superproject two"
+'
+
+test_expect_success 'lazy-fetch in submodule succeeds' '
+	test_when_finished "rm -rf src-super src-sub client" &&
+
+	test_config_global protocol.file.allow always &&
+	git clone --filter=blob:none --also-filter-submodules \
+		--recurse-submodules "file://$(pwd)/src-super" client &&
+
+	# Trigger lazy-fetch from the superproject
+	git -C client restore --recurse-submodules --source=HEAD^ :/
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
diff --git a/unpack-trees.c b/unpack-trees.c
index bae812156c..930a2a46f1 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
 	  ? ((o)->msgs[(type)])      \
 	  : (unpack_plumbing_errors[(type)]) )
 
-static const char *super_prefixed(const char *path)
+static const char *submodule_prefixed(const char *path)
 {
 	/*
 	 * It is necessary and sufficient to have two static buffers
@@ -79,28 +79,28 @@ static const char *super_prefixed(const char *path)
 	 * error() using the unpack_*_errors[] templates we see above.
 	 */
 	static struct strbuf buf[2] = {STRBUF_INIT, STRBUF_INIT};
-	static int super_prefix_len = -1;
+	static int submodule_prefix_len = -1;
 	static unsigned idx = ARRAY_SIZE(buf) - 1;
 
-	if (super_prefix_len < 0) {
-		const char *super_prefix = get_super_prefix();
-		if (!super_prefix) {
-			super_prefix_len = 0;
+	if (submodule_prefix_len < 0) {
+		const char *submodule_prefix = get_submodule_prefix();
+		if (!submodule_prefix) {
+			submodule_prefix_len = 0;
 		} else {
 			int i;
 			for (i = 0; i < ARRAY_SIZE(buf); i++)
-				strbuf_addstr(&buf[i], super_prefix);
-			super_prefix_len = buf[0].len;
+				strbuf_addstr(&buf[i], submodule_prefix);
+			submodule_prefix_len = buf[0].len;
 		}
 	}
 
-	if (!super_prefix_len)
+	if (!submodule_prefix_len)
 		return path;
 
 	if (++idx >= ARRAY_SIZE(buf))
 		idx = 0;
 
-	strbuf_setlen(&buf[idx], super_prefix_len);
+	strbuf_setlen(&buf[idx], submodule_prefix_len);
 	strbuf_addstr(&buf[idx], path);
 
 	return buf[idx].buf;
@@ -236,7 +236,7 @@ static int add_rejected_path(struct unpack_trees_options *o,
 		return -1;
 
 	if (!o->show_all_errors)
-		return error(ERRORMSG(o, e), super_prefixed(path));
+		return error(ERRORMSG(o, e), submodule_prefixed(path));
 
 	/*
 	 * Otherwise, insert in a list for future display by
@@ -263,7 +263,7 @@ static void display_error_msgs(struct unpack_trees_options *o)
 			error_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			error(ERRORMSG(o, e), super_prefixed(path.buf));
+			error(ERRORMSG(o, e), submodule_prefixed(path.buf));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -290,7 +290,7 @@ static void display_warning_msgs(struct unpack_trees_options *o)
 			warning_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			warning(ERRORMSG(o, e), super_prefixed(path.buf));
+			warning(ERRORMSG(o, e), submodule_prefixed(path.buf));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -2958,8 +2958,8 @@ int bind_merge(const struct cache_entry * const *src,
 	if (a && old)
 		return o->quiet ? -1 :
 			error(ERRORMSG(o, ERROR_BIND_OVERLAP),
-			      super_prefixed(a->name),
-			      super_prefixed(old->name));
+			      submodule_prefixed(a->name),
+			      submodule_prefixed(old->name));
 	if (!a)
 		return keep_entry(old, o);
 	else
@@ -3020,7 +3020,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,
 
 	if (worktree && untracked)
 		return error(_("worktree and untracked commit have duplicate entries: %s"),
-			     super_prefixed(worktree->name));
+			     submodule_prefixed(worktree->name));
 
 	return merged_entry(worktree ? worktree : untracked, NULL, o);
 }
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 4/4] git: remove --super-prefix
  2022-11-09  0:47 [RFC PATCH 0/4] git: remove --super-prefix Glen Choo
                   ` (2 preceding siblings ...)
  2022-11-09  0:47 ` [RFC PATCH 3/4] read-tree: teach --submodule-prefix Glen Choo
@ 2022-11-09  0:47 ` Glen Choo
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
  2022-11-09 21:16 ` [RFC PATCH 0/4] git: remove --super-prefix Taylor Blau
  5 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-09  0:47 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

It has no more users, and prospective new users can use per-command
flags instead, e.g. "git fetch --submodule-prefix" or "git
submodule--helper --toplevel-cwd-prefix".

Now that this flag is gone, also remove a now-defunct test from
t/t7527-builtin-fsmonitor.sh.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 Documentation/git.txt        |  7 +----
 builtin.h                    |  4 ---
 cache.h                      |  2 --
 environment.c                | 13 ----------
 git.c                        | 40 +++++------------------------
 t/t7527-builtin-fsmonitor.sh | 50 ------------------------------------
 6 files changed, 8 insertions(+), 108 deletions(-)

diff --git a/Documentation/git.txt b/Documentation/git.txt
index 1d33e083ab..85c7d9500e 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -13,7 +13,7 @@ SYNOPSIS
     [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
     [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
     [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
-    [--super-prefix=<path>] [--config-env=<name>=<envvar>]
+    [--config-env=<name>=<envvar>]
     <command> [<args>]
 
 DESCRIPTION
@@ -169,11 +169,6 @@ If you just want to run git as if it was started in `<path>` then use
 	details.  Equivalent to setting the `GIT_NAMESPACE` environment
 	variable.
 
---super-prefix=<path>::
-	Currently for internal use only.  Set a prefix which gives a path from
-	above a repository down to its root.  One use is to give submodules
-	context about the superproject that invoked it.
-
 --bare::
 	Treat the repository as a bare repository.  If GIT_DIR
 	environment is not set, it is set to the current working
diff --git a/builtin.h b/builtin.h
index 8901a34d6b..8264b7e524 100644
--- a/builtin.h
+++ b/builtin.h
@@ -51,10 +51,6 @@
  *	on bare repositories.
  *	This only makes sense when `RUN_SETUP` is also set.
  *
- * `SUPPORT_SUPER_PREFIX`:
- *
- *	The built-in supports `--super-prefix`.
- *
  * `DELAY_PAGER_CONFIG`:
  *
  *	If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
diff --git a/cache.h b/cache.h
index 26ed03bd6d..a4a0377b80 100644
--- a/cache.h
+++ b/cache.h
@@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)
 #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
-#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
 int get_common_dir(struct strbuf *sb, const char *gitdir);
 const char *get_git_namespace(void);
 const char *strip_namespace(const char *namespaced_ref);
-const char *get_super_prefix(void);
 const char *get_git_work_tree(void);
 
 /*
diff --git a/environment.c b/environment.c
index 18d042b467..1ee3686fd8 100644
--- a/environment.c
+++ b/environment.c
@@ -102,8 +102,6 @@ char *git_work_tree_cfg;
 
 static char *git_namespace;
 
-static char *super_prefix;
-
 /*
  * Repository-local GIT_* environment variables; see cache.h for details.
  */
@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {
 	NO_REPLACE_OBJECTS_ENVIRONMENT,
 	GIT_REPLACE_REF_BASE_ENVIRONMENT,
 	GIT_PREFIX_ENVIRONMENT,
-	GIT_SUPER_PREFIX_ENVIRONMENT,
 	GIT_SHALLOW_FILE_ENVIRONMENT,
 	GIT_COMMON_DIR_ENVIRONMENT,
 	NULL
@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)
 	return NULL;
 }
 
-const char *get_super_prefix(void)
-{
-	static int initialized;
-	if (!initialized) {
-		super_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));
-		initialized = 1;
-	}
-	return super_prefix;
-}
-
 static int git_work_tree_initialized;
 
 /*
diff --git a/git.c b/git.c
index fb69e60591..5548619aea 100644
--- a/git.c
+++ b/git.c
@@ -14,9 +14,8 @@
  * RUN_SETUP for reading from the configuration file.
  */
 #define NEED_WORK_TREE		(1<<3)
-#define SUPPORT_SUPER_PREFIX	(1<<4)
-#define DELAY_PAGER_CONFIG	(1<<5)
-#define NO_PARSEOPT		(1<<6) /* parse-options is not used */
+#define DELAY_PAGER_CONFIG	(1<<4)
+#define NO_PARSEOPT		(1<<5) /* parse-options is not used */
 
 struct cmd_struct {
 	const char *cmd;
@@ -29,7 +28,7 @@ const char git_usage_string[] =
 	   "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 	   "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
 	   "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-	   "           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
+	   "           [--config-env=<name>=<envvar>]\n"
 	   "           <command> [<args>]");
 
 const char git_more_info_string[] =
@@ -226,20 +225,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 			setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
 			if (envchanged)
 				*envchanged = 1;
-		} else if (!strcmp(cmd, "--super-prefix")) {
-			if (*argc < 2) {
-				fprintf(stderr, _("no prefix given for --super-prefix\n" ));
-				usage(git_usage_string);
-			}
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
-			if (envchanged)
-				*envchanged = 1;
-			(*argv)++;
-			(*argc)--;
-		} else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
-			if (envchanged)
-				*envchanged = 1;
 		} else if (!strcmp(cmd, "--bare")) {
 			char *cwd = xgetcwd();
 			is_bare_repository_cfg = 1;
@@ -449,11 +434,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 		trace_repo_setup(prefix);
 	commit_pager_choice();
 
-	if (!help && get_super_prefix()) {
-		if (!(p->option & SUPPORT_SUPER_PREFIX))
-			die(_("%s doesn't support --super-prefix"), p->cmd);
-	}
-
 	if (!help && p->option & NEED_WORK_TREE)
 		setup_work_tree();
 
@@ -504,7 +484,7 @@ static struct cmd_struct commands[] = {
 	{ "check-ref-format", cmd_check_ref_format, NO_PARSEOPT  },
 	{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout--worker", cmd_checkout__worker,
-		RUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },
+		RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout-index", cmd_checkout_index,
 		RUN_SETUP | NEED_WORK_TREE},
 	{ "cherry", cmd_cherry, RUN_SETUP },
@@ -539,7 +519,7 @@ static struct cmd_struct commands[] = {
 	{ "format-patch", cmd_format_patch, RUN_SETUP },
 	{ "fsck", cmd_fsck, RUN_SETUP },
 	{ "fsck-objects", cmd_fsck, RUN_SETUP },
-	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
+	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP },
 	{ "gc", cmd_gc, RUN_SETUP },
 	{ "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT },
 	{ "grep", cmd_grep, RUN_SETUP_GENTLY },
@@ -583,7 +563,7 @@ static struct cmd_struct commands[] = {
 	{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
 	{ "push", cmd_push, RUN_SETUP },
 	{ "range-diff", cmd_range_diff, RUN_SETUP | USE_PAGER },
-	{ "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
+	{ "read-tree", cmd_read_tree, RUN_SETUP },
 	{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
 	{ "receive-pack", cmd_receive_pack },
 	{ "reflog", cmd_reflog, RUN_SETUP },
@@ -610,7 +590,7 @@ static struct cmd_struct commands[] = {
 	{ "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
 	{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 	{ "stripspace", cmd_stripspace },
-	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },
+	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP },
 	{ "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
 	{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 	{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
@@ -727,9 +707,6 @@ static void execv_dashed_external(const char **argv)
 	struct child_process cmd = CHILD_PROCESS_INIT;
 	int status;
 
-	if (get_super_prefix())
-		die(_("%s doesn't support --super-prefix"), argv[0]);
-
 	if (use_pager == -1 && !is_builtin(argv[0]))
 		use_pager = check_pager_config(argv[0]);
 	commit_pager_choice();
@@ -799,9 +776,6 @@ static int run_argv(int *argcp, const char ***argv)
 			 */
 			trace2_cmd_name("_run_git_alias_");
 
-			if (get_super_prefix())
-				die("%s doesn't support --super-prefix", **argv);
-
 			commit_pager_choice();
 
 			strvec_push(&args, "git");
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
index 4abc74db2b..d11cb1854c 100755
--- a/t/t7527-builtin-fsmonitor.sh
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -860,56 +860,6 @@ test_expect_success 'submodule always visited' '
 	my_match_and_clean
 '
 
-# If a submodule has a `sub/.git/` directory (rather than a file
-# pointing to the super's `.git/modules/sub`) and `core.fsmonitor`
-# turned on in the submodule and the daemon is not yet started in
-# the submodule, and someone does a `git submodule absorbgitdirs`
-# in the super, Git will recursively invoke `git submodule--helper`
-# to do the work and this may try to read the index.  This will
-# try to start the daemon in the submodule *and* pass (either
-# directly or via inheritance) the `--super-prefix` arg to the
-# `git fsmonitor--daemon start` command inside the submodule.
-# This causes a warning because fsmonitor--daemon does take that
-# global arg (see the table in git.c)
-#
-# This causes a warning when trying to start the daemon that is
-# somewhat confusing.  It does not seem to hurt anything because
-# the fsmonitor code maps the query failure into a trivial response
-# and does the work anyway.
-#
-# It would be nice to silence the warning, however.
-
-have_t2_error_event () {
-	log=$1
-	msg="fsmonitor--daemon doesnQt support --super-prefix" &&
-
-	tr '\047' Q <$1 | grep -e "$msg"
-}
-
-test_expect_success "stray submodule super-prefix warning" '
-	test_when_finished "rm -rf super; \
-			    rm -rf sub;   \
-			    rm super-sub.trace" &&
-
-	create_super super &&
-	create_sub sub &&
-
-	# Copy rather than submodule add so that we get a .git dir.
-	cp -R ./sub ./super/dir_1/dir_2/sub &&
-
-	git -C super/dir_1/dir_2/sub config core.fsmonitor true &&
-
-	git -C super submodule add ../sub ./dir_1/dir_2/sub &&
-	git -C super commit -m "add sub" &&
-
-	test_path_is_dir super/dir_1/dir_2/sub/.git &&
-
-	GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
-		git -C super submodule absorbgitdirs &&
-
-	! have_t2_error_event super-sub.trace
-'
-
 # On a case-insensitive file system, confirm that the daemon
 # notices when the .git directory is moved/renamed/deleted
 # regardless of how it is spelled in the the FS event.
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 1/4] submodule--helper: teach --toplevel-cwd-prefix
  2022-11-09  0:47 ` [RFC PATCH 1/4] submodule--helper: teach --toplevel-cwd-prefix Glen Choo
@ 2022-11-09  2:37   ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09  2:37 UTC (permalink / raw)
  To: Glen Choo; +Cc: git


On Tue, Nov 08 2022, Glen Choo wrote:

> The top-level "--super-prefix" option (i.e. "git --super-prefix") is
> overloaded:
>
> - "git submodule--helper" passes the relative path between the top-level
>   "git" process's cwd and the current repository
> - "git read-tree" passes the path from the root of top-level
>   superproject's tree to the the current repository.
>
> In both cases, "--super-prefix" is only used to display meaningful paths
> from the superproject to a nested submodule.

The "overloaded" here could really use some elaboration.

Yes, we have different built-in commands that use it, but their use is
mostly mutually exclusive, i.e. when "submodule status" recurses into
itself it using an option called "--super-prefix" doesn't impact "git
read-tree", even though it uses the same option & env variable to
communicate the same concept.

But I'm totally willing to buy that it's simpler to e.g. have "git
submodule--helper status" or whatever use its own option to carry this
forward, rather than some option to "git" itself. Or if some commands
just need a --some-option, but not the environment variable.

But this doesn't really address that and ....

> Let's address this overloading by breaking it up into its constituent
> use cases. Teach "git submodule--helper" the "--toplevel-cwd-prefix"
> option, which replaces its usage of "git --super-prefix". (A future
> patch will address the "git read-tree" use case.) This value is only
> used in builtin/submodule--helper.c, but it is stored in submodule.c,
> since it may be needed by other builtins in the future.

...Uh, other built-ins might use it in the future? :) Wouldn't we be
right back to a --super-prefix then, which is a cross-built-in
semi-standard way to communicate this sort of information? So instead of
a hypothetical current:

	git submodule some-subcommand
		=> git --super-prefix submodule/ submodule -C submodule/ some-subcommand
			=> git --super-prefix submodule/ fetch

Or whatever, we'd do what? Have each of the now split-up commands take
their own flag for this? E.g.:

	git submodule some-subcommand
		=> git submodule -C submodule/ --toplevel-cwd-prefix submodule/ some-subcommand
			=> git fetch --submodule-prefix submodule/

Or are you really trying to say that it was a hassle to pass down this
through the various functions to all the callers, so emulating what we
did with the previous global was easier if it was a new global?
I.e. it's not about passing it to other built-ins, but between
submodule--helper itself?

I think doing that and chipping away at this from the bottom-up would be
a much better approach, at least for some cases.

E.g. just to have "absorbgitdirs" itself support a "--super-prefix"
option, not "git" or "git submodule--helper".

Then we just pass that down to absorb_git_dir_into_superproject(), which
will only invoke "git submodule--helper absorbgitdirs", which we'll then
tell about the super-prefix with a "--super-prefix" option to that
subcommand.

> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index c75e9e86b0..acb838e4d6 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -115,18 +115,18 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
>  /* the result should be freed by the caller. */
>  static char *get_submodule_displaypath(const char *path, const char *prefix)
>  {
> -	const char *super_prefix = get_super_prefix();
> +	const char *toplevel_cwd_prefix = get_toplevel_cwd_prefix();
>  
> -	if (prefix && super_prefix) {
> -		BUG("cannot have prefix '%s' and superprefix '%s'",
> -		    prefix, super_prefix);
> +	if (prefix && toplevel_cwd_prefix) {
> +		BUG("cannot have prefix '%s' and toplevel_cwd_prefix '%s'",
> +		    prefix, toplevel_cwd_prefix);
>  	} else if (prefix) {
>  		struct strbuf sb = STRBUF_INIT;
>  		char *displaypath = xstrdup(relative_path(path, prefix, &sb));
>  		strbuf_release(&sb);
>  		return displaypath;
> -	} else if (super_prefix) {
> -		return xstrfmt("%s%s", super_prefix, path);
> +	} else if (toplevel_cwd_prefix) {
> +		return xstrfmt("%s%s", toplevel_cwd_prefix, path);
>  	} else {
>  		return xstrdup(path);
>  	}

At the end of this series git.c has stopped knowing about
"--super-prefix", so I don't see why we need the churn of renaming
this. Even if we just make built-in commands take it now, isn't that
sufficient? We'd still need...

> @@ -364,9 +364,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
>  		cpr.dir = path;
>  		prepare_submodule_repo_env(&cpr.env);
>  
> -		strvec_pushl(&cpr.args, "--super-prefix", NULL);
> +		strvec_pushl(&cpr.args, "submodule--helper",
> +			     "--toplevel-cwd-prefix", NULL);
>  		strvec_pushf(&cpr.args, "%s/", displaypath);
> -		strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
> +		strvec_pushl(&cpr.args, "foreach", "--recursive",
>  			     NULL);
>  

...to do this, but not all the function & variable renames.

>  	struct option options[] = {
> +		OPT_CALLBACK_F(0, "toplevel-cwd-prefix", NULL, "path",
> +			       "path from top level cwd to working tree root",
> +			       0, option_parse_toplevel_cwd_prefix),
>  		OPT_SUBCOMMAND("clone", &fn, module_clone),
>  		OPT_SUBCOMMAND("add", &fn, module_add),
>  		OPT_SUBCOMMAND("update", &fn, module_update),
> @@ -3375,21 +3378,10 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
>  		OPT_SUBCOMMAND("set-url", &fn, module_set_url),
>  		OPT_SUBCOMMAND("set-branch", &fn, module_set_branch),
>  		OPT_SUBCOMMAND("create-branch", &fn, module_create_branch),
> +
>  		OPT_END()
>  	};
>  	argc = parse_options(argc, argv, prefix, options, usage, 0);
> -	subcmd = argv[0];
> -
> -	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
> -	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
> -	    strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") &&
> -	    get_super_prefix())
> -		/*
> -		 * xstrfmt() rather than "%s %s" to keep the translated
> -		 * string identical to git.c's.
> -		 */
> -		die(_("%s doesn't support --super-prefix"),
> -		    xstrfmt("'%s %s'", cmd, subcmd));
>  
>  	return fn(argc, argv, prefix);
>  }

Re some of the things I was aiming for in the WIP submodule built-in
series by splitting up "submodule--helper", before this we'll only
accept it for certain subcommands, e.g.:

	$ ./git --super-prefix=blah/ submodule--helper summary
	fatal: 'submodule--helper summary' doesn't support --super-prefix

Whereas now we'll accept it:

	$ ./git submodule--helper --toplevel-cwd-prefix=blah/ summary
	$

I'm not necessarily against that, but it does seem to run somewhat
counter to the divide-and-conquer of eventually getting rid of this
super-prefix (or whatever we call it) business.

And in any case, if that's what we're going to do let's loosen that up
and justify that change in its own commit, separate from a
rename/refactor. I.e. you could start by removing this strcmp(...) &&
strcmp(...), along with an explanation for why we won't need to care
about which "submodule--helper" subcommand needs it anymore.

> diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh
> index 2859695c6d..a9efebc7ec 100755
> --- a/t/t7412-submodule-absorbgitdirs.sh
> +++ b/t/t7412-submodule-absorbgitdirs.sh
> @@ -54,15 +54,24 @@ test_expect_success 'setup nested submodule' '
>  '
>  
>  test_expect_success 'absorb the git dir in a nested submodule' '
> +	# Touch the files so that they show up in git status
> +	>expect.err &&
> +	>actual.err &&
>  	git status >expect.1 &&
>  	git -C sub1/nested rev-parse HEAD >expect.2 &&
> -	git submodule absorbgitdirs &&
> +	git submodule absorbgitdirs 2>actual.err &&
>  	test -f sub1/nested/.git &&
>  	test -d .git/modules/sub1/modules/nested &&
>  	git status >actual.1 &&
>  	git -C sub1/nested rev-parse HEAD >actual.2 &&
>  	test_cmp expect.1 actual.1 &&
> -	test_cmp expect.2 actual.2
> +	test_cmp expect.2 actual.2 &&
> +	cat >expect.err <<-EOF &&
> +	Migrating git directory of ${SQ}sub1/nested${SQ} from
> +	${SQ}/Users/chooglen/Code/git/t/trash directory.t7412-submodule-absorbgitdirs/sub1/nested/.git${SQ} to
> +	${SQ}/Users/chooglen/Code/git/t/trash directory.t7412-submodule-absorbgitdirs/.git/modules/sub1/modules/nested${SQ}
> +	EOF
> +	test_cmp expect.err actual.err

I'm afraid I'll need to change my name & OS for that to pass for me :)

This reminded me to send in:
https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/
; which fixes this message, & adds more tests for this output.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 2/4] fetch: refactor --submodule-prefix
  2022-11-09  0:47 ` [RFC PATCH 2/4] fetch: refactor --submodule-prefix Glen Choo
@ 2022-11-09  3:06   ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09  3:06 UTC (permalink / raw)
  To: Glen Choo; +Cc: git


On Tue, Nov 08 2022, Glen Choo wrote:

> Since we've previously documented that repository.submodule_prefix is
> only set for submodules, introduce repository.is_submodule for
> distinguishing between the_repository and a submodule (although, this
> turns out to be unused, since no caller uses repository.submodule_prefix
> for that purpose).

There's more to chew on here, but just briefly on this:

> diff --git a/repository.c b/repository.c
> index 5d166b692c..1d454a0ac4 100644
> --- a/repository.c
> +++ b/repository.c
> @@ -229,6 +229,7 @@ int repo_submodule_init(struct repository *subrepo,
>  		}
>  	}
>  
> +	subrepo->is_submodule = 1;
>  	subrepo->submodule_prefix = xstrfmt("%s%s/",
>  					    superproject->submodule_prefix ?
>  					    superproject->submodule_prefix :
> diff --git a/repository.h b/repository.h
> index 24316ac944..1bc4afc2b6 100644
> --- a/repository.h
> +++ b/repository.h
> @@ -119,10 +119,15 @@ struct repository {
>  	 */
>  	char *worktree;
>  
> +	/*
> +	 * Whether this struct represents a submodule of this process's main
> +	 * repository.
> +	 */
> +	int is_submodule;
> +
>  	/*
>  	 * Path from the root of the top-level superproject down to this
> -	 * repository.  This is only non-NULL if the repository is initialized
> -	 * as a submodule of another repository.
> +	 * repository.
>  	 */
>  	char *submodule_prefix;
>  

Just deleting that "is_submodule" header addition and the assignment you
added on top of 4/4 has this series compile. So "this turns out to be
unused" ... because it's added here, but never used? So why do we need
to add it?

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 3/4] read-tree: teach --submodule-prefix
  2022-11-09  0:47 ` [RFC PATCH 3/4] read-tree: teach --submodule-prefix Glen Choo
@ 2022-11-09  3:13   ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09  3:13 UTC (permalink / raw)
  To: Glen Choo; +Cc: git


On Tue, Nov 08 2022, Glen Choo wrote:

Other things aside:

> This also fixes an existing bug where "git --super-prefix=<path>
> read-tree" (typically invoked by "git restore") in a partial clone with
> submodules could fail because we fetch promisor objects with "git
> fetch", but "git fetch" doesn't support "--super-prefix".
> [...]
> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
> index 037941b95d..9bec57a047 100755
> --- a/t/t5616-partial-clone.sh
> +++ b/t/t5616-partial-clone.sh
> @@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '
>  	grep "loosen_unused_packed_objects/loosened:0" trace
>  '
>  
> +test_expect_success 'setup src repo with submodules' '
> +	test_config_global protocol.file.allow always &&
> +
> +	git init src-sub &&
> +	git -C src-sub config uploadpack.allowfilter 1 &&
> +	git -C src-sub config uploadpack.allowanysha1inwant 1 &&
> +
> +	# This blob must be missing in the subsequent commit.
> +	echo foo >src-sub/file &&
> +	git -C src-sub add file &&
> +	git -C src-sub commit -m "submodule one" &&
> +	SUB_ONE=$(git -C src-sub rev-parse HEAD) &&
> +
> +	echo bar >src-sub/file &&
> +	git -C src-sub add file &&
> +	git -C src-sub commit -m "submodule two" &&
> +	SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
> +
> +	git init src-super &&
> +	git -C src-super config uploadpack.allowfilter 1 &&
> +	git -C src-super config uploadpack.allowanysha1inwant 1 &&
> +	git -C src-super submodule add ../src-sub src-sub &&
> +
> +	git -C src-super/src-sub checkout $SUB_ONE &&
> +	git -C src-super add src-sub &&
> +	git -C src-super commit -m "superproject one" &&
> +
> +	git -C src-super/src-sub checkout $SUB_TWO &&
> +	git -C src-super add src-sub &&
> +	git -C src-super commit -m "superproject two"
> +'
> +
> +test_expect_success 'lazy-fetch in submodule succeeds' '
> +	test_when_finished "rm -rf src-super src-sub client" &&
> +
> +	test_config_global protocol.file.allow always &&
> +	git clone --filter=blob:none --also-filter-submodules \
> +		--recurse-submodules "file://$(pwd)/src-super" client &&
> +
> +	# Trigger lazy-fetch from the superproject
> +	git -C client restore --recurse-submodules --source=HEAD^ :/
> +'
> +

If I take this test addition on top of "master", and don't apply any of
the C changes on this topic it'll fail in "fetch", and then in
"index-pack"/"unpack-objects" etc., as "fetch" invokes those, due to us
using the --super-prefix.

But just this test addition and this code change would also "fix it":
	
	diff --git a/builtin/fetch.c b/builtin/fetch.c
	index 7378cafeec9..c5709a9e37b 100644
	--- a/builtin/fetch.c
	+++ b/builtin/fetch.c
	@@ -2114,6 +2114,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
	 	int result = 0;
	 	int prune_tags_ok = 1;
	 
	+	unsetenv(GIT_SUPER_PREFIX_ENVIRONMENT);
	+
	 	packet_trace_identity("fetch");
	 
	 	/* Record the command line for the reflog */
	diff --git a/git.c b/git.c
	index 10202a7f126..b5e63a0a57b 100644
	--- a/git.c
	+++ b/git.c
	@@ -531,7 +531,7 @@ static struct cmd_struct commands[] = {
	 	{ "env--helper", cmd_env__helper },
	 	{ "fast-export", cmd_fast_export, RUN_SETUP },
	 	{ "fast-import", cmd_fast_import, RUN_SETUP | NO_PARSEOPT },
	-	{ "fetch", cmd_fetch, RUN_SETUP },
	+	{ "fetch", cmd_fetch, RUN_SETUP | SUPPORT_SUPER_PREFIX /* not really* */ },
	 	{ "fetch-pack", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },
	 	{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
	 	{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },

Doesn't that do an end-run around the goals of this topic, but just in a
much simpler way?

I.e. I'm all for not propagating the --super-prefix any more than we
need to, but part of that is because once we start passing it, we set it
in the environment, and then we'll *keep* passing it. So we've had some
commands "accept" it, when really they don't care, they're just being
invoked by other commands that needed it originally.

But maybe we can just unsetenv() the prefix before invoking any built-in
that doesn't have SUPPORT_SUPER_PREFIX, or not set it in the environment
in the first place, but rather carry it forward more explicitly only
with the "--super-prefix" flag to "git" (adn then only to those specific
commands?


^ permalink raw reply	[flat|nested] 79+ messages in thread

* [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-09  0:47 [RFC PATCH 0/4] git: remove --super-prefix Glen Choo
                   ` (3 preceding siblings ...)
  2022-11-09  0:47 ` [RFC PATCH 4/4] git: remove --super-prefix Glen Choo
@ 2022-11-09 19:34 ` Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 1/8] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
                     ` (10 more replies)
  2022-11-09 21:16 ` [RFC PATCH 0/4] git: remove --super-prefix Taylor Blau
  5 siblings, 11 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 19:34 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

An RFC alternative to Glen's [1], and what I *thought* he might be be
going for in the earlier discussion[2].

The difference is that in Glen's there's no "git --super-prefix", but
rather each set of commands still using it ("submodule--helper",
"read-tree" etc.) geit their own command-level option.

But it still works substantially the same, in that we're juggling a
global variable that we set, and read out later somewhere down the
stack.

Whereas here there's no renaming of the option, but:

 * For "submodule--helper" only the sub-commands that need it take the
   option, it's not an option to "submodule--helper" itself.

 * There's no passing of the "super_prefix" as a global, instead we
   pass it all the way along until we recurse to ourselves. For
   "submodule--helper" this is quite straightforward.

 * Then in 8/8 we're left with just "read-tree" needing the remaining
   "--super-prefix", and we likewise don't pass it as a global, but
   instead add it to the "struct unpack_trees_options", which will
   pass it all the way down into unpack-trees.c and entry.c, until
   we're going to recursively invoke another "read-tree".

This is on top of my "ab/submodule-helper-prep-only" which is now in
"next", and can make use of (but doesn't need) the better test
coverage for "absorbgitdirs" that I submitted in [3].

A non-RFC version of this should really steal Glen's tests, in
particular the "partial clone" one from [4]. That test passes with
this series.

1. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/
2. https://lore.kernel.org/git/kl6l8rkqy7no.fsf@chooglen-macbookpro.roam.corp.google.com/
3. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/
4. https://lore.kernel.org/git/20221109004708.97668-4-chooglen@google.com/.

Ævar Arnfjörð Bjarmason (8):
  submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  submodule--helper: "deinit" has never used "--super-prefix"
  submodule--helper: convert "foreach" to its own "--super-prefix"
  submodule--helper: convert "sync" to its own "--super-prefix"
  submodule--helper: convert "status" to its own "--super-prefix"
  submodule--helper: convert "{update,clone}" to their own
    "--super-prefix"
  submodule tests: test "git branch -t" output and stderr
  read-tree: add "--super-prefix" option, eliminate global

 Documentation/git.txt       |  8 +--
 builtin.h                   |  4 --
 builtin/checkout.c          |  2 +-
 builtin/read-tree.c         |  1 +
 builtin/submodule--helper.c | 95 ++++++++++++++++++++---------------
 cache.h                     |  2 -
 entry.c                     | 12 ++---
 entry.h                     |  6 ++-
 environment.c               | 13 -----
 git.c                       | 37 ++------------
 parse-options.h             |  4 ++
 submodule.c                 | 47 ++++++++----------
 submodule.h                 | 12 +++--
 t/lib-submodule-update.sh   | 98 +++++++++++++++++++++----------------
 t/t1001-read-tree-m-2way.sh |  2 +-
 unpack-trees.c              | 23 +++++----
 unpack-trees.h              |  1 +
 17 files changed, 177 insertions(+), 190 deletions(-)

-- 
2.38.0.1467.g709fbdff1a9


^ permalink raw reply	[flat|nested] 79+ messages in thread

* [RFC PATCH 1/8] submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-09 19:34   ` Ævar Arnfjörð Bjarmason
  2022-11-11  0:12     ` Glen Choo
  2022-11-09 19:34   ` [RFC PATCH 2/8] submodule--helper: "deinit" has never used "--super-prefix" Ævar Arnfjörð Bjarmason
                     ` (9 subsequent siblings)
  10 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 19:34 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

The "--super-prefix" facility was introduced in [1] has always been a
transitory hack, which is why we've made it an error to supply it as
an option to "git" to commands that don't know about it.

That's been a good goal, as it has a global effect we haven't wanted
calls to get_super_prefix() from built-ins we didn't expect.

But it has meant that when we've had chains of different built-ins
using it all of the processes in that "chain" have needed to support
it, and worse processes that don't need it have needed to ask for
"SUPPORT_SUPER_PREFIX" because their parent process needs it.

That's how "fsmonitor--daemon" ended up with it, per [2] it's called
from (among other things) "submodule--helper absorbgitdirs", but as we
declared "submodule--helper" as "SUPPORT_SUPER_PREFIX" we needed to
declare "fsmonitor--daemon" as accepting it too, even though it
doesn't care about it.

There's a parallel proposal to remove "--super-prefix" as an option to
"git" in [3], and some of the approach might be the easiest route in
some cases.

But in the case of "absorbgitdirs" it only needed "--super-prefix" to
invoke itself recursively, and we'd never have another "in-between"
process in the chain. So we didn't need the bigger hammer of "git
--super-prefix", and the "setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)"
that it entails.

Let's instead accept a hidden "--super-prefix" option to
"submodule--helper absorbgitdirs" itself.

Eventually (as with all other "--super-prefix" users) we'll want to
clean this code up so that this all happens in-process. I.e. needing
any variant of "--super-prefix" is itself a hack around our various
global state, and implicit reliance on "the_repository". This stepping
stone makes such an eventual change easier, as we'll need to deal with
less global state at that point.

1. 74866d75793 (git: make super-prefix option, 2016-10-07)
2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
   2022-05-26)
3. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c |  8 +++++---
 git.c                       |  2 +-
 parse-options.h             |  4 ++++
 submodule.c                 | 20 ++++++++++++--------
 submodule.h                 |  7 ++++++-
 5 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c75e9e86b06..427e793e204 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2828,7 +2828,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 	int i;
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
+	const char *super_prefix = NULL;
 	struct option embed_gitdir_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT_END()
 	};
 	const char *const git_submodule_helper_usage[] = {
@@ -2844,7 +2846,8 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 
 	for (i = 0; i < list.nr; i++)
-		absorb_git_dir_into_superproject(list.entries[i]->name);
+		absorb_git_dir_into_superproject_sp(list.entries[i]->name,
+						    super_prefix);
 
 	ret = 0;
 cleanup:
@@ -3382,8 +3385,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
 	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
-	    strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") &&
-	    get_super_prefix())
+	    strcmp(subcmd, "sync") && get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
diff --git a/git.c b/git.c
index 10202a7f126..b1b7e1a837e 100644
--- a/git.c
+++ b/git.c
@@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {
 	{ "format-patch", cmd_format_patch, RUN_SETUP },
 	{ "fsck", cmd_fsck, RUN_SETUP },
 	{ "fsck-objects", cmd_fsck, RUN_SETUP },
-	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
+	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP },
 	{ "gc", cmd_gc, RUN_SETUP },
 	{ "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT },
 	{ "grep", cmd_grep, RUN_SETUP_GENTLY },
diff --git a/parse-options.h b/parse-options.h
index b6ef86e0d15..50d852f2991 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
 	{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"),	\
 	  N_("use <n> digits to display object names"),	\
 	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+#define OPT__SUPER_PREFIX(var) \
+	OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
+		N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
+
 #define OPT__COLOR(var, h) \
 	OPT_COLOR_FLAG(0, "color", (var), (h))
 #define OPT_COLUMN(s, l, v, h) \
diff --git a/submodule.c b/submodule.c
index c47358097fd..d9fd0af81b6 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)
  * Embeds a single submodules git directory into the superprojects git dir,
  * non recursively.
  */
-static void relocate_single_git_dir_into_superproject(const char *path)
+static void relocate_single_git_dir_into_superproject(const char *path,
+						      const char *super_prefix)
 {
 	char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
 	struct strbuf new_gitdir = STRBUF_INIT;
@@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
 	       real_old_git_dir[off] == real_new_git_dir[off])
 		off++;
 	fprintf(stderr, _("Migrating git directory of '%s%s' from '%s' to '%s'\n"),
-		get_super_prefix_or_empty(), path,
+		(super_prefix ? super_prefix : ""), path,
 		real_old_git_dir + off, real_new_git_dir + off);
 
 	relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
@@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)
 	strbuf_release(&new_gitdir);
 }
 
-static void absorb_git_dir_into_superproject_recurse(const char *path)
+static void absorb_git_dir_into_superproject_recurse(const char *path,
+						     const char *super_prefix)
 {
 
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2321,10 +2323,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
 	cp.dir = path;
 	cp.git_cmd = 1;
 	cp.no_stdin = 1;
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	strvec_pushl(&cp.args, "submodule--helper",
 		     "absorbgitdirs", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
+		     super_prefix : "", path);
+
 	prepare_submodule_repo_env(&cp.env);
 	if (run_command(&cp))
 		die(_("could not recurse into submodule '%s'"), path);
@@ -2335,7 +2338,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
  * having its git directory within the working tree to the git dir nested
  * in its superprojects git dir under modules/.
  */
-void absorb_git_dir_into_superproject(const char *path)
+void absorb_git_dir_into_superproject_sp(const char *path,
+					 const char *super_prefix)
 {
 	int err_code;
 	const char *sub_git_dir;
@@ -2377,14 +2381,14 @@ void absorb_git_dir_into_superproject(const char *path)
 		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(path);
+			relocate_single_git_dir_into_superproject(path, super_prefix);
 
 		free(real_sub_git_dir);
 		free(real_common_git_dir);
 	}
 	strbuf_release(&gitdir);
 
-	absorb_git_dir_into_superproject_recurse(path);
+	absorb_git_dir_into_superproject_recurse(path, super_prefix);
 }
 
 int get_superproject_working_tree(struct strbuf *buf)
diff --git a/submodule.h b/submodule.h
index b52a4ff1e73..e5ee13fb06a 100644
--- a/submodule.h
+++ b/submodule.h
@@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);
  */
 void prepare_submodule_repo_env(struct strvec *env);
 
-void absorb_git_dir_into_superproject(const char *path);
+void absorb_git_dir_into_superproject_sp(const char *path,
+					 const char *super_prefix);
+static inline void absorb_git_dir_into_superproject(const char *path)
+{
+	absorb_git_dir_into_superproject_sp(path, NULL);
+}
 
 /*
  * Return the absolute path of the working tree of the superproject, which this
-- 
2.38.0.1467.g709fbdff1a9


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 2/8] submodule--helper: "deinit" has never used "--super-prefix"
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 1/8] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
@ 2022-11-09 19:34   ` Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 3/8] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 19:34 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

The "deinit_submodule()" function has never been able to use the "git
--super-prefix". It will call "absorb_git_dir_into_superproject()",
but it will only do so from the top-level project.

If "absorbgitdirs" recurses it will use the "path" passed to
"absorb_git_dir_into_superproject()" in "deinit_submodule()" as its
starting "--super-prefix".

So, let's introduce a "get_submodule_displaypath_sp()" helper, and
make our existing "get_submodule_displaypath()" a wrapper for it. In a
subsequent commit the wrapper will be going away, as the rest of the
commands here will stop using the global "get_super_prefix()".

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 427e793e204..c4d5e029b37 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
 }
 
 /* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *get_submodule_displaypath_sp(const char *path, const char *prefix,
+					  const char *super_prefix)
 {
-	const char *super_prefix = get_super_prefix();
-
 	if (prefix && super_prefix) {
 		BUG("cannot have prefix '%s' and superprefix '%s'",
 		    prefix, super_prefix);
@@ -132,6 +131,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)
 	}
 }
 
+static char *get_submodule_displaypath(const char *path, const char *prefix)
+{
+	const char *super_prefix = get_super_prefix();
+
+	return get_submodule_displaypath_sp(path, prefix, super_prefix);
+}
+
 static char *compute_rev_name(const char *sub_path, const char* object_id)
 {
 	struct strbuf sb = STRBUF_INIT;
@@ -1365,7 +1371,7 @@ static void deinit_submodule(const char *path, const char *prefix,
 	if (!sub || !sub->name)
 		goto cleanup;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath_sp(path, prefix, NULL);
 
 	/* remove the submodule work tree (unless the user already did it) */
 	if (is_directory(path)) {
-- 
2.38.0.1467.g709fbdff1a9


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 3/8] submodule--helper: convert "foreach" to its own "--super-prefix"
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 1/8] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 2/8] submodule--helper: "deinit" has never used "--super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-09 19:34   ` Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 4/8] submodule--helper: convert "sync" " Ævar Arnfjörð Bjarmason
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 19:34 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper foreach" to use its own "--super-prefix", instead
of relying on the global "--super-prefix" argument to "git"
itself. See that earlier commit for the rationale and background.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c4d5e029b37..989c75280af 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -285,6 +285,7 @@ struct foreach_cb {
 	int argc;
 	const char **argv;
 	const char *prefix;
+	const char *super_prefix;
 	int quiet;
 	int recursive;
 };
@@ -300,7 +301,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 	struct child_process cp = CHILD_PROCESS_INIT;
 	char *displaypath;
 
-	displaypath = get_submodule_displaypath(path, info->prefix);
+	displaypath = get_submodule_displaypath_sp(path, info->prefix,
+						   info->super_prefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -370,10 +372,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_pushl(&cpr.args, "--super-prefix", NULL);
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
 			     NULL);
+		strvec_pushl(&cpr.args, "--super-prefix", NULL);
+		strvec_pushf(&cpr.args, "%s/", displaypath);
 
 		if (info->quiet)
 			strvec_push(&cpr.args, "--quiet");
@@ -396,7 +398,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
 	struct foreach_cb info = FOREACH_CB_INIT;
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
+	const char *super_prefix = NULL;
 	struct option module_foreach_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
 		OPT_BOOL(0, "recursive", &info.recursive,
 			 N_("recurse into nested submodules")),
@@ -417,6 +421,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
 	info.argc = argc;
 	info.argv = argv;
 	info.prefix = prefix;
+	info.super_prefix = super_prefix;
 
 	for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
 
@@ -3390,8 +3395,8 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 	subcmd = argv[0];
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
-	    strcmp(subcmd, "sync") && get_super_prefix())
+	    strcmp(subcmd, "status") && strcmp(subcmd, "sync") &&
+	    get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
-- 
2.38.0.1467.g709fbdff1a9


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 4/8] submodule--helper: convert "sync" to its own "--super-prefix"
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
                     ` (2 preceding siblings ...)
  2022-11-09 19:34   ` [RFC PATCH 3/8] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-09 19:34   ` Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 5/8] submodule--helper: convert "status" " Ævar Arnfjörð Bjarmason
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 19:34 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper sync" to use its own "--super-prefix", instead of
relying on the global "--super-prefix" argument to "git" itself. See
that earlier commit for the rationale and background.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 989c75280af..db58fd5b2c4 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1214,12 +1214,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)
 
 struct sync_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define SYNC_CB_INIT { 0 }
 
 static void sync_submodule(const char *path, const char *prefix,
-			   unsigned int flags)
+			   const char *super_prefix, unsigned int flags)
 {
 	const struct submodule *sub;
 	char *remote_key = NULL;
@@ -1250,7 +1251,7 @@ static void sync_submodule(const char *path, const char *prefix,
 		super_config_url = xstrdup("");
 	}
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);
 
 	if (!(flags & OPT_QUIET))
 		printf(_("Synchronizing submodule url for '%s'\n"),
@@ -1287,10 +1288,11 @@ static void sync_submodule(const char *path, const char *prefix,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "sync",
 			     "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
+
 
 		if (flags & OPT_QUIET)
 			strvec_push(&cpr.args, "--quiet");
@@ -1313,7 +1315,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data
 {
 	struct sync_cb *info = cb_data;
 
-	sync_submodule(list_item->name, info->prefix, info->flags);
+	sync_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
 }
 
 static int module_sync(int argc, const char **argv, const char *prefix)
@@ -1323,7 +1326,9 @@ static int module_sync(int argc, const char **argv, const char *prefix)
 	struct module_list list = MODULE_LIST_INIT;
 	int quiet = 0;
 	int recursive = 0;
+	const char *super_prefix = NULL;
 	struct option module_sync_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
 		OPT_BOOL(0, "recursive", &recursive,
 			N_("recurse into nested submodules")),
@@ -1342,6 +1347,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 
 	info.prefix = prefix;
+	info.super_prefix = super_prefix;
 	if (quiet)
 		info.flags |= OPT_QUIET;
 	if (recursive)
@@ -2890,7 +2896,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
 	config_name = xstrfmt("submodule.%s.url", path);
 
 	config_set_in_gitmodules_file_gently(config_name, newurl);
-	sync_submodule(path, prefix, quiet ? OPT_QUIET : 0);
+	sync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);
 
 	free(config_name);
 
@@ -3395,8 +3401,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 	subcmd = argv[0];
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "status") && strcmp(subcmd, "sync") &&
-	    get_super_prefix())
+	    strcmp(subcmd, "status") && get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
-- 
2.38.0.1467.g709fbdff1a9


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 5/8] submodule--helper: convert "status" to its own "--super-prefix"
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
                     ` (3 preceding siblings ...)
  2022-11-09 19:34   ` [RFC PATCH 4/8] submodule--helper: convert "sync" " Ævar Arnfjörð Bjarmason
@ 2022-11-09 19:34   ` Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 6/8] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 19:34 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper status" to use its own "--super-prefix", instead of
relying on the global "--super-prefix" argument to "git" itself. See
that earlier commit for the rationale and background.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index db58fd5b2c4..40939b0b18e 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -581,6 +581,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
 
 struct status_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define STATUS_CB_INIT { 0 }
@@ -619,7 +620,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,
 
 static void status_submodule(const char *path, const struct object_id *ce_oid,
 			     unsigned int ce_flags, const char *prefix,
-			     unsigned int flags)
+			     const char *super_prefix, unsigned int flags)
 {
 	char *displaypath;
 	struct strvec diff_files_args = STRVEC_INIT;
@@ -635,7 +636,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		die(_("no submodule mapping found in .gitmodules for path '%s'"),
 		      path);
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);
 
 	if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
 		print_status(flags, 'U', path, null_oid(), displaypath);
@@ -693,10 +694,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "status",
 			     "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
 
 		if (flags & OPT_CACHED)
 			strvec_push(&cpr.args, "--cached");
@@ -720,7 +721,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,
 	struct status_cb *info = cb_data;
 
 	status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
-			 info->prefix, info->flags);
+			 info->prefix, info->super_prefix, info->flags);
 }
 
 static int module_status(int argc, const char **argv, const char *prefix)
@@ -729,7 +730,9 @@ static int module_status(int argc, const char **argv, const char *prefix)
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
 	int quiet = 0;
+	const char *super_prefix = NULL;
 	struct option module_status_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT__QUIET(&quiet, N_("suppress submodule status output")),
 		OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
 		OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
@@ -748,6 +751,7 @@ static int module_status(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 
 	info.prefix = prefix;
+	info.super_prefix = super_prefix;
 	if (quiet)
 		info.flags |= OPT_QUIET;
 
@@ -3401,7 +3405,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 	subcmd = argv[0];
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "status") && get_super_prefix())
+	    get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
-- 
2.38.0.1467.g709fbdff1a9


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 6/8] submodule--helper: convert "{update,clone}" to their own "--super-prefix"
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
                     ` (4 preceding siblings ...)
  2022-11-09 19:34   ` [RFC PATCH 5/8] submodule--helper: convert "status" " Ævar Arnfjörð Bjarmason
@ 2022-11-09 19:34   ` Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 7/8] submodule tests: test "git branch -t" output and stderr Ævar Arnfjörð Bjarmason
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 19:34 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper status" to use its own "--super-prefix", instead of
relying on the global "--super-prefix" argument to "git".

We need to convert both of these away from the global "--super-prefix"
at the same time, because "update" will call "clone", but "clone"
itself didn't make use of the global "--super-prefix" for displaying
paths. It was only on the list of sub-commands that accepted it
because "update"'s use of it would set it in its environment.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 45 ++++++++++++++++---------------------
 git.c                       |  2 +-
 2 files changed, 20 insertions(+), 27 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 40939b0b18e..e13615eb939 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -131,13 +131,6 @@ static char *get_submodule_displaypath_sp(const char *path, const char *prefix,
 	}
 }
 
-static char *get_submodule_displaypath(const char *path, const char *prefix)
-{
-	const char *super_prefix = get_super_prefix();
-
-	return get_submodule_displaypath_sp(path, prefix, super_prefix);
-}
-
 static char *compute_rev_name(const char *sub_path, const char* object_id)
 {
 	struct strbuf sb = STRBUF_INIT;
@@ -446,11 +439,13 @@ static int starts_with_dot_dot_slash(const char *const path)
 
 struct init_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define INIT_CB_INIT { 0 }
 
 static void init_submodule(const char *path, const char *prefix,
+			   const char *super_prefix,
 			   unsigned int flags)
 {
 	const struct submodule *sub;
@@ -458,7 +453,7 @@ static void init_submodule(const char *path, const char *prefix,
 	const char *upd;
 	char *url = NULL, *displaypath;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -534,7 +529,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data
 {
 	struct init_cb *info = cb_data;
 
-	init_submodule(list_item->name, info->prefix, info->flags);
+	init_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
 }
 
 static int module_init(int argc, const char **argv, const char *prefix)
@@ -802,6 +798,7 @@ struct summary_cb {
 	int argc;
 	const char **argv;
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int cached: 1;
 	unsigned int for_status: 1;
 	unsigned int files: 1;
@@ -963,7 +960,8 @@ static void generate_submodule_summary(struct summary_cb *info,
 		dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
 	}
 
-	displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+	displaypath = get_submodule_displaypath_sp(p->sm_path, info->prefix,
+						   info->super_prefix);
 
 	if (!missing_src && !missing_dst) {
 		struct child_process cp_rev_list = CHILD_PROCESS_INIT;
@@ -1904,6 +1902,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)
 
 struct update_data {
 	const char *prefix;
+	const char *super_prefix;
 	char *displaypath;
 	enum submodule_update_type update_default;
 	struct object_id suboid;
@@ -1979,7 +1978,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 	enum submodule_update_type update_type;
 	char *key;
 	const struct update_data *ud = suc->update_data;
-	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
+	char *displaypath = get_submodule_displaypath_sp(ce->name, ud->prefix,
+							 ud->super_prefix);
 	struct strbuf sb = STRBUF_INIT;
 	int needs_cloning = 0;
 	int need_free_url = 0;
@@ -2459,11 +2459,11 @@ static void update_data_to_args(const struct update_data *update_data,
 {
 	enum submodule_update_type update_type = update_data->update_default;
 
+	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
 	if (update_data->displaypath) {
 		strvec_push(args, "--super-prefix");
 		strvec_pushf(args, "%s/", update_data->displaypath);
 	}
-	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
 	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
 	if (update_data->quiet)
 		strvec_push(args, "--quiet");
@@ -2628,8 +2628,9 @@ static int update_submodules(struct update_data *update_data)
 		if (code)
 			goto fail;
 
-		update_data->displaypath = get_submodule_displaypath(
-			update_data->sm_path, update_data->prefix);
+		update_data->displaypath = get_submodule_displaypath_sp(
+			update_data->sm_path, update_data->prefix,
+			update_data->super_prefix);
 		code = update_submodule(update_data);
 		FREE_AND_NULL(update_data->displaypath);
 fail:
@@ -2654,7 +2655,9 @@ static int module_update(int argc, const char **argv, const char *prefix)
 	struct list_objects_filter_options filter_options =
 		LIST_OBJECTS_FILTER_INIT;
 	int ret;
+	const char *super_prefix = NULL;
 	struct option module_update_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
 		OPT_BOOL(0, "init", &opt.init,
 			 N_("initialize uninitialized submodules before update")),
@@ -2720,6 +2723,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 
 	opt.filter_options = &filter_options;
 	opt.prefix = prefix;
+	opt.super_prefix = super_prefix;
 
 	if (opt.update_default)
 		opt.update_strategy.type = opt.update_default;
@@ -2751,6 +2755,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 			module_list_active(&list);
 
 		info.prefix = opt.prefix;
+		info.super_prefix = super_prefix;
 		if (opt.quiet)
 			info.flags |= OPT_QUIET;
 
@@ -3377,8 +3382,6 @@ static int module_add(int argc, const char **argv, const char *prefix)
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 {
-	const char *cmd = argv[0];
-	const char *subcmd;
 	parse_opt_subcommand_fn *fn = NULL;
 	const char *const usage[] = {
 		N_("git submodule--helper <command>"),
@@ -3402,16 +3405,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
-	subcmd = argv[0];
-
-	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    get_super_prefix())
-		/*
-		 * xstrfmt() rather than "%s %s" to keep the translated
-		 * string identical to git.c's.
-		 */
-		die(_("%s doesn't support --super-prefix"),
-		    xstrfmt("'%s %s'", cmd, subcmd));
 
 	return fn(argc, argv, prefix);
 }
diff --git a/git.c b/git.c
index b1b7e1a837e..2bca22cfd9a 100644
--- a/git.c
+++ b/git.c
@@ -610,7 +610,7 @@ static struct cmd_struct commands[] = {
 	{ "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
 	{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 	{ "stripspace", cmd_stripspace },
-	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },
+	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP },
 	{ "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
 	{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 	{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
-- 
2.38.0.1467.g709fbdff1a9


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 7/8] submodule tests: test "git branch -t" output and stderr
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
                     ` (5 preceding siblings ...)
  2022-11-09 19:34   ` [RFC PATCH 6/8] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
@ 2022-11-09 19:34   ` Ævar Arnfjörð Bjarmason
  2022-11-09 19:34   ` [RFC PATCH 8/8] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 19:34 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

The "git branch" command will currently make use of the
"--super-prefix", as it will indirectly call submodule_move_head(),
which will have access to the "--super-prefix".

The output could thus be affected by the "--super-prefix". Right now
it isn't in this case, but let's exhaustively assert that that's the
case by testing the output of all of these "git branch -t" commands.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/lib-submodule-update.sh | 98 ++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 43 deletions(-)

diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 2d31fcfda1f..302d095ad9b 100644
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -245,6 +245,17 @@ reset_work_tree_to_interested () {
 	git -C submodule_update/.git/modules/sub1 config submodule.sub2.url "bogus"
 }
 
+test_branch_t_output () {
+	local branchname="$1" &&
+	local start_point="$2" &&
+	cat >expect <<-EOF &&
+	branch '$branchname' set up to track '$start_point'.
+	EOF
+	git branch -t "$branchname" "$start_point" >actual 2>err &&
+	test_must_be_empty err &&
+	test_cmp expect actual
+}
+
 # Test that the superproject contains the content according to commit "$1"
 # (the work tree must match the index for everything but submodules but the
 # index must exactly match the given commit including any submodule SHA-1s).
@@ -323,7 +334,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -345,7 +356,7 @@ test_submodule_switch_common () {
 		(
 			cd submodule_update &&
 			mkdir sub1 &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -360,7 +371,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to replace_sub1_with_file &&
 		(
 			cd submodule_update &&
-			git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
+			test_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&
 			$command replace_file_with_sub1 &&
 			test_superproject_content origin/replace_file_with_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -384,7 +395,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to replace_sub1_with_directory &&
 		(
 			cd submodule_update &&
-			git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
+			test_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
 			$command replace_directory_with_sub1 &&
 			test_superproject_content origin/replace_directory_with_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -406,7 +417,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t remove_sub1 origin/remove_sub1 &&
+			test_branch_t_output remove_sub1 origin/remove_sub1 &&
 			$command remove_sub1 &&
 			test_superproject_content origin/remove_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -418,7 +429,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t remove_sub1 origin/remove_sub1 &&
+			test_branch_t_output remove_sub1 origin/remove_sub1 &&
 			replace_gitfile_with_git_dir sub1 &&
 			$command remove_sub1 &&
 			test_superproject_content origin/remove_sub1 &&
@@ -447,7 +458,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			$command replace_sub1_with_directory test_must_fail &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -459,7 +470,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			replace_gitfile_with_git_dir sub1 &&
 			$command replace_sub1_with_directory test_must_fail &&
 			test_superproject_content origin/add_sub1 &&
@@ -474,7 +485,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			$command replace_sub1_with_file test_must_fail &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -487,7 +498,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			replace_gitfile_with_git_dir sub1 &&
 			$command replace_sub1_with_file test_must_fail &&
 			test_superproject_content origin/add_sub1 &&
@@ -512,7 +523,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			$command modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
 			test_submodule_content sub1 origin/add_sub1 &&
@@ -527,7 +538,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t invalid_sub1 origin/invalid_sub1 &&
+			test_branch_t_output invalid_sub1 origin/invalid_sub1 &&
 			$command invalid_sub1 &&
 			test_superproject_content origin/invalid_sub1 &&
 			test_submodule_content sub1 origin/add_sub1 &&
@@ -542,7 +553,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to invalid_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t valid_sub1 origin/valid_sub1 &&
+			test_branch_t_output valid_sub1 origin/valid_sub1 &&
 			$command valid_sub1 &&
 			test_superproject_content origin/valid_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -596,7 +607,7 @@ test_submodule_switch_func () {
 		reset_work_tree_to no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			>sub1 &&
 			$command add_sub1 test_must_fail &&
 			test_superproject_content origin/no_submodule &&
@@ -635,7 +646,7 @@ test_submodule_forced_switch () {
 		reset_work_tree_to no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			>sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
@@ -675,7 +686,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -688,7 +699,7 @@ test_submodule_recursing_with_args_common () {
 		(
 			cd submodule_update &&
 			mkdir sub1 &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -701,7 +712,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested replace_sub1_with_file &&
 		(
 			cd submodule_update &&
-			git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
+			test_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&
 			$command replace_file_with_sub1 &&
 			test_superproject_content origin/replace_file_with_sub1 &&
 			test_submodule_content sub1 origin/replace_file_with_sub1
@@ -713,19 +724,20 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested replace_sub1_with_directory &&
 		(
 			cd submodule_update &&
-			git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
+			test_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
 			$command replace_directory_with_sub1 &&
 			test_superproject_content origin/replace_directory_with_sub1 &&
 			test_submodule_content sub1 origin/replace_directory_with_sub1
 		)
 	'
+
 	# Switching to a commit with nested submodules recursively checks them out
 	test_expect_success "$command: nested submodules are checked out" '
 		prolog &&
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
+			test_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&
 			$command modify_sub1_recursively &&
 			test_superproject_content origin/modify_sub1_recursively &&
 			test_submodule_content sub1 origin/modify_sub1_recursively &&
@@ -740,7 +752,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t remove_sub1 origin/remove_sub1 &&
+			test_branch_t_output remove_sub1 origin/remove_sub1 &&
 			$command remove_sub1 &&
 			test_superproject_content origin/remove_sub1 &&
 			! test -e sub1 &&
@@ -753,7 +765,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t remove_sub1 origin/remove_sub1 &&
+			test_branch_t_output remove_sub1 origin/remove_sub1 &&
 			replace_gitfile_with_git_dir sub1 &&
 			rm -rf .git/modules &&
 			$command remove_sub1 &&
@@ -769,7 +781,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			$command replace_sub1_with_file &&
 			test_superproject_content origin/replace_sub1_with_file &&
 			test -f sub1
@@ -786,7 +798,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			: >sub1/untrackedfile &&
 			test_must_fail $command replace_sub1_with_file &&
 			test_superproject_content origin/add_sub1 &&
@@ -801,7 +813,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_nested_sub &&
 		(
 			cd submodule_update &&
-			git branch -t no_submodule origin/no_submodule &&
+			test_branch_t_output no_submodule origin/no_submodule &&
 			$command no_submodule &&
 			test_superproject_content origin/no_submodule &&
 			! test_path_is_dir sub1 &&
@@ -817,7 +829,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			$command modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
 			test_submodule_content sub1 origin/modify_sub1
@@ -830,7 +842,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t invalid_sub1 origin/invalid_sub1 &&
+			test_branch_t_output invalid_sub1 origin/invalid_sub1 &&
 			test_must_fail $command invalid_sub1 2>err &&
 			test_i18ngrep sub1 err &&
 			test_superproject_content origin/add_sub1 &&
@@ -844,13 +856,13 @@ test_submodule_recursing_with_args_common () {
 		(
 			cd submodule_update &&
 			git -C sub1 checkout -b keep_branch &&
-			git -C sub1 rev-parse HEAD >expect &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			git -C sub1 rev-parse HEAD >expect.rev-parse &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			$command modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
 			test_submodule_content sub1 origin/modify_sub1 &&
 			git -C sub1 rev-parse keep_branch >actual &&
-			test_cmp expect actual &&
+			test_cmp expect.rev-parse actual &&
 			test_must_fail git -C sub1 symbolic-ref HEAD
 		)
 	'
@@ -894,7 +906,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			: >sub1 &&
 			test_must_fail $command add_sub1 &&
 			test_superproject_content origin/no_submodule &&
@@ -908,7 +920,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			: >sub1 &&
 			mkdir .git/info &&
 			echo sub1 >.git/info/exclude &&
@@ -925,7 +937,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			$command replace_sub1_with_directory &&
 			test_superproject_content origin/replace_sub1_with_directory &&
 			test_submodule_content sub1 origin/replace_sub1_with_directory
@@ -937,7 +949,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			replace_gitfile_with_git_dir sub1 &&
 			rm -rf .git/modules &&
 			$command replace_sub1_with_directory &&
@@ -954,7 +966,7 @@ test_submodule_switch_recursing_with_args () {
 		(
 			cd submodule_update &&
 			rm -rf .git/modules/sub1/info &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			mkdir .git/modules/sub1/info &&
 			echo ignored >.git/modules/sub1/info/exclude &&
 			: >sub1/ignored &&
@@ -969,7 +981,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			git -c submodule.recurse=true $cmd_args modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
 			test_submodule_content sub1 origin/modify_sub1
@@ -981,7 +993,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_nested_sub &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
+			test_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&
 			$command modify_sub1_recursively &&
 			test_superproject_content origin/modify_sub1_recursively &&
 			test_submodule_content sub1 origin/modify_sub1_recursively &&
@@ -1009,7 +1021,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			>sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
@@ -1023,7 +1035,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			$command replace_sub1_with_directory &&
 			test_superproject_content origin/replace_sub1_with_directory
 		)
@@ -1034,7 +1046,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			replace_gitfile_with_git_dir sub1 &&
 			rm -rf .git/modules/sub1 &&
 			$command replace_sub1_with_directory &&
@@ -1049,7 +1061,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			: >sub1/expect &&
 			$command replace_sub1_with_file &&
 			test_superproject_content origin/replace_sub1_with_file
@@ -1062,7 +1074,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested invalid_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t valid_sub1 origin/valid_sub1 &&
+			test_branch_t_output valid_sub1 origin/valid_sub1 &&
 			$command valid_sub1 &&
 			test_superproject_content origin/valid_sub1 &&
 			test_submodule_content sub1 origin/valid_sub1
@@ -1077,7 +1089,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			echo "gitdir: bogus/path" >sub1/.git &&
 			$command modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
-- 
2.38.0.1467.g709fbdff1a9


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [RFC PATCH 8/8] read-tree: add "--super-prefix" option, eliminate global
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
                     ` (6 preceding siblings ...)
  2022-11-09 19:34   ` [RFC PATCH 7/8] submodule tests: test "git branch -t" output and stderr Ævar Arnfjörð Bjarmason
@ 2022-11-09 19:34   ` Ævar Arnfjörð Bjarmason
  2022-11-11  0:40     ` Glen Choo
  2022-11-09 21:21   ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Taylor Blau
                     ` (2 subsequent siblings)
  10 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 19:34 UTC (permalink / raw)
  To: git; +Cc: Glen Choo, Ævar Arnfjörð Bjarmason

The "--super-prefix" option to "git" was initially added in [1] for
use with "ls-files"[2], and shortly thereafter "submodule--helper"[3]
and "grep"[4]. It wasn't until [5] that "read-tree" made use of it.

At the time [5] made sense, but since then we've made "ls-files"
recurse in-process in [6], "grep" in [7], and finally
"submodule--helper" in the preceding commits.

Let's also remove it from "read-tree", which allows us to remove the
option to "git" itself.

We can do this because the only remaining user of it is the submodule
API, which will now invoke "read-tree" with its new "--super-prefix"
option. It will only do so when the "submodule_move_head()" function
is called.

That "submodule_move_head()" function was then only invoked by
"read-tree" itself, but now rather than setting an environment
variable to pass "--super-prefix" between cmd_read_tree() we:

- Set a new "super_prefix" in "struct unpack_trees_options". The
  "super_prefixed()" function in "unpack-trees.c" added in [5] will now
  use this, rather than get_super_prefix() looking up the environment
  variable we set earlier in the same process.

- Add the same field to the "struct checkout", which is only needed to
  ferry the "super_prefix" in the "struct unpack_trees_options" all the
  way down to the "entry.c" callers of "submodule_move_head()".

  Those calls which used the super prefix all originated in
  "cmd_read_tree()". The only other caller is the "unlink_entry()"
  caller in "builtin/checkout.c", which now passes a "NULL".

1. 74866d75793 (git: make super-prefix option, 2016-10-07)
2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)
3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)
4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)
5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)
6. 188dce131fa (ls-files: use repository object, 2017-06-22)
7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 Documentation/git.txt       |  8 +-------
 builtin.h                   |  4 ----
 builtin/checkout.c          |  2 +-
 builtin/read-tree.c         |  1 +
 cache.h                     |  2 --
 entry.c                     | 12 ++++++------
 entry.h                     |  6 +++++-
 environment.c               | 13 -------------
 git.c                       | 33 +++------------------------------
 submodule.c                 | 27 +++++++++------------------
 submodule.h                 |  5 ++---
 t/t1001-read-tree-m-2way.sh |  2 +-
 unpack-trees.c              | 23 +++++++++++++----------
 unpack-trees.h              |  1 +
 14 files changed, 43 insertions(+), 96 deletions(-)

diff --git a/Documentation/git.txt b/Documentation/git.txt
index 1d33e083ab8..f9a7a4554cd 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -13,8 +13,7 @@ SYNOPSIS
     [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
     [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
     [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
-    [--super-prefix=<path>] [--config-env=<name>=<envvar>]
-    <command> [<args>]
+    [--config-env=<name>=<envvar>] <command> [<args>]
 
 DESCRIPTION
 -----------
@@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use
 	details.  Equivalent to setting the `GIT_NAMESPACE` environment
 	variable.
 
---super-prefix=<path>::
-	Currently for internal use only.  Set a prefix which gives a path from
-	above a repository down to its root.  One use is to give submodules
-	context about the superproject that invoked it.
-
 --bare::
 	Treat the repository as a bare repository.  If GIT_DIR
 	environment is not set, it is set to the current working
diff --git a/builtin.h b/builtin.h
index 8901a34d6bf..8264b7e5241 100644
--- a/builtin.h
+++ b/builtin.h
@@ -51,10 +51,6 @@
  *	on bare repositories.
  *	This only makes sense when `RUN_SETUP` is also set.
  *
- * `SUPPORT_SUPER_PREFIX`:
- *
- *	The built-in supports `--super-prefix`.
- *
  * `DELAY_PAGER_CONFIG`:
  *
  *	If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2a132392fbe..dc008fb45e8 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -231,7 +231,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
 		pos++;
 	}
 	if (!overlay_mode) {
-		unlink_entry(ce);
+		unlink_entry(ce, NULL);
 		return 0;
 	}
 	if (stage == 2)
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index f4cbe460b97..4b6f22e58c1 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
 	int prefix_set = 0;
 	struct lock_file lock_file = LOCK_INIT;
 	const struct option read_tree_options[] = {
+		OPT__SUPER_PREFIX(&opts.super_prefix),
 		OPT_CALLBACK_F(0, "index-output", NULL, N_("file"),
 		  N_("write resulting index to <file>"),
 		  PARSE_OPT_NONEG, index_output_cb),
diff --git a/cache.h b/cache.h
index 26ed03bd6de..a4a0377b800 100644
--- a/cache.h
+++ b/cache.h
@@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)
 #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
-#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
 int get_common_dir(struct strbuf *sb, const char *gitdir);
 const char *get_git_namespace(void);
 const char *strip_namespace(const char *namespaced_ref);
-const char *get_super_prefix(void);
 const char *get_git_work_tree(void);
 
 /*
diff --git a/entry.c b/entry.c
index 616e4f073c1..971ab268714 100644
--- a/entry.c
+++ b/entry.c
@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
 			return error("cannot create submodule directory %s", path);
 		sub = submodule_from_ce(ce);
 		if (sub)
-			return submodule_move_head(ce->name,
+			return submodule_move_head(ce->name, state->super_prefix,
 				NULL, oid_to_hex(&ce->oid),
 				state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
 		break;
@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 			 * no pathname to return.
 			 */
 			BUG("Can't remove entry to a path");
-		unlink_entry(ce);
+		unlink_entry(ce, state->super_prefix);
 		return 0;
 	}
 
@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 				if (!(st.st_mode & S_IFDIR))
 					unlink_or_warn(ce->name);
 
-				return submodule_move_head(ce->name,
+				return submodule_move_head(ce->name, state->super_prefix,
 					NULL, oid_to_hex(&ce->oid), 0);
 			} else
-				return submodule_move_head(ce->name,
+				return submodule_move_head(ce->name, state->super_prefix,
 					"HEAD", oid_to_hex(&ce->oid),
 					state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
 		}
@@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 	return write_entry(ce, path.buf, ca, state, 0, nr_checkouts);
 }
 
-void unlink_entry(const struct cache_entry *ce)
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)
 {
 	const struct submodule *sub = submodule_from_ce(ce);
 	if (sub) {
 		/* state.force is set at the caller. */
-		submodule_move_head(ce->name, "HEAD", NULL,
+		submodule_move_head(ce->name, super_prefix, "HEAD", NULL,
 				    SUBMODULE_MOVE_HEAD_FORCE);
 	}
 	if (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)
diff --git a/entry.h b/entry.h
index 9be4659881e..2d4fbb88c8f 100644
--- a/entry.h
+++ b/entry.h
@@ -8,6 +8,7 @@ struct checkout {
 	struct index_state *istate;
 	const char *base_dir;
 	int base_dir_len;
+	const char *super_prefix;
 	struct delayed_checkout *delayed_checkout;
 	struct checkout_metadata meta;
 	unsigned force:1,
@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);
 /*
  * Unlink the last component and schedule the leading directories for
  * removal, such that empty directories get removed.
+ *
+ * The "super_prefix" is either NULL, or the "--super-prefix" passed
+ * down from "read-tree" et al.
  */
-void unlink_entry(const struct cache_entry *ce);
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);
 
 void *read_blob_entry(const struct cache_entry *ce, size_t *size);
 int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);
diff --git a/environment.c b/environment.c
index 18d042b467d..1ee3686fd8a 100644
--- a/environment.c
+++ b/environment.c
@@ -102,8 +102,6 @@ char *git_work_tree_cfg;
 
 static char *git_namespace;
 
-static char *super_prefix;
-
 /*
  * Repository-local GIT_* environment variables; see cache.h for details.
  */
@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {
 	NO_REPLACE_OBJECTS_ENVIRONMENT,
 	GIT_REPLACE_REF_BASE_ENVIRONMENT,
 	GIT_PREFIX_ENVIRONMENT,
-	GIT_SUPER_PREFIX_ENVIRONMENT,
 	GIT_SHALLOW_FILE_ENVIRONMENT,
 	GIT_COMMON_DIR_ENVIRONMENT,
 	NULL
@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)
 	return NULL;
 }
 
-const char *get_super_prefix(void)
-{
-	static int initialized;
-	if (!initialized) {
-		super_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));
-		initialized = 1;
-	}
-	return super_prefix;
-}
-
 static int git_work_tree_initialized;
 
 /*
diff --git a/git.c b/git.c
index 2bca22cfd9a..b848cd608ff 100644
--- a/git.c
+++ b/git.c
@@ -14,7 +14,6 @@
  * RUN_SETUP for reading from the configuration file.
  */
 #define NEED_WORK_TREE		(1<<3)
-#define SUPPORT_SUPER_PREFIX	(1<<4)
 #define DELAY_PAGER_CONFIG	(1<<5)
 #define NO_PARSEOPT		(1<<6) /* parse-options is not used */
 
@@ -29,8 +28,7 @@ const char git_usage_string[] =
 	   "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 	   "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
 	   "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-	   "           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-	   "           <command> [<args>]");
+	   "           [--config-env=<name>=<envvar>] <command> [<args>]");
 
 const char git_more_info_string[] =
 	N_("'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 			setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
 			if (envchanged)
 				*envchanged = 1;
-		} else if (!strcmp(cmd, "--super-prefix")) {
-			if (*argc < 2) {
-				fprintf(stderr, _("no prefix given for --super-prefix\n" ));
-				usage(git_usage_string);
-			}
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
-			if (envchanged)
-				*envchanged = 1;
-			(*argv)++;
-			(*argc)--;
-		} else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
-			if (envchanged)
-				*envchanged = 1;
 		} else if (!strcmp(cmd, "--bare")) {
 			char *cwd = xgetcwd();
 			is_bare_repository_cfg = 1;
@@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 		trace_repo_setup(prefix);
 	commit_pager_choice();
 
-	if (!help && get_super_prefix()) {
-		if (!(p->option & SUPPORT_SUPER_PREFIX))
-			die(_("%s doesn't support --super-prefix"), p->cmd);
-	}
-
 	if (!help && p->option & NEED_WORK_TREE)
 		setup_work_tree();
 
@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {
 	{ "check-ref-format", cmd_check_ref_format, NO_PARSEOPT  },
 	{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout--worker", cmd_checkout__worker,
-		RUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },
+		RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout-index", cmd_checkout_index,
 		RUN_SETUP | NEED_WORK_TREE},
 	{ "cherry", cmd_cherry, RUN_SETUP },
@@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {
 	{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
 	{ "push", cmd_push, RUN_SETUP },
 	{ "range-diff", cmd_range_diff, RUN_SETUP | USE_PAGER },
-	{ "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
+	{ "read-tree", cmd_read_tree, RUN_SETUP },
 	{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
 	{ "receive-pack", cmd_receive_pack },
 	{ "reflog", cmd_reflog, RUN_SETUP },
@@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)
 	struct child_process cmd = CHILD_PROCESS_INIT;
 	int status;
 
-	if (get_super_prefix())
-		die(_("%s doesn't support --super-prefix"), argv[0]);
-
 	if (use_pager == -1 && !is_builtin(argv[0]))
 		use_pager = check_pager_config(argv[0]);
 	commit_pager_choice();
@@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)
 			 */
 			trace2_cmd_name("_run_git_alias_");
 
-			if (get_super_prefix())
-				die("%s doesn't support --super-prefix", **argv);
-
 			commit_pager_choice();
 
 			strvec_push(&cmd.args, "git");
diff --git a/submodule.c b/submodule.c
index d9fd0af81b6..5ac4e1b0568 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2048,14 +2048,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)
 	strbuf_release(&config_path);
 }
 
-static const char *get_super_prefix_or_empty(void)
-{
-	const char *s = get_super_prefix();
-	if (!s)
-		s = "";
-	return s;
-}
-
 static int submodule_has_dirty_index(const struct submodule *sub)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2074,7 +2066,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)
 	return finish_command(&cp);
 }
 
-static void submodule_reset_index(const char *path)
+static void submodule_reset_index(const char *path, const char *super_prefix)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
 	prepare_submodule_repo_env(&cp.env);
@@ -2083,10 +2075,10 @@ static void submodule_reset_index(const char *path)
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	/* TODO: determine if this might overwright untracked files */
 	strvec_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+		     (super_prefix ? super_prefix : ""), path);
 
 	strvec_push(&cp.args, empty_tree_oid_hex());
 
@@ -2099,10 +2091,9 @@ static void submodule_reset_index(const char *path)
  * For edge cases (a submodule coming into existence or removing a submodule)
  * pass NULL for old or new respectively.
  */
-int submodule_move_head(const char *path,
-			 const char *old_head,
-			 const char *new_head,
-			 unsigned flags)
+int submodule_move_head(const char *path, const char *super_prefix,
+			const char *old_head, const char *new_head,
+			unsigned flags)
 {
 	int ret = 0;
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2148,7 +2139,7 @@ int submodule_move_head(const char *path,
 			strbuf_release(&gitdir);
 
 			/* make sure the index is clean as well */
-			submodule_reset_index(path);
+			submodule_reset_index(path, NULL);
 		}
 
 		if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
@@ -2166,9 +2157,9 @@ int submodule_move_head(const char *path,
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	strvec_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+		     (super_prefix ? super_prefix : ""), path);
 
 	if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
 		strvec_push(&cp.args, "-n");
diff --git a/submodule.h b/submodule.h
index e5ee13fb06a..36a7f7c5b32 100644
--- a/submodule.h
+++ b/submodule.h
@@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);
 
 #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)
 #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)
-int submodule_move_head(const char *path,
-			const char *old,
-			const char *new_head,
+int submodule_move_head(const char *path, const char *super_prefix,
+			const char *old_head, const char *new_head,
 			unsigned flags);
 
 void submodule_unset_core_worktree(const struct submodule *sub);
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 516a6112fdc..3fb1b0c162d 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '
 	cat <<-EOF >expect &&
 		error: Updating '\''fictional/a'\'' would lose untracked files in it
 	EOF
-	test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual &&
+	test_must_fail git read-tree --super-prefix fictional/ -u -m "$treeH" "$treeM" 2>actual &&
 	test_cmp expect actual
 '
 
diff --git a/unpack-trees.c b/unpack-trees.c
index bae812156c4..61c02285454 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
 	  ? ((o)->msgs[(type)])      \
 	  : (unpack_plumbing_errors[(type)]) )
 
-static const char *super_prefixed(const char *path)
+static const char *super_prefixed(const char *path, const char *super_prefix)
 {
 	/*
 	 * It is necessary and sufficient to have two static buffers
@@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)
 	static unsigned idx = ARRAY_SIZE(buf) - 1;
 
 	if (super_prefix_len < 0) {
-		const char *super_prefix = get_super_prefix();
 		if (!super_prefix) {
 			super_prefix_len = 0;
 		} else {
@@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,
 		return -1;
 
 	if (!o->show_all_errors)
-		return error(ERRORMSG(o, e), super_prefixed(path));
+		return error(ERRORMSG(o, e), super_prefixed(path,
+							    o->super_prefix));
 
 	/*
 	 * Otherwise, insert in a list for future display by
@@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)
 			error_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			error(ERRORMSG(o, e), super_prefixed(path.buf));
+			error(ERRORMSG(o, e), super_prefixed(path.buf,
+							     o->super_prefix));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)
 			warning_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			warning(ERRORMSG(o, e), super_prefixed(path.buf));
+			warning(ERRORMSG(o, e), super_prefixed(path.buf,
+							       o->super_prefix));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,
 	if (o->reset)
 		flags |= SUBMODULE_MOVE_HEAD_FORCE;
 
-	if (submodule_move_head(ce->name, old_id, new_id, flags))
+	if (submodule_move_head(ce->name, NULL, old_id, new_id, flags))
 		return add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
 	return 0;
 }
@@ -415,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,
 	int i, pc_workers, pc_threshold;
 
 	trace_performance_enter();
+	state.super_prefix = o->super_prefix;
 	state.force = 1;
 	state.quiet = 1;
 	state.refresh_cache = 1;
@@ -445,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,
 
 		if (ce->ce_flags & CE_WT_REMOVE) {
 			display_progress(progress, ++cnt);
-			unlink_entry(ce);
+			unlink_entry(ce, o->super_prefix);
 		}
 	}
 
@@ -2958,8 +2961,8 @@ int bind_merge(const struct cache_entry * const *src,
 	if (a && old)
 		return o->quiet ? -1 :
 			error(ERRORMSG(o, ERROR_BIND_OVERLAP),
-			      super_prefixed(a->name),
-			      super_prefixed(old->name));
+			      super_prefixed(a->name, o->super_prefix),
+			      super_prefixed(old->name, o->super_prefix));
 	if (!a)
 		return keep_entry(old, o);
 	else
@@ -3020,7 +3023,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,
 
 	if (worktree && untracked)
 		return error(_("worktree and untracked commit have duplicate entries: %s"),
-			     super_prefixed(worktree->name));
+			     super_prefixed(worktree->name, o->super_prefix));
 
 	return merged_entry(worktree ? worktree : untracked, NULL, o);
 }
diff --git a/unpack-trees.h b/unpack-trees.h
index efb9edfbb27..9b81e284073 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -74,6 +74,7 @@ struct unpack_trees_options {
 		     dry_run;
 	enum unpack_trees_reset_type reset;
 	const char *prefix;
+	const char *super_prefix;
 	int cache_bottom;
 	struct pathspec *pathspec;
 	merge_fn_t fn;
-- 
2.38.0.1467.g709fbdff1a9


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/4] git: remove --super-prefix
  2022-11-09  0:47 [RFC PATCH 0/4] git: remove --super-prefix Glen Choo
                   ` (4 preceding siblings ...)
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-09 21:16 ` Taylor Blau
  2022-11-09 23:55   ` Glen Choo
  5 siblings, 1 reply; 79+ messages in thread
From: Taylor Blau @ 2022-11-09 21:16 UTC (permalink / raw)
  To: Glen Choo; +Cc: git, Ævar Arnfjörð Bjarmason

On Tue, Nov 08, 2022 at 04:47:04PM -0800, Glen Choo wrote:
> *Note to maintainer*: See "Interactions with other series".

Thanks for the heads up ;-).

It looks like this series is broken, at least in my application of it.
On the first patch, running t7401, for example, I get:

    BUG: builtin/submodule--helper.c:121: cannot have prefix 'sub/' and toplevel_cwd_prefix ''
    Aborted

after running the first test (-x shows that it happens after running
'git submodule summary', unsurprisingly).

I pushed out the result of what I have to the 'gc/remove--super-prefix'
branch of git@github.com:ttaylorr/git.git. As you'll see, the base is
'master' (as of 319605f8f0 (The eleventh batch, 2022-11-08)) with a
--no-ff merge of 'ab/submodule-helper-prep-only'.

Let me know if I'm holding it wrong.

Thanks,
Taylor

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
                     ` (7 preceding siblings ...)
  2022-11-09 19:34   ` [RFC PATCH 8/8] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
@ 2022-11-09 21:21   ` Taylor Blau
  2022-11-09 21:47     ` Ævar Arnfjörð Bjarmason
  2022-11-10  0:45   ` Glen Choo
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
  10 siblings, 1 reply; 79+ messages in thread
From: Taylor Blau @ 2022-11-09 21:21 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Glen Choo

On Wed, Nov 09, 2022 at 08:34:28PM +0100, Ævar Arnfjörð Bjarmason wrote:
> An RFC alternative to Glen's [1], and what I *thought* he might be be
> going for in the earlier discussion[2].

I am a little puzzled with what to do with this series. For one, it
doesn't seem to apply cleanly on top of 'ab/remove--super-prefix':

    $ git log --oneline -1
    04e36effde (HEAD -> ab/remove--super-prefix) Merge branch 'ab/submodule-helper-prep-only' into ab/remove--super-prefix

    $ git am -sc3 ~/patch
    Applying: submodule--helper: don't use global --super-prefix in "absorbgitdirs"
    error: sha1 information is lacking or useless (submodule.c).
    error: could not build fake ancestor
    Patch failed at 0001 submodule--helper: don't use global --super-prefix in "absorbgitdirs"
    hint: Use 'git am --show-current-patch=diff' to see the failed patch
    When you have resolved this problem, run "git am --continue".
    If you prefer to skip this patch, run "git am --skip" instead.
    To restore the original branch and stop patching, run "git am --abort".

But it would be nice to have a clearer path forward between this and
Glen's series. I understand that they are both still RFCs, but I am
counting on you two working together to find a path forward that is
satisfactory to you both.

In the meantime, it would be nice to have a version of this series that
I can apply to start playing around with.

Thanks,
Taylor

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-09 21:21   ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Taylor Blau
@ 2022-11-09 21:47     ` Ævar Arnfjörð Bjarmason
  2022-11-09 22:27       ` Taylor Blau
  0 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 21:47 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, Glen Choo


On Wed, Nov 09 2022, Taylor Blau wrote:

> On Wed, Nov 09, 2022 at 08:34:28PM +0100, Ævar Arnfjörð Bjarmason wrote:
>> An RFC alternative to Glen's [1], and what I *thought* he might be be
>> going for in the earlier discussion[2].
>
> I am a little puzzled with what to do with this series. For one, it
> doesn't seem to apply cleanly on top of 'ab/remove--super-prefix':
>
>     $ git log --oneline -1
>     04e36effde (HEAD -> ab/remove--super-prefix) Merge branch 'ab/submodule-helper-prep-only' into ab/remove--super-prefix
>
>     $ git am -sc3 ~/patch
>     Applying: submodule--helper: don't use global --super-prefix in "absorbgitdirs"
>     error: sha1 information is lacking or useless (submodule.c).
>     error: could not build fake ancestor
>     Patch failed at 0001 submodule--helper: don't use global --super-prefix in "absorbgitdirs"
>     hint: Use 'git am --show-current-patch=diff' to see the failed patch
>     When you have resolved this problem, run "git am --continue".
>     If you prefer to skip this patch, run "git am --skip" instead.
>     To restore the original branch and stop patching, run "git am --abort".

My bad, the CL says:

	and can make use of (but doesn't need) the better test coverage
	for "absorbgitdirs" that I submitted in [3]
	(https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/)".

But it actually *does* need that, sorry. But with that, this works for me:

	git checkout master
	git reset --hard @{u}
	git merge --no-edit ttaylorr/ab/submodule-helper-prep-only
	(apply https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/)

Then apply this series. I've also got it at
https://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local;
but that's a locally rebased version of ab/submodule-helper-prep-only,
then that [3], and finally this series.

I figured I was just kicking ideas back & forth with Glen, so I didn't
go through my usual sanity checking :)

> But it would be nice to have a clearer path forward between this and
> Glen's series. I understand that they are both still RFCs, but I am
> counting on you two working together to find a path forward that is
> satisfactory to you both.

*nod*, I'm sure we can manage that.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-09 21:47     ` Ævar Arnfjörð Bjarmason
@ 2022-11-09 22:27       ` Taylor Blau
  2022-11-09 22:54         ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 79+ messages in thread
From: Taylor Blau @ 2022-11-09 22:27 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Glen Choo

On Wed, Nov 09, 2022 at 10:47:40PM +0100, Ævar Arnfjörð Bjarmason wrote:
>
> On Wed, Nov 09 2022, Taylor Blau wrote:
>
> > On Wed, Nov 09, 2022 at 08:34:28PM +0100, Ævar Arnfjörð Bjarmason wrote:
> >> An RFC alternative to Glen's [1], and what I *thought* he might be be
> >> going for in the earlier discussion[2].
> >
> > I am a little puzzled with what to do with this series. For one, it
> > doesn't seem to apply cleanly on top of 'ab/remove--super-prefix':
> >
> >     $ git log --oneline -1
> >     04e36effde (HEAD -> ab/remove--super-prefix) Merge branch 'ab/submodule-helper-prep-only' into ab/remove--super-prefix
> >
> >     $ git am -sc3 ~/patch
> >     Applying: submodule--helper: don't use global --super-prefix in "absorbgitdirs"
> >     error: sha1 information is lacking or useless (submodule.c).
> >     error: could not build fake ancestor
> >     Patch failed at 0001 submodule--helper: don't use global --super-prefix in "absorbgitdirs"
> >     hint: Use 'git am --show-current-patch=diff' to see the failed patch
> >     When you have resolved this problem, run "git am --continue".
> >     If you prefer to skip this patch, run "git am --skip" instead.
> >     To restore the original branch and stop patching, run "git am --abort".
>
> My bad, the CL says:
>
> 	and can make use of (but doesn't need) the better test coverage
> 	for "absorbgitdirs" that I submitted in [3]
> 	(https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/)".
>
> But it actually *does* need that, sorry. But with that, this works for me:
>
> 	git checkout master
> 	git reset --hard @{u}
> 	git merge --no-edit ttaylorr/ab/submodule-helper-prep-only
> 	(apply https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/)
>
> Then apply this series. I've also got it at
> https://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local;
> but that's a locally rebased version of ab/submodule-helper-prep-only,
> then that [3], and finally this series.

Yes, that works for me. I hadn't quite gotten to the later patch yet,
but I queued it as 'ab/remove--super-prefix' and then merged it into the
new branch (along with 'ab/submodule-helper-prep-only').

Then everything applied as expected, so that is good.

> I figured I was just kicking ideas back & forth with Glen, so I didn't
> go through my usual sanity checking :)

No worries, I figured. It's helpful to know whether you intended to
supersede, build on top of, or propose an alternative direction for
Glen's patch.

For what it's worth, I think it's totally fine to say: "I have this
alternative approach in a series, and here it is", but it is also
helpful to add "let's figure out a way to build these together instead
of queuing this alternative approach as-is".

> > But it would be nice to have a clearer path forward between this and
> > Glen's series. I understand that they are both still RFCs, but I am
> > counting on you two working together to find a path forward that is
> > satisfactory to you both.
>
> *nod*, I'm sure we can manage that.

Thanks very much.

Thanks,
Taylor

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-09 22:27       ` Taylor Blau
@ 2022-11-09 22:54         ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-09 22:54 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, Glen Choo


On Wed, Nov 09 2022, Taylor Blau wrote:

> On Wed, Nov 09, 2022 at 10:47:40PM +0100, Ævar Arnfjörð Bjarmason wrote:
>> [...]
>> I figured I was just kicking ideas back & forth with Glen, so I didn't
>> go through my usual sanity checking :)
>
> No worries, I figured. It's helpful to know whether you intended to
> supersede, build on top of, or propose an alternative direction for
> Glen's patch.
>
> For what it's worth, I think it's totally fine to say: "I have this
> alternative approach in a series, and here it is", but it is also
> helpful to add "let's figure out a way to build these together instead
> of queuing this alternative approach as-is".

To be clear: This is a proposed replacement for his, but I'm hoping
he'll also like it :)

I don't think there's any disagreement about where we eventually want to
end up.

I.e. for stuff like "read-tree" we shouldn't be calling a sub-process
recursively, but should instead be able to handle this in-process, ditto
"branch" having to invoke "git submodule" etc.

But getting there is a much longer journey. It doesn't just require
passing a "struct repository *r" around, but also untangling some other
global state & setup.

The "--super-prefix" feature was always something that was at least two
steps removed from that eventual goal. I.e. we didn't even have an easy
way to connect two codepaths within our own built-ins, so we just set an
environment variable at the start, and knew that if we spawned
sub-processes we could carry things forward like that.

Glen's RFC gets us about halfway past that state of affairs. It's not an
environment variable anymore, or a single global, but a split up
per-command global variable.

Whereas what I went for was an "all the way" solution of not having the
global at all. At least for submodule--helper I think 1-6/8 here shows
that that's pretty straightforward. We're usually only 1-3 function
calls away from the point at which we recurse to ourselves, so we can
just pass that state along as a function parameter, or for "foreach",
"sync" etc. via our own callback struct.

The 8/8 (and 7/8 prep test) then does that for "read-tree", which is
arguably a bit more gnarly (we need to ferry the state down two
different structs along the way), but even then it now becomes easy to
follow the full path to where we eventually recurse.

In terms of how this goes forward (and I'll wait for Glen to chime in,
and depending on what he thinks): If we go forward with my version of
this I think probably doing 1-6/8 here as its own topic just for
"submodule--helper" would make sense, as that's really quite
straightforward.

We could then do the somewhat tricker 8/8 separately.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/4] git: remove --super-prefix
  2022-11-09 21:16 ` [RFC PATCH 0/4] git: remove --super-prefix Taylor Blau
@ 2022-11-09 23:55   ` Glen Choo
  2022-11-10  2:14     ` Taylor Blau
  0 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-09 23:55 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, Ævar Arnfjörð Bjarmason

Taylor Blau <me@ttaylorr.com> writes:

> On Tue, Nov 08, 2022 at 04:47:04PM -0800, Glen Choo wrote:
>> *Note to maintainer*: See "Interactions with other series".
>
> Thanks for the heads up ;-).
>
> It looks like this series is broken, at least in my application of it.
> On the first patch, running t7401, for example, I get:
>
>     BUG: builtin/submodule--helper.c:121: cannot have prefix 'sub/' and toplevel_cwd_prefix ''
>     Aborted
>
> after running the first test (-x shows that it happens after running
> 'git submodule summary', unsurprisingly).
>
> I pushed out the result of what I have to the 'gc/remove--super-prefix'
> branch of git@github.com:ttaylorr/git.git. As you'll see, the base is
> 'master' (as of 319605f8f0 (The eleventh batch, 2022-11-08)) with a
> --no-ff merge of 'ab/submodule-helper-prep-only'.
>
> Let me know if I'm holding it wrong.

No, the problem seems to be entirely on my end. (I could've sworn I sent
this to CI..)

Given that we have another competing RFC, it doesn't seem like a great
use of time to reroll this just to unbreak "seen", but let me know if
I'm missing somthing.

>
> Thanks,
> Taylor

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
                     ` (8 preceding siblings ...)
  2022-11-09 21:21   ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Taylor Blau
@ 2022-11-10  0:45   ` Glen Choo
  2022-11-10 10:51     ` Ævar Arnfjörð Bjarmason
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
  10 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-10  0:45 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Ævar Arnfjörð Bjarmason

Thanks for the series! I haven't fully figured out where I stand on
this, but I can share some initial thoughts and comparisons to my RFC.

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> An RFC alternative to Glen's [1], and what I *thought* he might be be
> going for in the earlier discussion[2].
>
> The difference is that in Glen's there's no "git --super-prefix", but
> rather each set of commands still using it ("submodule--helper",
> "read-tree" etc.) geit their own command-level option.

Yes, and a secondary intent was to give exact definitions and a shared
implementation to the command-level options instead of having each new
command figure out what to do every time a similar use case pops up.

>
> But it still works substantially the same, in that we're juggling a
> global variable that we set, and read out later somewhere down the
> stack.

Yes, intentionally so. I was under the assumption that the various
prefixes would still be used, and that adding them to commands will be a
necessary evil, so it was better to have them share a single
implementation.

> Whereas here there's no renaming of the option, but:
>
>  * For "submodule--helper" only the sub-commands that need it take the
>    option, it's not an option to "submodule--helper" itself.

In writing [1], I ended up convincing myself that it isn't just that all
of "submodule--helper" _does_ support "--super-prefix", but that all of
it _should_ support "--super-prefix". I'll have to take another look.

At the very least, the subcommands that are just entrypoints for
git-submodule.sh should support it, since they all need to print
submodule paths in a semi-consistent way. I still think it would be nice
for these to take a top level flag.

There are other subcommands that are implementation details of other
commands that need to run in a submodule because of assumptions
the_repository, e.g. create-branch, push-check. Maybe these don't need
"--super-prefix", I'll take another look.

I'm not sure if there are others.

(As an aside, when you remove git-submodule.sh, I wonder if we should
split up submodule--helper along this dual-use line? e.g. the ones that
are entrypoints could be moved to "builtin/submodule.c", and the
implementation details can stay in "builtin/submodule--helper.c". Or
maybe you're already one step ahead of me here :))

As you noted (somewhere) in the series, only commands called recursively
need "--super-prefix", because otherwise "submodule--helper" is called
from the root of the superproject and the 'prefix' is already
well-known. I didn't make this argument because it was hard to word, so
I'm glad you mentioned it.

[1] https://lore.kernel.org/git/20221109004708.97668-2-chooglen@google.com/

>  * There's no passing of the "super_prefix" as a global, instead we
>    pass it all the way along until we recurse to ourselves. For
>    "submodule--helper" this is quite straightforward.
>
>  * Then in 8/8 we're left with just "read-tree" needing the remaining
>    "--super-prefix", and we likewise don't pass it as a global, but
>    instead add it to the "struct unpack_trees_options", which will
>    pass it all the way down into unpack-trees.c and entry.c, until
>    we're going to recursively invoke another "read-tree".

I worry a little about two "necessary evils":

- (As stated earlier) we may have to add "--super-prefix" or similar to
  more commands
- We may need to read "--super-prefix" from many parts of the code,
  since many parts might print paths.

Having globals makes both of these cases easier, and is quite a bit
closer to the original implementation of "--super-prefix" (so your
characterization of only getting to a halfway point is accurate). This
was mostly to stave off opposition that it would tedious to add new
per-command "--super-prefix"-es, but if nobody else cares, maybe it's ok
to get of the globals.

If we do want to pass a context object around, we probably have to be
more principled about it (e.g. in 8/8 I notice that checkout_stage()
doesn't receive the context object and we resort to passing NULL
instead), but we'd want that anyway if we want Git to move towards being
more library-like.

It's quite likely that if any new "--super-prefix"-es are added, they
would be added by a Googler (even the original ones were ;)), so I can
probably go through the roadmap and figure out how costly these extra
"--super-prefix"-es might be.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/4] git: remove --super-prefix
  2022-11-09 23:55   ` Glen Choo
@ 2022-11-10  2:14     ` Taylor Blau
  2022-11-10 23:49       ` Glen Choo
  0 siblings, 1 reply; 79+ messages in thread
From: Taylor Blau @ 2022-11-10  2:14 UTC (permalink / raw)
  To: Glen Choo; +Cc: Taylor Blau, git, Ævar Arnfjörð Bjarmason

On Wed, Nov 09, 2022 at 03:55:39PM -0800, Glen Choo wrote:
> > It looks like this series is broken, at least in my application of it.
> > On the first patch, running t7401, for example, I get:
> >
> >     BUG: builtin/submodule--helper.c:121: cannot have prefix 'sub/' and toplevel_cwd_prefix ''
> >     Aborted
> >
> > after running the first test (-x shows that it happens after running
> > 'git submodule summary', unsurprisingly).
> >
> > I pushed out the result of what I have to the 'gc/remove--super-prefix'
> > branch of git@github.com:ttaylorr/git.git. As you'll see, the base is
> > 'master' (as of 319605f8f0 (The eleventh batch, 2022-11-08)) with a
> > --no-ff merge of 'ab/submodule-helper-prep-only'.
> >
> > Let me know if I'm holding it wrong.
>
> No, the problem seems to be entirely on my end. (I could've sworn I sent
> this to CI..)
>
> Given that we have another competing RFC, it doesn't seem like a great
> use of time to reroll this just to unbreak "seen", but let me know if
> I'm missing somthing.

No problem. Let's drop this one for now, unless you have strong
objections.

Thanks,
Taylor

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-10  0:45   ` Glen Choo
@ 2022-11-10 10:51     ` Ævar Arnfjörð Bjarmason
  2022-11-11  1:07       ` Glen Choo
  0 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-10 10:51 UTC (permalink / raw)
  To: Glen Choo; +Cc: git


On Wed, Nov 09 2022, Glen Choo wrote:

> Thanks for the series! I haven't fully figured out where I stand on
> this, but I can share some initial thoughts and comparisons to my RFC.
>
> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> An RFC alternative to Glen's [1], and what I *thought* he might be be
>> going for in the earlier discussion[2].
>>
>> The difference is that in Glen's there's no "git --super-prefix", but
>> rather each set of commands still using it ("submodule--helper",
>> "read-tree" etc.) geit their own command-level option.
>
> Yes, and a secondary intent was to give exact definitions and a shared
> implementation to the command-level options instead of having each new
> command figure out what to do every time a similar use case pops up.

... (more below)...

>>
>> But it still works substantially the same, in that we're juggling a
>> global variable that we set, and read out later somewhere down the
>> stack.
>
> Yes, intentionally so. I was under the assumption that the various
> prefixes would still be used, and that adding them to commands will be a
> necessary evil, so it was better to have them share a single
> implementation.

I'm not sure I understand what you mean here exactly, but as an example
that might clarify things: In my "foreach" patch:
https://lore.kernel.org/git/RFC-patch-3.8-4858e2ad0ed-20221109T192315Z-avarab@gmail.com/

I'm making use of "OPT__SUPER_PREFIX()" to share the things that need to
be shared, and after that we ferry the "super_prefix" from
module_foreach() down through "struct foreach_cb" to
"runcommand_in_submodule_cb()", and that's all the places we need it.

With how OPT_SUBCOMMAND() works we'd need a file-level static variable
(or similar) if we took the "--super-prefix" in the
cmd_submodule__helper() instead, which we could do, and it would have
pretty much the same effect.

But I don't really see the advantage in any one individiual case. Isn't
it just trading that one repeated "OPT__SUPER_PREFIX()" line for more
clarity about who needs what?

>> Whereas here there's no renaming of the option, but:
>>
>>  * For "submodule--helper" only the sub-commands that need it take the
>>    option, it's not an option to "submodule--helper" itself.
>
> In writing [1], I ended up convincing myself that it isn't just that all
> of "submodule--helper" _does_ support "--super-prefix", but that all of
> it _should_ support "--super-prefix". I'll have to take another look.

I agree with your:

	"[...]"This is the only way the prefix is used in "git
	submodule--helper", and all of its subcommands already conform
	to this behavior (even the ones that weren't marked
	SUPPORT_SUPER_PREFIX) because they all use
	get_submodule_displaypath() when printing paths to
	submodules.[...]"

In that it's clear that e.g. if "add" were added to the list of
sub-commands that used "git --super-prefix" *and* we started calling
that recursively with the same method that "get_submodule_displaypath()"
makes it easier to construct such paths (which is also the case after my
series, just with the *_sp() variant).

But I don't see how that extends to an argument that we should be
blurring the lines about what does and doesn't need it *now*, which as I
pointed out in my "now we'll accept it" is what that commit is doing:
https://lore.kernel.org/git/221109.867d04rfnt.gmgdl@evledraar.gmail.com/

> At the very least, the subcommands that are just entrypoints for
> git-submodule.sh should support it, since they all need to print
> submodule paths in a semi-consistent way. I still think it would be nice
> for these to take a top level flag.

But they don't need it, and some of them will never need it. E.g. I
don't see how it would make sense for "set-url" and "get-url" ever to
get a "--recursive" option, those are inherently non-recursive (if
they're going to make any sense, you *could* set all your submodule URLs
to the same thing, but what's the use in that?).

But also re my:
https://lore.kernel.org/git/221110.86cz9vpvqk.gmgdl@evledraar.gmail.com/;
I think that *if* we add new recursion we're just as likely to not use
any "--submodule-prefix"-like functionality, but to instead just walk
the tree, constructing repo objects along the way. As my 8/8 summarizes
that's what we're doing in "grep", "ls-files" etc.

Still, if it was easier etc. to just provide this for the entire
command, even if all subcommands wouldn't need it I wouldn't mind
it. But as noted above it's trivial to add it on demand with
"OPT__SUPER_PREFIX()", you don't need to reason about globals etc. So I
just don't see the benefit...

> There are other subcommands that are implementation details of other
> commands that need to run in a submodule because of assumptions
> the_repository, e.g. create-branch, push-check. Maybe these don't need
> "--super-prefix", I'll take another look.

I you don't need to take much of a look, because on "master" they don't
have a "SUPPORT_SUPER_PREFIX" next to their listing at the bottom of
submodule--helper.c, ditto for the "if" chain I have in
"next". I.e. none of the ones listed in the "struct option options" as
OPT_SUBCOMMAND() use "git --super-prefix", except if they're listed in
the "if" chain below.

> I'm not sure if there are others.

We can be sure it's just clone/update/foreach/status/sync/absorbgitdirs,
because if the others are invoked with the --super-prefix they'll die().

Which aside from the specific approaches in either of our topics is, I
think, a really nice thing to have. I.e. it makes reasoning about the
code easier if we can confidently say "this is a feature with global
effect, but it only has an impact on this subset of stuff".

Which is an aspect of your proposed RFC that I don't like in
isolation. I.e. if/when we're going to do the eventual refactoring that
I've done in my RFC we'd need to reason that we need to change "foreach"
and not "create-branch" or whatever, which the current whitelisting
really helps us with.

> (As an aside, when you remove git-submodule.sh, I wonder if we should
> split up submodule--helper along this dual-use line? e.g. the ones that
> are entrypoints could be moved to "builtin/submodule.c", and the
> implementation details can stay in "builtin/submodule--helper.c". Or
> maybe you're already one step ahead of me here :))

Yes, I'm ahead of you there.

The ones that are purely internal, such as "push-check" etc. are still
going to be invoked as "submodule--helper push-check".

Before my RFC topic here I was planning on having both a "foreach" and
"submodule--helper-foreach", as seen in:
https://lore.kernel.org/git/221104.86wn8bzeus.gmgdl@evledraar.gmail.com/

That was because I:

 1. Didn't want to make "foreach"'s "--super-prefix" interface "public",
    which it isn't now, as it's a purely internal thing we're trying to
    eventually get rid of.
 2. Didn't want to list all of "submodule--helper" as accepting it, as
    some of it doesn't need it (e.g. "push-check").

So having a "git submodule foreach" *not* accept it and it then
recursing to an internal "git submodule--helper-foreach" which did
accept it seemed like the least sucky thing to do.

But if I rebase those patches on my RFC topic here we can invoke both as
just "git submodule foreach".

Pedantically, that's also exposing a "private" interface to the
public. But:

 * I'm listing it as OPT_HIDDEN, so we're not showing it outside fo
   --help-all.

 * More importantly, you need to provide that specific flag, it's not
   accepting it "at a distance" via an env variable, which was the main
   thing I was being paranod about.

   Or rather. Even if *I knew* that "read-tree" or whatever wasn't
   invoking a hook, which then invoked "submodule foreach" down the
   line, and that "foreach" was slurping up the env var, I wanted to
   leave it in a state where the next maintainer of this code didn't
   have to worry about that.

> As you noted (somewhere) in the series, only commands called recursively
> need "--super-prefix", because otherwise "submodule--helper" is called
> from the root of the superproject and the 'prefix' is already
> well-known. I didn't make this argument because it was hard to word, so
> I'm glad you mentioned it.

Right, and just to add to that: This is the super_prefix==NULL case in
get_submodule_displaypath() on "master" (i.e. aside from either of our
topics here).

> [1] https://lore.kernel.org/git/20221109004708.97668-2-chooglen@google.com/
>
>>  * There's no passing of the "super_prefix" as a global, instead we
>>    pass it all the way along until we recurse to ourselves. For
>>    "submodule--helper" this is quite straightforward.
>>
>>  * Then in 8/8 we're left with just "read-tree" needing the remaining
>>    "--super-prefix", and we likewise don't pass it as a global, but
>>    instead add it to the "struct unpack_trees_options", which will
>>    pass it all the way down into unpack-trees.c and entry.c, until
>>    we're going to recursively invoke another "read-tree".
>
> I worry a little about two "necessary evils":
>
> - (As stated earlier) we may have to add "--super-prefix" or similar to
>   more commands
> - We may need to read "--super-prefix" from many parts of the code,
>   since many parts might print paths.
>
> Having globals makes both of these cases easier, and is quite a bit
> closer to the original implementation of "--super-prefix" (so your
> characterization of only getting to a halfway point is accurate). This
> was mostly to stave off opposition that it would tedious to add new
> per-command "--super-prefix"-es, but if nobody else cares, maybe it's ok
> to get of the globals.
>
> If we do want to pass a context object around, we probably have to be
> more principled about it (e.g. in 8/8 I notice that checkout_stage()
> doesn't receive the context object and we resort to passing NULL
> instead), but we'd want that anyway if we want Git to move towards being
> more library-like.

Quick aside: Yes, that unlink_entry(ce) in builtin/checkout.c is now
unlink_entry(ce, NULL).

The API had only 3 users, and two potentially cared about the
super_prefix. So I just amended the existing function, we could also add
a unlink_entry_sp() or whatever.

> It's quite likely that if any new "--super-prefix"-es are added, they
> would be added by a Googler (even the original ones were ;)), so I can
> probably go through the roadmap and figure out how costly these extra
> "--super-prefix"-es might be.

I don't really see that happening, but let me just grant that point for
the sake of argument: 

Next month we're going to add a new "--super-prefix"-like use, and we're
going to want some combinatino of a global, setenv()/getenv() etc. back,
because it's the "sparse" code or whatever, and it'll be daunting to
pass the state through 30 levels of callstack, we'll want to bypass it.

I still don't see how it follows that we'd want to keep any of structure
for this, which I think my series shows none of the current code needs.

We can easily add such functionality back, adding a global variable
isn't hard, and I think if anything such a future future would benefit
from having to explain why it needs global state to do this sort of
thing, when these other commands and sub-commands don't.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/4] git: remove --super-prefix
  2022-11-10  2:14     ` Taylor Blau
@ 2022-11-10 23:49       ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-10 23:49 UTC (permalink / raw)
  To: Taylor Blau; +Cc: Taylor Blau, git, Ævar Arnfjörð Bjarmason

Taylor Blau <me@ttaylorr.com> writes:

> On Wed, Nov 09, 2022 at 03:55:39PM -0800, Glen Choo wrote:
>> > It looks like this series is broken, at least in my application of it.
>> > On the first patch, running t7401, for example, I get:
>> >
>> >     BUG: builtin/submodule--helper.c:121: cannot have prefix 'sub/' and toplevel_cwd_prefix ''
>> >     Aborted
>> >
>> > after running the first test (-x shows that it happens after running
>> > 'git submodule summary', unsurprisingly).
>> >
>> > I pushed out the result of what I have to the 'gc/remove--super-prefix'
>> > branch of git@github.com:ttaylorr/git.git. As you'll see, the base is
>> > 'master' (as of 319605f8f0 (The eleventh batch, 2022-11-08)) with a
>> > --no-ff merge of 'ab/submodule-helper-prep-only'.
>> >
>> > Let me know if I'm holding it wrong.
>>
>> No, the problem seems to be entirely on my end. (I could've sworn I sent
>> this to CI..)
>>
>> Given that we have another competing RFC, it doesn't seem like a great
>> use of time to reroll this just to unbreak "seen", but let me know if
>> I'm missing somthing.
>
> No problem. Let's drop this one for now, unless you have strong
> objections.

Yes let's drop my RFC for now, thanks.

>
> Thanks,
> Taylor

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 1/8] submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  2022-11-09 19:34   ` [RFC PATCH 1/8] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
@ 2022-11-11  0:12     ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-11  0:12 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> But in the case of "absorbgitdirs" it only needed "--super-prefix" to
> invoke itself recursively, and we'd never have another "in-between"
> process in the chain. So we didn't need the bigger hammer of "git
> --super-prefix", and the "setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)"
> that it entails.

I also thought this was the case, but in the proces of reviewing this, I
I'm not sure any more. More below..

> Eventually (as with all other "--super-prefix" users) we'll want to
> clean this code up so that this all happens in-process. I.e. needing
> any variant of "--super-prefix" is itself a hack around our various
> global state, and implicit reliance on "the_repository". This stepping
> stone makes such an eventual change easier, as we'll need to deal with
> less global state at that point.

Yes, I 100% agree. I am not optimistic that we can clean all of these up
any time soon, but I can buy the argument that we will have to remove
the extra global state at some point, so we should just bite the bullet
now.

> diff --git a/parse-options.h b/parse-options.h
> index b6ef86e0d15..50d852f2991 100644
> --- a/parse-options.h
> +++ b/parse-options.h
> @@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
>  	{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"),	\
>  	  N_("use <n> digits to display object names"),	\
>  	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
> +#define OPT__SUPER_PREFIX(var) \
> +	OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
> +		N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
> +
>  #define OPT__COLOR(var, h) \
>  	OPT_COLOR_FLAG(0, "color", (var), (h))
>  #define OPT_COLUMN(s, l, v, h) \
> diff --git a/submodule.c b/submodule.c
> index c47358097fd..d9fd0af81b6 100644
> --- a/submodule.c
> +++ b/submodule.c
> @@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)
>   * Embeds a single submodules git directory into the superprojects git dir,
>   * non recursively.
>   */
> -static void relocate_single_git_dir_into_superproject(const char *path)
> +static void relocate_single_git_dir_into_superproject(const char *path,
> +						      const char *super_prefix)
>  {
>  	char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
>  	struct strbuf new_gitdir = STRBUF_INIT;
> @@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
>  	       real_old_git_dir[off] == real_new_git_dir[off])
>  		off++;
>  	fprintf(stderr, _("Migrating git directory of '%s%s' from '%s' to '%s'\n"),
> -		get_super_prefix_or_empty(), path,
> +		(super_prefix ? super_prefix : ""), path,
>  		real_old_git_dir + off, real_new_git_dir + off);
>  
>  	relocate_gitdir(path, real_old_git_dir, real_new_git_dir);

When this gets cleaned up post-RFC, I think we should have
OPT__SUPER_PREFIX handle this "default to empty" behavior for us.

> diff --git a/submodule.h b/submodule.h
> index b52a4ff1e73..e5ee13fb06a 100644
> --- a/submodule.h
> +++ b/submodule.h
> @@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);
>   */
>  void prepare_submodule_repo_env(struct strvec *env);
>  
> -void absorb_git_dir_into_superproject(const char *path);
> +void absorb_git_dir_into_superproject_sp(const char *path,
> +					 const char *super_prefix);
> +static inline void absorb_git_dir_into_superproject(const char *path)
> +{
> +	absorb_git_dir_into_superproject_sp(path, NULL);
> +}

Since absorb_git_dir_into_superproject() is called by
submodule_move_head() (the function that handles submodule changes in
unpack_trees()), it can be called from "git read-tree".

So we really do end up mixing the different values of --super-prefix;
invoking "absorbgitdirs" directly would print the relative path from
cwd, but invoking it indirectly via "read-tree" would print the path
from the root of the superproject tree. I guess that result makes sense,
since "read-tree" and friends print paths from the root of the tree, but
it feels a bit odd.

I'll propose a test for this after I finish reading through the series.
To avoid masking this behavior, I think we'll have to avoid going down
the *_sp() path and just plumb super_prefix everywhere.

>  
>  /*
>   * Return the absolute path of the working tree of the superproject, which this
> -- 
> 2.38.0.1467.g709fbdff1a9

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 8/8] read-tree: add "--super-prefix" option, eliminate global
  2022-11-09 19:34   ` [RFC PATCH 8/8] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
@ 2022-11-11  0:40     ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-11  0:40 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> That "submodule_move_head()" function was then only invoked by
> "read-tree" itself, but now rather than setting an environment
> variable to pass "--super-prefix" between cmd_read_tree() we:
>
> - Set a new "super_prefix" in "struct unpack_trees_options". The
>   "super_prefixed()" function in "unpack-trees.c" added in [5] will now
>   use this, rather than get_super_prefix() looking up the environment
>   variable we set earlier in the same process.
>
> - Add the same field to the "struct checkout", which is only needed to
>   ferry the "super_prefix" in the "struct unpack_trees_options" all the
>   way down to the "entry.c" callers of "submodule_move_head()".
>
>   Those calls which used the super prefix all originated in
>   "cmd_read_tree()". The only other caller is the "unlink_entry()"
>   caller in "builtin/checkout.c", which now passes a "NULL".
>
> 1. 74866d75793 (git: make super-prefix option, 2016-10-07)
> 2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)
> 3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)
> 4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)
> 5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)
> 6. 188dce131fa (ls-files: use repository object, 2017-06-22)
> 7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

[...]

> diff --git a/submodule.h b/submodule.h
> index e5ee13fb06a..36a7f7c5b32 100644
> --- a/submodule.h
> +++ b/submodule.h
> @@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);
>  
>  #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)
>  #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)
> -int submodule_move_head(const char *path,
> -			const char *old,
> -			const char *new_head,
> +int submodule_move_head(const char *path, const char *super_prefix,
> +			const char *old_head, const char *new_head,
>  			unsigned flags);
>  
>  void submodule_unset_core_worktree(const struct submodule *sub);

This signature change turned out to be far less disruptive than I
expected, nice. It helps that we already had a natural home for these,
i.e. "struct checkout" and "struct unpack_trees_options".

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-10 10:51     ` Ævar Arnfjörð Bjarmason
@ 2022-11-11  1:07       ` Glen Choo
  2022-11-11 18:29         ` Glen Choo
  0 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-11  1:07 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git

Rereading this series and thinking about this some more, let's go with
your approach, primarily because it avoids global state.

From this series, it seems that it's not that hard to make this change
and support whatever use cases we currently have.

This does make it more tedious to add more "--super-prefix" in the
future, but that's a good push for us to do more things in-process
and/or be more principled about passing context objects through the call
stack instead of relying on globals.

Let me know what I can add to this effort besides reviewing :)

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Wed, Nov 09 2022, Glen Choo wrote:
>
>> Thanks for the series! I haven't fully figured out where I stand on
>> this, but I can share some initial thoughts and comparisons to my RFC.
>>
>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>>
>>> An RFC alternative to Glen's [1], and what I *thought* he might be be
>>> going for in the earlier discussion[2].
>>>
>>> The difference is that in Glen's there's no "git --super-prefix", but
>>> rather each set of commands still using it ("submodule--helper",
>>> "read-tree" etc.) geit their own command-level option.
>>
>> Yes, and a secondary intent was to give exact definitions and a shared
>> implementation to the command-level options instead of having each new
>> command figure out what to do every time a similar use case pops up.
>
> ... (more below)...
>
>>>
>>> But it still works substantially the same, in that we're juggling a
>>> global variable that we set, and read out later somewhere down the
>>> stack.
>>
>> Yes, intentionally so. I was under the assumption that the various
>> prefixes would still be used, and that adding them to commands will be a
>> necessary evil, so it was better to have them share a single
>> implementation.
>
> I'm not sure I understand what you mean here exactly, but as an example
> that might clarify things: In my "foreach" patch:
> https://lore.kernel.org/git/RFC-patch-3.8-4858e2ad0ed-20221109T192315Z-avarab@gmail.com/
>
> I'm making use of "OPT__SUPER_PREFIX()" to share the things that need to
> be shared, and after that we ferry the "super_prefix" from
> module_foreach() down through "struct foreach_cb" to
> "runcommand_in_submodule_cb()", and that's all the places we need it.
>
> With how OPT_SUBCOMMAND() works we'd need a file-level static variable
> (or similar) if we took the "--super-prefix" in the
> cmd_submodule__helper() instead, which we could do, and it would have
> pretty much the same effect.
>
> But I don't really see the advantage in any one individiual case. Isn't
> it just trading that one repeated "OPT__SUPER_PREFIX()" line for more
> clarity about who needs what?

The other concern I had was that we'd have to repeat the "super_prefix"
field in all of the command options structs, and then pass them down
through all of the call chain that would need it. Or even worse, create
new structs for call chains that didn't have them.

But, since want to move away from global state altogether, the "effort
saving" of having a global will end up causing more headache for us in
the future, so we should just bite the bullet now, especially since this
series shows thats it's not _that_ hard.

> We can be sure it's just clone/update/foreach/status/sync/absorbgitdirs,
> because if the others are invoked with the --super-prefix they'll die().
>
> Which aside from the specific approaches in either of our topics is, I
> think, a really nice thing to have. I.e. it makes reasoning about the
> code easier if we can confidently say "this is a feature with global
> effect, but it only has an impact on this subset of stuff".
>
> Which is an aspect of your proposed RFC that I don't like in
> isolation. I.e. if/when we're going to do the eventual refactoring that
> I've done in my RFC we'd need to reason that we need to change "foreach"
> and not "create-branch" or whatever, which the current whitelisting
> really helps us with.

Fair. I also had the same worries, which is probably a sign of smelly
code.

>
>> (As an aside, when you remove git-submodule.sh, I wonder if we should
>> split up submodule--helper along this dual-use line? e.g. the ones that
>> are entrypoints could be moved to "builtin/submodule.c", and the
>> implementation details can stay in "builtin/submodule--helper.c". Or
>> maybe you're already one step ahead of me here :))
>
> Yes, I'm ahead of you there.
>
> The ones that are purely internal, such as "push-check" etc. are still
> going to be invoked as "submodule--helper push-check".
>
> Before my RFC topic here I was planning on having both a "foreach" and
> "submodule--helper-foreach", as seen in:
> https://lore.kernel.org/git/221104.86wn8bzeus.gmgdl@evledraar.gmail.com/
>
> That was because I:
>
>  1. Didn't want to make "foreach"'s "--super-prefix" interface "public",
>     which it isn't now, as it's a purely internal thing we're trying to
>     eventually get rid of.
>  2. Didn't want to list all of "submodule--helper" as accepting it, as
>     some of it doesn't need it (e.g. "push-check").
>
> So having a "git submodule foreach" *not* accept it and it then
> recursing to an internal "git submodule--helper-foreach" which did
> accept it seemed like the least sucky thing to do.
>
> But if I rebase those patches on my RFC topic here we can invoke both as
> just "git submodule foreach".
>
> Pedantically, that's also exposing a "private" interface to the
> public. But:
>
>  * I'm listing it as OPT_HIDDEN, so we're not showing it outside fo
>    --help-all.

IMO I think OPT_HIDDEN is good enough, so yes, let's avoid having
"submodule foo" and "submodule--helper foo".

>  * More importantly, you need to provide that specific flag, it's not
>    accepting it "at a distance" via an env variable, which was the main
>    thing I was being paranod about.
>
>    Or rather. Even if *I knew* that "read-tree" or whatever wasn't
>    invoking a hook, which then invoked "submodule foreach" down the
>    line, and that "foreach" was slurping up the env var, I wanted to
>    leave it in a state where the next maintainer of this code didn't
>    have to worry about that.

Agree.

>> [1] https://lore.kernel.org/git/20221109004708.97668-2-chooglen@google.com/
>>
>>>  * There's no passing of the "super_prefix" as a global, instead we
>>>    pass it all the way along until we recurse to ourselves. For
>>>    "submodule--helper" this is quite straightforward.
>>>
>>>  * Then in 8/8 we're left with just "read-tree" needing the remaining
>>>    "--super-prefix", and we likewise don't pass it as a global, but
>>>    instead add it to the "struct unpack_trees_options", which will
>>>    pass it all the way down into unpack-trees.c and entry.c, until
>>>    we're going to recursively invoke another "read-tree".
>>
>> I worry a little about two "necessary evils":
>>
>> - (As stated earlier) we may have to add "--super-prefix" or similar to
>>   more commands
>> - We may need to read "--super-prefix" from many parts of the code,
>>   since many parts might print paths.
>>
>> Having globals makes both of these cases easier, and is quite a bit
>> closer to the original implementation of "--super-prefix" (so your
>> characterization of only getting to a halfway point is accurate). This
>> was mostly to stave off opposition that it would tedious to add new
>> per-command "--super-prefix"-es, but if nobody else cares, maybe it's ok
>> to get of the globals.
>>
>> If we do want to pass a context object around, we probably have to be
>> more principled about it (e.g. in 8/8 I notice that checkout_stage()
>> doesn't receive the context object and we resort to passing NULL
>> instead), but we'd want that anyway if we want Git to move towards being
>> more library-like.
>
> Quick aside: Yes, that unlink_entry(ce) in builtin/checkout.c is now
> unlink_entry(ce, NULL).
>
> The API had only 3 users, and two potentially cared about the
> super_prefix. So I just amended the existing function, we could also add
> a unlink_entry_sp() or whatever.

I definitely prefer modifying the existing function in place since it
avoids accidental omissions of the super prefix.

My original diagnosis is wrong though, that checkout_stage() caller
is passed "struct checkout", so there is a super_prefix available.

>
>> It's quite likely that if any new "--super-prefix"-es are added, they
>> would be added by a Googler (even the original ones were ;)), so I can
>> probably go through the roadmap and figure out how costly these extra
>> "--super-prefix"-es might be.
>
> I don't really see that happening, but let me just grant that point for
> the sake of argument: 
>
> Next month we're going to add a new "--super-prefix"-like use, and we're
> going to want some combinatino of a global, setenv()/getenv() etc. back,
> because it's the "sparse" code or whatever, and it'll be daunting to
> pass the state through 30 levels of callstack, we'll want to bypass it.
>
> I still don't see how it follows that we'd want to keep any of structure
> for this, which I think my series shows none of the current code needs.
>
> We can easily add such functionality back, adding a global variable
> isn't hard, and I think if anything such a future future would benefit
> from having to explain why it needs global state to do this sort of
> thing, when these other commands and sub-commands don't.

Yeah, I think the stakes of removing the global variable weren't as
high as I originally thought.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-11  1:07       ` Glen Choo
@ 2022-11-11 18:29         ` Glen Choo
  2022-11-11 21:17           ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-11 18:29 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git

Glen Choo <chooglen@google.com> writes:

> Rereading this series and thinking about this some more, let's go with
> your approach, primarily because it avoids global state.
>
> From this series, it seems that it's not that hard to make this change
> and support whatever use cases we currently have.
>
> This does make it more tedious to add more "--super-prefix" in the
> future, but that's a good push for us to do more things in-process
> and/or be more principled about passing context objects through the call
> stack instead of relying on globals.
>
> Let me know what I can add to this effort besides reviewing :)

Specifically, if you have other things on your plate, I'd be happy to
pick up where where this RFC has left off.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-11 18:29         ` Glen Choo
@ 2022-11-11 21:17           ` Ævar Arnfjörð Bjarmason
  2022-11-11 21:51             ` Taylor Blau
  2022-11-12  1:10             ` Glen Choo
  0 siblings, 2 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-11 21:17 UTC (permalink / raw)
  To: Glen Choo; +Cc: git


On Fri, Nov 11 2022, Glen Choo wrote:

> Glen Choo <chooglen@google.com> writes:
>
>> Rereading this series and thinking about this some more, let's go with
>> your approach, primarily because it avoids global state.
>>
>> From this series, it seems that it's not that hard to make this change
>> and support whatever use cases we currently have.
>>
>> This does make it more tedious to add more "--super-prefix" in the
>> future, but that's a good push for us to do more things in-process
>> and/or be more principled about passing context objects through the call
>> stack instead of relying on globals.
>>
>> Let me know what I can add to this effort besides reviewing :)
>
> Specifically, if you have other things on your plate, I'd be happy to
> pick up where where this RFC has left off.

I was going to get around to re-rolling this in the next few days, but
I'd also be happy to have you beat me to it.

My plan was basically:

 * Steal the test from your series, put them at the beginning, and for
   those that fail make them "test_expect_failure", then
   "test_expect_success" later when they pass.

 * Pretty much my RFC as-is. If you're re-rolling it I'll leave to you
   whether it makes sense to do it with the "read-tree" included (I
   think probably yes, but "just the submodule--helper" is smaller).

   Rewording the commit message referring to "the other approach"
   (i.e. your series) probably makes sense in light of later discussion
   (probably just dropping it).

 * Right now I can't remember if that one test failed until the
   "read-tree" patch, or if the "submodule--helper" was sufficient, so
   maybe we need the "read-tree" one to flip the
   "test_expect_failure"...

 * The 8/8 has a wart where I just removed "SUPPORT_SUPER_PREFIX" from
   git.c, but didn't adjust the rest of the bitfields, i.e. it should be
   1<<0..6, not 1<<0..3,5..9 at the end (having removed "1<<4". You got
   that right in your version...

If you can do that and address any other nits/issues you find that would
be great. I don't think I'd get to it before next week otherwise, but
it's earlier in the -0800 TZ :)

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-11 21:17           ` Ævar Arnfjörð Bjarmason
@ 2022-11-11 21:51             ` Taylor Blau
  2022-11-12  1:10             ` Glen Choo
  1 sibling, 0 replies; 79+ messages in thread
From: Taylor Blau @ 2022-11-11 21:51 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Glen Choo, git

On Fri, Nov 11, 2022 at 10:17:44PM +0100, Ævar Arnfjörð Bjarmason wrote:
> If you can do that and address any other nits/issues you find that would
> be great. I don't think I'd get to it before next week otherwise, but
> it's earlier in the -0800 TZ :)

Thanks, both.


Thanks,
Taylor

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-11 21:17           ` Ævar Arnfjörð Bjarmason
  2022-11-11 21:51             ` Taylor Blau
@ 2022-11-12  1:10             ` Glen Choo
  2022-11-14 10:09               ` Ævar Arnfjörð Bjarmason
  1 sibling, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-12  1:10 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Fri, Nov 11 2022, Glen Choo wrote:
>
>> Glen Choo <chooglen@google.com> writes:
>>
>>> Rereading this series and thinking about this some more, let's go with
>>> your approach, primarily because it avoids global state.
>>>
>>> From this series, it seems that it's not that hard to make this change
>>> and support whatever use cases we currently have.
>>>
>>> This does make it more tedious to add more "--super-prefix" in the
>>> future, but that's a good push for us to do more things in-process
>>> and/or be more principled about passing context objects through the call
>>> stack instead of relying on globals.
>>>
>>> Let me know what I can add to this effort besides reviewing :)
>>
>> Specifically, if you have other things on your plate, I'd be happy to
>> pick up where where this RFC has left off.
>
> I was going to get around to re-rolling this in the next few days, but
> I'd also be happy to have you beat me to it.

Ah, well, I didn't mean that I was planning to work on this over the
weekend, but I can certainly get to it on Monday. I meant something
closer to "If you didn't want to think about git-submodule.sh for the
next week or so, I can pick this up".

Alternatively, I think it also makes sense if you want to reroll only
the submodule--helper bits (1-7/8) to unblock your git-submodule.sh
work, and I can prepare the rest of the "nuke --super-prefix" stuff on
top of that. That should save you a context switch, and since I sent out
[1], nuking --super-prefix shouldn't be urgent.

If you don't really care any which way, I'll just re-roll this :)

[1] https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com

>
> My plan was basically:
>
>  * Steal the test from your series, put them at the beginning, and for
>    those that fail make them "test_expect_failure", then
>    "test_expect_success" later when they pass.
>
>  * Pretty much my RFC as-is. If you're re-rolling it I'll leave to you
>    whether it makes sense to do it with the "read-tree" included (I
>    think probably yes, but "just the submodule--helper" is smaller).
>
>    Rewording the commit message referring to "the other approach"
>    (i.e. your series) probably makes sense in light of later discussion
>    (probably just dropping it).
>
>  * Right now I can't remember if that one test failed until the
>    "read-tree" patch, or if the "submodule--helper" was sufficient, so
>    maybe we need the "read-tree" one to flip the
>    "test_expect_failure"...
>
>  * The 8/8 has a wart where I just removed "SUPPORT_SUPER_PREFIX" from
>    git.c, but didn't adjust the rest of the bitfields, i.e. it should be
>    1<<0..6, not 1<<0..3,5..9 at the end (having removed "1<<4". You got
>    that right in your version...

Yeah, this plan makes sense. One thing I'd add is that I'd also use
OPT__SUPER_PREFIX to handle "git fetch --submodule-prefix".

>
> If you can do that and address any other nits/issues you find that would
> be great. I don't think I'd get to it before next week otherwise, but
> it's earlier in the -0800 TZ :)

^ permalink raw reply	[flat|nested] 79+ messages in thread

* [PATCH v2 00/10] Get rid of "git --super-prefix"
  2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
                     ` (9 preceding siblings ...)
  2022-11-10  0:45   ` Glen Choo
@ 2022-11-14 10:08   ` Ævar Arnfjörð Bjarmason
  2022-11-14 10:08     ` [PATCH v2 01/10] read-tree + fetch tests: test failing "--super-prefix" interaction Ævar Arnfjörð Bjarmason
                       ` (13 more replies)
  10 siblings, 14 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

= Summary

What's "--super-prefix"? The "git" command takes an "internal use
only" "--super-prefix" option, which is used to inform processes
invoked in submodules what the path prefix to the invoking
superproject is.

This is so so that e.g. "git submodule absorbgitdirs" can report
"sub-1/sub-2", instead of "sub-2" when being invoked in the "sub-1"
submodule.

For this the "--super-prefix" facility has been doing a
setenv("GIT_INTERNAL_SUPER_PREFIX", "sub-1/") as soon as it got the
"--supre-prefix=sub-1/". We'd then pass that along via the environment
when invoking the sub-process.

As this series shows we don't need such a hands-off global facility to
do this, we can instead just pass the relevant context directly in
each command. E.g. "git submodule absorbgitdirs" can pass the path to
the "git submodule absorbgitdirs" sub-process it's about to invoke.

= Relation to other submissions

This is a non-RFC version of my earlier RFC to get rid of
"--super-prefix"[1], which itself was an alternate proposal to Glen's
[2]. Per [3] he's agreed to go with this approach.

This is on top of "ab/submodule-helper-prep-only" (currently in
"next"[4]) and "ab/submodule-no-abspath" (currently in "seen"[5]).

It's also proposing to replace Glen's one-patch[6], which is working
around the problem shown in the test added in 1/10 here. Per
downthread of [7] I think Glen was aiming for getting a more narrow
fix in case we split off 9/10 here into some later fix.

As we're fixing an edge case in something that's always been broken
(and thus wouldn't backport) I think it's better to just fix the
problem directly, rather than introducing new "--super-prefix" use,
just to take it away later.

= Changes since the RFC

* Added Glen's "git fetch" test as a 1/10, with an updated commit message
* Updated 2/10's commit message for the non-RFC, and adjusted and
  incorporated a variant of Glen's fsmonitor test change.
* 9/10: Correctly re-arrange bitfield define's when removing one, make
  the test added in 1/10 pass.

* 10/10: New commit to make "git fetch" use our own "--super-prefix"
  instead of its "--submodule-prefix", which makes it consistent with
  the other command-level "--super-prefix" introduced here.

  Personally I'm rather "meh" on this. It's not actually needed by the
  main body of the series, but Glen seems to prefer it in[9], and
  doing it is easy enough.

  That change is a pure refactoring clean-up for consistency. The only
  reason it's 10/10 and not 1/10 is because it uses the
  "OPT__SUPER_PREFIX()" introduced in 2/10.

= CI & fetch URL

Passing at: https://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local-2

1. https://lore.kernel.org/git/RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com/
2. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/
3. https://lore.kernel.org/git/kl6l5yfm2taf.fsf@chooglen-macbookpro.roam.corp.google.com/
4. c0c4f4d1c33 (Merge branch 'ab/submodule-helper-prep-only' into next, 2022-11-08)
5. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/
6. https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com/
7. https://lore.kernel.org/git/221111.86fsepmbhe.gmgdl@evledraar.gmail.com/
8. https://lore.kernel.org/git/20221109004708.97668-3-chooglen@google.com/
9. https://lore.kernel.org/git/kl6lsfip0yfx.fsf@chooglen-macbookpro.roam.corp.google.com/

Glen Choo (1):
  read-tree + fetch tests: test failing "--super-prefix" interaction

Ævar Arnfjörð Bjarmason (9):
  submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  submodule--helper: "deinit" has never used "--super-prefix"
  submodule--helper: convert "foreach" to its own "--super-prefix"
  submodule--helper: convert "sync" to its own "--super-prefix"
  submodule--helper: convert "status" to its own "--super-prefix"
  submodule--helper: convert "{update,clone}" to their own
    "--super-prefix"
  submodule tests: test "git branch -t" output and stderr
  read-tree: add "--super-prefix" option, eliminate global
  fetch: rename "--submodule-prefix" to "--super-prefix"

 Documentation/fetch-options.txt |  5 --
 Documentation/git.txt           |  8 +--
 builtin.h                       |  4 --
 builtin/checkout.c              |  2 +-
 builtin/fetch.c                 |  7 +--
 builtin/read-tree.c             |  1 +
 builtin/submodule--helper.c     | 95 ++++++++++++++++++--------------
 cache.h                         |  2 -
 entry.c                         | 12 ++--
 entry.h                         |  6 +-
 environment.c                   | 13 -----
 git.c                           | 41 +++-----------
 parse-options.h                 |  4 ++
 submodule.c                     | 70 +++++++++++------------
 submodule.h                     | 12 ++--
 t/lib-submodule-update.sh       | 98 ++++++++++++++++++---------------
 t/t1001-read-tree-m-2way.sh     |  2 +-
 t/t5616-partial-clone.sh        | 43 +++++++++++++++
 t/t7527-builtin-fsmonitor.sh    | 33 +++--------
 unpack-trees.c                  | 23 ++++----
 unpack-trees.h                  |  1 +
 21 files changed, 244 insertions(+), 238 deletions(-)

Range-diff against v1:
 -:  ----------- >  1:  1114a4ff666 read-tree + fetch tests: test failing "--super-prefix" interaction
 1:  ad0356b596f !  2:  5a35f7b75b3 submodule--helper: don't use global --super-prefix in "absorbgitdirs"
    @@ Commit message
         declare "fsmonitor--daemon" as accepting it too, even though it
         doesn't care about it.
     
    -    There's a parallel proposal to remove "--super-prefix" as an option to
    -    "git" in [3], and some of the approach might be the easiest route in
    -    some cases.
    -
         But in the case of "absorbgitdirs" it only needed "--super-prefix" to
         invoke itself recursively, and we'd never have another "in-between"
         process in the chain. So we didn't need the bigger hammer of "git
    @@ Commit message
         stone makes such an eventual change easier, as we'll need to deal with
         less global state at that point.
     
    +    The "fsmonitor--daemon" test adjusted here was added in [3]. The
    +    comment added in that commit has been out-of-date from the beginning,
    +    and the "have_t2_error_event()" was being overly specific in testing
    +    for a bug that we *don't* have. Let's instead test for the stdout and
    +    stderr that we *do have*.
    +
         1. 74866d75793 (git: make super-prefix option, 2016-10-07)
         2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
            2022-05-26)
    -    3. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/
    +    3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
    +       2022-05-26)
     
    +    Signed-off-by: Glen Choo <chooglen@google.com>
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/submodule--helper.c ##
    @@ submodule.h: void submodule_unset_core_worktree(const struct submodule *sub);
      
      /*
       * Return the absolute path of the working tree of the superproject, which this
    +
    + ## t/t7527-builtin-fsmonitor.sh ##
    +@@ t/t7527-builtin-fsmonitor.sh: test_expect_success 'submodule always visited' '
    + # the submodule, and someone does a `git submodule absorbgitdirs`
    + # in the super, Git will recursively invoke `git submodule--helper`
    + # to do the work and this may try to read the index.  This will
    +-# try to start the daemon in the submodule *and* pass (either
    +-# directly or via inheritance) the `--super-prefix` arg to the
    +-# `git fsmonitor--daemon start` command inside the submodule.
    +-# This causes a warning because fsmonitor--daemon does take that
    +-# global arg (see the table in git.c)
    +-#
    +-# This causes a warning when trying to start the daemon that is
    +-# somewhat confusing.  It does not seem to hurt anything because
    +-# the fsmonitor code maps the query failure into a trivial response
    +-# and does the work anyway.
    +-#
    +-# It would be nice to silence the warning, however.
    +-
    +-have_t2_error_event () {
    +-	log=$1
    +-	msg="fsmonitor--daemon doesnQt support --super-prefix" &&
    +-
    +-	tr '\047' Q <$1 | grep -e "$msg"
    +-}
    ++# try to start the daemon in the submodule.
    + 
    + test_expect_success "stray submodule super-prefix warning" '
    + 	test_when_finished "rm -rf super; \
    +-			    rm -rf sub;   \
    +-			    rm super-sub.trace" &&
    ++			    rm -rf sub" &&
    + 
    + 	create_super super &&
    + 	create_sub sub &&
    +@@ t/t7527-builtin-fsmonitor.sh: test_expect_success "stray submodule super-prefix warning" '
    + 
    + 	test_path_is_dir super/dir_1/dir_2/sub/.git &&
    + 
    +-	GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
    +-		git -C super submodule absorbgitdirs &&
    +-
    +-	! have_t2_error_event super-sub.trace
    ++	cat >expect <<-\EOF &&
    ++	Migrating git directory of '\''dir_1/dir_2/sub'\'' from '\''dir_1/dir_2/sub/.git'\'' to '\''.git/modules/dir_1/dir_2/sub'\''
    ++	EOF
    ++	git -C super submodule absorbgitdirs >out 2>actual &&
    ++	test_cmp expect actual &&
    ++	test_must_be_empty out
    + '
    + 
    + # On a case-insensitive file system, confirm that the daemon
 2:  87a780eb9bf =  3:  a7a1f9487dc submodule--helper: "deinit" has never used "--super-prefix"
 3:  4858e2ad0ed =  4:  935d8070834 submodule--helper: convert "foreach" to its own "--super-prefix"
 4:  5ffe4407e46 =  5:  933c752513d submodule--helper: convert "sync" to its own "--super-prefix"
 5:  a46540b63c2 =  6:  67273f729e0 submodule--helper: convert "status" to its own "--super-prefix"
 6:  78ebf0e2abf =  7:  eaa73f5b1e4 submodule--helper: convert "{update,clone}" to their own "--super-prefix"
 7:  00a9e789be7 =  8:  172b5865811 submodule tests: test "git branch -t" output and stderr
 8:  3ba894a6698 !  9:  9fdeab60773 read-tree: add "--super-prefix" option, eliminate global
    @@ git.c
       */
      #define NEED_WORK_TREE		(1<<3)
     -#define SUPPORT_SUPER_PREFIX	(1<<4)
    - #define DELAY_PAGER_CONFIG	(1<<5)
    - #define NO_PARSEOPT		(1<<6) /* parse-options is not used */
    +-#define DELAY_PAGER_CONFIG	(1<<5)
    +-#define NO_PARSEOPT		(1<<6) /* parse-options is not used */
    ++#define DELAY_PAGER_CONFIG	(1<<4)
    ++#define NO_PARSEOPT		(1<<5) /* parse-options is not used */
      
    + struct cmd_struct {
    + 	const char *cmd;
     @@ git.c: const char git_usage_string[] =
      	   "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
      	   "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
    @@ t/t1001-read-tree-m-2way.sh: test_expect_success 'read-tree supports the super-p
      '
      
     
    + ## t/t5616-partial-clone.sh ##
    +@@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor objects' '
    + 	grep "loosen_unused_packed_objects/loosened:0" trace
    + '
    + 
    +-test_expect_failure 'lazy-fetch in submodule succeeds' '
    ++test_expect_success 'lazy-fetch in submodule succeeds' '
    + 	# setup
    + 	test_config_global protocol.file.allow always &&
    + 
    +
      ## unpack-trees.c ##
     @@ unpack-trees.c: static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
      	  ? ((o)->msgs[(type)])      \
 -:  ----------- > 10:  100ba36dfb7 fetch: rename "--submodule-prefix" to "--super-prefix"
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply	[flat|nested] 79+ messages in thread

* [PATCH v2 01/10] read-tree + fetch tests: test failing "--super-prefix" interaction
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 19:00       ` Glen Choo
  2022-11-14 10:08     ` [PATCH v2 02/10] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
                       ` (12 subsequent siblings)
  13 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

From: Glen Choo <chooglen@google.com>

Ever since "git fetch --refetch" was introduced in 0f5e8851737 (Merge
branch 'rc/fetch-refetch', 2022-04-04) the test being added here would
fail. This is because "restore" will "read-tree .. --reset <hash>",
which will in turn invoke "fetch". The "fetch" will then die with:

	fatal: fetch doesn't support --super-prefix

This edge case and other "--super-prefix" bugs will be fixed in
subsequent commits, but let's first add a "test_expect_failure" test
for it. It passes until the very last command in the test.

Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 037941b95d2..e56466580cf 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '
 	grep "loosen_unused_packed_objects/loosened:0" trace
 '
 
+test_expect_failure 'lazy-fetch in submodule succeeds' '
+	# setup
+	test_config_global protocol.file.allow always &&
+
+	git init src-sub &&
+	git -C src-sub config uploadpack.allowfilter 1 &&
+	git -C src-sub config uploadpack.allowanysha1inwant 1 &&
+
+	# This blob must be missing in the subsequent commit.
+	echo foo >src-sub/file &&
+	git -C src-sub add file &&
+	git -C src-sub commit -m "submodule one" &&
+	SUB_ONE=$(git -C src-sub rev-parse HEAD) &&
+
+	echo bar >src-sub/file &&
+	git -C src-sub add file &&
+	git -C src-sub commit -m "submodule two" &&
+	SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
+
+	git init src-super &&
+	git -C src-super config uploadpack.allowfilter 1 &&
+	git -C src-super config uploadpack.allowanysha1inwant 1 &&
+	git -C src-super submodule add ../src-sub src-sub &&
+
+	git -C src-super/src-sub checkout $SUB_ONE &&
+	git -C src-super add src-sub &&
+	git -C src-super commit -m "superproject one" &&
+
+	git -C src-super/src-sub checkout $SUB_TWO &&
+	git -C src-super add src-sub &&
+	git -C src-super commit -m "superproject two" &&
+
+	# the fetch
+	test_when_finished "rm -rf src-super src-sub client" &&
+
+	test_config_global protocol.file.allow always &&
+	git clone --filter=blob:none --also-filter-submodules \
+		--recurse-submodules "file://$(pwd)/src-super" client &&
+
+	# Trigger lazy-fetch from the superproject
+	git -C client restore --recurse-submodules --source=HEAD^ :/
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v2 02/10] submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
  2022-11-14 10:08     ` [PATCH v2 01/10] read-tree + fetch tests: test failing "--super-prefix" interaction Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 21:22       ` Glen Choo
  2022-11-14 10:08     ` [PATCH v2 03/10] submodule--helper: "deinit" has never used "--super-prefix" Ævar Arnfjörð Bjarmason
                       ` (11 subsequent siblings)
  13 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

The "--super-prefix" facility was introduced in [1] has always been a
transitory hack, which is why we've made it an error to supply it as
an option to "git" to commands that don't know about it.

That's been a good goal, as it has a global effect we haven't wanted
calls to get_super_prefix() from built-ins we didn't expect.

But it has meant that when we've had chains of different built-ins
using it all of the processes in that "chain" have needed to support
it, and worse processes that don't need it have needed to ask for
"SUPPORT_SUPER_PREFIX" because their parent process needs it.

That's how "fsmonitor--daemon" ended up with it, per [2] it's called
from (among other things) "submodule--helper absorbgitdirs", but as we
declared "submodule--helper" as "SUPPORT_SUPER_PREFIX" we needed to
declare "fsmonitor--daemon" as accepting it too, even though it
doesn't care about it.

But in the case of "absorbgitdirs" it only needed "--super-prefix" to
invoke itself recursively, and we'd never have another "in-between"
process in the chain. So we didn't need the bigger hammer of "git
--super-prefix", and the "setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)"
that it entails.

Let's instead accept a hidden "--super-prefix" option to
"submodule--helper absorbgitdirs" itself.

Eventually (as with all other "--super-prefix" users) we'll want to
clean this code up so that this all happens in-process. I.e. needing
any variant of "--super-prefix" is itself a hack around our various
global state, and implicit reliance on "the_repository". This stepping
stone makes such an eventual change easier, as we'll need to deal with
less global state at that point.

The "fsmonitor--daemon" test adjusted here was added in [3]. The
comment added in that commit has been out-of-date from the beginning,
and the "have_t2_error_event()" was being overly specific in testing
for a bug that we *don't* have. Let's instead test for the stdout and
stderr that we *do have*.

1. 74866d75793 (git: make super-prefix option, 2016-10-07)
2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
   2022-05-26)
3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
   2022-05-26)

Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c  |  8 +++++---
 git.c                        |  2 +-
 parse-options.h              |  4 ++++
 submodule.c                  | 20 ++++++++++++--------
 submodule.h                  |  7 ++++++-
 t/t7527-builtin-fsmonitor.sh | 33 ++++++++-------------------------
 6 files changed, 36 insertions(+), 38 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c75e9e86b06..427e793e204 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2828,7 +2828,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 	int i;
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
+	const char *super_prefix = NULL;
 	struct option embed_gitdir_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT_END()
 	};
 	const char *const git_submodule_helper_usage[] = {
@@ -2844,7 +2846,8 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 
 	for (i = 0; i < list.nr; i++)
-		absorb_git_dir_into_superproject(list.entries[i]->name);
+		absorb_git_dir_into_superproject_sp(list.entries[i]->name,
+						    super_prefix);
 
 	ret = 0;
 cleanup:
@@ -3382,8 +3385,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
 	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
-	    strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") &&
-	    get_super_prefix())
+	    strcmp(subcmd, "sync") && get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
diff --git a/git.c b/git.c
index 10202a7f126..b1b7e1a837e 100644
--- a/git.c
+++ b/git.c
@@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {
 	{ "format-patch", cmd_format_patch, RUN_SETUP },
 	{ "fsck", cmd_fsck, RUN_SETUP },
 	{ "fsck-objects", cmd_fsck, RUN_SETUP },
-	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
+	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP },
 	{ "gc", cmd_gc, RUN_SETUP },
 	{ "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT },
 	{ "grep", cmd_grep, RUN_SETUP_GENTLY },
diff --git a/parse-options.h b/parse-options.h
index b6ef86e0d15..50d852f2991 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
 	{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"),	\
 	  N_("use <n> digits to display object names"),	\
 	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+#define OPT__SUPER_PREFIX(var) \
+	OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
+		N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
+
 #define OPT__COLOR(var, h) \
 	OPT_COLOR_FLAG(0, "color", (var), (h))
 #define OPT_COLUMN(s, l, v, h) \
diff --git a/submodule.c b/submodule.c
index c47358097fd..d9fd0af81b6 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)
  * Embeds a single submodules git directory into the superprojects git dir,
  * non recursively.
  */
-static void relocate_single_git_dir_into_superproject(const char *path)
+static void relocate_single_git_dir_into_superproject(const char *path,
+						      const char *super_prefix)
 {
 	char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
 	struct strbuf new_gitdir = STRBUF_INIT;
@@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
 	       real_old_git_dir[off] == real_new_git_dir[off])
 		off++;
 	fprintf(stderr, _("Migrating git directory of '%s%s' from '%s' to '%s'\n"),
-		get_super_prefix_or_empty(), path,
+		(super_prefix ? super_prefix : ""), path,
 		real_old_git_dir + off, real_new_git_dir + off);
 
 	relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
@@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)
 	strbuf_release(&new_gitdir);
 }
 
-static void absorb_git_dir_into_superproject_recurse(const char *path)
+static void absorb_git_dir_into_superproject_recurse(const char *path,
+						     const char *super_prefix)
 {
 
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2321,10 +2323,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
 	cp.dir = path;
 	cp.git_cmd = 1;
 	cp.no_stdin = 1;
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	strvec_pushl(&cp.args, "submodule--helper",
 		     "absorbgitdirs", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
+		     super_prefix : "", path);
+
 	prepare_submodule_repo_env(&cp.env);
 	if (run_command(&cp))
 		die(_("could not recurse into submodule '%s'"), path);
@@ -2335,7 +2338,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
  * having its git directory within the working tree to the git dir nested
  * in its superprojects git dir under modules/.
  */
-void absorb_git_dir_into_superproject(const char *path)
+void absorb_git_dir_into_superproject_sp(const char *path,
+					 const char *super_prefix)
 {
 	int err_code;
 	const char *sub_git_dir;
@@ -2377,14 +2381,14 @@ void absorb_git_dir_into_superproject(const char *path)
 		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(path);
+			relocate_single_git_dir_into_superproject(path, super_prefix);
 
 		free(real_sub_git_dir);
 		free(real_common_git_dir);
 	}
 	strbuf_release(&gitdir);
 
-	absorb_git_dir_into_superproject_recurse(path);
+	absorb_git_dir_into_superproject_recurse(path, super_prefix);
 }
 
 int get_superproject_working_tree(struct strbuf *buf)
diff --git a/submodule.h b/submodule.h
index b52a4ff1e73..e5ee13fb06a 100644
--- a/submodule.h
+++ b/submodule.h
@@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);
  */
 void prepare_submodule_repo_env(struct strvec *env);
 
-void absorb_git_dir_into_superproject(const char *path);
+void absorb_git_dir_into_superproject_sp(const char *path,
+					 const char *super_prefix);
+static inline void absorb_git_dir_into_superproject(const char *path)
+{
+	absorb_git_dir_into_superproject_sp(path, NULL);
+}
 
 /*
  * Return the absolute path of the working tree of the superproject, which this
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
index 4abc74db2bb..31526937d95 100755
--- a/t/t7527-builtin-fsmonitor.sh
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -866,30 +866,11 @@ test_expect_success 'submodule always visited' '
 # the submodule, and someone does a `git submodule absorbgitdirs`
 # in the super, Git will recursively invoke `git submodule--helper`
 # to do the work and this may try to read the index.  This will
-# try to start the daemon in the submodule *and* pass (either
-# directly or via inheritance) the `--super-prefix` arg to the
-# `git fsmonitor--daemon start` command inside the submodule.
-# This causes a warning because fsmonitor--daemon does take that
-# global arg (see the table in git.c)
-#
-# This causes a warning when trying to start the daemon that is
-# somewhat confusing.  It does not seem to hurt anything because
-# the fsmonitor code maps the query failure into a trivial response
-# and does the work anyway.
-#
-# It would be nice to silence the warning, however.
-
-have_t2_error_event () {
-	log=$1
-	msg="fsmonitor--daemon doesnQt support --super-prefix" &&
-
-	tr '\047' Q <$1 | grep -e "$msg"
-}
+# try to start the daemon in the submodule.
 
 test_expect_success "stray submodule super-prefix warning" '
 	test_when_finished "rm -rf super; \
-			    rm -rf sub;   \
-			    rm super-sub.trace" &&
+			    rm -rf sub" &&
 
 	create_super super &&
 	create_sub sub &&
@@ -904,10 +885,12 @@ test_expect_success "stray submodule super-prefix warning" '
 
 	test_path_is_dir super/dir_1/dir_2/sub/.git &&
 
-	GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
-		git -C super submodule absorbgitdirs &&
-
-	! have_t2_error_event super-sub.trace
+	cat >expect <<-\EOF &&
+	Migrating git directory of '\''dir_1/dir_2/sub'\'' from '\''dir_1/dir_2/sub/.git'\'' to '\''.git/modules/dir_1/dir_2/sub'\''
+	EOF
+	git -C super submodule absorbgitdirs >out 2>actual &&
+	test_cmp expect actual &&
+	test_must_be_empty out
 '
 
 # On a case-insensitive file system, confirm that the daemon
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v2 03/10] submodule--helper: "deinit" has never used "--super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
  2022-11-14 10:08     ` [PATCH v2 01/10] read-tree + fetch tests: test failing "--super-prefix" interaction Ævar Arnfjörð Bjarmason
  2022-11-14 10:08     ` [PATCH v2 02/10] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 10:08     ` [PATCH v2 04/10] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
                       ` (10 subsequent siblings)
  13 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

The "deinit_submodule()" function has never been able to use the "git
--super-prefix". It will call "absorb_git_dir_into_superproject()",
but it will only do so from the top-level project.

If "absorbgitdirs" recurses it will use the "path" passed to
"absorb_git_dir_into_superproject()" in "deinit_submodule()" as its
starting "--super-prefix".

So, let's introduce a "get_submodule_displaypath_sp()" helper, and
make our existing "get_submodule_displaypath()" a wrapper for it. In a
subsequent commit the wrapper will be going away, as the rest of the
commands here will stop using the global "get_super_prefix()".

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 427e793e204..c4d5e029b37 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
 }
 
 /* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *get_submodule_displaypath_sp(const char *path, const char *prefix,
+					  const char *super_prefix)
 {
-	const char *super_prefix = get_super_prefix();
-
 	if (prefix && super_prefix) {
 		BUG("cannot have prefix '%s' and superprefix '%s'",
 		    prefix, super_prefix);
@@ -132,6 +131,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)
 	}
 }
 
+static char *get_submodule_displaypath(const char *path, const char *prefix)
+{
+	const char *super_prefix = get_super_prefix();
+
+	return get_submodule_displaypath_sp(path, prefix, super_prefix);
+}
+
 static char *compute_rev_name(const char *sub_path, const char* object_id)
 {
 	struct strbuf sb = STRBUF_INIT;
@@ -1365,7 +1371,7 @@ static void deinit_submodule(const char *path, const char *prefix,
 	if (!sub || !sub->name)
 		goto cleanup;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath_sp(path, prefix, NULL);
 
 	/* remove the submodule work tree (unless the user already did it) */
 	if (is_directory(path)) {
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v2 04/10] submodule--helper: convert "foreach" to its own "--super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (2 preceding siblings ...)
  2022-11-14 10:08     ` [PATCH v2 03/10] submodule--helper: "deinit" has never used "--super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 21:56       ` Glen Choo
  2022-11-14 10:08     ` [PATCH v2 05/10] submodule--helper: convert "sync" " Ævar Arnfjörð Bjarmason
                       ` (9 subsequent siblings)
  13 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper foreach" to use its own "--super-prefix", instead
of relying on the global "--super-prefix" argument to "git"
itself. See that earlier commit for the rationale and background.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c4d5e029b37..989c75280af 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -285,6 +285,7 @@ struct foreach_cb {
 	int argc;
 	const char **argv;
 	const char *prefix;
+	const char *super_prefix;
 	int quiet;
 	int recursive;
 };
@@ -300,7 +301,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 	struct child_process cp = CHILD_PROCESS_INIT;
 	char *displaypath;
 
-	displaypath = get_submodule_displaypath(path, info->prefix);
+	displaypath = get_submodule_displaypath_sp(path, info->prefix,
+						   info->super_prefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -370,10 +372,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_pushl(&cpr.args, "--super-prefix", NULL);
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
 			     NULL);
+		strvec_pushl(&cpr.args, "--super-prefix", NULL);
+		strvec_pushf(&cpr.args, "%s/", displaypath);
 
 		if (info->quiet)
 			strvec_push(&cpr.args, "--quiet");
@@ -396,7 +398,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
 	struct foreach_cb info = FOREACH_CB_INIT;
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
+	const char *super_prefix = NULL;
 	struct option module_foreach_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
 		OPT_BOOL(0, "recursive", &info.recursive,
 			 N_("recurse into nested submodules")),
@@ -417,6 +421,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
 	info.argc = argc;
 	info.argv = argv;
 	info.prefix = prefix;
+	info.super_prefix = super_prefix;
 
 	for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
 
@@ -3390,8 +3395,8 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 	subcmd = argv[0];
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
-	    strcmp(subcmd, "sync") && get_super_prefix())
+	    strcmp(subcmd, "status") && strcmp(subcmd, "sync") &&
+	    get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v2 05/10] submodule--helper: convert "sync" to its own "--super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (3 preceding siblings ...)
  2022-11-14 10:08     ` [PATCH v2 04/10] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 10:08     ` [PATCH v2 06/10] submodule--helper: convert "status" " Ævar Arnfjörð Bjarmason
                       ` (8 subsequent siblings)
  13 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper sync" to use its own "--super-prefix", instead of
relying on the global "--super-prefix" argument to "git" itself. See
that earlier commit for the rationale and background.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 989c75280af..db58fd5b2c4 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1214,12 +1214,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)
 
 struct sync_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define SYNC_CB_INIT { 0 }
 
 static void sync_submodule(const char *path, const char *prefix,
-			   unsigned int flags)
+			   const char *super_prefix, unsigned int flags)
 {
 	const struct submodule *sub;
 	char *remote_key = NULL;
@@ -1250,7 +1251,7 @@ static void sync_submodule(const char *path, const char *prefix,
 		super_config_url = xstrdup("");
 	}
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);
 
 	if (!(flags & OPT_QUIET))
 		printf(_("Synchronizing submodule url for '%s'\n"),
@@ -1287,10 +1288,11 @@ static void sync_submodule(const char *path, const char *prefix,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "sync",
 			     "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
+
 
 		if (flags & OPT_QUIET)
 			strvec_push(&cpr.args, "--quiet");
@@ -1313,7 +1315,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data
 {
 	struct sync_cb *info = cb_data;
 
-	sync_submodule(list_item->name, info->prefix, info->flags);
+	sync_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
 }
 
 static int module_sync(int argc, const char **argv, const char *prefix)
@@ -1323,7 +1326,9 @@ static int module_sync(int argc, const char **argv, const char *prefix)
 	struct module_list list = MODULE_LIST_INIT;
 	int quiet = 0;
 	int recursive = 0;
+	const char *super_prefix = NULL;
 	struct option module_sync_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
 		OPT_BOOL(0, "recursive", &recursive,
 			N_("recurse into nested submodules")),
@@ -1342,6 +1347,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 
 	info.prefix = prefix;
+	info.super_prefix = super_prefix;
 	if (quiet)
 		info.flags |= OPT_QUIET;
 	if (recursive)
@@ -2890,7 +2896,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
 	config_name = xstrfmt("submodule.%s.url", path);
 
 	config_set_in_gitmodules_file_gently(config_name, newurl);
-	sync_submodule(path, prefix, quiet ? OPT_QUIET : 0);
+	sync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);
 
 	free(config_name);
 
@@ -3395,8 +3401,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 	subcmd = argv[0];
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "status") && strcmp(subcmd, "sync") &&
-	    get_super_prefix())
+	    strcmp(subcmd, "status") && get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v2 06/10] submodule--helper: convert "status" to its own "--super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (4 preceding siblings ...)
  2022-11-14 10:08     ` [PATCH v2 05/10] submodule--helper: convert "sync" " Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 10:08     ` [PATCH v2 07/10] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
                       ` (7 subsequent siblings)
  13 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper status" to use its own "--super-prefix", instead of
relying on the global "--super-prefix" argument to "git" itself. See
that earlier commit for the rationale and background.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index db58fd5b2c4..40939b0b18e 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -581,6 +581,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
 
 struct status_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define STATUS_CB_INIT { 0 }
@@ -619,7 +620,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,
 
 static void status_submodule(const char *path, const struct object_id *ce_oid,
 			     unsigned int ce_flags, const char *prefix,
-			     unsigned int flags)
+			     const char *super_prefix, unsigned int flags)
 {
 	char *displaypath;
 	struct strvec diff_files_args = STRVEC_INIT;
@@ -635,7 +636,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		die(_("no submodule mapping found in .gitmodules for path '%s'"),
 		      path);
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);
 
 	if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
 		print_status(flags, 'U', path, null_oid(), displaypath);
@@ -693,10 +694,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "status",
 			     "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
 
 		if (flags & OPT_CACHED)
 			strvec_push(&cpr.args, "--cached");
@@ -720,7 +721,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,
 	struct status_cb *info = cb_data;
 
 	status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
-			 info->prefix, info->flags);
+			 info->prefix, info->super_prefix, info->flags);
 }
 
 static int module_status(int argc, const char **argv, const char *prefix)
@@ -729,7 +730,9 @@ static int module_status(int argc, const char **argv, const char *prefix)
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
 	int quiet = 0;
+	const char *super_prefix = NULL;
 	struct option module_status_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT__QUIET(&quiet, N_("suppress submodule status output")),
 		OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
 		OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
@@ -748,6 +751,7 @@ static int module_status(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 
 	info.prefix = prefix;
+	info.super_prefix = super_prefix;
 	if (quiet)
 		info.flags |= OPT_QUIET;
 
@@ -3401,7 +3405,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 	subcmd = argv[0];
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "status") && get_super_prefix())
+	    get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v2 07/10] submodule--helper: convert "{update,clone}" to their own "--super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (5 preceding siblings ...)
  2022-11-14 10:08     ` [PATCH v2 06/10] submodule--helper: convert "status" " Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 22:04       ` Glen Choo
  2022-11-14 10:08     ` [PATCH v2 08/10] submodule tests: test "git branch -t" output and stderr Ævar Arnfjörð Bjarmason
                       ` (6 subsequent siblings)
  13 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper status" to use its own "--super-prefix", instead of
relying on the global "--super-prefix" argument to "git".

We need to convert both of these away from the global "--super-prefix"
at the same time, because "update" will call "clone", but "clone"
itself didn't make use of the global "--super-prefix" for displaying
paths. It was only on the list of sub-commands that accepted it
because "update"'s use of it would set it in its environment.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 45 ++++++++++++++++---------------------
 git.c                       |  2 +-
 2 files changed, 20 insertions(+), 27 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 40939b0b18e..e13615eb939 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -131,13 +131,6 @@ static char *get_submodule_displaypath_sp(const char *path, const char *prefix,
 	}
 }
 
-static char *get_submodule_displaypath(const char *path, const char *prefix)
-{
-	const char *super_prefix = get_super_prefix();
-
-	return get_submodule_displaypath_sp(path, prefix, super_prefix);
-}
-
 static char *compute_rev_name(const char *sub_path, const char* object_id)
 {
 	struct strbuf sb = STRBUF_INIT;
@@ -446,11 +439,13 @@ static int starts_with_dot_dot_slash(const char *const path)
 
 struct init_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define INIT_CB_INIT { 0 }
 
 static void init_submodule(const char *path, const char *prefix,
+			   const char *super_prefix,
 			   unsigned int flags)
 {
 	const struct submodule *sub;
@@ -458,7 +453,7 @@ static void init_submodule(const char *path, const char *prefix,
 	const char *upd;
 	char *url = NULL, *displaypath;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -534,7 +529,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data
 {
 	struct init_cb *info = cb_data;
 
-	init_submodule(list_item->name, info->prefix, info->flags);
+	init_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
 }
 
 static int module_init(int argc, const char **argv, const char *prefix)
@@ -802,6 +798,7 @@ struct summary_cb {
 	int argc;
 	const char **argv;
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int cached: 1;
 	unsigned int for_status: 1;
 	unsigned int files: 1;
@@ -963,7 +960,8 @@ static void generate_submodule_summary(struct summary_cb *info,
 		dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
 	}
 
-	displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+	displaypath = get_submodule_displaypath_sp(p->sm_path, info->prefix,
+						   info->super_prefix);
 
 	if (!missing_src && !missing_dst) {
 		struct child_process cp_rev_list = CHILD_PROCESS_INIT;
@@ -1904,6 +1902,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)
 
 struct update_data {
 	const char *prefix;
+	const char *super_prefix;
 	char *displaypath;
 	enum submodule_update_type update_default;
 	struct object_id suboid;
@@ -1979,7 +1978,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 	enum submodule_update_type update_type;
 	char *key;
 	const struct update_data *ud = suc->update_data;
-	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
+	char *displaypath = get_submodule_displaypath_sp(ce->name, ud->prefix,
+							 ud->super_prefix);
 	struct strbuf sb = STRBUF_INIT;
 	int needs_cloning = 0;
 	int need_free_url = 0;
@@ -2459,11 +2459,11 @@ static void update_data_to_args(const struct update_data *update_data,
 {
 	enum submodule_update_type update_type = update_data->update_default;
 
+	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
 	if (update_data->displaypath) {
 		strvec_push(args, "--super-prefix");
 		strvec_pushf(args, "%s/", update_data->displaypath);
 	}
-	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
 	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
 	if (update_data->quiet)
 		strvec_push(args, "--quiet");
@@ -2628,8 +2628,9 @@ static int update_submodules(struct update_data *update_data)
 		if (code)
 			goto fail;
 
-		update_data->displaypath = get_submodule_displaypath(
-			update_data->sm_path, update_data->prefix);
+		update_data->displaypath = get_submodule_displaypath_sp(
+			update_data->sm_path, update_data->prefix,
+			update_data->super_prefix);
 		code = update_submodule(update_data);
 		FREE_AND_NULL(update_data->displaypath);
 fail:
@@ -2654,7 +2655,9 @@ static int module_update(int argc, const char **argv, const char *prefix)
 	struct list_objects_filter_options filter_options =
 		LIST_OBJECTS_FILTER_INIT;
 	int ret;
+	const char *super_prefix = NULL;
 	struct option module_update_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
 		OPT_BOOL(0, "init", &opt.init,
 			 N_("initialize uninitialized submodules before update")),
@@ -2720,6 +2723,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 
 	opt.filter_options = &filter_options;
 	opt.prefix = prefix;
+	opt.super_prefix = super_prefix;
 
 	if (opt.update_default)
 		opt.update_strategy.type = opt.update_default;
@@ -2751,6 +2755,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 			module_list_active(&list);
 
 		info.prefix = opt.prefix;
+		info.super_prefix = super_prefix;
 		if (opt.quiet)
 			info.flags |= OPT_QUIET;
 
@@ -3377,8 +3382,6 @@ static int module_add(int argc, const char **argv, const char *prefix)
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 {
-	const char *cmd = argv[0];
-	const char *subcmd;
 	parse_opt_subcommand_fn *fn = NULL;
 	const char *const usage[] = {
 		N_("git submodule--helper <command>"),
@@ -3402,16 +3405,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
-	subcmd = argv[0];
-
-	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    get_super_prefix())
-		/*
-		 * xstrfmt() rather than "%s %s" to keep the translated
-		 * string identical to git.c's.
-		 */
-		die(_("%s doesn't support --super-prefix"),
-		    xstrfmt("'%s %s'", cmd, subcmd));
 
 	return fn(argc, argv, prefix);
 }
diff --git a/git.c b/git.c
index b1b7e1a837e..2bca22cfd9a 100644
--- a/git.c
+++ b/git.c
@@ -610,7 +610,7 @@ static struct cmd_struct commands[] = {
 	{ "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
 	{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 	{ "stripspace", cmd_stripspace },
-	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },
+	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP },
 	{ "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
 	{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 	{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v2 08/10] submodule tests: test "git branch -t" output and stderr
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (6 preceding siblings ...)
  2022-11-14 10:08     ` [PATCH v2 07/10] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 22:20       ` Glen Choo
  2022-11-14 10:08     ` [PATCH v2 09/10] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
                       ` (5 subsequent siblings)
  13 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

The "git branch" command will currently make use of the
"--super-prefix", as it will indirectly call submodule_move_head(),
which will have access to the "--super-prefix".

The output could thus be affected by the "--super-prefix". Right now
it isn't in this case, but let's exhaustively assert that that's the
case by testing the output of all of these "git branch -t" commands.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/lib-submodule-update.sh | 98 ++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 43 deletions(-)

diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 2d31fcfda1f..302d095ad9b 100644
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -245,6 +245,17 @@ reset_work_tree_to_interested () {
 	git -C submodule_update/.git/modules/sub1 config submodule.sub2.url "bogus"
 }
 
+test_branch_t_output () {
+	local branchname="$1" &&
+	local start_point="$2" &&
+	cat >expect <<-EOF &&
+	branch '$branchname' set up to track '$start_point'.
+	EOF
+	git branch -t "$branchname" "$start_point" >actual 2>err &&
+	test_must_be_empty err &&
+	test_cmp expect actual
+}
+
 # Test that the superproject contains the content according to commit "$1"
 # (the work tree must match the index for everything but submodules but the
 # index must exactly match the given commit including any submodule SHA-1s).
@@ -323,7 +334,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -345,7 +356,7 @@ test_submodule_switch_common () {
 		(
 			cd submodule_update &&
 			mkdir sub1 &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -360,7 +371,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to replace_sub1_with_file &&
 		(
 			cd submodule_update &&
-			git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
+			test_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&
 			$command replace_file_with_sub1 &&
 			test_superproject_content origin/replace_file_with_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -384,7 +395,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to replace_sub1_with_directory &&
 		(
 			cd submodule_update &&
-			git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
+			test_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
 			$command replace_directory_with_sub1 &&
 			test_superproject_content origin/replace_directory_with_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -406,7 +417,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t remove_sub1 origin/remove_sub1 &&
+			test_branch_t_output remove_sub1 origin/remove_sub1 &&
 			$command remove_sub1 &&
 			test_superproject_content origin/remove_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -418,7 +429,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t remove_sub1 origin/remove_sub1 &&
+			test_branch_t_output remove_sub1 origin/remove_sub1 &&
 			replace_gitfile_with_git_dir sub1 &&
 			$command remove_sub1 &&
 			test_superproject_content origin/remove_sub1 &&
@@ -447,7 +458,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			$command replace_sub1_with_directory test_must_fail &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -459,7 +470,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			replace_gitfile_with_git_dir sub1 &&
 			$command replace_sub1_with_directory test_must_fail &&
 			test_superproject_content origin/add_sub1 &&
@@ -474,7 +485,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			$command replace_sub1_with_file test_must_fail &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -487,7 +498,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			replace_gitfile_with_git_dir sub1 &&
 			$command replace_sub1_with_file test_must_fail &&
 			test_superproject_content origin/add_sub1 &&
@@ -512,7 +523,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			$command modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
 			test_submodule_content sub1 origin/add_sub1 &&
@@ -527,7 +538,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t invalid_sub1 origin/invalid_sub1 &&
+			test_branch_t_output invalid_sub1 origin/invalid_sub1 &&
 			$command invalid_sub1 &&
 			test_superproject_content origin/invalid_sub1 &&
 			test_submodule_content sub1 origin/add_sub1 &&
@@ -542,7 +553,7 @@ test_submodule_switch_common () {
 		reset_work_tree_to invalid_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t valid_sub1 origin/valid_sub1 &&
+			test_branch_t_output valid_sub1 origin/valid_sub1 &&
 			$command valid_sub1 &&
 			test_superproject_content origin/valid_sub1 &&
 			test_dir_is_empty sub1 &&
@@ -596,7 +607,7 @@ test_submodule_switch_func () {
 		reset_work_tree_to no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			>sub1 &&
 			$command add_sub1 test_must_fail &&
 			test_superproject_content origin/no_submodule &&
@@ -635,7 +646,7 @@ test_submodule_forced_switch () {
 		reset_work_tree_to no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			>sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
@@ -675,7 +686,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -688,7 +699,7 @@ test_submodule_recursing_with_args_common () {
 		(
 			cd submodule_update &&
 			mkdir sub1 &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
@@ -701,7 +712,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested replace_sub1_with_file &&
 		(
 			cd submodule_update &&
-			git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
+			test_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&
 			$command replace_file_with_sub1 &&
 			test_superproject_content origin/replace_file_with_sub1 &&
 			test_submodule_content sub1 origin/replace_file_with_sub1
@@ -713,19 +724,20 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested replace_sub1_with_directory &&
 		(
 			cd submodule_update &&
-			git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
+			test_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
 			$command replace_directory_with_sub1 &&
 			test_superproject_content origin/replace_directory_with_sub1 &&
 			test_submodule_content sub1 origin/replace_directory_with_sub1
 		)
 	'
+
 	# Switching to a commit with nested submodules recursively checks them out
 	test_expect_success "$command: nested submodules are checked out" '
 		prolog &&
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
+			test_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&
 			$command modify_sub1_recursively &&
 			test_superproject_content origin/modify_sub1_recursively &&
 			test_submodule_content sub1 origin/modify_sub1_recursively &&
@@ -740,7 +752,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t remove_sub1 origin/remove_sub1 &&
+			test_branch_t_output remove_sub1 origin/remove_sub1 &&
 			$command remove_sub1 &&
 			test_superproject_content origin/remove_sub1 &&
 			! test -e sub1 &&
@@ -753,7 +765,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t remove_sub1 origin/remove_sub1 &&
+			test_branch_t_output remove_sub1 origin/remove_sub1 &&
 			replace_gitfile_with_git_dir sub1 &&
 			rm -rf .git/modules &&
 			$command remove_sub1 &&
@@ -769,7 +781,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			$command replace_sub1_with_file &&
 			test_superproject_content origin/replace_sub1_with_file &&
 			test -f sub1
@@ -786,7 +798,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			: >sub1/untrackedfile &&
 			test_must_fail $command replace_sub1_with_file &&
 			test_superproject_content origin/add_sub1 &&
@@ -801,7 +813,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_nested_sub &&
 		(
 			cd submodule_update &&
-			git branch -t no_submodule origin/no_submodule &&
+			test_branch_t_output no_submodule origin/no_submodule &&
 			$command no_submodule &&
 			test_superproject_content origin/no_submodule &&
 			! test_path_is_dir sub1 &&
@@ -817,7 +829,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			$command modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
 			test_submodule_content sub1 origin/modify_sub1
@@ -830,7 +842,7 @@ test_submodule_recursing_with_args_common () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t invalid_sub1 origin/invalid_sub1 &&
+			test_branch_t_output invalid_sub1 origin/invalid_sub1 &&
 			test_must_fail $command invalid_sub1 2>err &&
 			test_i18ngrep sub1 err &&
 			test_superproject_content origin/add_sub1 &&
@@ -844,13 +856,13 @@ test_submodule_recursing_with_args_common () {
 		(
 			cd submodule_update &&
 			git -C sub1 checkout -b keep_branch &&
-			git -C sub1 rev-parse HEAD >expect &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			git -C sub1 rev-parse HEAD >expect.rev-parse &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			$command modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
 			test_submodule_content sub1 origin/modify_sub1 &&
 			git -C sub1 rev-parse keep_branch >actual &&
-			test_cmp expect actual &&
+			test_cmp expect.rev-parse actual &&
 			test_must_fail git -C sub1 symbolic-ref HEAD
 		)
 	'
@@ -894,7 +906,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			: >sub1 &&
 			test_must_fail $command add_sub1 &&
 			test_superproject_content origin/no_submodule &&
@@ -908,7 +920,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			: >sub1 &&
 			mkdir .git/info &&
 			echo sub1 >.git/info/exclude &&
@@ -925,7 +937,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			$command replace_sub1_with_directory &&
 			test_superproject_content origin/replace_sub1_with_directory &&
 			test_submodule_content sub1 origin/replace_sub1_with_directory
@@ -937,7 +949,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			replace_gitfile_with_git_dir sub1 &&
 			rm -rf .git/modules &&
 			$command replace_sub1_with_directory &&
@@ -954,7 +966,7 @@ test_submodule_switch_recursing_with_args () {
 		(
 			cd submodule_update &&
 			rm -rf .git/modules/sub1/info &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			mkdir .git/modules/sub1/info &&
 			echo ignored >.git/modules/sub1/info/exclude &&
 			: >sub1/ignored &&
@@ -969,7 +981,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			git -c submodule.recurse=true $cmd_args modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
 			test_submodule_content sub1 origin/modify_sub1
@@ -981,7 +993,7 @@ test_submodule_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_nested_sub &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
+			test_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&
 			$command modify_sub1_recursively &&
 			test_superproject_content origin/modify_sub1_recursively &&
 			test_submodule_content sub1 origin/modify_sub1_recursively &&
@@ -1009,7 +1021,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested no_submodule &&
 		(
 			cd submodule_update &&
-			git branch -t add_sub1 origin/add_sub1 &&
+			test_branch_t_output add_sub1 origin/add_sub1 &&
 			>sub1 &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
@@ -1023,7 +1035,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			$command replace_sub1_with_directory &&
 			test_superproject_content origin/replace_sub1_with_directory
 		)
@@ -1034,7 +1046,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
 			replace_gitfile_with_git_dir sub1 &&
 			rm -rf .git/modules/sub1 &&
 			$command replace_sub1_with_directory &&
@@ -1049,7 +1061,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
 			: >sub1/expect &&
 			$command replace_sub1_with_file &&
 			test_superproject_content origin/replace_sub1_with_file
@@ -1062,7 +1074,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested invalid_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t valid_sub1 origin/valid_sub1 &&
+			test_branch_t_output valid_sub1 origin/valid_sub1 &&
 			$command valid_sub1 &&
 			test_superproject_content origin/valid_sub1 &&
 			test_submodule_content sub1 origin/valid_sub1
@@ -1077,7 +1089,7 @@ test_submodule_forced_switch_recursing_with_args () {
 		reset_work_tree_to_interested add_sub1 &&
 		(
 			cd submodule_update &&
-			git branch -t modify_sub1 origin/modify_sub1 &&
+			test_branch_t_output modify_sub1 origin/modify_sub1 &&
 			echo "gitdir: bogus/path" >sub1/.git &&
 			$command modify_sub1 &&
 			test_superproject_content origin/modify_sub1 &&
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v2 09/10] read-tree: add "--super-prefix" option, eliminate global
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (7 preceding siblings ...)
  2022-11-14 10:08     ` [PATCH v2 08/10] submodule tests: test "git branch -t" output and stderr Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 22:28       ` Glen Choo
  2022-11-14 10:08     ` [PATCH v2 10/10] fetch: rename "--submodule-prefix" to "--super-prefix" Ævar Arnfjörð Bjarmason
                       ` (4 subsequent siblings)
  13 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

The "--super-prefix" option to "git" was initially added in [1] for
use with "ls-files"[2], and shortly thereafter "submodule--helper"[3]
and "grep"[4]. It wasn't until [5] that "read-tree" made use of it.

At the time [5] made sense, but since then we've made "ls-files"
recurse in-process in [6], "grep" in [7], and finally
"submodule--helper" in the preceding commits.

Let's also remove it from "read-tree", which allows us to remove the
option to "git" itself.

We can do this because the only remaining user of it is the submodule
API, which will now invoke "read-tree" with its new "--super-prefix"
option. It will only do so when the "submodule_move_head()" function
is called.

That "submodule_move_head()" function was then only invoked by
"read-tree" itself, but now rather than setting an environment
variable to pass "--super-prefix" between cmd_read_tree() we:

- Set a new "super_prefix" in "struct unpack_trees_options". The
  "super_prefixed()" function in "unpack-trees.c" added in [5] will now
  use this, rather than get_super_prefix() looking up the environment
  variable we set earlier in the same process.

- Add the same field to the "struct checkout", which is only needed to
  ferry the "super_prefix" in the "struct unpack_trees_options" all the
  way down to the "entry.c" callers of "submodule_move_head()".

  Those calls which used the super prefix all originated in
  "cmd_read_tree()". The only other caller is the "unlink_entry()"
  caller in "builtin/checkout.c", which now passes a "NULL".

1. 74866d75793 (git: make super-prefix option, 2016-10-07)
2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)
3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)
4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)
5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)
6. 188dce131fa (ls-files: use repository object, 2017-06-22)
7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 Documentation/git.txt       |  8 +-------
 builtin.h                   |  4 ----
 builtin/checkout.c          |  2 +-
 builtin/read-tree.c         |  1 +
 cache.h                     |  2 --
 entry.c                     | 12 ++++++------
 entry.h                     |  6 +++++-
 environment.c               | 13 -------------
 git.c                       | 37 +++++--------------------------------
 submodule.c                 | 27 +++++++++------------------
 submodule.h                 |  5 ++---
 t/t1001-read-tree-m-2way.sh |  2 +-
 t/t5616-partial-clone.sh    |  2 +-
 unpack-trees.c              | 23 +++++++++++++----------
 unpack-trees.h              |  1 +
 15 files changed, 46 insertions(+), 99 deletions(-)

diff --git a/Documentation/git.txt b/Documentation/git.txt
index 1d33e083ab8..f9a7a4554cd 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -13,8 +13,7 @@ SYNOPSIS
     [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
     [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
     [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
-    [--super-prefix=<path>] [--config-env=<name>=<envvar>]
-    <command> [<args>]
+    [--config-env=<name>=<envvar>] <command> [<args>]
 
 DESCRIPTION
 -----------
@@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use
 	details.  Equivalent to setting the `GIT_NAMESPACE` environment
 	variable.
 
---super-prefix=<path>::
-	Currently for internal use only.  Set a prefix which gives a path from
-	above a repository down to its root.  One use is to give submodules
-	context about the superproject that invoked it.
-
 --bare::
 	Treat the repository as a bare repository.  If GIT_DIR
 	environment is not set, it is set to the current working
diff --git a/builtin.h b/builtin.h
index 8901a34d6bf..8264b7e5241 100644
--- a/builtin.h
+++ b/builtin.h
@@ -51,10 +51,6 @@
  *	on bare repositories.
  *	This only makes sense when `RUN_SETUP` is also set.
  *
- * `SUPPORT_SUPER_PREFIX`:
- *
- *	The built-in supports `--super-prefix`.
- *
  * `DELAY_PAGER_CONFIG`:
  *
  *	If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2a132392fbe..dc008fb45e8 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -231,7 +231,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
 		pos++;
 	}
 	if (!overlay_mode) {
-		unlink_entry(ce);
+		unlink_entry(ce, NULL);
 		return 0;
 	}
 	if (stage == 2)
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index f4cbe460b97..4b6f22e58c1 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
 	int prefix_set = 0;
 	struct lock_file lock_file = LOCK_INIT;
 	const struct option read_tree_options[] = {
+		OPT__SUPER_PREFIX(&opts.super_prefix),
 		OPT_CALLBACK_F(0, "index-output", NULL, N_("file"),
 		  N_("write resulting index to <file>"),
 		  PARSE_OPT_NONEG, index_output_cb),
diff --git a/cache.h b/cache.h
index 26ed03bd6de..a4a0377b800 100644
--- a/cache.h
+++ b/cache.h
@@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)
 #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
-#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
 int get_common_dir(struct strbuf *sb, const char *gitdir);
 const char *get_git_namespace(void);
 const char *strip_namespace(const char *namespaced_ref);
-const char *get_super_prefix(void);
 const char *get_git_work_tree(void);
 
 /*
diff --git a/entry.c b/entry.c
index 616e4f073c1..971ab268714 100644
--- a/entry.c
+++ b/entry.c
@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
 			return error("cannot create submodule directory %s", path);
 		sub = submodule_from_ce(ce);
 		if (sub)
-			return submodule_move_head(ce->name,
+			return submodule_move_head(ce->name, state->super_prefix,
 				NULL, oid_to_hex(&ce->oid),
 				state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
 		break;
@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 			 * no pathname to return.
 			 */
 			BUG("Can't remove entry to a path");
-		unlink_entry(ce);
+		unlink_entry(ce, state->super_prefix);
 		return 0;
 	}
 
@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 				if (!(st.st_mode & S_IFDIR))
 					unlink_or_warn(ce->name);
 
-				return submodule_move_head(ce->name,
+				return submodule_move_head(ce->name, state->super_prefix,
 					NULL, oid_to_hex(&ce->oid), 0);
 			} else
-				return submodule_move_head(ce->name,
+				return submodule_move_head(ce->name, state->super_prefix,
 					"HEAD", oid_to_hex(&ce->oid),
 					state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
 		}
@@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 	return write_entry(ce, path.buf, ca, state, 0, nr_checkouts);
 }
 
-void unlink_entry(const struct cache_entry *ce)
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)
 {
 	const struct submodule *sub = submodule_from_ce(ce);
 	if (sub) {
 		/* state.force is set at the caller. */
-		submodule_move_head(ce->name, "HEAD", NULL,
+		submodule_move_head(ce->name, super_prefix, "HEAD", NULL,
 				    SUBMODULE_MOVE_HEAD_FORCE);
 	}
 	if (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)
diff --git a/entry.h b/entry.h
index 9be4659881e..2d4fbb88c8f 100644
--- a/entry.h
+++ b/entry.h
@@ -8,6 +8,7 @@ struct checkout {
 	struct index_state *istate;
 	const char *base_dir;
 	int base_dir_len;
+	const char *super_prefix;
 	struct delayed_checkout *delayed_checkout;
 	struct checkout_metadata meta;
 	unsigned force:1,
@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);
 /*
  * Unlink the last component and schedule the leading directories for
  * removal, such that empty directories get removed.
+ *
+ * The "super_prefix" is either NULL, or the "--super-prefix" passed
+ * down from "read-tree" et al.
  */
-void unlink_entry(const struct cache_entry *ce);
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);
 
 void *read_blob_entry(const struct cache_entry *ce, size_t *size);
 int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);
diff --git a/environment.c b/environment.c
index 18d042b467d..1ee3686fd8a 100644
--- a/environment.c
+++ b/environment.c
@@ -102,8 +102,6 @@ char *git_work_tree_cfg;
 
 static char *git_namespace;
 
-static char *super_prefix;
-
 /*
  * Repository-local GIT_* environment variables; see cache.h for details.
  */
@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {
 	NO_REPLACE_OBJECTS_ENVIRONMENT,
 	GIT_REPLACE_REF_BASE_ENVIRONMENT,
 	GIT_PREFIX_ENVIRONMENT,
-	GIT_SUPER_PREFIX_ENVIRONMENT,
 	GIT_SHALLOW_FILE_ENVIRONMENT,
 	GIT_COMMON_DIR_ENVIRONMENT,
 	NULL
@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)
 	return NULL;
 }
 
-const char *get_super_prefix(void)
-{
-	static int initialized;
-	if (!initialized) {
-		super_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));
-		initialized = 1;
-	}
-	return super_prefix;
-}
-
 static int git_work_tree_initialized;
 
 /*
diff --git a/git.c b/git.c
index 2bca22cfd9a..00baaf23590 100644
--- a/git.c
+++ b/git.c
@@ -14,9 +14,8 @@
  * RUN_SETUP for reading from the configuration file.
  */
 #define NEED_WORK_TREE		(1<<3)
-#define SUPPORT_SUPER_PREFIX	(1<<4)
-#define DELAY_PAGER_CONFIG	(1<<5)
-#define NO_PARSEOPT		(1<<6) /* parse-options is not used */
+#define DELAY_PAGER_CONFIG	(1<<4)
+#define NO_PARSEOPT		(1<<5) /* parse-options is not used */
 
 struct cmd_struct {
 	const char *cmd;
@@ -29,8 +28,7 @@ const char git_usage_string[] =
 	   "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 	   "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
 	   "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-	   "           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-	   "           <command> [<args>]");
+	   "           [--config-env=<name>=<envvar>] <command> [<args>]");
 
 const char git_more_info_string[] =
 	N_("'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 			setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
 			if (envchanged)
 				*envchanged = 1;
-		} else if (!strcmp(cmd, "--super-prefix")) {
-			if (*argc < 2) {
-				fprintf(stderr, _("no prefix given for --super-prefix\n" ));
-				usage(git_usage_string);
-			}
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
-			if (envchanged)
-				*envchanged = 1;
-			(*argv)++;
-			(*argc)--;
-		} else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
-			if (envchanged)
-				*envchanged = 1;
 		} else if (!strcmp(cmd, "--bare")) {
 			char *cwd = xgetcwd();
 			is_bare_repository_cfg = 1;
@@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 		trace_repo_setup(prefix);
 	commit_pager_choice();
 
-	if (!help && get_super_prefix()) {
-		if (!(p->option & SUPPORT_SUPER_PREFIX))
-			die(_("%s doesn't support --super-prefix"), p->cmd);
-	}
-
 	if (!help && p->option & NEED_WORK_TREE)
 		setup_work_tree();
 
@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {
 	{ "check-ref-format", cmd_check_ref_format, NO_PARSEOPT  },
 	{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout--worker", cmd_checkout__worker,
-		RUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },
+		RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout-index", cmd_checkout_index,
 		RUN_SETUP | NEED_WORK_TREE},
 	{ "cherry", cmd_cherry, RUN_SETUP },
@@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {
 	{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
 	{ "push", cmd_push, RUN_SETUP },
 	{ "range-diff", cmd_range_diff, RUN_SETUP | USE_PAGER },
-	{ "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
+	{ "read-tree", cmd_read_tree, RUN_SETUP },
 	{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
 	{ "receive-pack", cmd_receive_pack },
 	{ "reflog", cmd_reflog, RUN_SETUP },
@@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)
 	struct child_process cmd = CHILD_PROCESS_INIT;
 	int status;
 
-	if (get_super_prefix())
-		die(_("%s doesn't support --super-prefix"), argv[0]);
-
 	if (use_pager == -1 && !is_builtin(argv[0]))
 		use_pager = check_pager_config(argv[0]);
 	commit_pager_choice();
@@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)
 			 */
 			trace2_cmd_name("_run_git_alias_");
 
-			if (get_super_prefix())
-				die("%s doesn't support --super-prefix", **argv);
-
 			commit_pager_choice();
 
 			strvec_push(&cmd.args, "git");
diff --git a/submodule.c b/submodule.c
index d9fd0af81b6..5ac4e1b0568 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2048,14 +2048,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)
 	strbuf_release(&config_path);
 }
 
-static const char *get_super_prefix_or_empty(void)
-{
-	const char *s = get_super_prefix();
-	if (!s)
-		s = "";
-	return s;
-}
-
 static int submodule_has_dirty_index(const struct submodule *sub)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2074,7 +2066,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)
 	return finish_command(&cp);
 }
 
-static void submodule_reset_index(const char *path)
+static void submodule_reset_index(const char *path, const char *super_prefix)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
 	prepare_submodule_repo_env(&cp.env);
@@ -2083,10 +2075,10 @@ static void submodule_reset_index(const char *path)
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	/* TODO: determine if this might overwright untracked files */
 	strvec_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+		     (super_prefix ? super_prefix : ""), path);
 
 	strvec_push(&cp.args, empty_tree_oid_hex());
 
@@ -2099,10 +2091,9 @@ static void submodule_reset_index(const char *path)
  * For edge cases (a submodule coming into existence or removing a submodule)
  * pass NULL for old or new respectively.
  */
-int submodule_move_head(const char *path,
-			 const char *old_head,
-			 const char *new_head,
-			 unsigned flags)
+int submodule_move_head(const char *path, const char *super_prefix,
+			const char *old_head, const char *new_head,
+			unsigned flags)
 {
 	int ret = 0;
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2148,7 +2139,7 @@ int submodule_move_head(const char *path,
 			strbuf_release(&gitdir);
 
 			/* make sure the index is clean as well */
-			submodule_reset_index(path);
+			submodule_reset_index(path, NULL);
 		}
 
 		if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
@@ -2166,9 +2157,9 @@ int submodule_move_head(const char *path,
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	strvec_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+		     (super_prefix ? super_prefix : ""), path);
 
 	if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
 		strvec_push(&cp.args, "-n");
diff --git a/submodule.h b/submodule.h
index e5ee13fb06a..36a7f7c5b32 100644
--- a/submodule.h
+++ b/submodule.h
@@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);
 
 #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)
 #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)
-int submodule_move_head(const char *path,
-			const char *old,
-			const char *new_head,
+int submodule_move_head(const char *path, const char *super_prefix,
+			const char *old_head, const char *new_head,
 			unsigned flags);
 
 void submodule_unset_core_worktree(const struct submodule *sub);
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 516a6112fdc..3fb1b0c162d 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '
 	cat <<-EOF >expect &&
 		error: Updating '\''fictional/a'\'' would lose untracked files in it
 	EOF
-	test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual &&
+	test_must_fail git read-tree --super-prefix fictional/ -u -m "$treeH" "$treeM" 2>actual &&
 	test_cmp expect actual
 '
 
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index e56466580cf..18375bff535 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -644,7 +644,7 @@ test_expect_success 'repack does not loosen promisor objects' '
 	grep "loosen_unused_packed_objects/loosened:0" trace
 '
 
-test_expect_failure 'lazy-fetch in submodule succeeds' '
+test_expect_success 'lazy-fetch in submodule succeeds' '
 	# setup
 	test_config_global protocol.file.allow always &&
 
diff --git a/unpack-trees.c b/unpack-trees.c
index bae812156c4..61c02285454 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
 	  ? ((o)->msgs[(type)])      \
 	  : (unpack_plumbing_errors[(type)]) )
 
-static const char *super_prefixed(const char *path)
+static const char *super_prefixed(const char *path, const char *super_prefix)
 {
 	/*
 	 * It is necessary and sufficient to have two static buffers
@@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)
 	static unsigned idx = ARRAY_SIZE(buf) - 1;
 
 	if (super_prefix_len < 0) {
-		const char *super_prefix = get_super_prefix();
 		if (!super_prefix) {
 			super_prefix_len = 0;
 		} else {
@@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,
 		return -1;
 
 	if (!o->show_all_errors)
-		return error(ERRORMSG(o, e), super_prefixed(path));
+		return error(ERRORMSG(o, e), super_prefixed(path,
+							    o->super_prefix));
 
 	/*
 	 * Otherwise, insert in a list for future display by
@@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)
 			error_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			error(ERRORMSG(o, e), super_prefixed(path.buf));
+			error(ERRORMSG(o, e), super_prefixed(path.buf,
+							     o->super_prefix));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)
 			warning_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			warning(ERRORMSG(o, e), super_prefixed(path.buf));
+			warning(ERRORMSG(o, e), super_prefixed(path.buf,
+							       o->super_prefix));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,
 	if (o->reset)
 		flags |= SUBMODULE_MOVE_HEAD_FORCE;
 
-	if (submodule_move_head(ce->name, old_id, new_id, flags))
+	if (submodule_move_head(ce->name, NULL, old_id, new_id, flags))
 		return add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
 	return 0;
 }
@@ -415,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,
 	int i, pc_workers, pc_threshold;
 
 	trace_performance_enter();
+	state.super_prefix = o->super_prefix;
 	state.force = 1;
 	state.quiet = 1;
 	state.refresh_cache = 1;
@@ -445,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,
 
 		if (ce->ce_flags & CE_WT_REMOVE) {
 			display_progress(progress, ++cnt);
-			unlink_entry(ce);
+			unlink_entry(ce, o->super_prefix);
 		}
 	}
 
@@ -2958,8 +2961,8 @@ int bind_merge(const struct cache_entry * const *src,
 	if (a && old)
 		return o->quiet ? -1 :
 			error(ERRORMSG(o, ERROR_BIND_OVERLAP),
-			      super_prefixed(a->name),
-			      super_prefixed(old->name));
+			      super_prefixed(a->name, o->super_prefix),
+			      super_prefixed(old->name, o->super_prefix));
 	if (!a)
 		return keep_entry(old, o);
 	else
@@ -3020,7 +3023,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,
 
 	if (worktree && untracked)
 		return error(_("worktree and untracked commit have duplicate entries: %s"),
-			     super_prefixed(worktree->name));
+			     super_prefixed(worktree->name, o->super_prefix));
 
 	return merged_entry(worktree ? worktree : untracked, NULL, o);
 }
diff --git a/unpack-trees.h b/unpack-trees.h
index efb9edfbb27..9b81e284073 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -74,6 +74,7 @@ struct unpack_trees_options {
 		     dry_run;
 	enum unpack_trees_reset_type reset;
 	const char *prefix;
+	const char *super_prefix;
 	int cache_bottom;
 	struct pathspec *pathspec;
 	merge_fn_t fn;
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v2 10/10] fetch: rename "--submodule-prefix" to "--super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (8 preceding siblings ...)
  2022-11-14 10:08     ` [PATCH v2 09/10] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
@ 2022-11-14 10:08     ` Ævar Arnfjörð Bjarmason
  2022-11-14 22:31       ` Glen Choo
  2022-11-14 21:59     ` [PATCH v2 00/10] Get rid of "git --super-prefix" Taylor Blau
                       ` (3 subsequent siblings)
  13 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:08 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

In preceding commits we've introduced a command-level "--super-prefix"
option, which unlike the "git --super-prefix" it replaced doesn't rely
on setenv() or getenv(), it's just a normal command-line option that
the command passes down.

Since we've done that, let's rename the "--submodule-prefix" option
added in 7dce19d374a (fetch/pull: Add the --recurse-submodules option,
2010-11-12) to "--super-prefix" for consistency. This:

 * Allows us to use OPT__SUPER_PREFIX().
 * Leaves an unspecified "--super-prefix" with a "NULL" value, rather
   than an empty string, as is the case with the other "--super-prefix"
   users. We coerce the NULL to "" in submodule.c before using it.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 Documentation/fetch-options.txt |  5 -----
 builtin/fetch.c                 |  7 +++----
 submodule.c                     | 23 +++++++++++------------
 3 files changed, 14 insertions(+), 21 deletions(-)

diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 622bd84768b..20cbd2c2910 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -241,11 +241,6 @@ endif::git-pull[]
 	linkgit:git-config[1].
 
 ifndef::git-pull[]
---submodule-prefix=<path>::
-	Prepend <path> to paths printed in informative messages
-	such as "Fetching submodule foo".  This option is used
-	internally when recursing over submodules.
-
 --recurse-submodules-default=[yes|on-demand]::
 	This option is used internally to temporarily provide a
 	non-negative default value for the --recurse-submodules
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7378cafeec9..353bcd36d24 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -74,7 +74,7 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
 static struct strbuf default_rla = STRBUF_INIT;
 static struct transport *gtransport;
 static struct transport *gsecondary;
-static const char *submodule_prefix = "";
+static const char *super_prefix;
 static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
@@ -195,8 +195,7 @@ static struct option builtin_fetch_options[] = {
 	OPT_SET_INT_F(0, "refetch", &refetch,
 		      N_("re-fetch without negotiating common commits"),
 		      1, PARSE_OPT_NONEG),
-	{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
-		   N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
+	OPT__SUPER_PREFIX(&super_prefix),
 	OPT_CALLBACK_F(0, "recurse-submodules-default",
 		   &recurse_submodules_default, N_("on-demand"),
 		   N_("default for recursive fetching of submodules "
@@ -2300,7 +2299,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		add_options_to_argv(&options);
 		result = fetch_submodules(the_repository,
 					  &options,
-					  submodule_prefix,
+					  super_prefix,
 					  recurse_submodules,
 					  recurse_submodules_default,
 					  verbosity < 0,
diff --git a/submodule.c b/submodule.c
index 5ac4e1b0568..1e4eee3492b 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1376,7 +1376,7 @@ struct submodule_parallel_fetch {
 	int changed_count;
 	struct strvec args;
 	struct repository *r;
-	const char *prefix;
+	const char *super_prefix;
 	int command_line_option;
 	int default_option;
 	int quiet;
@@ -1567,7 +1567,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
 		if (task->repo) {
 			if (!spf->quiet)
 				strbuf_addf(err, _("Fetching submodule %s%s\n"),
-					    spf->prefix, ce->name);
+					    spf->super_prefix, ce->name);
 
 			spf->index_count++;
 			return task;
@@ -1629,7 +1629,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
 		if (!spf->quiet)
 			strbuf_addf(err,
 				    _("Fetching submodule %s%s at commit %s\n"),
-				    spf->prefix, task->sub->path,
+				    spf->super_prefix, task->sub->path,
 				    find_unique_abbrev(cs_data->super_oid,
 						       DEFAULT_ABBREV));
 
@@ -1687,11 +1687,10 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
 			strvec_pushv(&cp->args, task->git_args.v);
 		strvec_pushv(&cp->args, spf->args.v);
 		strvec_push(&cp->args, task->default_argv);
-		strvec_push(&cp->args, "--submodule-prefix");
+		strvec_push(&cp->args, "--super-prefix");
 
-		strbuf_addf(&submodule_prefix, "%s%s/",
-						spf->prefix,
-						task->sub->path);
+		strbuf_addf(&submodule_prefix, "%s%s/", spf->super_prefix,
+			    task->sub->path);
 		strvec_push(&cp->args, submodule_prefix.buf);
 		*task_cb = task;
 
@@ -1707,7 +1706,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
 		spf->oid_fetch_tasks_nr--;
 
 		strbuf_addf(&submodule_prefix, "%s%s/",
-			    spf->prefix, task->sub->path);
+			    spf->super_prefix, task->sub->path);
 
 		child_process_init(cp);
 		prepare_submodule_repo_env_in_gitdir(&cp->env);
@@ -1717,7 +1716,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
 		strvec_init(&cp->args);
 		strvec_pushv(&cp->args, spf->args.v);
 		strvec_push(&cp->args, "on-demand");
-		strvec_push(&cp->args, "--submodule-prefix");
+		strvec_push(&cp->args, "--super-prefix");
 		strvec_push(&cp->args, submodule_prefix.buf);
 
 		/* NEEDSWORK: have get_default_remote from submodule--helper */
@@ -1813,7 +1812,7 @@ static int fetch_finish(int retvalue, struct strbuf *err,
 
 int fetch_submodules(struct repository *r,
 		     const struct strvec *options,
-		     const char *prefix, int command_line_option,
+		     const char *super_prefix, int command_line_option,
 		     int default_option,
 		     int quiet, int max_parallel_jobs)
 {
@@ -1835,7 +1834,7 @@ int fetch_submodules(struct repository *r,
 	spf.command_line_option = command_line_option;
 	spf.default_option = default_option;
 	spf.quiet = quiet;
-	spf.prefix = prefix;
+	spf.super_prefix = super_prefix ? super_prefix : "";
 
 	if (!r->worktree)
 		goto out;
@@ -1847,7 +1846,7 @@ int fetch_submodules(struct repository *r,
 	for (i = 0; i < options->nr; i++)
 		strvec_push(&spf.args, options->v[i]);
 	strvec_push(&spf.args, "--recurse-submodules-default");
-	/* default value, "--submodule-prefix" and its value are added later */
+	/* default value, "--super-prefix" and its value are added later */
 
 	calculate_changed_submodule_paths(r, &spf.changed_submodule_names);
 	string_list_sort(&spf.changed_submodule_names);
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-12  1:10             ` Glen Choo
@ 2022-11-14 10:09               ` Ævar Arnfjörð Bjarmason
  2022-11-14 23:33                 ` Glen Choo
  0 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 10:09 UTC (permalink / raw)
  To: Glen Choo; +Cc: git


On Fri, Nov 11 2022, Glen Choo wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> On Fri, Nov 11 2022, Glen Choo wrote:
>>
>>> Glen Choo <chooglen@google.com> writes:
>>>
>>>> Rereading this series and thinking about this some more, let's go with
>>>> your approach, primarily because it avoids global state.
>>>>
>>>> From this series, it seems that it's not that hard to make this change
>>>> and support whatever use cases we currently have.
>>>>
>>>> This does make it more tedious to add more "--super-prefix" in the
>>>> future, but that's a good push for us to do more things in-process
>>>> and/or be more principled about passing context objects through the call
>>>> stack instead of relying on globals.
>>>>
>>>> Let me know what I can add to this effort besides reviewing :)
>>>
>>> Specifically, if you have other things on your plate, I'd be happy to
>>> pick up where where this RFC has left off.
>>
>> I was going to get around to re-rolling this in the next few days, but
>> I'd also be happy to have you beat me to it.
>
> Ah, well, I didn't mean that I was planning to work on this over the
> weekend, but I can certainly get to it on Monday. I meant something
> closer to "If you didn't want to think about git-submodule.sh for the
> next week or so, I can pick this up".
>
> Alternatively, I think it also makes sense if you want to reroll only
> the submodule--helper bits (1-7/8) to unblock your git-submodule.sh
> work, and I can prepare the rest of the "nuke --super-prefix" stuff on
> top of that. That should save you a context switch, and since I sent out
> [1], nuking --super-prefix shouldn't be urgent.
>
> If you don't really care any which way, I'll just re-roll this :)
>
> [1] https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com

I just re-rolled it at
https://lore.kernel.org/git/cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com/;
Mainly because I think just going for the "read-tree" fix directly instead of:

 1. Adding --super-prefix to "fetch" first, and reviewing any new
    side-effects that may have (i.e. your PR above).
 2. Concurrently, just the "submodule--helper" part of this RFC
 3. Finally, the "read-tree" part, and getting rid of "git
    --super-prefix", which would need to depend on both #1 and #2 above.

Will involve too much avoidable juggling, when getting rid of the global
directly isn't too hard to reason about, in which case we can skip #1
entirely.

Let me know what you think...

> Yeah, this plan makes sense. One thing I'd add is that I'd also use
> OPT__SUPER_PREFIX to handle "git fetch --submodule-prefix".

As noted in the CL above I included this because I see you're keen to
include it, but I'm personally a bit "meh" on it. I.e. it's just
renaming an existing unrelated option, although being able to use
OPT__SUPER_PREFIX() makes it slightly nicer.

As post-cleanups go I think removing the "submodule_prefix" from the
"struct repository" would make more sense, and maybe it's worth peeling
off the 10/10 to include in such a post-cleanup series? I.e. the below
on top of all of this works, and reduces allocations and cargo-culting
around the submodule API.

-- >8 --
Subject: [PATCH] repo & submodule API: stop carrying "repo->submodule_prefix"

As this change shows the "submodule_prefix" field to "struct
repository" added in 96dc883b3cd (repository: enable initialization of
submodules, 2017-06-22) was only used by "ls-files" and "grep". Let's
have those two carry forward the "super_prefix" instead.

Having every user of "struct repository" needing to worry about this
created a mismatch in the API where e.g. "grep" would re-compute a
"name_base_len" which we knew before. Now we use a "struct strbuf" in
the "struct grep_opt" there instead, so we'll know the length
already. This simplifies "grep_cache()" and "grep_tree()".

We're also deleting cargo-culted code that the previous API foisted
upon us. In 605f0ec1350 (submodule: use submodule repos for object
lookup, 2018-12-14) the "Mark it as a submodule" code was added to
"open_submodule()", but the resulting xstrdup()'d "submodule_prefix"
was never used by anything.

Still, removing this field might not be a good move, as the
"super_prefix" might be a common enough case in the future, e.g. when
eventually migrating the "submodule--helper" users[1] to run
in-process.

As the "grep" example demonstrates I don't think that's the
case. There instead of xstrdup()-ing all the way down we're now
carrying a single "super_prefix" in the form of a "struct strbuf". As
we recurse we then append to it, and strbuf_setlen() it back when we
we recurse out of that submodule. This is similar to how e.g. the
"read_tree_at()" API works.

Doing it that way means that we have just one allocation, which in the
common case we might realloc() if we don't have enough room in the
"struct strbuf".

1. https://lore.kernel.org/git/cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com/
2. https://github.com/avar/git/tree/avar/grep-post-drop-prefix-cleanup

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/grep.c     | 18 ++++++++----------
 builtin/ls-files.c | 40 +++++++++++++++++++++++++---------------
 grep.c             |  6 +++---
 grep.h             |  2 ++
 repository.c       |  7 -------
 repository.h       |  7 -------
 submodule.c        |  3 ---
 7 files changed, 38 insertions(+), 45 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 5fa927d4e22..69826daba26 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -437,6 +437,7 @@ static int grep_submodule(struct grep_opt *opt,
 	struct repository *superproject = opt->repo;
 	struct grep_opt subopt;
 	int hit = 0;
+	size_t oldlen = opt->super_prefix.len;
 
 	if (!is_submodule_active(superproject, path))
 		return 0;
@@ -497,6 +498,7 @@ static int grep_submodule(struct grep_opt *opt,
 	add_submodule_odb_by_path(subrepo->objects->odb->path);
 	obj_read_unlock();
 
+	strbuf_addf(&opt->super_prefix, "%s/", path);
 	memcpy(&subopt, opt, sizeof(subopt));
 	subopt.repo = subrepo;
 
@@ -527,6 +529,7 @@ static int grep_submodule(struct grep_opt *opt,
 	} else {
 		hit = grep_cache(&subopt, pathspec, cached);
 	}
+	strbuf_setlen(&opt->super_prefix, oldlen);
 
 	return hit;
 }
@@ -538,11 +541,8 @@ static int grep_cache(struct grep_opt *opt,
 	int hit = 0;
 	int nr;
 	struct strbuf name = STRBUF_INIT;
-	int name_base_len = 0;
-	if (repo->submodule_prefix) {
-		name_base_len = strlen(repo->submodule_prefix);
-		strbuf_addstr(&name, repo->submodule_prefix);
-	}
+	size_t name_base_len = opt->super_prefix.len;
+	strbuf_addbuf(&name, &opt->super_prefix);
 
 	if (repo_read_index(repo) < 0)
 		die(_("index file corrupt"));
@@ -618,11 +618,9 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 	struct name_entry entry;
 	int old_baselen = base->len;
 	struct strbuf name = STRBUF_INIT;
-	int name_base_len = 0;
-	if (repo->submodule_prefix) {
-		strbuf_addstr(&name, repo->submodule_prefix);
-		name_base_len = name.len;
-	}
+	size_t name_base_len = opt->super_prefix.len;
+
+	strbuf_addbuf(&name, &opt->super_prefix);
 
 	while (tree_entry(tree, &entry)) {
 		int te_len = tree_entry_len(&entry);
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 4cf8a236483..c76a6be2fbe 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -216,10 +216,12 @@ static void show_killed_files(struct index_state *istate,
 	}
 }
 
-static void show_files(struct repository *repo, struct dir_struct *dir);
+static void show_files(struct repository *repo, struct dir_struct *dir,
+		       const char *super_prefix);
 
 static void show_submodule(struct repository *superproject,
-			   struct dir_struct *dir, const char *path)
+			   struct dir_struct *dir, const char *path,
+			   const char *super_prefix)
 {
 	struct repository subrepo;
 
@@ -229,7 +231,7 @@ static void show_submodule(struct repository *superproject,
 	if (repo_read_index(&subrepo) < 0)
 		die("index file corrupt");
 
-	show_files(&subrepo, dir);
+	show_files(&subrepo, dir, super_prefix);
 
 	repo_clear(&subrepo);
 }
@@ -303,14 +305,19 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
 
 static void show_ce(struct repository *repo, struct dir_struct *dir,
 		    const struct cache_entry *ce, const char *fullname,
-		    const char *tag)
+		    const char *tag, const char *super_prefix)
 {
 	if (max_prefix_len > strlen(fullname))
 		die("git ls-files: internal error - cache entry not superset of prefix");
 
 	if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
 	    is_submodule_active(repo, ce->name)) {
-		show_submodule(repo, dir, ce->name);
+		struct strbuf sp = STRBUF_INIT;
+
+		strbuf_addf(&sp, "%s%s/", super_prefix ? super_prefix : "",
+			    ce->name);
+		show_submodule(repo, dir, ce->name, sp.buf);
+		strbuf_release(&sp);
 	} else if (match_pathspec(repo->index, &pathspec, fullname, strlen(fullname),
 				  max_prefix_len, ps_matched,
 				  S_ISDIR(ce->ce_mode) ||
@@ -374,16 +381,17 @@ static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
 	return is_excluded(dir, istate, fullname, &dtype);
 }
 
-static void construct_fullname(struct strbuf *out, const struct repository *repo,
-			       const struct cache_entry *ce)
+static void construct_fullname(struct strbuf *out, const struct cache_entry *ce,
+			       const char *super_prefix)
 {
 	strbuf_reset(out);
-	if (repo->submodule_prefix)
-		strbuf_addstr(out, repo->submodule_prefix);
+	if (super_prefix)
+		strbuf_addstr(out, super_prefix);
 	strbuf_addstr(out, ce->name);
 }
 
-static void show_files(struct repository *repo, struct dir_struct *dir)
+static void show_files(struct repository *repo, struct dir_struct *dir,
+		       const char *super_prefix)
 {
 	int i;
 	struct strbuf fullname = STRBUF_INIT;
@@ -410,7 +418,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir)
 		struct stat st;
 		int stat_err;
 
-		construct_fullname(&fullname, repo, ce);
+		construct_fullname(&fullname, ce, super_prefix);
 
 		if ((dir->flags & DIR_SHOW_IGNORED) &&
 			!ce_excluded(dir, repo->index, fullname.buf, ce))
@@ -422,7 +430,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir)
 			show_ce(repo, dir, ce, fullname.buf,
 				ce_stage(ce) ? tag_unmerged :
 				(ce_skip_worktree(ce) ? tag_skip_worktree :
-				 tag_cached));
+				 tag_cached), super_prefix);
 			if (skipping_duplicates)
 				goto skip_to_next_name;
 		}
@@ -435,13 +443,15 @@ static void show_files(struct repository *repo, struct dir_struct *dir)
 		if (stat_err && (errno != ENOENT && errno != ENOTDIR))
 			error_errno("cannot lstat '%s'", fullname.buf);
 		if (stat_err && show_deleted) {
-			show_ce(repo, dir, ce, fullname.buf, tag_removed);
+			show_ce(repo, dir, ce, fullname.buf, tag_removed,
+				super_prefix);
 			if (skipping_duplicates)
 				goto skip_to_next_name;
 		}
 		if (show_modified &&
 		    (stat_err || ie_modified(repo->index, ce, &st, 0))) {
-			show_ce(repo, dir, ce, fullname.buf, tag_modified);
+			show_ce(repo, dir, ce, fullname.buf, tag_modified,
+				super_prefix);
 			if (skipping_duplicates)
 				goto skip_to_next_name;
 		}
@@ -874,7 +884,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
 	}
 
-	show_files(the_repository, &dir);
+	show_files(the_repository, &dir, NULL);
 
 	if (show_resolve_undo)
 		show_ru_info(the_repository->index);
diff --git a/grep.c b/grep.c
index 06eed694936..10d52219229 100644
--- a/grep.c
+++ b/grep.c
@@ -791,9 +791,9 @@ void free_grep_patterns(struct grep_opt *opt)
 		free(p);
 	}
 
-	if (!opt->pattern_expression)
-		return;
-	free_pattern_expr(opt->pattern_expression);
+	if (opt->pattern_expression)
+		free_pattern_expr(opt->pattern_expression);
+	strbuf_release(&opt->super_prefix);
 }
 
 static const char *end_of_line(const char *cp, unsigned long *left)
diff --git a/grep.h b/grep.h
index 6075f997e68..d353bfa21ce 100644
--- a/grep.h
+++ b/grep.h
@@ -133,6 +133,7 @@ struct grep_opt {
 	 * t7814-grep-recurse-submodules.sh for more information.
 	 */
 	struct repository *repo;
+	struct strbuf super_prefix;
 
 	int linenum;
 	int columnnum;
@@ -178,6 +179,7 @@ struct grep_opt {
 };
 
 #define GREP_OPT_INIT { \
+	.super_prefix = STRBUF_INIT, \
 	.relative = 1, \
 	.pathname = 1, \
 	.max_depth = -1, \
diff --git a/repository.c b/repository.c
index 5d166b692c8..2f8581c517d 100644
--- a/repository.c
+++ b/repository.c
@@ -228,12 +228,6 @@ int repo_submodule_init(struct repository *subrepo,
 			goto out;
 		}
 	}
-
-	subrepo->submodule_prefix = xstrfmt("%s%s/",
-					    superproject->submodule_prefix ?
-					    superproject->submodule_prefix :
-					    "", path);
-
 out:
 	strbuf_release(&gitdir);
 	strbuf_release(&worktree);
@@ -261,7 +255,6 @@ void repo_clear(struct repository *repo)
 	FREE_AND_NULL(repo->graft_file);
 	FREE_AND_NULL(repo->index_file);
 	FREE_AND_NULL(repo->worktree);
-	FREE_AND_NULL(repo->submodule_prefix);
 
 	raw_object_store_clear(repo->objects);
 	FREE_AND_NULL(repo->objects);
diff --git a/repository.h b/repository.h
index 6c461c5b9de..a08da26133c 100644
--- a/repository.h
+++ b/repository.h
@@ -120,13 +120,6 @@ struct repository {
 	 */
 	char *worktree;
 
-	/*
-	 * Path from the root of the top-level superproject down to this
-	 * repository.  This is only non-NULL if the repository is initialized
-	 * as a submodule of another repository.
-	 */
-	char *submodule_prefix;
-
 	struct repo_settings settings;
 
 	/* Subsystems */
diff --git a/submodule.c b/submodule.c
index 1e4eee3492b..1c5ef904a03 100644
--- a/submodule.c
+++ b/submodule.c
@@ -528,9 +528,6 @@ static struct repository *open_submodule(const char *path)
 		return NULL;
 	}
 
-	/* Mark it as a submodule */
-	out->submodule_prefix = xstrdup(path);
-
 	strbuf_release(&sb);
 	return out;
 }
-- 
2.38.0.1471.ge4d8947e7aa


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 01/10] read-tree + fetch tests: test failing "--super-prefix" interaction
  2022-11-14 10:08     ` [PATCH v2 01/10] read-tree + fetch tests: test failing "--super-prefix" interaction Ævar Arnfjörð Bjarmason
@ 2022-11-14 19:00       ` Glen Choo
  2022-11-14 19:14         ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-14 19:00 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> From: Glen Choo <chooglen@google.com>
>
> Ever since "git fetch --refetch" was introduced in 0f5e8851737 (Merge
> branch 'rc/fetch-refetch', 2022-04-04) the test being added here would
> fail. This is because "restore" will "read-tree .. --reset <hash>",
> which will in turn invoke "fetch". The "fetch" will then die with:
>
> 	fatal: fetch doesn't support --super-prefix
>
> This edge case and other "--super-prefix" bugs will be fixed in
> subsequent commits, but let's first add a "test_expect_failure" test
> for it. It passes until the very last command in the test.
>
> Signed-off-by: Glen Choo <chooglen@google.com>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
>
> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
> index 037941b95d2..e56466580cf 100755
> --- a/t/t5616-partial-clone.sh
> +++ b/t/t5616-partial-clone.sh
> @@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '
>  	grep "loosen_unused_packed_objects/loosened:0" trace
>  '
>  
> +test_expect_failure 'lazy-fetch in submodule succeeds' '
> +	# setup
> +	test_config_global protocol.file.allow always &&
> +
> +	git init src-sub &&
> +	git -C src-sub config uploadpack.allowfilter 1 &&
> +	git -C src-sub config uploadpack.allowanysha1inwant 1 &&
> +
> +	# This blob must be missing in the subsequent commit.
> +	echo foo >src-sub/file &&
> +	git -C src-sub add file &&
> +	git -C src-sub commit -m "submodule one" &&
> +	SUB_ONE=$(git -C src-sub rev-parse HEAD) &&
> +
> +	echo bar >src-sub/file &&
> +	git -C src-sub add file &&
> +	git -C src-sub commit -m "submodule two" &&
> +	SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
> +
> +	git init src-super &&
> +	git -C src-super config uploadpack.allowfilter 1 &&
> +	git -C src-super config uploadpack.allowanysha1inwant 1 &&
> +	git -C src-super submodule add ../src-sub src-sub &&
> +
> +	git -C src-super/src-sub checkout $SUB_ONE &&
> +	git -C src-super add src-sub &&
> +	git -C src-super commit -m "superproject one" &&
> +
> +	git -C src-super/src-sub checkout $SUB_TWO &&
> +	git -C src-super add src-sub &&
> +	git -C src-super commit -m "superproject two" &&
> +
> +	# the fetch
> +	test_when_finished "rm -rf src-super src-sub client" &&

(Genuinely curious) are we okay with test_when_finished in the middle of
the test body instead of at the top?

> +
> +	test_config_global protocol.file.allow always &&

We have this exact same test_config_global line at the top of this test,
so we can drop this one.

> +	git clone --filter=blob:none --also-filter-submodules \
> +		--recurse-submodules "file://$(pwd)/src-super" client &&
> +
> +	# Trigger lazy-fetch from the superproject
> +	git -C client restore --recurse-submodules --source=HEAD^ :/
> +'
> +
>  . "$TEST_DIRECTORY"/lib-httpd.sh
>  start_httpd
>  
> -- 
> 2.38.0.1471.ge4d8947e7aa

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 01/10] read-tree + fetch tests: test failing "--super-prefix" interaction
  2022-11-14 19:00       ` Glen Choo
@ 2022-11-14 19:14         ` Ævar Arnfjörð Bjarmason
  2022-11-14 19:49           ` Glen Choo
  0 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-14 19:14 UTC (permalink / raw)
  To: Glen Choo; +Cc: git, Taylor Blau, Robert Coup


On Mon, Nov 14 2022, Glen Choo wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> From: Glen Choo <chooglen@google.com>
>>
>> Ever since "git fetch --refetch" was introduced in 0f5e8851737 (Merge
>> branch 'rc/fetch-refetch', 2022-04-04) the test being added here would
>> fail. This is because "restore" will "read-tree .. --reset <hash>",
>> which will in turn invoke "fetch". The "fetch" will then die with:
>>
>> 	fatal: fetch doesn't support --super-prefix
>>
>> This edge case and other "--super-prefix" bugs will be fixed in
>> subsequent commits, but let's first add a "test_expect_failure" test
>> for it. It passes until the very last command in the test.
>>
>> Signed-off-by: Glen Choo <chooglen@google.com>
>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>> ---
>>  t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 43 insertions(+)
>>
>> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
>> index 037941b95d2..e56466580cf 100755
>> --- a/t/t5616-partial-clone.sh
>> +++ b/t/t5616-partial-clone.sh
>> @@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '
>>  	grep "loosen_unused_packed_objects/loosened:0" trace
>>  '
>>  
>> +test_expect_failure 'lazy-fetch in submodule succeeds' '
>> +	# setup
>> +	test_config_global protocol.file.allow always &&
>> +
>> +	git init src-sub &&
>> +	git -C src-sub config uploadpack.allowfilter 1 &&
>> +	git -C src-sub config uploadpack.allowanysha1inwant 1 &&
>> +
>> +	# This blob must be missing in the subsequent commit.
>> +	echo foo >src-sub/file &&
>> +	git -C src-sub add file &&
>> +	git -C src-sub commit -m "submodule one" &&
>> +	SUB_ONE=$(git -C src-sub rev-parse HEAD) &&
>> +
>> +	echo bar >src-sub/file &&
>> +	git -C src-sub add file &&
>> +	git -C src-sub commit -m "submodule two" &&
>> +	SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
>> +
>> +	git init src-super &&
>> +	git -C src-super config uploadpack.allowfilter 1 &&
>> +	git -C src-super config uploadpack.allowanysha1inwant 1 &&
>> +	git -C src-super submodule add ../src-sub src-sub &&
>> +
>> +	git -C src-super/src-sub checkout $SUB_ONE &&
>> +	git -C src-super add src-sub &&
>> +	git -C src-super commit -m "superproject one" &&
>> +
>> +	git -C src-super/src-sub checkout $SUB_TWO &&
>> +	git -C src-super add src-sub &&
>> +	git -C src-super commit -m "superproject two" &&
>> +
>> +	# the fetch
>> +	test_when_finished "rm -rf src-super src-sub client" &&
>
> (Genuinely curious) are we okay with test_when_finished in the middle of
> the test body instead of at the top?

Yeah, and it's not just supported, but preferred, usually we do:

	test_when_finished "rm -rf repo" &&
	git init repo &&

So at the top makes sense, but if there's a bunch of stuff we might fail
on first it makes sense not to attempt the cleanup.

But I see in this case the "src-super" part of it should be earlier, and
"src-sub", but the "client" should be just before the clone below, don't
know how I missed that. Will fix.

>> +
>> +	test_config_global protocol.file.allow always &&
>
> We have this exact same test_config_global line at the top of this test,
> so we can drop this one.

Ditto, thanks, I'll fix that. A mistake when combining the tests.

You had these as two tests, but one was mandatory setup for the other,
and when making it test_expect_failure I wanted to have it atomic..

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 01/10] read-tree + fetch tests: test failing "--super-prefix" interaction
  2022-11-14 19:14         ` Ævar Arnfjörð Bjarmason
@ 2022-11-14 19:49           ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-14 19:49 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Taylor Blau, Robert Coup

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Mon, Nov 14 2022, Glen Choo wrote:
>
>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>>
>>> From: Glen Choo <chooglen@google.com>
>>>
>>> Ever since "git fetch --refetch" was introduced in 0f5e8851737 (Merge
>>> branch 'rc/fetch-refetch', 2022-04-04) the test being added here would
>>> fail. This is because "restore" will "read-tree .. --reset <hash>",
>>> which will in turn invoke "fetch". The "fetch" will then die with:
>>>
>>> 	fatal: fetch doesn't support --super-prefix
>>>
>>> This edge case and other "--super-prefix" bugs will be fixed in
>>> subsequent commits, but let's first add a "test_expect_failure" test
>>> for it. It passes until the very last command in the test.
>>>
>>> Signed-off-by: Glen Choo <chooglen@google.com>
>>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>>> ---
>>>  t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 43 insertions(+)
>>>
>>> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
>>> index 037941b95d2..e56466580cf 100755
>>> --- a/t/t5616-partial-clone.sh
>>> +++ b/t/t5616-partial-clone.sh
>>> @@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '
>>>  	grep "loosen_unused_packed_objects/loosened:0" trace
>>>  '
>>>  
>>> +test_expect_failure 'lazy-fetch in submodule succeeds' '
>>> +	# setup
>>> +	test_config_global protocol.file.allow always &&
>>> +
>>> +	git init src-sub &&
>>> +	git -C src-sub config uploadpack.allowfilter 1 &&
>>> +	git -C src-sub config uploadpack.allowanysha1inwant 1 &&
>>> +
>>> +	# This blob must be missing in the subsequent commit.
>>> +	echo foo >src-sub/file &&
>>> +	git -C src-sub add file &&
>>> +	git -C src-sub commit -m "submodule one" &&
>>> +	SUB_ONE=$(git -C src-sub rev-parse HEAD) &&
>>> +
>>> +	echo bar >src-sub/file &&
>>> +	git -C src-sub add file &&
>>> +	git -C src-sub commit -m "submodule two" &&
>>> +	SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
>>> +
>>> +	git init src-super &&
>>> +	git -C src-super config uploadpack.allowfilter 1 &&
>>> +	git -C src-super config uploadpack.allowanysha1inwant 1 &&
>>> +	git -C src-super submodule add ../src-sub src-sub &&
>>> +
>>> +	git -C src-super/src-sub checkout $SUB_ONE &&
>>> +	git -C src-super add src-sub &&
>>> +	git -C src-super commit -m "superproject one" &&
>>> +
>>> +	git -C src-super/src-sub checkout $SUB_TWO &&
>>> +	git -C src-super add src-sub &&
>>> +	git -C src-super commit -m "superproject two" &&
>>> +
>>> +	# the fetch
>>> +	test_when_finished "rm -rf src-super src-sub client" &&
>>
>> (Genuinely curious) are we okay with test_when_finished in the middle of
>> the test body instead of at the top?
>
> Yeah, and it's not just supported, but preferred, usually we do:
>
> 	test_when_finished "rm -rf repo" &&
> 	git init repo &&
>
> So at the top makes sense, but if there's a bunch of stuff we might fail
> on first it makes sense not to attempt the cleanup.
>
> But I see in this case the "src-super" part of it should be earlier, and
> "src-sub", but the "client" should be just before the clone below, don't
> know how I missed that. Will fix.

Ah, I see. Yeah that makes sense.

>
>>> +
>>> +	test_config_global protocol.file.allow always &&
>>
>> We have this exact same test_config_global line at the top of this test,
>> so we can drop this one.
>
> Ditto, thanks, I'll fix that. A mistake when combining the tests.
>
> You had these as two tests, but one was mandatory setup for the other,
> and when making it test_expect_failure I wanted to have it atomic..

Makes sense too. I initially had them separate for readability purposes,
but the inline comments work too.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 02/10] submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  2022-11-14 10:08     ` [PATCH v2 02/10] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
@ 2022-11-14 21:22       ` Glen Choo
  2022-11-17 18:10         ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-14 21:22 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> The "--super-prefix" facility was introduced in [1] has always been a
> transitory hack, which is why we've made it an error to supply it as
> an option to "git" to commands that don't know about it.
>
> That's been a good goal, as it has a global effect we haven't wanted
> calls to get_super_prefix() from built-ins we didn't expect.
>
> But it has meant that when we've had chains of different built-ins
> using it all of the processes in that "chain" have needed to support
> it, and worse processes that don't need it have needed to ask for
> "SUPPORT_SUPER_PREFIX" because their parent process needs it.
>
> That's how "fsmonitor--daemon" ended up with it, per [2] it's called
> from (among other things) "submodule--helper absorbgitdirs", but as we
> declared "submodule--helper" as "SUPPORT_SUPER_PREFIX" we needed to
> declare "fsmonitor--daemon" as accepting it too, even though it
> doesn't care about it.
>
> But in the case of "absorbgitdirs" it only needed "--super-prefix" to
> invoke itself recursively, and we'd never have another "in-between"
> process in the chain. So we didn't need the bigger hammer of "git
> --super-prefix", and the "setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)"
> that it entails.
>
> Let's instead accept a hidden "--super-prefix" option to
> "submodule--helper absorbgitdirs" itself.
>
> Eventually (as with all other "--super-prefix" users) we'll want to
> clean this code up so that this all happens in-process. I.e. needing
> any variant of "--super-prefix" is itself a hack around our various
> global state, and implicit reliance on "the_repository". This stepping
> stone makes such an eventual change easier, as we'll need to deal with
> less global state at that point.
>
> The "fsmonitor--daemon" test adjusted here was added in [3]. The
> comment added in that commit has been out-of-date from the beginning,
> and the "have_t2_error_event()" was being overly specific in testing
> for a bug that we *don't* have. Let's instead test for the stdout and
> stderr that we *do have*.

I didn't understand this bit initially, because I read this as
"have_t2_error_event() isn't catching bugs", which isn't true. But I see
what you mean after inspecting the test_cmp output:

  @@ -1 +1,2 @@
  Migrating git directory of 'dir_1/dir_2/sub' from 'dir_1/dir_2/sub/.git' to '.git/modules/dir_1/dir_2/sub'
  +fatal: fsmonitor--daemon doesn't support --super-prefix

IOW, it doesn't make sense to inspecting the tr2 output for stray
warnings when our stderr is so obviously broken. But at the end of the
series, I don't think we even need this test at all because if we don't
have a global "--super-prefix", there's literally no reason for
fsmonitor--daemon to worry about absorbgitdirs or "supporting" the super
prefix. That's why I removed it in [1].

Wondering aloud, that stderr suggests that the "git submodule absorbgitdirs"
invocation failed. I wonder why the test didn't catch a bad exit code
(and resulting in us inspecting stderr unnecessarily). I think it's not
worth looking too closely at right now, but we could revisit this after
we get builtin/submodule.c.

[1] https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com

>
> 1. 74866d75793 (git: make super-prefix option, 2016-10-07)
> 2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
>    2022-05-26)
> 3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
>    2022-05-26)
>
> Signed-off-by: Glen Choo <chooglen@google.com>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  builtin/submodule--helper.c  |  8 +++++---
>  git.c                        |  2 +-
>  parse-options.h              |  4 ++++
>  submodule.c                  | 20 ++++++++++++--------
>  submodule.h                  |  7 ++++++-
>  t/t7527-builtin-fsmonitor.sh | 33 ++++++++-------------------------
>  6 files changed, 36 insertions(+), 38 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index c75e9e86b06..427e793e204 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -2828,7 +2828,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
>  	int i;
>  	struct pathspec pathspec = { 0 };
>  	struct module_list list = MODULE_LIST_INIT;
> +	const char *super_prefix = NULL;
>  	struct option embed_gitdir_options[] = {
> +		OPT__SUPER_PREFIX(&super_prefix),
>  		OPT_END()
>  	};
>  	const char *const git_submodule_helper_usage[] = {
> @@ -2844,7 +2846,8 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
>  		goto cleanup;
>  
>  	for (i = 0; i < list.nr; i++)
> -		absorb_git_dir_into_superproject(list.entries[i]->name);
> +		absorb_git_dir_into_superproject_sp(list.entries[i]->name,
> +						    super_prefix);
>  
>  	ret = 0;
>  cleanup:
> @@ -3382,8 +3385,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
>  
>  	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
>  	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
> -	    strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") &&
> -	    get_super_prefix())
> +	    strcmp(subcmd, "sync") && get_super_prefix())
>  		/*
>  		 * xstrfmt() rather than "%s %s" to keep the translated
>  		 * string identical to git.c's.
> diff --git a/git.c b/git.c
> index 10202a7f126..b1b7e1a837e 100644
> --- a/git.c
> +++ b/git.c
> @@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {
>  	{ "format-patch", cmd_format_patch, RUN_SETUP },
>  	{ "fsck", cmd_fsck, RUN_SETUP },
>  	{ "fsck-objects", cmd_fsck, RUN_SETUP },
> -	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
> +	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP },
>  	{ "gc", cmd_gc, RUN_SETUP },
>  	{ "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT },
>  	{ "grep", cmd_grep, RUN_SETUP_GENTLY },
> diff --git a/parse-options.h b/parse-options.h
> index b6ef86e0d15..50d852f2991 100644
> --- a/parse-options.h
> +++ b/parse-options.h
> @@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
>  	{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"),	\
>  	  N_("use <n> digits to display object names"),	\
>  	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
> +#define OPT__SUPER_PREFIX(var) \
> +	OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
> +		N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
> +

Could we default to "" instead of NULL? (possibly via a callback). I
think there's never any good reason to have NULL instead of "", e.g.
since this is internal, we don't care to distinguish between
"--super-prefix=''" and not passing "--super-prefix" at all...

>  #define OPT__COLOR(var, h) \
>  	OPT_COLOR_FLAG(0, "color", (var), (h))
>  #define OPT_COLUMN(s, l, v, h) \
> diff --git a/submodule.c b/submodule.c
> index c47358097fd..d9fd0af81b6 100644
> --- a/submodule.c
> +++ b/submodule.c
> @@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)
>   * Embeds a single submodules git directory into the superprojects git dir,
>   * non recursively.
>   */
> -static void relocate_single_git_dir_into_superproject(const char *path)
> +static void relocate_single_git_dir_into_superproject(const char *path,
> +						      const char *super_prefix)
>  {
>  	char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
>  	struct strbuf new_gitdir = STRBUF_INIT;
> @@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
>  	       real_old_git_dir[off] == real_new_git_dir[off])
>  		off++;
>  	fprintf(stderr, _("Migrating git directory of '%s%s' from '%s' to '%s'\n"),
> -		get_super_prefix_or_empty(), path,
> +		(super_prefix ? super_prefix : ""), path,
>  		real_old_git_dir + off, real_new_git_dir + off);


Which would make sites like these a bit cleaner.

Tangentially, 'default to "" if NULL' sounds like a common pattern. Is
there a good reason not to have a macro or inline function to do that?
e.g. we think the ternary expression is good enough?)

>  
>  	relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
> @@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)
>  	strbuf_release(&new_gitdir);
>  }
>  
> -static void absorb_git_dir_into_superproject_recurse(const char *path)
> +static void absorb_git_dir_into_superproject_recurse(const char *path,
> +						     const char *super_prefix)
>  {
>  
>  	struct child_process cp = CHILD_PROCESS_INIT;
> @@ -2321,10 +2323,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
>  	cp.dir = path;
>  	cp.git_cmd = 1;
>  	cp.no_stdin = 1;
> -	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
> -		     get_super_prefix_or_empty(), path);
>  	strvec_pushl(&cp.args, "submodule--helper",
>  		     "absorbgitdirs", NULL);
> +	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
> +		     super_prefix : "", path);
> +
>  	prepare_submodule_repo_env(&cp.env);
>  	if (run_command(&cp))
>  		die(_("could not recurse into submodule '%s'"), path);
> @@ -2335,7 +2338,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
>   * having its git directory within the working tree to the git dir nested
>   * in its superprojects git dir under modules/.
>   */
> -void absorb_git_dir_into_superproject(const char *path)
> +void absorb_git_dir_into_superproject_sp(const char *path,
> +					 const char *super_prefix)
>  {
>  	int err_code;
>  	const char *sub_git_dir;
> @@ -2377,14 +2381,14 @@ void absorb_git_dir_into_superproject(const char *path)
>  		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(path);
> +			relocate_single_git_dir_into_superproject(path, super_prefix);
>  
>  		free(real_sub_git_dir);
>  		free(real_common_git_dir);
>  	}
>  	strbuf_release(&gitdir);
>  
> -	absorb_git_dir_into_superproject_recurse(path);
> +	absorb_git_dir_into_superproject_recurse(path, super_prefix);
>  }
>  
>  int get_superproject_working_tree(struct strbuf *buf)
> diff --git a/submodule.h b/submodule.h
> index b52a4ff1e73..e5ee13fb06a 100644
> --- a/submodule.h
> +++ b/submodule.h
> @@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);
>   */
>  void prepare_submodule_repo_env(struct strvec *env);
>  
> -void absorb_git_dir_into_superproject(const char *path);
> +void absorb_git_dir_into_superproject_sp(const char *path,
> +					 const char *super_prefix);
> +static inline void absorb_git_dir_into_superproject(const char *path)
> +{
> +	absorb_git_dir_into_superproject_sp(path, NULL);
> +}

Is there a reason you chose to go with _sp() instead of changing the
original function signature? I tested out that change, and it seems
rather small (absorb_git_dir_into_superproject() only has 4 call sites).

Crucially, changing the signature catches a "git read-tree" call site:

  diff --git a/submodule.c b/submodule.c
  index d9fd0af81b..e79a04d3e3 100644
  --- a/submodule.c
  +++ b/submodule.c
  @@ -2139,7 +2139,9 @@ int submodule_move_head(const char *path,
          if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
                  if (old_head) {
                          if (!submodule_uses_gitfile(path))
  -                               absorb_git_dir_into_superproject(path);
  +                               /* Pass super_prefix properly later. */
  +                               absorb_git_dir_into_superproject(path,
  +                                                                get_super_prefix());
                  } else {
                          struct strbuf gitdir = STRBUF_INIT;
                          submodule_name_to_gitdir(&gitdir, the_repository,

which would otherwise be broken since we used to read the global super
prefix, but we don't do that in this patch. This has no test coverage
(bleh), but it shouldn't be too hard, something like:

  git init super &&
  cd super &&
  # Create an unabsorbed submodule right in the worktree
  git init sub &&
  test_commit -C sub "foo" &&
  git add sub &&
  git commit -m "Add submodule" &&
  test_commit "bar" &&
  # This should invoke "git read-tree" and absorb the git dir.
  # Or maybe we should invoke "git read-tree" directly?
  git checkout --recurse-submodules HEAD^ 2>err &&
  # Search for the shortened message
  grep "Migrating submodule sub from sub to .git/modules/...." err

>  /*
>   * Return the absolute path of the working tree of the superproject, which this
> diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
> index 4abc74db2bb..31526937d95 100755
> --- a/t/t7527-builtin-fsmonitor.sh
> +++ b/t/t7527-builtin-fsmonitor.sh
> @@ -866,30 +866,11 @@ test_expect_success 'submodule always visited' '
>  # the submodule, and someone does a `git submodule absorbgitdirs`
>  # in the super, Git will recursively invoke `git submodule--helper`
>  # to do the work and this may try to read the index.  This will
> -# try to start the daemon in the submodule *and* pass (either
> -# directly or via inheritance) the `--super-prefix` arg to the
> -# `git fsmonitor--daemon start` command inside the submodule.
> -# This causes a warning because fsmonitor--daemon does take that
> -# global arg (see the table in git.c)
> -#
> -# This causes a warning when trying to start the daemon that is
> -# somewhat confusing.  It does not seem to hurt anything because
> -# the fsmonitor code maps the query failure into a trivial response
> -# and does the work anyway.
> -#
> -# It would be nice to silence the warning, however.
> -
> -have_t2_error_event () {
> -	log=$1
> -	msg="fsmonitor--daemon doesnQt support --super-prefix" &&
> -
> -	tr '\047' Q <$1 | grep -e "$msg"
> -}
> +# try to start the daemon in the submodule.
>  
>  test_expect_success "stray submodule super-prefix warning" '
>  	test_when_finished "rm -rf super; \
> -			    rm -rf sub;   \
> -			    rm super-sub.trace" &&
> +			    rm -rf sub" &&
>  
>  	create_super super &&
>  	create_sub sub &&
> @@ -904,10 +885,12 @@ test_expect_success "stray submodule super-prefix warning" '
>  
>  	test_path_is_dir super/dir_1/dir_2/sub/.git &&
>  
> -	GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
> -		git -C super submodule absorbgitdirs &&
> -
> -	! have_t2_error_event super-sub.trace
> +	cat >expect <<-\EOF &&
> +	Migrating git directory of '\''dir_1/dir_2/sub'\'' from '\''dir_1/dir_2/sub/.git'\'' to '\''.git/modules/dir_1/dir_2/sub'\''
> +	EOF
> +	git -C super submodule absorbgitdirs >out 2>actual &&
> +	test_cmp expect actual &&
> +	test_must_be_empty out
>  '
>  
>  # On a case-insensitive file system, confirm that the daemon
> -- 
> 2.38.0.1471.ge4d8947e7aa

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 04/10] submodule--helper: convert "foreach" to its own "--super-prefix"
  2022-11-14 10:08     ` [PATCH v2 04/10] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-14 21:56       ` Glen Choo
  2022-11-17 18:14         ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-14 21:56 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> As with a preceding commit to convert "absorbgitdirs", we can convert
> "submodule--helper foreach" to use its own "--super-prefix", instead
> of relying on the global "--super-prefix" argument to "git"
> itself. See that earlier commit for the rationale and background.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  builtin/submodule--helper.c | 15 ++++++++++-----
>  1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index c4d5e029b37..989c75280af 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -396,7 +398,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
>  	struct foreach_cb info = FOREACH_CB_INIT;
>  	struct pathspec pathspec = { 0 };
>  	struct module_list list = MODULE_LIST_INIT;
> +	const char *super_prefix = NULL;
>  	struct option module_foreach_options[] = {
> +		OPT__SUPER_PREFIX(&super_prefix),
>  		OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
>  		OPT_BOOL(0, "recursive", &info.recursive,
>  			 N_("recurse into nested submodules")),
> @@ -417,6 +421,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
>  	info.argc = argc;
>  	info.argv = argv;
>  	info.prefix = prefix;
> +	info.super_prefix = super_prefix;

(Also applies to subsequent patches) Why don't we assign the super
prefix directly to the struct's field? e.g.

		OPT__SUPER_PREFIX(&info.super_prefix),

>  
>  	for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
>  

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 00/10] Get rid of "git --super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (9 preceding siblings ...)
  2022-11-14 10:08     ` [PATCH v2 10/10] fetch: rename "--submodule-prefix" to "--super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-14 21:59     ` Taylor Blau
  2022-11-14 23:20     ` Glen Choo
                       ` (2 subsequent siblings)
  13 siblings, 0 replies; 79+ messages in thread
From: Taylor Blau @ 2022-11-14 21:59 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Glen Choo, Taylor Blau, Robert Coup

On Mon, Nov 14, 2022 at 11:08:40AM +0100, Ævar Arnfjörð Bjarmason wrote:
> = Relation to other submissions
>
> This is a non-RFC version of my earlier RFC to get rid of
> "--super-prefix"[1], which itself was an alternate proposal to Glen's
> [2]. Per [3] he's agreed to go with this approach.

Thanks for working it out together, and for a clear summary of how this
series interacts with and depends on others in-flight.

Thanks,
Taylor

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 07/10] submodule--helper: convert "{update,clone}" to their own "--super-prefix"
  2022-11-14 10:08     ` [PATCH v2 07/10] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
@ 2022-11-14 22:04       ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-14 22:04 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 40939b0b18e..e13615eb939 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -131,13 +131,6 @@ static char *get_submodule_displaypath_sp(const char *path, const char *prefix,
>  	}
>  }
>  
> -static char *get_submodule_displaypath(const char *path, const char *prefix)
> -{
> -	const char *super_prefix = get_super_prefix();
> -
> -	return get_submodule_displaypath_sp(path, prefix, super_prefix);
> -}
> -

It feels a bit odd that the function we keep is the one with _sp,
especially since the "original" is gone. FWIW, I wouldn't mind if we
just changed the signature of get_submodule_displaypath() instead of
introducing the _sp helper.


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 08/10] submodule tests: test "git branch -t" output and stderr
  2022-11-14 10:08     ` [PATCH v2 08/10] submodule tests: test "git branch -t" output and stderr Ævar Arnfjörð Bjarmason
@ 2022-11-14 22:20       ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-14 22:20 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> The "git branch" command will currently make use of the
> "--super-prefix", as it will indirectly call submodule_move_head(),
> which will have access to the "--super-prefix".

I couldn't figure out how "git branch" ends up calling
submodule_move_head(), could you include the call chain?

I find it very odd because AFAICT we only call submodule_move_head()
when we are modifying the working tree (or checking if it is safe to
modify), and "git branch" shouldn't touch the working tree.

> The output could thus be affected by the "--super-prefix". Right now
> it isn't in this case, but let's exhaustively assert that that's the
> case by testing the output of all of these "git branch -t" commands.

It's reasonable to be worried if the output contained paths to the
working tree, but...

> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  t/lib-submodule-update.sh | 98 ++++++++++++++++++++++-----------------
>  1 file changed, 55 insertions(+), 43 deletions(-)
>
> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
> index 2d31fcfda1f..302d095ad9b 100644
> --- a/t/lib-submodule-update.sh
> +++ b/t/lib-submodule-update.sh
> @@ -245,6 +245,17 @@ reset_work_tree_to_interested () {
>  	git -C submodule_update/.git/modules/sub1 config submodule.sub2.url "bogus"
>  }
>  
> +test_branch_t_output () {
> +	local branchname="$1" &&
> +	local start_point="$2" &&
> +	cat >expect <<-EOF &&
> +	branch '$branchname' set up to track '$start_point'.
> +	EOF
> +	git branch -t "$branchname" "$start_point" >actual 2>err &&
> +	test_must_be_empty err &&
> +	test_cmp expect actual
> +}
> +

it looks like the output is based entirely on the ref store, which has
no reason to use the super prefix. Based on the commit message in
74866d7579 (git: make super-prefix option, 2016-10-07):

  When such a super-prefix is specified, the paths reported by Git
  are prefixed with it to make them relative to that directory "above".
  The paths given by the user on the command line
  (e.g. "git subcmd --output-file=path/to/a/file" and pathspecs) are taken
  relative to the directory "above" to match.

and the fact that the super prefix has never been used for anything
other than the working tree, I don't think this level of paranoia is
necessary.

>  # Test that the superproject contains the content according to commit "$1"
>  # (the work tree must match the index for everything but submodules but the
>  # index must exactly match the given commit including any submodule SHA-1s).
> @@ -323,7 +334,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to no_submodule &&
>  		(
>  			cd submodule_update &&
> -			git branch -t add_sub1 origin/add_sub1 &&
> +			test_branch_t_output add_sub1 origin/add_sub1 &&
>  			$command add_sub1 &&
>  			test_superproject_content origin/add_sub1 &&
>  			test_dir_is_empty sub1 &&
> @@ -345,7 +356,7 @@ test_submodule_switch_common () {
>  		(
>  			cd submodule_update &&
>  			mkdir sub1 &&
> -			git branch -t add_sub1 origin/add_sub1 &&
> +			test_branch_t_output add_sub1 origin/add_sub1 &&
>  			$command add_sub1 &&
>  			test_superproject_content origin/add_sub1 &&
>  			test_dir_is_empty sub1 &&
> @@ -360,7 +371,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to replace_sub1_with_file &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
> +			test_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&
>  			$command replace_file_with_sub1 &&
>  			test_superproject_content origin/replace_file_with_sub1 &&
>  			test_dir_is_empty sub1 &&
> @@ -384,7 +395,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to replace_sub1_with_directory &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
> +			test_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
>  			$command replace_directory_with_sub1 &&
>  			test_superproject_content origin/replace_directory_with_sub1 &&
>  			test_dir_is_empty sub1 &&
> @@ -406,7 +417,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t remove_sub1 origin/remove_sub1 &&
> +			test_branch_t_output remove_sub1 origin/remove_sub1 &&
>  			$command remove_sub1 &&
>  			test_superproject_content origin/remove_sub1 &&
>  			test_submodule_content sub1 origin/add_sub1
> @@ -418,7 +429,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t remove_sub1 origin/remove_sub1 &&
> +			test_branch_t_output remove_sub1 origin/remove_sub1 &&
>  			replace_gitfile_with_git_dir sub1 &&
>  			$command remove_sub1 &&
>  			test_superproject_content origin/remove_sub1 &&
> @@ -447,7 +458,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
> +			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
>  			$command replace_sub1_with_directory test_must_fail &&
>  			test_superproject_content origin/add_sub1 &&
>  			test_submodule_content sub1 origin/add_sub1
> @@ -459,7 +470,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
> +			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
>  			replace_gitfile_with_git_dir sub1 &&
>  			$command replace_sub1_with_directory test_must_fail &&
>  			test_superproject_content origin/add_sub1 &&
> @@ -474,7 +485,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
> +			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
>  			$command replace_sub1_with_file test_must_fail &&
>  			test_superproject_content origin/add_sub1 &&
>  			test_submodule_content sub1 origin/add_sub1
> @@ -487,7 +498,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
> +			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
>  			replace_gitfile_with_git_dir sub1 &&
>  			$command replace_sub1_with_file test_must_fail &&
>  			test_superproject_content origin/add_sub1 &&
> @@ -512,7 +523,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t modify_sub1 origin/modify_sub1 &&
> +			test_branch_t_output modify_sub1 origin/modify_sub1 &&
>  			$command modify_sub1 &&
>  			test_superproject_content origin/modify_sub1 &&
>  			test_submodule_content sub1 origin/add_sub1 &&
> @@ -527,7 +538,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t invalid_sub1 origin/invalid_sub1 &&
> +			test_branch_t_output invalid_sub1 origin/invalid_sub1 &&
>  			$command invalid_sub1 &&
>  			test_superproject_content origin/invalid_sub1 &&
>  			test_submodule_content sub1 origin/add_sub1 &&
> @@ -542,7 +553,7 @@ test_submodule_switch_common () {
>  		reset_work_tree_to invalid_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t valid_sub1 origin/valid_sub1 &&
> +			test_branch_t_output valid_sub1 origin/valid_sub1 &&
>  			$command valid_sub1 &&
>  			test_superproject_content origin/valid_sub1 &&
>  			test_dir_is_empty sub1 &&
> @@ -596,7 +607,7 @@ test_submodule_switch_func () {
>  		reset_work_tree_to no_submodule &&
>  		(
>  			cd submodule_update &&
> -			git branch -t add_sub1 origin/add_sub1 &&
> +			test_branch_t_output add_sub1 origin/add_sub1 &&
>  			>sub1 &&
>  			$command add_sub1 test_must_fail &&
>  			test_superproject_content origin/no_submodule &&
> @@ -635,7 +646,7 @@ test_submodule_forced_switch () {
>  		reset_work_tree_to no_submodule &&
>  		(
>  			cd submodule_update &&
> -			git branch -t add_sub1 origin/add_sub1 &&
> +			test_branch_t_output add_sub1 origin/add_sub1 &&
>  			>sub1 &&
>  			$command add_sub1 &&
>  			test_superproject_content origin/add_sub1 &&
> @@ -675,7 +686,7 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested no_submodule &&
>  		(
>  			cd submodule_update &&
> -			git branch -t add_sub1 origin/add_sub1 &&
> +			test_branch_t_output add_sub1 origin/add_sub1 &&
>  			$command add_sub1 &&
>  			test_superproject_content origin/add_sub1 &&
>  			test_submodule_content sub1 origin/add_sub1
> @@ -688,7 +699,7 @@ test_submodule_recursing_with_args_common () {
>  		(
>  			cd submodule_update &&
>  			mkdir sub1 &&
> -			git branch -t add_sub1 origin/add_sub1 &&
> +			test_branch_t_output add_sub1 origin/add_sub1 &&
>  			$command add_sub1 &&
>  			test_superproject_content origin/add_sub1 &&
>  			test_submodule_content sub1 origin/add_sub1
> @@ -701,7 +712,7 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested replace_sub1_with_file &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
> +			test_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&
>  			$command replace_file_with_sub1 &&
>  			test_superproject_content origin/replace_file_with_sub1 &&
>  			test_submodule_content sub1 origin/replace_file_with_sub1
> @@ -713,19 +724,20 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested replace_sub1_with_directory &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
> +			test_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
>  			$command replace_directory_with_sub1 &&
>  			test_superproject_content origin/replace_directory_with_sub1 &&
>  			test_submodule_content sub1 origin/replace_directory_with_sub1
>  		)
>  	'
> +
>  	# Switching to a commit with nested submodules recursively checks them out
>  	test_expect_success "$command: nested submodules are checked out" '
>  		prolog &&
>  		reset_work_tree_to_interested no_submodule &&
>  		(
>  			cd submodule_update &&
> -			git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
> +			test_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&
>  			$command modify_sub1_recursively &&
>  			test_superproject_content origin/modify_sub1_recursively &&
>  			test_submodule_content sub1 origin/modify_sub1_recursively &&
> @@ -740,7 +752,7 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t remove_sub1 origin/remove_sub1 &&
> +			test_branch_t_output remove_sub1 origin/remove_sub1 &&
>  			$command remove_sub1 &&
>  			test_superproject_content origin/remove_sub1 &&
>  			! test -e sub1 &&
> @@ -753,7 +765,7 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t remove_sub1 origin/remove_sub1 &&
> +			test_branch_t_output remove_sub1 origin/remove_sub1 &&
>  			replace_gitfile_with_git_dir sub1 &&
>  			rm -rf .git/modules &&
>  			$command remove_sub1 &&
> @@ -769,7 +781,7 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
> +			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
>  			$command replace_sub1_with_file &&
>  			test_superproject_content origin/replace_sub1_with_file &&
>  			test -f sub1
> @@ -786,7 +798,7 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
> +			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
>  			: >sub1/untrackedfile &&
>  			test_must_fail $command replace_sub1_with_file &&
>  			test_superproject_content origin/add_sub1 &&
> @@ -801,7 +813,7 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested add_nested_sub &&
>  		(
>  			cd submodule_update &&
> -			git branch -t no_submodule origin/no_submodule &&
> +			test_branch_t_output no_submodule origin/no_submodule &&
>  			$command no_submodule &&
>  			test_superproject_content origin/no_submodule &&
>  			! test_path_is_dir sub1 &&
> @@ -817,7 +829,7 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t modify_sub1 origin/modify_sub1 &&
> +			test_branch_t_output modify_sub1 origin/modify_sub1 &&
>  			$command modify_sub1 &&
>  			test_superproject_content origin/modify_sub1 &&
>  			test_submodule_content sub1 origin/modify_sub1
> @@ -830,7 +842,7 @@ test_submodule_recursing_with_args_common () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t invalid_sub1 origin/invalid_sub1 &&
> +			test_branch_t_output invalid_sub1 origin/invalid_sub1 &&
>  			test_must_fail $command invalid_sub1 2>err &&
>  			test_i18ngrep sub1 err &&
>  			test_superproject_content origin/add_sub1 &&
> @@ -844,13 +856,13 @@ test_submodule_recursing_with_args_common () {
>  		(
>  			cd submodule_update &&
>  			git -C sub1 checkout -b keep_branch &&
> -			git -C sub1 rev-parse HEAD >expect &&
> -			git branch -t modify_sub1 origin/modify_sub1 &&
> +			git -C sub1 rev-parse HEAD >expect.rev-parse &&
> +			test_branch_t_output modify_sub1 origin/modify_sub1 &&
>  			$command modify_sub1 &&
>  			test_superproject_content origin/modify_sub1 &&
>  			test_submodule_content sub1 origin/modify_sub1 &&
>  			git -C sub1 rev-parse keep_branch >actual &&
> -			test_cmp expect actual &&
> +			test_cmp expect.rev-parse actual &&
>  			test_must_fail git -C sub1 symbolic-ref HEAD
>  		)
>  	'
> @@ -894,7 +906,7 @@ test_submodule_switch_recursing_with_args () {
>  		reset_work_tree_to_interested no_submodule &&
>  		(
>  			cd submodule_update &&
> -			git branch -t add_sub1 origin/add_sub1 &&
> +			test_branch_t_output add_sub1 origin/add_sub1 &&
>  			: >sub1 &&
>  			test_must_fail $command add_sub1 &&
>  			test_superproject_content origin/no_submodule &&
> @@ -908,7 +920,7 @@ test_submodule_switch_recursing_with_args () {
>  		reset_work_tree_to_interested no_submodule &&
>  		(
>  			cd submodule_update &&
> -			git branch -t add_sub1 origin/add_sub1 &&
> +			test_branch_t_output add_sub1 origin/add_sub1 &&
>  			: >sub1 &&
>  			mkdir .git/info &&
>  			echo sub1 >.git/info/exclude &&
> @@ -925,7 +937,7 @@ test_submodule_switch_recursing_with_args () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
> +			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
>  			$command replace_sub1_with_directory &&
>  			test_superproject_content origin/replace_sub1_with_directory &&
>  			test_submodule_content sub1 origin/replace_sub1_with_directory
> @@ -937,7 +949,7 @@ test_submodule_switch_recursing_with_args () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
> +			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
>  			replace_gitfile_with_git_dir sub1 &&
>  			rm -rf .git/modules &&
>  			$command replace_sub1_with_directory &&
> @@ -954,7 +966,7 @@ test_submodule_switch_recursing_with_args () {
>  		(
>  			cd submodule_update &&
>  			rm -rf .git/modules/sub1/info &&
> -			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
> +			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
>  			mkdir .git/modules/sub1/info &&
>  			echo ignored >.git/modules/sub1/info/exclude &&
>  			: >sub1/ignored &&
> @@ -969,7 +981,7 @@ test_submodule_switch_recursing_with_args () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t modify_sub1 origin/modify_sub1 &&
> +			test_branch_t_output modify_sub1 origin/modify_sub1 &&
>  			git -c submodule.recurse=true $cmd_args modify_sub1 &&
>  			test_superproject_content origin/modify_sub1 &&
>  			test_submodule_content sub1 origin/modify_sub1
> @@ -981,7 +993,7 @@ test_submodule_switch_recursing_with_args () {
>  		reset_work_tree_to_interested add_nested_sub &&
>  		(
>  			cd submodule_update &&
> -			git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
> +			test_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&
>  			$command modify_sub1_recursively &&
>  			test_superproject_content origin/modify_sub1_recursively &&
>  			test_submodule_content sub1 origin/modify_sub1_recursively &&
> @@ -1009,7 +1021,7 @@ test_submodule_forced_switch_recursing_with_args () {
>  		reset_work_tree_to_interested no_submodule &&
>  		(
>  			cd submodule_update &&
> -			git branch -t add_sub1 origin/add_sub1 &&
> +			test_branch_t_output add_sub1 origin/add_sub1 &&
>  			>sub1 &&
>  			$command add_sub1 &&
>  			test_superproject_content origin/add_sub1 &&
> @@ -1023,7 +1035,7 @@ test_submodule_forced_switch_recursing_with_args () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
> +			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
>  			$command replace_sub1_with_directory &&
>  			test_superproject_content origin/replace_sub1_with_directory
>  		)
> @@ -1034,7 +1046,7 @@ test_submodule_forced_switch_recursing_with_args () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
> +			test_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&
>  			replace_gitfile_with_git_dir sub1 &&
>  			rm -rf .git/modules/sub1 &&
>  			$command replace_sub1_with_directory &&
> @@ -1049,7 +1061,7 @@ test_submodule_forced_switch_recursing_with_args () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
> +			test_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&
>  			: >sub1/expect &&
>  			$command replace_sub1_with_file &&
>  			test_superproject_content origin/replace_sub1_with_file
> @@ -1062,7 +1074,7 @@ test_submodule_forced_switch_recursing_with_args () {
>  		reset_work_tree_to_interested invalid_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t valid_sub1 origin/valid_sub1 &&
> +			test_branch_t_output valid_sub1 origin/valid_sub1 &&
>  			$command valid_sub1 &&
>  			test_superproject_content origin/valid_sub1 &&
>  			test_submodule_content sub1 origin/valid_sub1
> @@ -1077,7 +1089,7 @@ test_submodule_forced_switch_recursing_with_args () {
>  		reset_work_tree_to_interested add_sub1 &&
>  		(
>  			cd submodule_update &&
> -			git branch -t modify_sub1 origin/modify_sub1 &&
> +			test_branch_t_output modify_sub1 origin/modify_sub1 &&
>  			echo "gitdir: bogus/path" >sub1/.git &&
>  			$command modify_sub1 &&
>  			test_superproject_content origin/modify_sub1 &&
> -- 
> 2.38.0.1471.ge4d8947e7aa

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 09/10] read-tree: add "--super-prefix" option, eliminate global
  2022-11-14 10:08     ` [PATCH v2 09/10] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
@ 2022-11-14 22:28       ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-14 22:28 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> The "--super-prefix" option to "git" was initially added in [1] for
> use with "ls-files"[2], and shortly thereafter "submodule--helper"[3]
> and "grep"[4]. It wasn't until [5] that "read-tree" made use of it.
>
> At the time [5] made sense, but since then we've made "ls-files"
> recurse in-process in [6], "grep" in [7], and finally
> "submodule--helper" in the preceding commits.
>
> Let's also remove it from "read-tree", which allows us to remove the
> option to "git" itself.
>
> We can do this because the only remaining user of it is the submodule
> API, which will now invoke "read-tree" with its new "--super-prefix"
> option. It will only do so when the "submodule_move_head()" function
> is called.
>
> That "submodule_move_head()" function was then only invoked by
> "read-tree" itself, but now rather than setting an environment
> variable to pass "--super-prefix" between cmd_read_tree() we:
>
> - Set a new "super_prefix" in "struct unpack_trees_options". The
>   "super_prefixed()" function in "unpack-trees.c" added in [5] will now
>   use this, rather than get_super_prefix() looking up the environment
>   variable we set earlier in the same process.
>
> - Add the same field to the "struct checkout", which is only needed to
>   ferry the "super_prefix" in the "struct unpack_trees_options" all the
>   way down to the "entry.c" callers of "submodule_move_head()".
>
>   Those calls which used the super prefix all originated in
>   "cmd_read_tree()". The only other caller is the "unlink_entry()"
>   caller in "builtin/checkout.c", which now passes a "NULL".
>
> 1. 74866d75793 (git: make super-prefix option, 2016-10-07)
> 2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)
> 3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)
> 4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)
> 5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)
> 6. 188dce131fa (ls-files: use repository object, 2017-06-22)
> 7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  Documentation/git.txt       |  8 +-------
>  builtin.h                   |  4 ----
>  builtin/checkout.c          |  2 +-
>  builtin/read-tree.c         |  1 +
>  cache.h                     |  2 --
>  entry.c                     | 12 ++++++------
>  entry.h                     |  6 +++++-
>  environment.c               | 13 -------------
>  git.c                       | 37 +++++--------------------------------
>  submodule.c                 | 27 +++++++++------------------
>  submodule.h                 |  5 ++---
>  t/t1001-read-tree-m-2way.sh |  2 +-
>  t/t5616-partial-clone.sh    |  2 +-
>  unpack-trees.c              | 23 +++++++++++++----------
>  unpack-trees.h              |  1 +
>  15 files changed, 46 insertions(+), 99 deletions(-)
>
> diff --git a/Documentation/git.txt b/Documentation/git.txt
> index 1d33e083ab8..f9a7a4554cd 100644
> --- a/Documentation/git.txt
> +++ b/Documentation/git.txt
> @@ -13,8 +13,7 @@ SYNOPSIS
>      [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
>      [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
>      [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
> -    [--super-prefix=<path>] [--config-env=<name>=<envvar>]
> -    <command> [<args>]
> +    [--config-env=<name>=<envvar>] <command> [<args>]
>  
>  DESCRIPTION
>  -----------
> @@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use
>  	details.  Equivalent to setting the `GIT_NAMESPACE` environment
>  	variable.
>  
> ---super-prefix=<path>::
> -	Currently for internal use only.  Set a prefix which gives a path from
> -	above a repository down to its root.  One use is to give submodules
> -	context about the superproject that invoked it.
> -
>  --bare::
>  	Treat the repository as a bare repository.  If GIT_DIR
>  	environment is not set, it is set to the current working
> diff --git a/builtin.h b/builtin.h
> index 8901a34d6bf..8264b7e5241 100644
> --- a/builtin.h
> +++ b/builtin.h
> @@ -51,10 +51,6 @@
>   *	on bare repositories.
>   *	This only makes sense when `RUN_SETUP` is also set.
>   *
> - * `SUPPORT_SUPER_PREFIX`:
> - *
> - *	The built-in supports `--super-prefix`.
> - *
>   * `DELAY_PAGER_CONFIG`:
>   *
>   *	If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
> diff --git a/builtin/checkout.c b/builtin/checkout.c
> index 2a132392fbe..dc008fb45e8 100644
> --- a/builtin/checkout.c
> +++ b/builtin/checkout.c
> @@ -231,7 +231,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
>  		pos++;
>  	}
>  	if (!overlay_mode) {
> -		unlink_entry(ce);
> +		unlink_entry(ce, NULL);
>  		return 0;
>  	}
>  	if (stage == 2)
> diff --git a/builtin/read-tree.c b/builtin/read-tree.c
> index f4cbe460b97..4b6f22e58c1 100644
> --- a/builtin/read-tree.c
> +++ b/builtin/read-tree.c
> @@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
>  	int prefix_set = 0;
>  	struct lock_file lock_file = LOCK_INIT;
>  	const struct option read_tree_options[] = {
> +		OPT__SUPER_PREFIX(&opts.super_prefix),
>  		OPT_CALLBACK_F(0, "index-output", NULL, N_("file"),
>  		  N_("write resulting index to <file>"),
>  		  PARSE_OPT_NONEG, index_output_cb),
> diff --git a/cache.h b/cache.h
> index 26ed03bd6de..a4a0377b800 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)
>  #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
>  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
>  #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
> -#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
>  #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
>  #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
>  #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
> @@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
>  int get_common_dir(struct strbuf *sb, const char *gitdir);
>  const char *get_git_namespace(void);
>  const char *strip_namespace(const char *namespaced_ref);
> -const char *get_super_prefix(void);
>  const char *get_git_work_tree(void);
>  
>  /*
> diff --git a/entry.c b/entry.c
> index 616e4f073c1..971ab268714 100644
> --- a/entry.c
> +++ b/entry.c
> @@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
>  			return error("cannot create submodule directory %s", path);
>  		sub = submodule_from_ce(ce);
>  		if (sub)
> -			return submodule_move_head(ce->name,
> +			return submodule_move_head(ce->name, state->super_prefix,
>  				NULL, oid_to_hex(&ce->oid),
>  				state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
>  		break;
> @@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
>  			 * no pathname to return.
>  			 */
>  			BUG("Can't remove entry to a path");
> -		unlink_entry(ce);
> +		unlink_entry(ce, state->super_prefix);
>  		return 0;
>  	}
>  
> @@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
>  				if (!(st.st_mode & S_IFDIR))
>  					unlink_or_warn(ce->name);
>  
> -				return submodule_move_head(ce->name,
> +				return submodule_move_head(ce->name, state->super_prefix,
>  					NULL, oid_to_hex(&ce->oid), 0);
>  			} else
> -				return submodule_move_head(ce->name,
> +				return submodule_move_head(ce->name, state->super_prefix,
>  					"HEAD", oid_to_hex(&ce->oid),
>  					state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
>  		}
> @@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
>  	return write_entry(ce, path.buf, ca, state, 0, nr_checkouts);
>  }
>  
> -void unlink_entry(const struct cache_entry *ce)
> +void unlink_entry(const struct cache_entry *ce, const char *super_prefix)
>  {
>  	const struct submodule *sub = submodule_from_ce(ce);
>  	if (sub) {
>  		/* state.force is set at the caller. */
> -		submodule_move_head(ce->name, "HEAD", NULL,
> +		submodule_move_head(ce->name, super_prefix, "HEAD", NULL,
>  				    SUBMODULE_MOVE_HEAD_FORCE);
>  	}
>  	if (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)
> diff --git a/entry.h b/entry.h
> index 9be4659881e..2d4fbb88c8f 100644
> --- a/entry.h
> +++ b/entry.h
> @@ -8,6 +8,7 @@ struct checkout {
>  	struct index_state *istate;
>  	const char *base_dir;
>  	int base_dir_len;
> +	const char *super_prefix;
>  	struct delayed_checkout *delayed_checkout;
>  	struct checkout_metadata meta;
>  	unsigned force:1,
> @@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);
>  /*
>   * Unlink the last component and schedule the leading directories for
>   * removal, such that empty directories get removed.
> + *
> + * The "super_prefix" is either NULL, or the "--super-prefix" passed
> + * down from "read-tree" et al.
>   */
> -void unlink_entry(const struct cache_entry *ce);
> +void unlink_entry(const struct cache_entry *ce, const char *super_prefix);
>  
>  void *read_blob_entry(const struct cache_entry *ce, size_t *size);
>  int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);
> diff --git a/environment.c b/environment.c
> index 18d042b467d..1ee3686fd8a 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -102,8 +102,6 @@ char *git_work_tree_cfg;
>  
>  static char *git_namespace;
>  
> -static char *super_prefix;
> -
>  /*
>   * Repository-local GIT_* environment variables; see cache.h for details.
>   */
> @@ -121,7 +119,6 @@ const char * const local_repo_env[] = {
>  	NO_REPLACE_OBJECTS_ENVIRONMENT,
>  	GIT_REPLACE_REF_BASE_ENVIRONMENT,
>  	GIT_PREFIX_ENVIRONMENT,
> -	GIT_SUPER_PREFIX_ENVIRONMENT,
>  	GIT_SHALLOW_FILE_ENVIRONMENT,
>  	GIT_COMMON_DIR_ENVIRONMENT,
>  	NULL
> @@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)
>  	return NULL;
>  }
>  
> -const char *get_super_prefix(void)
> -{
> -	static int initialized;
> -	if (!initialized) {
> -		super_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));
> -		initialized = 1;
> -	}
> -	return super_prefix;
> -}
> -
>  static int git_work_tree_initialized;
>  
>  /*
> diff --git a/git.c b/git.c
> index 2bca22cfd9a..00baaf23590 100644
> --- a/git.c
> +++ b/git.c
> @@ -14,9 +14,8 @@
>   * RUN_SETUP for reading from the configuration file.
>   */
>  #define NEED_WORK_TREE		(1<<3)
> -#define SUPPORT_SUPER_PREFIX	(1<<4)
> -#define DELAY_PAGER_CONFIG	(1<<5)
> -#define NO_PARSEOPT		(1<<6) /* parse-options is not used */
> +#define DELAY_PAGER_CONFIG	(1<<4)
> +#define NO_PARSEOPT		(1<<5) /* parse-options is not used */
>  
>  struct cmd_struct {
>  	const char *cmd;
> @@ -29,8 +28,7 @@ const char git_usage_string[] =
>  	   "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
>  	   "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
>  	   "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
> -	   "           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
> -	   "           <command> [<args>]");
> +	   "           [--config-env=<name>=<envvar>] <command> [<args>]");
>  
>  const char git_more_info_string[] =
>  	N_("'git help -a' and 'git help -g' list available subcommands and some\n"
> @@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
>  			setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
>  			if (envchanged)
>  				*envchanged = 1;
> -		} else if (!strcmp(cmd, "--super-prefix")) {
> -			if (*argc < 2) {
> -				fprintf(stderr, _("no prefix given for --super-prefix\n" ));
> -				usage(git_usage_string);
> -			}
> -			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
> -			if (envchanged)
> -				*envchanged = 1;
> -			(*argv)++;
> -			(*argc)--;
> -		} else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
> -			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
> -			if (envchanged)
> -				*envchanged = 1;
>  		} else if (!strcmp(cmd, "--bare")) {
>  			char *cwd = xgetcwd();
>  			is_bare_repository_cfg = 1;
> @@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
>  		trace_repo_setup(prefix);
>  	commit_pager_choice();
>  
> -	if (!help && get_super_prefix()) {
> -		if (!(p->option & SUPPORT_SUPER_PREFIX))
> -			die(_("%s doesn't support --super-prefix"), p->cmd);
> -	}
> -
>  	if (!help && p->option & NEED_WORK_TREE)
>  		setup_work_tree();
>  
> @@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {
>  	{ "check-ref-format", cmd_check_ref_format, NO_PARSEOPT  },
>  	{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
>  	{ "checkout--worker", cmd_checkout__worker,
> -		RUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },
> +		RUN_SETUP | NEED_WORK_TREE },
>  	{ "checkout-index", cmd_checkout_index,
>  		RUN_SETUP | NEED_WORK_TREE},
>  	{ "cherry", cmd_cherry, RUN_SETUP },
> @@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {
>  	{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
>  	{ "push", cmd_push, RUN_SETUP },
>  	{ "range-diff", cmd_range_diff, RUN_SETUP | USE_PAGER },
> -	{ "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
> +	{ "read-tree", cmd_read_tree, RUN_SETUP },
>  	{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
>  	{ "receive-pack", cmd_receive_pack },
>  	{ "reflog", cmd_reflog, RUN_SETUP },
> @@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)
>  	struct child_process cmd = CHILD_PROCESS_INIT;
>  	int status;
>  
> -	if (get_super_prefix())
> -		die(_("%s doesn't support --super-prefix"), argv[0]);
> -
>  	if (use_pager == -1 && !is_builtin(argv[0]))
>  		use_pager = check_pager_config(argv[0]);
>  	commit_pager_choice();
> @@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)
>  			 */
>  			trace2_cmd_name("_run_git_alias_");
>  
> -			if (get_super_prefix())
> -				die("%s doesn't support --super-prefix", **argv);
> -
>  			commit_pager_choice();
>  
>  			strvec_push(&cmd.args, "git");
> diff --git a/submodule.c b/submodule.c
> index d9fd0af81b6..5ac4e1b0568 100644
> --- a/submodule.c
> +++ b/submodule.c
> @@ -2048,14 +2048,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)
>  	strbuf_release(&config_path);
>  }
>  
> -static const char *get_super_prefix_or_empty(void)
> -{
> -	const char *s = get_super_prefix();
> -	if (!s)
> -		s = "";
> -	return s;
> -}
> -
>  static int submodule_has_dirty_index(const struct submodule *sub)
>  {
>  	struct child_process cp = CHILD_PROCESS_INIT;
> @@ -2074,7 +2066,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)
>  	return finish_command(&cp);
>  }
>  
> -static void submodule_reset_index(const char *path)
> +static void submodule_reset_index(const char *path, const char *super_prefix)
>  {
>  	struct child_process cp = CHILD_PROCESS_INIT;
>  	prepare_submodule_repo_env(&cp.env);
> @@ -2083,10 +2075,10 @@ static void submodule_reset_index(const char *path)
>  	cp.no_stdin = 1;
>  	cp.dir = path;
>  
> -	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
> -		     get_super_prefix_or_empty(), path);
>  	/* TODO: determine if this might overwright untracked files */
>  	strvec_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
> +	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
> +		     (super_prefix ? super_prefix : ""), path);
>  
>  	strvec_push(&cp.args, empty_tree_oid_hex());
>  
> @@ -2099,10 +2091,9 @@ static void submodule_reset_index(const char *path)
>   * For edge cases (a submodule coming into existence or removing a submodule)
>   * pass NULL for old or new respectively.
>   */
> -int submodule_move_head(const char *path,
> -			 const char *old_head,
> -			 const char *new_head,
> -			 unsigned flags)
> +int submodule_move_head(const char *path, const char *super_prefix,
> +			const char *old_head, const char *new_head,
> +			unsigned flags)
>  {
>  	int ret = 0;
>  	struct child_process cp = CHILD_PROCESS_INIT;
> @@ -2148,7 +2139,7 @@ int submodule_move_head(const char *path,
>  			strbuf_release(&gitdir);
>  
>  			/* make sure the index is clean as well */
> -			submodule_reset_index(path);
> +			submodule_reset_index(path, NULL);

Shouldn't we be passing the super prefix? i.e.

  submodule_reset_index(path, super_prefix)

>  		}
>  
>  		if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
> @@ -2166,9 +2157,9 @@ int submodule_move_head(const char *path,
>  	cp.no_stdin = 1;
>  	cp.dir = path;
>  
> -	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
> -		     get_super_prefix_or_empty(), path);
>  	strvec_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
> +	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
> +		     (super_prefix ? super_prefix : ""), path);
>  
>  	if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
>  		strvec_push(&cp.args, "-n");
> diff --git a/submodule.h b/submodule.h
> index e5ee13fb06a..36a7f7c5b32 100644
> --- a/submodule.h
> +++ b/submodule.h
> @@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);
>  
>  #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)
>  #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)
> -int submodule_move_head(const char *path,
> -			const char *old,
> -			const char *new_head,
> +int submodule_move_head(const char *path, const char *super_prefix,
> +			const char *old_head, const char *new_head,
>  			unsigned flags);
>  
>  void submodule_unset_core_worktree(const struct submodule *sub);
> diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
> index 516a6112fdc..3fb1b0c162d 100755
> --- a/t/t1001-read-tree-m-2way.sh
> +++ b/t/t1001-read-tree-m-2way.sh
> @@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '
>  	cat <<-EOF >expect &&
>  		error: Updating '\''fictional/a'\'' would lose untracked files in it
>  	EOF
> -	test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual &&
> +	test_must_fail git read-tree --super-prefix fictional/ -u -m "$treeH" "$treeM" 2>actual &&
>  	test_cmp expect actual
>  '
>  
> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
> index e56466580cf..18375bff535 100755
> --- a/t/t5616-partial-clone.sh
> +++ b/t/t5616-partial-clone.sh
> @@ -644,7 +644,7 @@ test_expect_success 'repack does not loosen promisor objects' '
>  	grep "loosen_unused_packed_objects/loosened:0" trace
>  '
>  
> -test_expect_failure 'lazy-fetch in submodule succeeds' '
> +test_expect_success 'lazy-fetch in submodule succeeds' '
>  	# setup
>  	test_config_global protocol.file.allow always &&
>  
> diff --git a/unpack-trees.c b/unpack-trees.c
> index bae812156c4..61c02285454 100644
> --- a/unpack-trees.c
> +++ b/unpack-trees.c
> @@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
>  	  ? ((o)->msgs[(type)])      \
>  	  : (unpack_plumbing_errors[(type)]) )
>  
> -static const char *super_prefixed(const char *path)
> +static const char *super_prefixed(const char *path, const char *super_prefix)
>  {
>  	/*
>  	 * It is necessary and sufficient to have two static buffers
> @@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)
>  	static unsigned idx = ARRAY_SIZE(buf) - 1;
>  
>  	if (super_prefix_len < 0) {
> -		const char *super_prefix = get_super_prefix();
>  		if (!super_prefix) {
>  			super_prefix_len = 0;
>  		} else {
> @@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,
>  		return -1;
>  
>  	if (!o->show_all_errors)
> -		return error(ERRORMSG(o, e), super_prefixed(path));
> +		return error(ERRORMSG(o, e), super_prefixed(path,
> +							    o->super_prefix));
>  
>  	/*
>  	 * Otherwise, insert in a list for future display by
> @@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)
>  			error_displayed = 1;
>  			for (i = 0; i < rejects->nr; i++)
>  				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
> -			error(ERRORMSG(o, e), super_prefixed(path.buf));
> +			error(ERRORMSG(o, e), super_prefixed(path.buf,
> +							     o->super_prefix));
>  			strbuf_release(&path);
>  		}
>  		string_list_clear(rejects, 0);
> @@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)
>  			warning_displayed = 1;
>  			for (i = 0; i < rejects->nr; i++)
>  				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
> -			warning(ERRORMSG(o, e), super_prefixed(path.buf));
> +			warning(ERRORMSG(o, e), super_prefixed(path.buf,
> +							       o->super_prefix));
>  			strbuf_release(&path);
>  		}
>  		string_list_clear(rejects, 0);
> @@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,
>  	if (o->reset)
>  		flags |= SUBMODULE_MOVE_HEAD_FORCE;
>  
> -	if (submodule_move_head(ce->name, old_id, new_id, flags))
> +	if (submodule_move_head(ce->name, NULL, old_id, new_id, flags))

Similarly, shouldn't this be

  - submodule_move_head(ce->name, NULL, old_id, new_id, flags)
  + submodule_move_head(ce->name, o->super_prefix, old_id, new_id, flags)

>  		return add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
>  	return 0;
>  }
> @@ -415,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,
>  	int i, pc_workers, pc_threshold;
>  
>  	trace_performance_enter();
> +	state.super_prefix = o->super_prefix;
>  	state.force = 1;
>  	state.quiet = 1;
>  	state.refresh_cache = 1;
> @@ -445,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,
>  
>  		if (ce->ce_flags & CE_WT_REMOVE) {
>  			display_progress(progress, ++cnt);
> -			unlink_entry(ce);
> +			unlink_entry(ce, o->super_prefix);
>  		}
>  	}
>  
> @@ -2958,8 +2961,8 @@ int bind_merge(const struct cache_entry * const *src,
>  	if (a && old)
>  		return o->quiet ? -1 :
>  			error(ERRORMSG(o, ERROR_BIND_OVERLAP),
> -			      super_prefixed(a->name),
> -			      super_prefixed(old->name));
> +			      super_prefixed(a->name, o->super_prefix),
> +			      super_prefixed(old->name, o->super_prefix));
>  	if (!a)
>  		return keep_entry(old, o);
>  	else
> @@ -3020,7 +3023,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,
>  
>  	if (worktree && untracked)
>  		return error(_("worktree and untracked commit have duplicate entries: %s"),
> -			     super_prefixed(worktree->name));
> +			     super_prefixed(worktree->name, o->super_prefix));
>  
>  	return merged_entry(worktree ? worktree : untracked, NULL, o);
>  }
> diff --git a/unpack-trees.h b/unpack-trees.h
> index efb9edfbb27..9b81e284073 100644
> --- a/unpack-trees.h
> +++ b/unpack-trees.h
> @@ -74,6 +74,7 @@ struct unpack_trees_options {
>  		     dry_run;
>  	enum unpack_trees_reset_type reset;
>  	const char *prefix;
> +	const char *super_prefix;
>  	int cache_bottom;
>  	struct pathspec *pathspec;
>  	merge_fn_t fn;
> -- 
> 2.38.0.1471.ge4d8947e7aa

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 10/10] fetch: rename "--submodule-prefix" to "--super-prefix"
  2022-11-14 10:08     ` [PATCH v2 10/10] fetch: rename "--submodule-prefix" to "--super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-14 22:31       ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-14 22:31 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Thanks for picking this up, especially since you feel "meh" about it :)

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> In preceding commits we've introduced a command-level "--super-prefix"
> option, which unlike the "git --super-prefix" it replaced doesn't rely
> on setenv() or getenv(), it's just a normal command-line option that
> the command passes down.
>
> Since we've done that, let's rename the "--submodule-prefix" option
> added in 7dce19d374a (fetch/pull: Add the --recurse-submodules option,
> 2010-11-12) to "--super-prefix" for consistency. This:
>
>  * Allows us to use OPT__SUPER_PREFIX().
>  * Leaves an unspecified "--super-prefix" with a "NULL" value, rather
>    than an empty string, as is the case with the other "--super-prefix"
>    users. We coerce the NULL to "" in submodule.c before using it.

[...]

>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  Documentation/fetch-options.txt |  5 -----
>  builtin/fetch.c                 |  7 +++----
>  submodule.c                     | 23 +++++++++++------------
>  3 files changed, 14 insertions(+), 21 deletions(-)
>
> diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
> index 622bd84768b..20cbd2c2910 100644
> --- a/Documentation/fetch-options.txt
> +++ b/Documentation/fetch-options.txt
> @@ -241,11 +241,6 @@ endif::git-pull[]
>  	linkgit:git-config[1].
>  
>  ifndef::git-pull[]
> ---submodule-prefix=<path>::
> -	Prepend <path> to paths printed in informative messages
> -	such as "Fetching submodule foo".  This option is used
> -	internally when recursing over submodules.
> -
>  --recurse-submodules-default=[yes|on-demand]::
>  	This option is used internally to temporarily provide a
>  	non-negative default value for the --recurse-submodules
> diff --git a/builtin/fetch.c b/builtin/fetch.c
> index 7378cafeec9..353bcd36d24 100644
> --- a/builtin/fetch.c
> +++ b/builtin/fetch.c
> @@ -74,7 +74,7 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
>  static struct strbuf default_rla = STRBUF_INIT;
>  static struct transport *gtransport;
>  static struct transport *gsecondary;
> -static const char *submodule_prefix = "";
> +static const char *super_prefix;

Is there a reason we can't keep the '= ""'?

>  static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
>  static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
>  static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
> @@ -195,8 +195,7 @@ static struct option builtin_fetch_options[] = {
>  	OPT_SET_INT_F(0, "refetch", &refetch,
>  		      N_("re-fetch without negotiating common commits"),
>  		      1, PARSE_OPT_NONEG),
> -	{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
> -		   N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
> +	OPT__SUPER_PREFIX(&super_prefix),
>  	OPT_CALLBACK_F(0, "recurse-submodules-default",
>  		   &recurse_submodules_default, N_("on-demand"),
>  		   N_("default for recursive fetching of submodules "
> @@ -2300,7 +2299,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
>  		add_options_to_argv(&options);
>  		result = fetch_submodules(the_repository,
>  					  &options,
> -					  submodule_prefix,
> +					  super_prefix,
>  					  recurse_submodules,
>  					  recurse_submodules_default,
>  					  verbosity < 0,
> diff --git a/submodule.c b/submodule.c
> index 5ac4e1b0568..1e4eee3492b 100644
> --- a/submodule.c
> +++ b/submodule.c
> @@ -1376,7 +1376,7 @@ struct submodule_parallel_fetch {
>  	int changed_count;
>  	struct strvec args;
>  	struct repository *r;
> -	const char *prefix;
> +	const char *super_prefix;
>  	int command_line_option;
>  	int default_option;
>  	int quiet;
> @@ -1567,7 +1567,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
>  		if (task->repo) {
>  			if (!spf->quiet)
>  				strbuf_addf(err, _("Fetching submodule %s%s\n"),
> -					    spf->prefix, ce->name);
> +					    spf->super_prefix, ce->name);
>  
>  			spf->index_count++;
>  			return task;
> @@ -1629,7 +1629,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
>  		if (!spf->quiet)
>  			strbuf_addf(err,
>  				    _("Fetching submodule %s%s at commit %s\n"),
> -				    spf->prefix, task->sub->path,
> +				    spf->super_prefix, task->sub->path,
>  				    find_unique_abbrev(cs_data->super_oid,
>  						       DEFAULT_ABBREV));
>  
> @@ -1687,11 +1687,10 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
>  			strvec_pushv(&cp->args, task->git_args.v);
>  		strvec_pushv(&cp->args, spf->args.v);
>  		strvec_push(&cp->args, task->default_argv);
> -		strvec_push(&cp->args, "--submodule-prefix");
> +		strvec_push(&cp->args, "--super-prefix");
>  
> -		strbuf_addf(&submodule_prefix, "%s%s/",
> -						spf->prefix,
> -						task->sub->path);
> +		strbuf_addf(&submodule_prefix, "%s%s/", spf->super_prefix,
> +			    task->sub->path);
>  		strvec_push(&cp->args, submodule_prefix.buf);
>  		*task_cb = task;
>  
> @@ -1707,7 +1706,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
>  		spf->oid_fetch_tasks_nr--;
>  
>  		strbuf_addf(&submodule_prefix, "%s%s/",
> -			    spf->prefix, task->sub->path);
> +			    spf->super_prefix, task->sub->path);
>  
>  		child_process_init(cp);
>  		prepare_submodule_repo_env_in_gitdir(&cp->env);
> @@ -1717,7 +1716,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
>  		strvec_init(&cp->args);
>  		strvec_pushv(&cp->args, spf->args.v);
>  		strvec_push(&cp->args, "on-demand");
> -		strvec_push(&cp->args, "--submodule-prefix");
> +		strvec_push(&cp->args, "--super-prefix");
>  		strvec_push(&cp->args, submodule_prefix.buf);
>  
>  		/* NEEDSWORK: have get_default_remote from submodule--helper */
> @@ -1813,7 +1812,7 @@ static int fetch_finish(int retvalue, struct strbuf *err,
>  
>  int fetch_submodules(struct repository *r,
>  		     const struct strvec *options,
> -		     const char *prefix, int command_line_option,
> +		     const char *super_prefix, int command_line_option,
>  		     int default_option,
>  		     int quiet, int max_parallel_jobs)
>  {
> @@ -1835,7 +1834,7 @@ int fetch_submodules(struct repository *r,
>  	spf.command_line_option = command_line_option;
>  	spf.default_option = default_option;
>  	spf.quiet = quiet;
> -	spf.prefix = prefix;
> +	spf.super_prefix = super_prefix ? super_prefix : "";
>  
>  	if (!r->worktree)
>  		goto out;
> @@ -1847,7 +1846,7 @@ int fetch_submodules(struct repository *r,
>  	for (i = 0; i < options->nr; i++)
>  		strvec_push(&spf.args, options->v[i]);
>  	strvec_push(&spf.args, "--recurse-submodules-default");
> -	/* default value, "--submodule-prefix" and its value are added later */
> +	/* default value, "--super-prefix" and its value are added later */
>  
>  	calculate_changed_submodule_paths(r, &spf.changed_submodule_names);
>  	string_list_sort(&spf.changed_submodule_names);
> -- 
> 2.38.0.1471.ge4d8947e7aa

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 00/10] Get rid of "git --super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (10 preceding siblings ...)
  2022-11-14 21:59     ` [PATCH v2 00/10] Get rid of "git --super-prefix" Taylor Blau
@ 2022-11-14 23:20     ` Glen Choo
  2022-11-14 23:39     ` Glen Choo
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
  13 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-14 23:20 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Thanks for taking this forward as a non-RFC (and sorry for the
coordinating confusion last week). I'm really happy to see this go
forward.

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> = Summary
>
> What's "--super-prefix"? The "git" command takes an "internal use
> only" "--super-prefix" option, which is used to inform processes
> invoked in submodules what the path prefix to the invoking
> superproject is.
>
> This is so so that e.g. "git submodule absorbgitdirs" can report
> "sub-1/sub-2", instead of "sub-2" when being invoked in the "sub-1"
> submodule.
>
> For this the "--super-prefix" facility has been doing a
> setenv("GIT_INTERNAL_SUPER_PREFIX", "sub-1/") as soon as it got the
> "--supre-prefix=sub-1/". We'd then pass that along via the environment
> when invoking the sub-process.
>
> As this series shows we don't need such a hands-off global facility to
> do this, we can instead just pass the relevant context directly in
> each command. E.g. "git submodule absorbgitdirs" can pass the path to
> the "git submodule absorbgitdirs" sub-process it's about to invoke.
>

To play devil's advocate, we don't need it now, but one could argue that
we'll need it in the future, and having some global facility for this
would continue to be helpful. In [1], I mentioned that it is "helpful"
in this way, but that this "helpfulness" is a trap, because we want to
be moving more things in-process anyway (and we're making pretty good
strides in that direction), and adding more global state makes it harder
to reason about who should own the variables when we libify the
internals (do we move the state into per-process struct?
the_repository? something else?)

In addition, you also mentioned earlier in the [1] thread that this
global state also makes it possible accidentally affect commands we
didn't mean to, and having less global state makes behavior easier to
reason about.

So I think the argument I find most convincing isn't just "We don't need
it now.", but also "Global state is the wrong way to do this, so let's
stop.".

[1] https://lore.kernel.org/git/kl6l5yfm2taf.fsf@chooglen-macbookpro.roam.corp.google.com

> It's also proposing to replace Glen's one-patch[6], which is working
> around the problem shown in the test added in 1/10 here. Per
> downthread of [7] I think Glen was aiming for getting a more narrow
> fix in case we split off 9/10 here into some later fix.
>
> As we're fixing an edge case in something that's always been broken
> (and thus wouldn't backport) I think it's better to just fix the
> problem directly, rather than introducing new "--super-prefix" use,
> just to take it away later.

(I'll share my thoughts on this on another email).

> = Changes since the RFC
>
> * Added Glen's "git fetch" test as a 1/10, with an updated commit message
> * Updated 2/10's commit message for the non-RFC, and adjusted and
>   incorporated a variant of Glen's fsmonitor test change.
> * 9/10: Correctly re-arrange bitfield define's when removing one, make
>   the test added in 1/10 pass.
>
> * 10/10: New commit to make "git fetch" use our own "--super-prefix"
>   instead of its "--submodule-prefix", which makes it consistent with
>   the other command-level "--super-prefix" introduced here.
>
>   Personally I'm rather "meh" on this. It's not actually needed by the
>   main body of the series, but Glen seems to prefer it in[9], and
>   doing it is easy enough.
>
>   That change is a pure refactoring clean-up for consistency. The only
>   reason it's 10/10 and not 1/10 is because it uses the
>   "OPT__SUPER_PREFIX()" introduced in 2/10.

Thanks for this, I really appreciate it :)

> = CI & fetch URL
>
> Passing at: https://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local-2
>
> 1. https://lore.kernel.org/git/RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com/
> 2. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/
> 3. https://lore.kernel.org/git/kl6l5yfm2taf.fsf@chooglen-macbookpro.roam.corp.google.com/
> 4. c0c4f4d1c33 (Merge branch 'ab/submodule-helper-prep-only' into next, 2022-11-08)
> 5. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/
> 6. https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com/
> 7. https://lore.kernel.org/git/221111.86fsepmbhe.gmgdl@evledraar.gmail.com/
> 8. https://lore.kernel.org/git/20221109004708.97668-3-chooglen@google.com/
> 9. https://lore.kernel.org/git/kl6lsfip0yfx.fsf@chooglen-macbookpro.roam.corp.google.com/
>
> Glen Choo (1):
>   read-tree + fetch tests: test failing "--super-prefix" interaction
>
> Ævar Arnfjörð Bjarmason (9):
>   submodule--helper: don't use global --super-prefix in "absorbgitdirs"
>   submodule--helper: "deinit" has never used "--super-prefix"
>   submodule--helper: convert "foreach" to its own "--super-prefix"
>   submodule--helper: convert "sync" to its own "--super-prefix"
>   submodule--helper: convert "status" to its own "--super-prefix"
>   submodule--helper: convert "{update,clone}" to their own
>     "--super-prefix"
>   submodule tests: test "git branch -t" output and stderr
>   read-tree: add "--super-prefix" option, eliminate global
>   fetch: rename "--submodule-prefix" to "--super-prefix"
>
>  Documentation/fetch-options.txt |  5 --
>  Documentation/git.txt           |  8 +--
>  builtin.h                       |  4 --
>  builtin/checkout.c              |  2 +-
>  builtin/fetch.c                 |  7 +--
>  builtin/read-tree.c             |  1 +
>  builtin/submodule--helper.c     | 95 ++++++++++++++++++--------------
>  cache.h                         |  2 -
>  entry.c                         | 12 ++--
>  entry.h                         |  6 +-
>  environment.c                   | 13 -----
>  git.c                           | 41 +++-----------
>  parse-options.h                 |  4 ++
>  submodule.c                     | 70 +++++++++++------------
>  submodule.h                     | 12 ++--
>  t/lib-submodule-update.sh       | 98 ++++++++++++++++++---------------
>  t/t1001-read-tree-m-2way.sh     |  2 +-
>  t/t5616-partial-clone.sh        | 43 +++++++++++++++
>  t/t7527-builtin-fsmonitor.sh    | 33 +++--------
>  unpack-trees.c                  | 23 ++++----
>  unpack-trees.h                  |  1 +
>  21 files changed, 244 insertions(+), 238 deletions(-)
>
> Range-diff against v1:
>  -:  ----------- >  1:  1114a4ff666 read-tree + fetch tests: test failing "--super-prefix" interaction
>  1:  ad0356b596f !  2:  5a35f7b75b3 submodule--helper: don't use global --super-prefix in "absorbgitdirs"
>     @@ Commit message
>          declare "fsmonitor--daemon" as accepting it too, even though it
>          doesn't care about it.
>      
>     -    There's a parallel proposal to remove "--super-prefix" as an option to
>     -    "git" in [3], and some of the approach might be the easiest route in
>     -    some cases.
>     -
>          But in the case of "absorbgitdirs" it only needed "--super-prefix" to
>          invoke itself recursively, and we'd never have another "in-between"
>          process in the chain. So we didn't need the bigger hammer of "git
>     @@ Commit message
>          stone makes such an eventual change easier, as we'll need to deal with
>          less global state at that point.
>      
>     +    The "fsmonitor--daemon" test adjusted here was added in [3]. The
>     +    comment added in that commit has been out-of-date from the beginning,
>     +    and the "have_t2_error_event()" was being overly specific in testing
>     +    for a bug that we *don't* have. Let's instead test for the stdout and
>     +    stderr that we *do have*.
>     +
>          1. 74866d75793 (git: make super-prefix option, 2016-10-07)
>          2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
>             2022-05-26)
>     -    3. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/
>     +    3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
>     +       2022-05-26)
>      
>     +    Signed-off-by: Glen Choo <chooglen@google.com>
>          Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>      
>       ## builtin/submodule--helper.c ##
>     @@ submodule.h: void submodule_unset_core_worktree(const struct submodule *sub);
>       
>       /*
>        * Return the absolute path of the working tree of the superproject, which this
>     +
>     + ## t/t7527-builtin-fsmonitor.sh ##
>     +@@ t/t7527-builtin-fsmonitor.sh: test_expect_success 'submodule always visited' '
>     + # the submodule, and someone does a `git submodule absorbgitdirs`
>     + # in the super, Git will recursively invoke `git submodule--helper`
>     + # to do the work and this may try to read the index.  This will
>     +-# try to start the daemon in the submodule *and* pass (either
>     +-# directly or via inheritance) the `--super-prefix` arg to the
>     +-# `git fsmonitor--daemon start` command inside the submodule.
>     +-# This causes a warning because fsmonitor--daemon does take that
>     +-# global arg (see the table in git.c)
>     +-#
>     +-# This causes a warning when trying to start the daemon that is
>     +-# somewhat confusing.  It does not seem to hurt anything because
>     +-# the fsmonitor code maps the query failure into a trivial response
>     +-# and does the work anyway.
>     +-#
>     +-# It would be nice to silence the warning, however.
>     +-
>     +-have_t2_error_event () {
>     +-	log=$1
>     +-	msg="fsmonitor--daemon doesnQt support --super-prefix" &&
>     +-
>     +-	tr '\047' Q <$1 | grep -e "$msg"
>     +-}
>     ++# try to start the daemon in the submodule.
>     + 
>     + test_expect_success "stray submodule super-prefix warning" '
>     + 	test_when_finished "rm -rf super; \
>     +-			    rm -rf sub;   \
>     +-			    rm super-sub.trace" &&
>     ++			    rm -rf sub" &&
>     + 
>     + 	create_super super &&
>     + 	create_sub sub &&
>     +@@ t/t7527-builtin-fsmonitor.sh: test_expect_success "stray submodule super-prefix warning" '
>     + 
>     + 	test_path_is_dir super/dir_1/dir_2/sub/.git &&
>     + 
>     +-	GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
>     +-		git -C super submodule absorbgitdirs &&
>     +-
>     +-	! have_t2_error_event super-sub.trace
>     ++	cat >expect <<-\EOF &&
>     ++	Migrating git directory of '\''dir_1/dir_2/sub'\'' from '\''dir_1/dir_2/sub/.git'\'' to '\''.git/modules/dir_1/dir_2/sub'\''
>     ++	EOF
>     ++	git -C super submodule absorbgitdirs >out 2>actual &&
>     ++	test_cmp expect actual &&
>     ++	test_must_be_empty out
>     + '
>     + 
>     + # On a case-insensitive file system, confirm that the daemon
>  2:  87a780eb9bf =  3:  a7a1f9487dc submodule--helper: "deinit" has never used "--super-prefix"
>  3:  4858e2ad0ed =  4:  935d8070834 submodule--helper: convert "foreach" to its own "--super-prefix"
>  4:  5ffe4407e46 =  5:  933c752513d submodule--helper: convert "sync" to its own "--super-prefix"
>  5:  a46540b63c2 =  6:  67273f729e0 submodule--helper: convert "status" to its own "--super-prefix"
>  6:  78ebf0e2abf =  7:  eaa73f5b1e4 submodule--helper: convert "{update,clone}" to their own "--super-prefix"
>  7:  00a9e789be7 =  8:  172b5865811 submodule tests: test "git branch -t" output and stderr
>  8:  3ba894a6698 !  9:  9fdeab60773 read-tree: add "--super-prefix" option, eliminate global
>     @@ git.c
>        */
>       #define NEED_WORK_TREE		(1<<3)
>      -#define SUPPORT_SUPER_PREFIX	(1<<4)
>     - #define DELAY_PAGER_CONFIG	(1<<5)
>     - #define NO_PARSEOPT		(1<<6) /* parse-options is not used */
>     +-#define DELAY_PAGER_CONFIG	(1<<5)
>     +-#define NO_PARSEOPT		(1<<6) /* parse-options is not used */
>     ++#define DELAY_PAGER_CONFIG	(1<<4)
>     ++#define NO_PARSEOPT		(1<<5) /* parse-options is not used */
>       
>     + struct cmd_struct {
>     + 	const char *cmd;
>      @@ git.c: const char git_usage_string[] =
>       	   "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
>       	   "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
>     @@ t/t1001-read-tree-m-2way.sh: test_expect_success 'read-tree supports the super-p
>       '
>       
>      
>     + ## t/t5616-partial-clone.sh ##
>     +@@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor objects' '
>     + 	grep "loosen_unused_packed_objects/loosened:0" trace
>     + '
>     + 
>     +-test_expect_failure 'lazy-fetch in submodule succeeds' '
>     ++test_expect_success 'lazy-fetch in submodule succeeds' '
>     + 	# setup
>     + 	test_config_global protocol.file.allow always &&
>     + 
>     +
>       ## unpack-trees.c ##
>      @@ unpack-trees.c: static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
>       	  ? ((o)->msgs[(type)])      \
>  -:  ----------- > 10:  100ba36dfb7 fetch: rename "--submodule-prefix" to "--super-prefix"
> -- 
> 2.38.0.1471.ge4d8947e7aa

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-14 10:09               ` Ævar Arnfjörð Bjarmason
@ 2022-11-14 23:33                 ` Glen Choo
  2022-11-15  1:37                   ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-14 23:33 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> As noted in the CL above I included this because I see you're keen to
> include it, but I'm personally a bit "meh" on it. I.e. it's just
> renaming an existing unrelated option, although being able to use
> OPT__SUPER_PREFIX() makes it slightly nicer.
>
> As post-cleanups go I think removing the "submodule_prefix" from the
> "struct repository" would make more sense, and maybe it's worth peeling
> off the 10/10 to include in such a post-cleanup series? I.e. the below
> on top of all of this works, and reduces allocations and cargo-culting
> around the submodule API.

As a first impression I'm not particularly keen on this, since it makes
perfect sense to me to have a repo->submodule_prefix, especially when
recursing into N-level deep submodules...

>
> -- >8 --
> Subject: [PATCH] repo & submodule API: stop carrying "repo->submodule_prefix"
>
> As this change shows the "submodule_prefix" field to "struct
> repository" added in 96dc883b3cd (repository: enable initialization of
> submodules, 2017-06-22) was only used by "ls-files" and "grep". Let's
> have those two carry forward the "super_prefix" instead.
>
> Having every user of "struct repository" needing to worry about this
> created a mismatch in the API where e.g. "grep" would re-compute a
> "name_base_len" which we knew before. Now we use a "struct strbuf" in
> the "struct grep_opt" there instead, so we'll know the length
> already. This simplifies "grep_cache()" and "grep_tree()".
>
> We're also deleting cargo-culted code that the previous API foisted
> upon us. In 605f0ec1350 (submodule: use submodule repos for object
> lookup, 2018-12-14) the "Mark it as a submodule" code was added to
> "open_submodule()", but the resulting xstrdup()'d "submodule_prefix"
> was never used by anything.

(As an aside, I think open_submodule() should have been replaced by
repo_submodule_init().)

In which case, yes it isn't used by anything in that code path, but
being meticulous about maintaining .super_prefix means that other
callers could use it if they wanted to, which might be crucial once we
start plumb "struct repository" deeper and deeper and...

>
> Still, removing this field might not be a good move, as the
> "super_prefix" might be a common enough case in the future, e.g. when
> eventually migrating the "submodule--helper" users[1] to run
> in-process.
>
> As the "grep" example demonstrates I don't think that's the
> case. There instead of xstrdup()-ing all the way down we're now
> carrying a single "super_prefix" in the form of a "struct strbuf". As
> we recurse we then append to it, and strbuf_setlen() it back when we
> we recurse out of that submodule. This is similar to how e.g. the
> "read_tree_at()" API works.

This technique might no longer be so appealing. We _could_ pass both
"struct repository" and "super_prefix", but that seems odd given that
the super prefix is tied to the repository.

But that's just a first impression anyway. I don't mind taking another
look if this gets a standalone review.

>
> Doing it that way means that we have just one allocation, which in the
> common case we might realloc() if we don't have enough room in the
> "struct strbuf".
>
> 1. https://lore.kernel.org/git/cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com/
> 2. https://github.com/avar/git/tree/avar/grep-post-drop-prefix-cleanup
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  builtin/grep.c     | 18 ++++++++----------
>  builtin/ls-files.c | 40 +++++++++++++++++++++++++---------------
>  grep.c             |  6 +++---
>  grep.h             |  2 ++
>  repository.c       |  7 -------
>  repository.h       |  7 -------
>  submodule.c        |  3 ---
>  7 files changed, 38 insertions(+), 45 deletions(-)
>
> diff --git a/builtin/grep.c b/builtin/grep.c
> index 5fa927d4e22..69826daba26 100644
> --- a/builtin/grep.c
> +++ b/builtin/grep.c
> @@ -437,6 +437,7 @@ static int grep_submodule(struct grep_opt *opt,
>  	struct repository *superproject = opt->repo;
>  	struct grep_opt subopt;
>  	int hit = 0;
> +	size_t oldlen = opt->super_prefix.len;
>  
>  	if (!is_submodule_active(superproject, path))
>  		return 0;
> @@ -497,6 +498,7 @@ static int grep_submodule(struct grep_opt *opt,
>  	add_submodule_odb_by_path(subrepo->objects->odb->path);
>  	obj_read_unlock();
>  
> +	strbuf_addf(&opt->super_prefix, "%s/", path);
>  	memcpy(&subopt, opt, sizeof(subopt));
>  	subopt.repo = subrepo;
>  
> @@ -527,6 +529,7 @@ static int grep_submodule(struct grep_opt *opt,
>  	} else {
>  		hit = grep_cache(&subopt, pathspec, cached);
>  	}
> +	strbuf_setlen(&opt->super_prefix, oldlen);
>  
>  	return hit;
>  }
> @@ -538,11 +541,8 @@ static int grep_cache(struct grep_opt *opt,
>  	int hit = 0;
>  	int nr;
>  	struct strbuf name = STRBUF_INIT;
> -	int name_base_len = 0;
> -	if (repo->submodule_prefix) {
> -		name_base_len = strlen(repo->submodule_prefix);
> -		strbuf_addstr(&name, repo->submodule_prefix);
> -	}
> +	size_t name_base_len = opt->super_prefix.len;
> +	strbuf_addbuf(&name, &opt->super_prefix);
>  
>  	if (repo_read_index(repo) < 0)
>  		die(_("index file corrupt"));
> @@ -618,11 +618,9 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
>  	struct name_entry entry;
>  	int old_baselen = base->len;
>  	struct strbuf name = STRBUF_INIT;
> -	int name_base_len = 0;
> -	if (repo->submodule_prefix) {
> -		strbuf_addstr(&name, repo->submodule_prefix);
> -		name_base_len = name.len;
> -	}
> +	size_t name_base_len = opt->super_prefix.len;
> +
> +	strbuf_addbuf(&name, &opt->super_prefix);
>  
>  	while (tree_entry(tree, &entry)) {
>  		int te_len = tree_entry_len(&entry);
> diff --git a/builtin/ls-files.c b/builtin/ls-files.c
> index 4cf8a236483..c76a6be2fbe 100644
> --- a/builtin/ls-files.c
> +++ b/builtin/ls-files.c
> @@ -216,10 +216,12 @@ static void show_killed_files(struct index_state *istate,
>  	}
>  }
>  
> -static void show_files(struct repository *repo, struct dir_struct *dir);
> +static void show_files(struct repository *repo, struct dir_struct *dir,
> +		       const char *super_prefix);
>  
>  static void show_submodule(struct repository *superproject,
> -			   struct dir_struct *dir, const char *path)
> +			   struct dir_struct *dir, const char *path,
> +			   const char *super_prefix)
>  {
>  	struct repository subrepo;
>  
> @@ -229,7 +231,7 @@ static void show_submodule(struct repository *superproject,
>  	if (repo_read_index(&subrepo) < 0)
>  		die("index file corrupt");
>  
> -	show_files(&subrepo, dir);
> +	show_files(&subrepo, dir, super_prefix);
>  
>  	repo_clear(&subrepo);
>  }
> @@ -303,14 +305,19 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
>  
>  static void show_ce(struct repository *repo, struct dir_struct *dir,
>  		    const struct cache_entry *ce, const char *fullname,
> -		    const char *tag)
> +		    const char *tag, const char *super_prefix)
>  {
>  	if (max_prefix_len > strlen(fullname))
>  		die("git ls-files: internal error - cache entry not superset of prefix");
>  
>  	if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
>  	    is_submodule_active(repo, ce->name)) {
> -		show_submodule(repo, dir, ce->name);
> +		struct strbuf sp = STRBUF_INIT;
> +
> +		strbuf_addf(&sp, "%s%s/", super_prefix ? super_prefix : "",
> +			    ce->name);
> +		show_submodule(repo, dir, ce->name, sp.buf);
> +		strbuf_release(&sp);
>  	} else if (match_pathspec(repo->index, &pathspec, fullname, strlen(fullname),
>  				  max_prefix_len, ps_matched,
>  				  S_ISDIR(ce->ce_mode) ||
> @@ -374,16 +381,17 @@ static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
>  	return is_excluded(dir, istate, fullname, &dtype);
>  }
>  
> -static void construct_fullname(struct strbuf *out, const struct repository *repo,
> -			       const struct cache_entry *ce)
> +static void construct_fullname(struct strbuf *out, const struct cache_entry *ce,
> +			       const char *super_prefix)
>  {
>  	strbuf_reset(out);
> -	if (repo->submodule_prefix)
> -		strbuf_addstr(out, repo->submodule_prefix);
> +	if (super_prefix)
> +		strbuf_addstr(out, super_prefix);
>  	strbuf_addstr(out, ce->name);
>  }
>  
> -static void show_files(struct repository *repo, struct dir_struct *dir)
> +static void show_files(struct repository *repo, struct dir_struct *dir,
> +		       const char *super_prefix)
>  {
>  	int i;
>  	struct strbuf fullname = STRBUF_INIT;
> @@ -410,7 +418,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir)
>  		struct stat st;
>  		int stat_err;
>  
> -		construct_fullname(&fullname, repo, ce);
> +		construct_fullname(&fullname, ce, super_prefix);
>  
>  		if ((dir->flags & DIR_SHOW_IGNORED) &&
>  			!ce_excluded(dir, repo->index, fullname.buf, ce))
> @@ -422,7 +430,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir)
>  			show_ce(repo, dir, ce, fullname.buf,
>  				ce_stage(ce) ? tag_unmerged :
>  				(ce_skip_worktree(ce) ? tag_skip_worktree :
> -				 tag_cached));
> +				 tag_cached), super_prefix);
>  			if (skipping_duplicates)
>  				goto skip_to_next_name;
>  		}
> @@ -435,13 +443,15 @@ static void show_files(struct repository *repo, struct dir_struct *dir)
>  		if (stat_err && (errno != ENOENT && errno != ENOTDIR))
>  			error_errno("cannot lstat '%s'", fullname.buf);
>  		if (stat_err && show_deleted) {
> -			show_ce(repo, dir, ce, fullname.buf, tag_removed);
> +			show_ce(repo, dir, ce, fullname.buf, tag_removed,
> +				super_prefix);
>  			if (skipping_duplicates)
>  				goto skip_to_next_name;
>  		}
>  		if (show_modified &&
>  		    (stat_err || ie_modified(repo->index, ce, &st, 0))) {
> -			show_ce(repo, dir, ce, fullname.buf, tag_modified);
> +			show_ce(repo, dir, ce, fullname.buf, tag_modified,
> +				super_prefix);
>  			if (skipping_duplicates)
>  				goto skip_to_next_name;
>  		}
> @@ -874,7 +884,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
>  		overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
>  	}
>  
> -	show_files(the_repository, &dir);
> +	show_files(the_repository, &dir, NULL);
>  
>  	if (show_resolve_undo)
>  		show_ru_info(the_repository->index);
> diff --git a/grep.c b/grep.c
> index 06eed694936..10d52219229 100644
> --- a/grep.c
> +++ b/grep.c
> @@ -791,9 +791,9 @@ void free_grep_patterns(struct grep_opt *opt)
>  		free(p);
>  	}
>  
> -	if (!opt->pattern_expression)
> -		return;
> -	free_pattern_expr(opt->pattern_expression);
> +	if (opt->pattern_expression)
> +		free_pattern_expr(opt->pattern_expression);
> +	strbuf_release(&opt->super_prefix);
>  }
>  
>  static const char *end_of_line(const char *cp, unsigned long *left)
> diff --git a/grep.h b/grep.h
> index 6075f997e68..d353bfa21ce 100644
> --- a/grep.h
> +++ b/grep.h
> @@ -133,6 +133,7 @@ struct grep_opt {
>  	 * t7814-grep-recurse-submodules.sh for more information.
>  	 */
>  	struct repository *repo;
> +	struct strbuf super_prefix;
>  
>  	int linenum;
>  	int columnnum;
> @@ -178,6 +179,7 @@ struct grep_opt {
>  };
>  
>  #define GREP_OPT_INIT { \
> +	.super_prefix = STRBUF_INIT, \
>  	.relative = 1, \
>  	.pathname = 1, \
>  	.max_depth = -1, \
> diff --git a/repository.c b/repository.c
> index 5d166b692c8..2f8581c517d 100644
> --- a/repository.c
> +++ b/repository.c
> @@ -228,12 +228,6 @@ int repo_submodule_init(struct repository *subrepo,
>  			goto out;
>  		}
>  	}
> -
> -	subrepo->submodule_prefix = xstrfmt("%s%s/",
> -					    superproject->submodule_prefix ?
> -					    superproject->submodule_prefix :
> -					    "", path);
> -
>  out:
>  	strbuf_release(&gitdir);
>  	strbuf_release(&worktree);
> @@ -261,7 +255,6 @@ void repo_clear(struct repository *repo)
>  	FREE_AND_NULL(repo->graft_file);
>  	FREE_AND_NULL(repo->index_file);
>  	FREE_AND_NULL(repo->worktree);
> -	FREE_AND_NULL(repo->submodule_prefix);
>  
>  	raw_object_store_clear(repo->objects);
>  	FREE_AND_NULL(repo->objects);
> diff --git a/repository.h b/repository.h
> index 6c461c5b9de..a08da26133c 100644
> --- a/repository.h
> +++ b/repository.h
> @@ -120,13 +120,6 @@ struct repository {
>  	 */
>  	char *worktree;
>  
> -	/*
> -	 * Path from the root of the top-level superproject down to this
> -	 * repository.  This is only non-NULL if the repository is initialized
> -	 * as a submodule of another repository.
> -	 */
> -	char *submodule_prefix;
> -
>  	struct repo_settings settings;
>  
>  	/* Subsystems */
> diff --git a/submodule.c b/submodule.c
> index 1e4eee3492b..1c5ef904a03 100644
> --- a/submodule.c
> +++ b/submodule.c
> @@ -528,9 +528,6 @@ static struct repository *open_submodule(const char *path)
>  		return NULL;
>  	}
>  
> -	/* Mark it as a submodule */
> -	out->submodule_prefix = xstrdup(path);
> -
>  	strbuf_release(&sb);
>  	return out;
>  }
> -- 
> 2.38.0.1471.ge4d8947e7aa

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 00/10] Get rid of "git --super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (11 preceding siblings ...)
  2022-11-14 23:20     ` Glen Choo
@ 2022-11-14 23:39     ` Glen Choo
  2022-11-15  1:27       ` Ævar Arnfjörð Bjarmason
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
  13 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-14 23:39 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git, Taylor Blau
  Cc: Robert Coup, Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> It's also proposing to replace Glen's one-patch[6], which is working
> around the problem shown in the test added in 1/10 here. Per
> downthread of [7] I think Glen was aiming for getting a more narrow
> fix in case we split off 9/10 here into some later fix.
>
> As we're fixing an edge case in something that's always been broken
> (and thus wouldn't backport) I think it's better to just fix the
> problem directly, rather than introducing new "--super-prefix" use,
> just to take it away later.

I still prefer that we take the one-patch to unbreak new releases,
because partial clone + submodules is absolutely broken (e.g. it's
already causing quite a lot of headaches at $DAYJOB) and the patch is
obviously harmless.

And more importantly, it lets us take our time with this series and get
it right without time pressure. It's not as pressing as, e.g. a
regression fix, but it does render certain Git setups unusable.

With regards to urgency and when to choose "small and harmless fixes vs
bigger and better fixes", I think Junio has generally made those calls
in the past. @Taylor if you have an opinion, I'd love to hear it.

> 6. https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com/
> 7. https://lore.kernel.org/git/221111.86fsepmbhe.gmgdl@evledraar.gmail.com/

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 00/10] Get rid of "git --super-prefix"
  2022-11-14 23:39     ` Glen Choo
@ 2022-11-15  1:27       ` Ævar Arnfjörð Bjarmason
  2022-11-16 21:07         ` Glen Choo
  0 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-15  1:27 UTC (permalink / raw)
  To: Glen Choo; +Cc: git, Taylor Blau, Robert Coup


On Mon, Nov 14 2022, Glen Choo wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> It's also proposing to replace Glen's one-patch[6], which is working
>> around the problem shown in the test added in 1/10 here. Per
>> downthread of [7] I think Glen was aiming for getting a more narrow
>> fix in case we split off 9/10 here into some later fix.
>>
>> As we're fixing an edge case in something that's always been broken
>> (and thus wouldn't backport) I think it's better to just fix the
>> problem directly, rather than introducing new "--super-prefix" use,
>> just to take it away later.
>
> I still prefer that we take the one-patch to unbreak new releases,
> because partial clone + submodules is absolutely broken (e.g. it's
> already causing quite a lot of headaches at $DAYJOB) and the patch is
> obviously harmless.
>
> And more importantly, it lets us take our time with this series and get
> it right without time pressure. It's not as pressing as, e.g. a
> regression fix, but it does render certain Git setups unusable.
>
> With regards to urgency and when to choose "small and harmless fixes vs
> bigger and better fixes", I think Junio has generally made those calls
> in the past. @Taylor if you have an opinion, I'd love to hear it.

I feel like I'm missing something here. What's the regression? The test
you're adding here didn't work at all until 0f5e8851737 (Merge branch
'rc/fetch-refetch', 2022-04-04), as the command didn't exist yet. That
commit went out with v2.36.0.

If it never worked there's no regression, and we wouldn't be merging
down a fix for older point-releases.

Or is there some case I've missed here which did work before, doesn't
now, but just isn't captured in this test? If so what case is that, and
when did it break?

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [RFC PATCH 0/8] Get rid of "git --super-prefix"
  2022-11-14 23:33                 ` Glen Choo
@ 2022-11-15  1:37                   ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-15  1:37 UTC (permalink / raw)
  To: Glen Choo; +Cc: git


On Mon, Nov 14 2022, Glen Choo wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> As noted in the CL above I included this because I see you're keen to
>> include it, but I'm personally a bit "meh" on it. I.e. it's just
>> renaming an existing unrelated option, although being able to use
>> OPT__SUPER_PREFIX() makes it slightly nicer.
>>
>> As post-cleanups go I think removing the "submodule_prefix" from the
>> "struct repository" would make more sense, and maybe it's worth peeling
>> off the 10/10 to include in such a post-cleanup series? I.e. the below
>> on top of all of this works, and reduces allocations and cargo-culting
>> around the submodule API.
>
> As a first impression I'm not particularly keen on this, since it makes
> perfect sense to me to have a repo->submodule_prefix, especially when
> recursing into N-level deep submodules...

This is mainly a quick experiment I drafted up, with that context...

>> -- >8 --
>> Subject: [PATCH] repo & submodule API: stop carrying "repo->submodule_prefix"
>>
>> As this change shows the "submodule_prefix" field to "struct
>> repository" added in 96dc883b3cd (repository: enable initialization of
>> submodules, 2017-06-22) was only used by "ls-files" and "grep". Let's
>> have those two carry forward the "super_prefix" instead.
>>
>> Having every user of "struct repository" needing to worry about this
>> created a mismatch in the API where e.g. "grep" would re-compute a
>> "name_base_len" which we knew before. Now we use a "struct strbuf" in
>> the "struct grep_opt" there instead, so we'll know the length
>> already. This simplifies "grep_cache()" and "grep_tree()".
>>
>> We're also deleting cargo-culted code that the previous API foisted
>> upon us. In 605f0ec1350 (submodule: use submodule repos for object
>> lookup, 2018-12-14) the "Mark it as a submodule" code was added to
>> "open_submodule()", but the resulting xstrdup()'d "submodule_prefix"
>> was never used by anything.
>
> (As an aside, I think open_submodule() should have been replaced by
> repo_submodule_init().)
>
> In which case, yes it isn't used by anything in that code path, but
> being meticulous about maintaining .super_prefix means that other
> callers could use it if they wanted to, which might be crucial once we
> start plumb "struct repository" deeper and deeper and...

...I just don't see the point of maintaining an API with this sort of
reach for just two callers, when it's a bad fit for what those two
callers need.

>>
>> Still, removing this field might not be a good move, as the
>> "super_prefix" might be a common enough case in the future, e.g. when
>> eventually migrating the "submodule--helper" users[1] to run
>> in-process.
>>
>> As the "grep" example demonstrates I don't think that's the
>> case. There instead of xstrdup()-ing all the way down we're now
>> carrying a single "super_prefix" in the form of a "struct strbuf". As
>> we recurse we then append to it, and strbuf_setlen() it back when we
>> we recurse out of that submodule. This is similar to how e.g. the
>> "read_tree_at()" API works.
>
> This technique might no longer be so appealing. We _could_ pass both
> "struct repository" and "super_prefix", but that seems odd given that
> the super prefix is tied to the repository.

FWIW I don't even think a "super_prefix" being tied to a repository is a
useful abstraction level in general.

E.g. I've got some local hacky patches to make "git ls-tree" able to
recurse down submodules, and for that code you usually just want to
print the prefix to the current *dir*, and having to print the prefix to
the current module, then the current dir-within-module, then the file
just makes things needlessly complex.

> But that's just a first impression anyway. I don't mind taking another
> look if this gets a standalone review.

*nod*

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 00/10] Get rid of "git --super-prefix"
  2022-11-15  1:27       ` Ævar Arnfjörð Bjarmason
@ 2022-11-16 21:07         ` Glen Choo
  2022-11-17 18:07           ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 79+ messages in thread
From: Glen Choo @ 2022-11-16 21:07 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Taylor Blau, Robert Coup

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Mon, Nov 14 2022, Glen Choo wrote:
>
>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>>
>>> It's also proposing to replace Glen's one-patch[6], which is working
>>> around the problem shown in the test added in 1/10 here. Per
>>> downthread of [7] I think Glen was aiming for getting a more narrow
>>> fix in case we split off 9/10 here into some later fix.
>>>
>>> As we're fixing an edge case in something that's always been broken
>>> (and thus wouldn't backport) I think it's better to just fix the
>>> problem directly, rather than introducing new "--super-prefix" use,
>>> just to take it away later.
>>
>> I still prefer that we take the one-patch to unbreak new releases,
>> because partial clone + submodules is absolutely broken (e.g. it's
>> already causing quite a lot of headaches at $DAYJOB) and the patch is
>> obviously harmless.
>>
>> And more importantly, it lets us take our time with this series and get
>> it right without time pressure. It's not as pressing as, e.g. a
>> regression fix, but it does render certain Git setups unusable.
>>
>> With regards to urgency and when to choose "small and harmless fixes vs
>> bigger and better fixes", I think Junio has generally made those calls
>> in the past. @Taylor if you have an opinion, I'd love to hear it.
>
> I feel like I'm missing something here. What's the regression? The test
> you're adding here didn't work at all until 0f5e8851737 (Merge branch
> 'rc/fetch-refetch', 2022-04-04), as the command didn't exist yet. That
> commit went out with v2.36.0.
>
> If it never worked there's no regression, and we wouldn't be merging
> down a fix for older point-releases.
>
> Or is there some case I've missed here which did work before, doesn't
> now, but just isn't captured in this test? If so what case is that, and
> when did it break?

Right, this wasn't meant to be a regression fix at all. There's good
reason to believe that this was always broken, so I never went digging
to see if it ever worked.

Even so, it doesn't change the fact that it's a use case that we've
expected to work, but doesn't due to some internal silliness, and that
we could fix it without invoking questions of the "--super-prefix"
design and dragging out the process (which is admittedly what I should
have done in the first place). Since we have such an easy fix in front
of us, I don't feel good about not fixing this before the next release.

At any rate, I'm wiling to accept that I'm being overly cautious,
because it's quite likely that this series will make it into the next
release. (We could technically we unbreak 'next', though I don't know
who distributes that other than internally @ Google.) I'm ok to drop my
patch for now, but I'll revive it if it starts to look like this series
won't make it into the next release.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 00/10] Get rid of "git --super-prefix"
  2022-11-16 21:07         ` Glen Choo
@ 2022-11-17 18:07           ` Ævar Arnfjörð Bjarmason
  2022-11-21 19:16             ` Glen Choo
  0 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-17 18:07 UTC (permalink / raw)
  To: Glen Choo; +Cc: git, Taylor Blau, Robert Coup


On Wed, Nov 16 2022, Glen Choo wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> On Mon, Nov 14 2022, Glen Choo wrote:
>>
>>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>>>
>>>> It's also proposing to replace Glen's one-patch[6], which is working
>>>> around the problem shown in the test added in 1/10 here. Per
>>>> downthread of [7] I think Glen was aiming for getting a more narrow
>>>> fix in case we split off 9/10 here into some later fix.
>>>>
>>>> As we're fixing an edge case in something that's always been broken
>>>> (and thus wouldn't backport) I think it's better to just fix the
>>>> problem directly, rather than introducing new "--super-prefix" use,
>>>> just to take it away later.
>>>
>>> I still prefer that we take the one-patch to unbreak new releases,
>>> because partial clone + submodules is absolutely broken (e.g. it's
>>> already causing quite a lot of headaches at $DAYJOB) and the patch is
>>> obviously harmless.
>>>
>>> And more importantly, it lets us take our time with this series and get
>>> it right without time pressure. It's not as pressing as, e.g. a
>>> regression fix, but it does render certain Git setups unusable.
>>>
>>> With regards to urgency and when to choose "small and harmless fixes vs
>>> bigger and better fixes", I think Junio has generally made those calls
>>> in the past. @Taylor if you have an opinion, I'd love to hear it.
>>
>> I feel like I'm missing something here. What's the regression? The test
>> you're adding here didn't work at all until 0f5e8851737 (Merge branch
>> 'rc/fetch-refetch', 2022-04-04), as the command didn't exist yet. That
>> commit went out with v2.36.0.
>>
>> If it never worked there's no regression, and we wouldn't be merging
>> down a fix for older point-releases.
>>
>> Or is there some case I've missed here which did work before, doesn't
>> now, but just isn't captured in this test? If so what case is that, and
>> when did it break?
>
> Right, this wasn't meant to be a regression fix at all. There's good
> reason to believe that this was always broken, so I never went digging
> to see if it ever worked.
>
> Even so, it doesn't change the fact that it's a use case that we've
> expected to work, but doesn't due to some internal silliness, and that
> we could fix it without invoking questions of the "--super-prefix"
> design and dragging out the process (which is admittedly what I should
> have done in the first place). Since we have such an easy fix in front
> of us, I don't feel good about not fixing this before the next release.
>
> At any rate, I'm wiling to accept that I'm being overly cautious,
> because it's quite likely that this series will make it into the next
> release. (We could technically we unbreak 'next', though I don't know
> who distributes that other than internally @ Google.) I'm ok to drop my
> patch for now, but I'll revive it if it starts to look like this series
> won't make it into the next release.

Understood, I'm re-rolling this v2, will send it out soon.

I'll keep that patch out for now, but if we're starting to run up
against the next release how about we split it out? So it'll depend on
how fast we can review & test this, and if/when Taylor is OK with
merging it down.

I really don't care if the fix comes first, but just thought I was
missing something and it didn't seem urgent, as it was in the "never
worked" and not "a regression" category AFAICT. But if you'd still like
it shout, and I'll just stack it at the start...


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 02/10] submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  2022-11-14 21:22       ` Glen Choo
@ 2022-11-17 18:10         ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-17 18:10 UTC (permalink / raw)
  To: Glen Choo; +Cc: git, Taylor Blau, Robert Coup


On Mon, Nov 14 2022, Glen Choo wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> The "--super-prefix" facility was introduced in [1] has always been a
>> transitory hack, which is why we've made it an error to supply it as
>> an option to "git" to commands that don't know about it.
>>
>> That's been a good goal, as it has a global effect we haven't wanted
>> calls to get_super_prefix() from built-ins we didn't expect.
>>
>> But it has meant that when we've had chains of different built-ins
>> using it all of the processes in that "chain" have needed to support
>> it, and worse processes that don't need it have needed to ask for
>> "SUPPORT_SUPER_PREFIX" because their parent process needs it.
>>
>> That's how "fsmonitor--daemon" ended up with it, per [2] it's called
>> from (among other things) "submodule--helper absorbgitdirs", but as we
>> declared "submodule--helper" as "SUPPORT_SUPER_PREFIX" we needed to
>> declare "fsmonitor--daemon" as accepting it too, even though it
>> doesn't care about it.
>>
>> But in the case of "absorbgitdirs" it only needed "--super-prefix" to
>> invoke itself recursively, and we'd never have another "in-between"
>> process in the chain. So we didn't need the bigger hammer of "git
>> --super-prefix", and the "setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)"
>> that it entails.
>>
>> Let's instead accept a hidden "--super-prefix" option to
>> "submodule--helper absorbgitdirs" itself.
>>
>> Eventually (as with all other "--super-prefix" users) we'll want to
>> clean this code up so that this all happens in-process. I.e. needing
>> any variant of "--super-prefix" is itself a hack around our various
>> global state, and implicit reliance on "the_repository". This stepping
>> stone makes such an eventual change easier, as we'll need to deal with
>> less global state at that point.
>>
>> The "fsmonitor--daemon" test adjusted here was added in [3]. The
>> comment added in that commit has been out-of-date from the beginning,
>> and the "have_t2_error_event()" was being overly specific in testing
>> for a bug that we *don't* have. Let's instead test for the stdout and
>> stderr that we *do have*.
>
> I didn't understand this bit initially, because I read this as
> "have_t2_error_event() isn't catching bugs", which isn't true. But I see
> what you mean after inspecting the test_cmp output:
>
>   @@ -1 +1,2 @@
>   Migrating git directory of 'dir_1/dir_2/sub' from 'dir_1/dir_2/sub/.git' to '.git/modules/dir_1/dir_2/sub'
>   +fatal: fsmonitor--daemon doesn't support --super-prefix
>
> IOW, it doesn't make sense to inspecting the tr2 output for stray
> warnings when our stderr is so obviously broken. But at the end of the
> series, I don't think we even need this test at all because if we don't
> have a global "--super-prefix", there's literally no reason for
> fsmonitor--daemon to worry about absorbgitdirs or "supporting" the super
> prefix. That's why I removed it in [1].
>
> Wondering aloud, that stderr suggests that the "git submodule absorbgitdirs"
> invocation failed. I wonder why the test didn't catch a bad exit code
> (and resulting in us inspecting stderr unnecessarily). I think it's not
> worth looking too closely at right now, but we could revisit this after
> we get builtin/submodule.c.
>
> [1] https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com

I'm prepping a re-roll where I'll keep some of this test, as testing
fsmonitor+absorbgitdirs is worthhwile, but the commit message etc. is
rephrased.

>> diff --git a/git.c b/git.c
>> index 10202a7f126..b1b7e1a837e 100644
>> --- a/git.c
>> +++ b/git.c
>> @@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {
>>  	{ "format-patch", cmd_format_patch, RUN_SETUP },
>>  	{ "fsck", cmd_fsck, RUN_SETUP },
>>  	{ "fsck-objects", cmd_fsck, RUN_SETUP },
>> -	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
>> +	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP },
>>  	{ "gc", cmd_gc, RUN_SETUP },
>>  	{ "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT },
>>  	{ "grep", cmd_grep, RUN_SETUP_GENTLY },
>> diff --git a/parse-options.h b/parse-options.h
>> index b6ef86e0d15..50d852f2991 100644
>> --- a/parse-options.h
>> +++ b/parse-options.h
>> @@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
>>  	{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"),	\
>>  	  N_("use <n> digits to display object names"),	\
>>  	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
>> +#define OPT__SUPER_PREFIX(var) \
>> +	OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
>> +		N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
>> +
>
> Could we default to "" instead of NULL? (possibly via a callback). I
> think there's never any good reason to have NULL instead of "", e.g.
> since this is internal, we don't care to distinguish between
> "--super-prefix=''" and not passing "--super-prefix" at all...

I saw this comment on another patch, I think I'll keep it for now, but I
updated the reason: It's because the "prefix" is either NULL or a
non-zero length string, so we're doing the same here to be consistent
with it.

I think that makes sense, but ultimately it's an arbitrary choice, but
as they're sibling variables in the cases they're used doing the same
seems worthwhile...

>>  #define OPT__COLOR(var, h) \
>>  	OPT_COLOR_FLAG(0, "color", (var), (h))
>>  #define OPT_COLUMN(s, l, v, h) \
>> diff --git a/submodule.c b/submodule.c
>> index c47358097fd..d9fd0af81b6 100644
>> --- a/submodule.c
>> +++ b/submodule.c
>> @@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)
>>   * Embeds a single submodules git directory into the superprojects git dir,
>>   * non recursively.
>>   */
>> -static void relocate_single_git_dir_into_superproject(const char *path)
>> +static void relocate_single_git_dir_into_superproject(const char *path,
>> +						      const char *super_prefix)
>>  {
>>  	char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
>>  	struct strbuf new_gitdir = STRBUF_INIT;
>> @@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
>>  	       real_old_git_dir[off] == real_new_git_dir[off])
>>  		off++;
>>  	fprintf(stderr, _("Migrating git directory of '%s%s' from '%s' to '%s'\n"),
>> -		get_super_prefix_or_empty(), path,
>> +		(super_prefix ? super_prefix : ""), path,
>>  		real_old_git_dir + off, real_new_git_dir + off);
>
>
> Which would make sites like these a bit cleaner.
>
> Tangentially, 'default to "" if NULL' sounds like a common pattern. Is
> there a good reason not to have a macro or inline function to do that?
> e.g. we think the ternary expression is good enough?)

See above.

>>  
>>  	relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
>> @@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)
>>  	strbuf_release(&new_gitdir);
>>  }
>>  
>> -static void absorb_git_dir_into_superproject_recurse(const char *path)
>> +static void absorb_git_dir_into_superproject_recurse(const char *path,
>> +						     const char *super_prefix)
>>  {
>>  
>>  	struct child_process cp = CHILD_PROCESS_INIT;
>> @@ -2321,10 +2323,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
>>  	cp.dir = path;
>>  	cp.git_cmd = 1;
>>  	cp.no_stdin = 1;
>> -	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
>> -		     get_super_prefix_or_empty(), path);
>>  	strvec_pushl(&cp.args, "submodule--helper",
>>  		     "absorbgitdirs", NULL);
>> +	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
>> +		     super_prefix : "", path);
>> +
>>  	prepare_submodule_repo_env(&cp.env);
>>  	if (run_command(&cp))
>>  		die(_("could not recurse into submodule '%s'"), path);
>> @@ -2335,7 +2338,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
>>   * having its git directory within the working tree to the git dir nested
>>   * in its superprojects git dir under modules/.
>>   */
>> -void absorb_git_dir_into_superproject(const char *path)
>> +void absorb_git_dir_into_superproject_sp(const char *path,
>> +					 const char *super_prefix)
>>  {
>>  	int err_code;
>>  	const char *sub_git_dir;
>> @@ -2377,14 +2381,14 @@ void absorb_git_dir_into_superproject(const char *path)
>>  		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(path);
>> +			relocate_single_git_dir_into_superproject(path, super_prefix);
>>  
>>  		free(real_sub_git_dir);
>>  		free(real_common_git_dir);
>>  	}
>>  	strbuf_release(&gitdir);
>>  
>> -	absorb_git_dir_into_superproject_recurse(path);
>> +	absorb_git_dir_into_superproject_recurse(path, super_prefix);
>>  }
>>  
>>  int get_superproject_working_tree(struct strbuf *buf)
>> diff --git a/submodule.h b/submodule.h
>> index b52a4ff1e73..e5ee13fb06a 100644
>> --- a/submodule.h
>> +++ b/submodule.h
>> @@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);
>>   */
>>  void prepare_submodule_repo_env(struct strvec *env);
>>  
>> -void absorb_git_dir_into_superproject(const char *path);
>> +void absorb_git_dir_into_superproject_sp(const char *path,
>> +					 const char *super_prefix);
>> +static inline void absorb_git_dir_into_superproject(const char *path)
>> +{
>> +	absorb_git_dir_into_superproject_sp(path, NULL);
>> +}
>
> Is there a reason you chose to go with _sp() instead of changing the
> original function signature? I tested out that change, and it seems
> rather small (absorb_git_dir_into_superproject() only has 4 call sites).

I've just changed that, so no more *_sp()...

> Crucially, changing the signature catches a "git read-tree" call site:
>
>   diff --git a/submodule.c b/submodule.c
>   index d9fd0af81b..e79a04d3e3 100644
>   --- a/submodule.c
>   +++ b/submodule.c
>   @@ -2139,7 +2139,9 @@ int submodule_move_head(const char *path,
>           if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
>                   if (old_head) {
>                           if (!submodule_uses_gitfile(path))
>   -                               absorb_git_dir_into_superproject(path);
>   +                               /* Pass super_prefix properly later. */
>   +                               absorb_git_dir_into_superproject(path,
>   +                                                                get_super_prefix());
>                   } else {
>                           struct strbuf gitdir = STRBUF_INIT;
>                           submodule_name_to_gitdir(&gitdir, the_repository,
>
> which would otherwise be broken since we used to read the global super
> prefix, but we don't do that in this patch. This has no test coverage
> (bleh), but it shouldn't be too hard, something like:
>
>   git init super &&
>   cd super &&
>   # Create an unabsorbed submodule right in the worktree
>   git init sub &&
>   test_commit -C sub "foo" &&
>   git add sub &&
>   git commit -m "Add submodule" &&
>   test_commit "bar" &&
>   # This should invoke "git read-tree" and absorb the git dir.
>   # Or maybe we should invoke "git read-tree" directly?
>   git checkout --recurse-submodules HEAD^ 2>err &&
>   # Search for the shortened message
>   grep "Migrating submodule sub from sub to .git/modules/...." err

Ah! Yeah that is a good catch, and a great reason to do it this way.

I tried to come up with a test case that actually tested this. I.e. I
set a "here = 1" at that absorb_git_dir_into_superproject() in the diff
above, and then if BUG()'d out in that function, but the part where
we're about to recurse.

I couldn't get it to trigger, but I didn't look at it very
long. I.e. doesn't this require not this sort of test, but something
where it's being absorbed, *and* we'd walk and absorb it recursiveyl?

At least with checkout we then run into an error (can't remember the
message, sorry, this was earlier), and I haven't found a way to trigger
it.

But I'll poke it some more, but if you happen to have a test case for it
that would really help...

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 04/10] submodule--helper: convert "foreach" to its own "--super-prefix"
  2022-11-14 21:56       ` Glen Choo
@ 2022-11-17 18:14         ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-17 18:14 UTC (permalink / raw)
  To: Glen Choo; +Cc: git, Taylor Blau, Robert Coup


On Mon, Nov 14 2022, Glen Choo wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> As with a preceding commit to convert "absorbgitdirs", we can convert
>> "submodule--helper foreach" to use its own "--super-prefix", instead
>> of relying on the global "--super-prefix" argument to "git"
>> itself. See that earlier commit for the rationale and background.
>>
>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>> ---
>>  builtin/submodule--helper.c | 15 ++++++++++-----
>>  1 file changed, 10 insertions(+), 5 deletions(-)
>>
>> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
>> index c4d5e029b37..989c75280af 100644
>> --- a/builtin/submodule--helper.c
>> +++ b/builtin/submodule--helper.c
>> @@ -396,7 +398,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
>>  	struct foreach_cb info = FOREACH_CB_INIT;
>>  	struct pathspec pathspec = { 0 };
>>  	struct module_list list = MODULE_LIST_INIT;
>> +	const char *super_prefix = NULL;
>>  	struct option module_foreach_options[] = {
>> +		OPT__SUPER_PREFIX(&super_prefix),
>>  		OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
>>  		OPT_BOOL(0, "recursive", &info.recursive,
>>  			 N_("recurse into nested submodules")),
>> @@ -417,6 +421,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
>>  	info.argc = argc;
>>  	info.argv = argv;
>>  	info.prefix = prefix;
>> +	info.super_prefix = super_prefix;
>
> (Also applies to subsequent patches) Why don't we assign the super
> prefix directly to the struct's field? e.g.
>
> 		OPT__SUPER_PREFIX(&info.super_prefix),

Good point! I've done that consistently in my WIP re-roll.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* [PATCH v3 0/9] Get rid of "git --super-prefix"
  2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
                       ` (12 preceding siblings ...)
  2022-11-14 23:39     ` Glen Choo
@ 2022-11-19 12:41     ` Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 1/9] read-tree + fetch tests: test failing "--super-prefix" interaction Ævar Arnfjörð Bjarmason
                         ` (9 more replies)
  13 siblings, 10 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

= Summary

What's "--super-prefix"? The "git" command takes an "internal use
only" "--super-prefix" option, which is used to inform processes
invoked in submodules what the path prefix to the invoking
superproject is.

This is so so that e.g. "git submodule absorbgitdirs" can report
"sub-1/sub-2", instead of "sub-2" when being invoked in the "sub-1"
submodule.

For this the "--super-prefix" facility has been doing a
setenv("GIT_INTERNAL_SUPER_PREFIX", "sub-1/") as soon as it got the
"--supre-prefix=sub-1/". We'd then pass that along via the environment
when invoking the sub-process.

As this series shows we don't need such a hands-off global facility to
do this, we can instead just pass the relevant context directly in
each command. E.g. "git submodule absorbgitdirs" can pass the path to
the "git submodule absorbgitdirs" sub-process it's about to invoke.

= Relation to other submissions

This is on top of "ab/submodule-helper-prep-only" and
"ab/submodule-no-abspath", buth currently in "next".

= Changes since v2:

* Fixes for test_when_finished() in test setup, and got rid of
  redundant test_config_global.

* There's a new 2/9, which passes along get_super_prefix() as a
  parameter. This allows us to gradually replace it, and drop the
  *_sp() variants of functions that the previous version introduced,
  and it adds "super_prefix" to the absorb_git_dir_into_superproject()
  call in submodule_move_head(), which as Glen noticed I'd missed

* Squashed the "deinit" change into that 2/9.

* Explain why we keep the "fsmonitor" test bits that we do.

* Dropped the new "git branch" output tests, turns out I was just
  wrong, and was conflating it with the subsequent read-tree
  invocation...

So, this should address all outstanding feedbakc, unless I've missed
something.

The one loose end here is that I still have no idea if you can invoke
get "read-tree" to invoke that submodule_move_head() in such a way as
to have the "super_prefix" used, I've failed to come up with a test
case for that.

But for the purposes of this topic it doesn't really matter. In 8/10
we'll start passing the new "--super-prefix" that "read-tree" gets
down to that function. At worst we're handing it to it redundantly,
but that was the case before too.

So we can leave potentially turning that into a "NULL" for some other
time, for now providing the "super_prefix" is harmless, and guarantees
that we avoid any regression in that area from not providing it, in
case I've missed a way to have it matter in that case.

= CI & fetch URL

Passing at: https://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local-3

Glen Choo (1):
  read-tree + fetch tests: test failing "--super-prefix" interaction

Ævar Arnfjörð Bjarmason (8):
  submodule.c & submodule--helper: pass along "super_prefix" param
  submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  submodule--helper: convert "foreach" to its own "--super-prefix"
  submodule--helper: convert "sync" to its own "--super-prefix"
  submodule--helper: convert "status" to its own "--super-prefix"
  submodule--helper: convert "{update,clone}" to their own
    "--super-prefix"
  read-tree: add "--super-prefix" option, eliminate global
  fetch: rename "--submodule-prefix" to "--super-prefix"

 Documentation/fetch-options.txt |  5 --
 Documentation/git.txt           |  8 +--
 builtin.h                       |  4 --
 builtin/checkout.c              |  2 +-
 builtin/fetch.c                 |  7 ++-
 builtin/read-tree.c             |  1 +
 builtin/rm.c                    |  2 +-
 builtin/submodule--helper.c     | 87 ++++++++++++++++++---------------
 cache.h                         |  2 -
 entry.c                         | 12 ++---
 entry.h                         |  6 ++-
 environment.c                   | 13 -----
 git.c                           | 41 +++-------------
 parse-options.h                 |  4 ++
 submodule.c                     | 73 +++++++++++++--------------
 submodule.h                     |  8 +--
 t/t1001-read-tree-m-2way.sh     |  2 +-
 t/t5616-partial-clone.sh        | 43 ++++++++++++++++
 t/t7527-builtin-fsmonitor.sh    | 33 +++----------
 unpack-trees.c                  | 23 +++++----
 unpack-trees.h                  |  1 +
 21 files changed, 180 insertions(+), 197 deletions(-)

Range-diff against v2:
 1:  1114a4ff666 !  1:  c930fc38356 read-tree + fetch tests: test failing "--super-prefix" interaction
    @@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor o
     +	# setup
     +	test_config_global protocol.file.allow always &&
     +
    ++	test_when_finished "rm -rf src-sub" &&
     +	git init src-sub &&
     +	git -C src-sub config uploadpack.allowfilter 1 &&
     +	git -C src-sub config uploadpack.allowanysha1inwant 1 &&
    @@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor o
     +	git -C src-sub commit -m "submodule two" &&
     +	SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
     +
    ++	test_when_finished "rm -rf src-super" &&
     +	git init src-super &&
     +	git -C src-super config uploadpack.allowfilter 1 &&
     +	git -C src-super config uploadpack.allowanysha1inwant 1 &&
    @@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor o
     +	git -C src-super commit -m "superproject two" &&
     +
     +	# the fetch
    -+	test_when_finished "rm -rf src-super src-sub client" &&
    -+
    -+	test_config_global protocol.file.allow always &&
    ++	test_when_finished "rm -rf client" &&
     +	git clone --filter=blob:none --also-filter-submodules \
     +		--recurse-submodules "file://$(pwd)/src-super" client &&
     +
 3:  a7a1f9487dc !  2:  2e4a2236898 submodule--helper: "deinit" has never used "--super-prefix"
    @@ Metadata
     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## Commit message ##
    -    submodule--helper: "deinit" has never used "--super-prefix"
    +    submodule.c & submodule--helper: pass along "super_prefix" param
     
    -    The "deinit_submodule()" function has never been able to use the "git
    -    --super-prefix". It will call "absorb_git_dir_into_superproject()",
    -    but it will only do so from the top-level project.
    +    Start passing the "super_prefix" along as a parameter to
    +    get_submodule_displaypath() and absorb_git_dir_into_superproject(),
    +    rather than get the value directly as a global.
     
    -    If "absorbgitdirs" recurses it will use the "path" passed to
    -    "absorb_git_dir_into_superproject()" in "deinit_submodule()" as its
    -    starting "--super-prefix".
    +    This is in preparation for subsequent commits, where we'll gradually
    +    phase out get_super_prefix() for an alternative way of getting the
    +    "super_prefix".
     
    -    So, let's introduce a "get_submodule_displaypath_sp()" helper, and
    -    make our existing "get_submodule_displaypath()" a wrapper for it. In a
    -    subsequent commit the wrapper will be going away, as the rest of the
    -    commands here will stop using the global "get_super_prefix()".
    +    Most of the users of this get a get_super_prefix() value, either
    +    directly or by indirection. The exceptions are:
    +
    +    - builtin/rm.c: Doesn't declare SUPPORT_SUPER_PREFIX, so we'd have
    +      died if this was provided, so it's safe to passs "NULL".
    +
    +    - deinit_submodule(): The "deinit_submodule()" function has never been
    +      able to use the "git -super-prefix". It will call
    +      "absorb_git_dir_into_superproject()", but it will only do so from the
    +      top-level project.
    +
    +      If "absorbgitdirs" recurses it will use the "path" passed to
    +      "absorb_git_dir_into_superproject()" in "deinit_submodule()" as its
    +      starting "--super-prefix". So we can safely remove the
    +      get_super_prefix() call here, and pass NULL instead.
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    + ## builtin/rm.c ##
    +@@ builtin/rm.c: static void submodules_absorb_gitdir_if_needed(void)
    + 			continue;
    + 
    + 		if (!submodule_uses_gitfile(name))
    +-			absorb_git_dir_into_superproject(name);
    ++			absorb_git_dir_into_superproject(name, NULL);
    + 	}
    + }
    + 
    +
      ## builtin/submodule--helper.c ##
     @@ builtin/submodule--helper.c: static char *resolve_relative_url(const char *rel_url, const char *up_path, int
      }
      
      /* the result should be freed by the caller. */
     -static char *get_submodule_displaypath(const char *path, const char *prefix)
    -+static char *get_submodule_displaypath_sp(const char *path, const char *prefix,
    -+					  const char *super_prefix)
    ++static char *get_submodule_displaypath(const char *path, const char *prefix,
    ++				       const char *super_prefix)
      {
     -	const char *super_prefix = get_super_prefix();
     -
      	if (prefix && super_prefix) {
      		BUG("cannot have prefix '%s' and superprefix '%s'",
      		    prefix, super_prefix);
    -@@ builtin/submodule--helper.c: static char *get_submodule_displaypath(const char *path, const char *prefix)
    +@@ builtin/submodule--helper.c: static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
    + 	struct child_process cp = CHILD_PROCESS_INIT;
    + 	char *displaypath;
    + 
    +-	displaypath = get_submodule_displaypath(path, info->prefix);
    ++	displaypath = get_submodule_displaypath(path, info->prefix,
    ++						get_super_prefix());
    + 
    + 	sub = submodule_from_path(the_repository, null_oid(), path);
    + 
    +@@ builtin/submodule--helper.c: static void init_submodule(const char *path, const char *prefix,
    + 	const char *upd;
    + 	char *url = NULL, *displaypath;
    + 
    +-	displaypath = get_submodule_displaypath(path, prefix);
    ++	displaypath = get_submodule_displaypath(path, prefix,
    ++						get_super_prefix());
    + 
    + 	sub = submodule_from_path(the_repository, null_oid(), path);
    + 
    +@@ builtin/submodule--helper.c: static void status_submodule(const char *path, const struct object_id *ce_oid,
    + 		die(_("no submodule mapping found in .gitmodules for path '%s'"),
    + 		      path);
    + 
    +-	displaypath = get_submodule_displaypath(path, prefix);
    ++	displaypath = get_submodule_displaypath(path, prefix,
    ++						get_super_prefix());
    + 
    + 	if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
    + 		print_status(flags, 'U', path, null_oid(), displaypath);
    +@@ builtin/submodule--helper.c: static void generate_submodule_summary(struct summary_cb *info,
    + 		dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
      	}
    - }
      
    -+static char *get_submodule_displaypath(const char *path, const char *prefix)
    -+{
    -+	const char *super_prefix = get_super_prefix();
    -+
    -+	return get_submodule_displaypath_sp(path, prefix, super_prefix);
    -+}
    -+
    - static char *compute_rev_name(const char *sub_path, const char* object_id)
    - {
    - 	struct strbuf sb = STRBUF_INIT;
    +-	displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
    ++	displaypath = get_submodule_displaypath(p->sm_path, info->prefix,
    ++						get_super_prefix());
    + 
    + 	if (!missing_src && !missing_dst) {
    + 		struct child_process cp_rev_list = CHILD_PROCESS_INIT;
    +@@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const char *prefix,
    + 		super_config_url = xstrdup("");
    + 	}
    + 
    +-	displaypath = get_submodule_displaypath(path, prefix);
    ++	displaypath = get_submodule_displaypath(path, prefix,
    ++						get_super_prefix());
    + 
    + 	if (!(flags & OPT_QUIET))
    + 		printf(_("Synchronizing submodule url for '%s'\n"),
     @@ builtin/submodule--helper.c: static void deinit_submodule(const char *path, const char *prefix,
      	if (!sub || !sub->name)
      		goto cleanup;
      
     -	displaypath = get_submodule_displaypath(path, prefix);
    -+	displaypath = get_submodule_displaypath_sp(path, prefix, NULL);
    ++	displaypath = get_submodule_displaypath(path, prefix, NULL);
      
      	/* remove the submodule work tree (unless the user already did it) */
      	if (is_directory(path)) {
    +@@ builtin/submodule--helper.c: static void deinit_submodule(const char *path, const char *prefix,
    + 					  ".git file by using absorbgitdirs."),
    + 					displaypath);
    + 
    +-			absorb_git_dir_into_superproject(path);
    ++			absorb_git_dir_into_superproject(path, NULL);
    + 
    + 		}
    + 
    +@@ builtin/submodule--helper.c: static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
    + 	enum submodule_update_type update_type;
    + 	char *key;
    + 	const struct update_data *ud = suc->update_data;
    +-	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
    ++	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix,
    ++						      get_super_prefix());
    + 	struct strbuf sb = STRBUF_INIT;
    + 	int needs_cloning = 0;
    + 	int need_free_url = 0;
    +@@ builtin/submodule--helper.c: static int update_submodules(struct update_data *update_data)
    + 			goto fail;
    + 
    + 		update_data->displaypath = get_submodule_displaypath(
    +-			update_data->sm_path, update_data->prefix);
    ++			update_data->sm_path, update_data->prefix,
    ++			get_super_prefix());
    + 		code = update_submodule(update_data);
    + 		FREE_AND_NULL(update_data->displaypath);
    + fail:
    +@@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
    + 	int i;
    + 	struct pathspec pathspec = { 0 };
    + 	struct module_list list = MODULE_LIST_INIT;
    ++	const char *super_prefix;
    + 	struct option embed_gitdir_options[] = {
    + 		OPT_END()
    + 	};
    +@@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
    + 	if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
    + 		goto cleanup;
    + 
    ++	super_prefix = get_super_prefix();
    + 	for (i = 0; i < list.nr; i++)
    +-		absorb_git_dir_into_superproject(list.entries[i]->name);
    ++		absorb_git_dir_into_superproject(list.entries[i]->name,
    ++						 super_prefix);
    + 
    + 	ret = 0;
    + cleanup:
    +
    + ## submodule.c ##
    +@@ submodule.c: int submodule_move_head(const char *path,
    + 	if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
    + 		if (old_head) {
    + 			if (!submodule_uses_gitfile(path))
    +-				absorb_git_dir_into_superproject(path);
    ++				absorb_git_dir_into_superproject(path,
    ++								 get_super_prefix());
    + 		} else {
    + 			struct strbuf gitdir = STRBUF_INIT;
    + 			submodule_name_to_gitdir(&gitdir, the_repository,
    +@@ submodule.c: static void relocate_single_git_dir_into_superproject(const char *path)
    + 	strbuf_release(&new_gitdir);
    + }
    + 
    +-static void absorb_git_dir_into_superproject_recurse(const char *path)
    ++static void absorb_git_dir_into_superproject_recurse(const char *path,
    ++						     const char *super_prefix)
    + {
    + 
    + 	struct child_process cp = CHILD_PROCESS_INIT;
    +@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path)
    + 	cp.dir = path;
    + 	cp.git_cmd = 1;
    + 	cp.no_stdin = 1;
    +-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
    +-		     get_super_prefix_or_empty(), path);
    ++	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
    ++		     super_prefix : "", path);
    + 	strvec_pushl(&cp.args, "submodule--helper",
    + 		     "absorbgitdirs", NULL);
    + 	prepare_submodule_repo_env(&cp.env);
    +@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path)
    +  * having its git directory within the working tree to the git dir nested
    +  * in its superprojects git dir under modules/.
    +  */
    +-void absorb_git_dir_into_superproject(const char *path)
    ++void absorb_git_dir_into_superproject(const char *path,
    ++				      const char *super_prefix)
    + {
    + 	int err_code;
    + 	const char *sub_git_dir;
    +@@ submodule.c: void absorb_git_dir_into_superproject(const char *path)
    + 	}
    + 	strbuf_release(&gitdir);
    + 
    +-	absorb_git_dir_into_superproject_recurse(path);
    ++	absorb_git_dir_into_superproject_recurse(path, super_prefix);
    + }
    + 
    + int get_superproject_working_tree(struct strbuf *buf)
    +
    + ## submodule.h ##
    +@@ submodule.h: void submodule_unset_core_worktree(const struct submodule *sub);
    +  */
    + void prepare_submodule_repo_env(struct strvec *env);
    + 
    +-void absorb_git_dir_into_superproject(const char *path);
    ++void absorb_git_dir_into_superproject(const char *path,
    ++				      const char *super_prefix);
    + 
    + /*
    +  * Return the absolute path of the working tree of the superproject, which this
 2:  5a35f7b75b3 !  3:  6e10a47c60a submodule--helper: don't use global --super-prefix in "absorbgitdirs"
    @@ Commit message
         stone makes such an eventual change easier, as we'll need to deal with
         less global state at that point.
     
    -    The "fsmonitor--daemon" test adjusted here was added in [3]. The
    -    comment added in that commit has been out-of-date from the beginning,
    -    and the "have_t2_error_event()" was being overly specific in testing
    -    for a bug that we *don't* have. Let's instead test for the stdout and
    -    stderr that we *do have*.
    +    The "fsmonitor--daemon" test adjusted here was added in [3]. To assert
    +    that it didn't run into the "--super-prefix" message it was asserting
    +    the output it didn't have. Let's instead assert the full output that
    +    we *do* have, which we can do here as this is based on a change[4] to
    +    make it predictable (until [4] it contained absolute paths).
    +
    +    We could also remove the test entirely (as [5] did), but even though
    +    the initial reason for having it is gone we're still getting some
    +    marginal benefit from testing the "fsmonitor" and "submodule
    +    absorbgitdirs" interaction, so let's keep it.
    +
    +    The change here to have either a NULL or non-"" string as a
    +    "super_prefix" instead of the previous arrangement of "" or non-"" is
    +    somewhat arbitrary. We could also decide to never have to check for
    +    NULL.
    +
    +    As we'll be changing the rest of the "git --super-prefix" users to the
    +    same pattern, leaving them all consistent makes sense. Why not pick ""
    +    over NULL? Because that's how the "prefix" works[6], and having
    +    "prefix" and "super_prefix" work the same way will be less
    +    confusing. That "prefix" picked NULL instead of "" is itself
    +    arbitrary, but as it's easy to make this small bit of our overall API
    +    consistent, let's go with that.
     
         1. 74866d75793 (git: make super-prefix option, 2016-10-07)
         2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
            2022-05-26)
         3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
            2022-05-26)
    +    4. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/
    +    5. https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com/
    +    6. 9725c8dda20 (built-ins: trust the "prefix" from run_builtin(),
    +       2022-02-16)
     
         Signed-off-by: Glen Choo <chooglen@google.com>
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
    @@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **a
      	int i;
      	struct pathspec pathspec = { 0 };
      	struct module_list list = MODULE_LIST_INIT;
    +-	const char *super_prefix;
     +	const char *super_prefix = NULL;
      	struct option embed_gitdir_options[] = {
     +		OPT__SUPER_PREFIX(&super_prefix),
    @@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **a
      	};
      	const char *const git_submodule_helper_usage[] = {
     @@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
    + 	if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
      		goto cleanup;
      
    +-	super_prefix = get_super_prefix();
      	for (i = 0; i < list.nr; i++)
    --		absorb_git_dir_into_superproject(list.entries[i]->name);
    -+		absorb_git_dir_into_superproject_sp(list.entries[i]->name,
    -+						    super_prefix);
    - 
    - 	ret = 0;
    - cleanup:
    + 		absorb_git_dir_into_superproject(list.entries[i]->name,
    + 						 super_prefix);
     @@ builtin/submodule--helper.c: int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
      
      	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
    @@ submodule.c: static void relocate_single_git_dir_into_superproject(const char *p
      		off++;
      	fprintf(stderr, _("Migrating git directory of '%s%s' from '%s' to '%s'\n"),
     -		get_super_prefix_or_empty(), path,
    -+		(super_prefix ? super_prefix : ""), path,
    ++		super_prefix ? super_prefix : "", path,
      		real_old_git_dir + off, real_new_git_dir + off);
      
      	relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
    -@@ submodule.c: static void relocate_single_git_dir_into_superproject(const char *path)
    - 	strbuf_release(&new_gitdir);
    - }
    - 
    --static void absorb_git_dir_into_superproject_recurse(const char *path)
    -+static void absorb_git_dir_into_superproject_recurse(const char *path,
    -+						     const char *super_prefix)
    - {
    - 
    - 	struct child_process cp = CHILD_PROCESS_INIT;
    -@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path)
    +@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path,
      	cp.dir = path;
      	cp.git_cmd = 1;
      	cp.no_stdin = 1;
    --	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
    --		     get_super_prefix_or_empty(), path);
    +-	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
    +-		     super_prefix : "", path);
      	strvec_pushl(&cp.args, "submodule--helper",
      		     "absorbgitdirs", NULL);
     +	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
    @@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *pa
      	prepare_submodule_repo_env(&cp.env);
      	if (run_command(&cp))
      		die(_("could not recurse into submodule '%s'"), path);
    -@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path)
    -  * having its git directory within the working tree to the git dir nested
    -  * in its superprojects git dir under modules/.
    -  */
    --void absorb_git_dir_into_superproject(const char *path)
    -+void absorb_git_dir_into_superproject_sp(const char *path,
    -+					 const char *super_prefix)
    - {
    - 	int err_code;
    - 	const char *sub_git_dir;
    -@@ submodule.c: void absorb_git_dir_into_superproject(const char *path)
    +@@ submodule.c: void absorb_git_dir_into_superproject(const char *path,
      		char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
      
      		if (!starts_with(real_sub_git_dir, real_common_git_dir))
    @@ submodule.c: void absorb_git_dir_into_superproject(const char *path)
      
      		free(real_sub_git_dir);
      		free(real_common_git_dir);
    - 	}
    - 	strbuf_release(&gitdir);
    - 
    --	absorb_git_dir_into_superproject_recurse(path);
    -+	absorb_git_dir_into_superproject_recurse(path, super_prefix);
    - }
    - 
    - int get_superproject_working_tree(struct strbuf *buf)
    -
    - ## submodule.h ##
    -@@ submodule.h: void submodule_unset_core_worktree(const struct submodule *sub);
    -  */
    - void prepare_submodule_repo_env(struct strvec *env);
    - 
    --void absorb_git_dir_into_superproject(const char *path);
    -+void absorb_git_dir_into_superproject_sp(const char *path,
    -+					 const char *super_prefix);
    -+static inline void absorb_git_dir_into_superproject(const char *path)
    -+{
    -+	absorb_git_dir_into_superproject_sp(path, NULL);
    -+}
    - 
    - /*
    -  * Return the absolute path of the working tree of the superproject, which this
     
      ## t/t7527-builtin-fsmonitor.sh ##
     @@ t/t7527-builtin-fsmonitor.sh: test_expect_success 'submodule always visited' '
 4:  935d8070834 !  4:  da86eb3b867 submodule--helper: convert "foreach" to its own "--super-prefix"
    @@ builtin/submodule--helper.c: struct foreach_cb {
      	int recursive;
      };
     @@ builtin/submodule--helper.c: static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
    - 	struct child_process cp = CHILD_PROCESS_INIT;
      	char *displaypath;
      
    --	displaypath = get_submodule_displaypath(path, info->prefix);
    -+	displaypath = get_submodule_displaypath_sp(path, info->prefix,
    -+						   info->super_prefix);
    + 	displaypath = get_submodule_displaypath(path, info->prefix,
    +-						get_super_prefix());
    ++						info->super_prefix);
      
      	sub = submodule_from_path(the_repository, null_oid(), path);
      
    @@ builtin/submodule--helper.c: static void runcommand_in_submodule_cb(const struct
      		if (info->quiet)
      			strvec_push(&cpr.args, "--quiet");
     @@ builtin/submodule--helper.c: static int module_foreach(int argc, const char **argv, const char *prefix)
    - 	struct foreach_cb info = FOREACH_CB_INIT;
      	struct pathspec pathspec = { 0 };
      	struct module_list list = MODULE_LIST_INIT;
    -+	const char *super_prefix = NULL;
      	struct option module_foreach_options[] = {
    -+		OPT__SUPER_PREFIX(&super_prefix),
    ++		OPT__SUPER_PREFIX(&info.super_prefix),
      		OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
      		OPT_BOOL(0, "recursive", &info.recursive,
      			 N_("recurse into nested submodules")),
    -@@ builtin/submodule--helper.c: static int module_foreach(int argc, const char **argv, const char *prefix)
    - 	info.argc = argc;
    - 	info.argv = argv;
    - 	info.prefix = prefix;
    -+	info.super_prefix = super_prefix;
    - 
    - 	for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
    - 
     @@ builtin/submodule--helper.c: int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
      	subcmd = argv[0];
      
 5:  933c752513d !  5:  2eb583148a6 submodule--helper: convert "sync" to its own "--super-prefix"
    @@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const
      		super_config_url = xstrdup("");
      	}
      
    --	displaypath = get_submodule_displaypath(path, prefix);
    -+	displaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);
    +-	displaypath = get_submodule_displaypath(path, prefix,
    +-						get_super_prefix());
    ++	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
      
      	if (!(flags & OPT_QUIET))
      		printf(_("Synchronizing submodule url for '%s'\n"),
    @@ builtin/submodule--helper.c: static void sync_submodule_cb(const struct cache_en
      
      static int module_sync(int argc, const char **argv, const char *prefix)
     @@ builtin/submodule--helper.c: static int module_sync(int argc, const char **argv, const char *prefix)
    - 	struct module_list list = MODULE_LIST_INIT;
      	int quiet = 0;
      	int recursive = 0;
    -+	const char *super_prefix = NULL;
      	struct option module_sync_options[] = {
    -+		OPT__SUPER_PREFIX(&super_prefix),
    ++		OPT__SUPER_PREFIX(&info.super_prefix),
      		OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
      		OPT_BOOL(0, "recursive", &recursive,
      			N_("recurse into nested submodules")),
    -@@ builtin/submodule--helper.c: static int module_sync(int argc, const char **argv, const char *prefix)
    - 		goto cleanup;
    - 
    - 	info.prefix = prefix;
    -+	info.super_prefix = super_prefix;
    - 	if (quiet)
    - 		info.flags |= OPT_QUIET;
    - 	if (recursive)
     @@ builtin/submodule--helper.c: static int module_set_url(int argc, const char **argv, const char *prefix)
      	config_name = xstrfmt("submodule.%s.url", path);
      
 6:  67273f729e0 !  6:  8d8925c7e1f submodule--helper: convert "status" to its own "--super-prefix"
    @@ builtin/submodule--helper.c: static void status_submodule(const char *path, cons
      		die(_("no submodule mapping found in .gitmodules for path '%s'"),
      		      path);
      
    --	displaypath = get_submodule_displaypath(path, prefix);
    -+	displaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);
    +-	displaypath = get_submodule_displaypath(path, prefix,
    +-						get_super_prefix());
    ++	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
      
      	if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
      		print_status(flags, 'U', path, null_oid(), displaypath);
    @@ builtin/submodule--helper.c: static void status_submodule_cb(const struct cache_
      
      static int module_status(int argc, const char **argv, const char *prefix)
     @@ builtin/submodule--helper.c: static int module_status(int argc, const char **argv, const char *prefix)
    - 	struct pathspec pathspec = { 0 };
      	struct module_list list = MODULE_LIST_INIT;
      	int quiet = 0;
    -+	const char *super_prefix = NULL;
      	struct option module_status_options[] = {
    -+		OPT__SUPER_PREFIX(&super_prefix),
    ++		OPT__SUPER_PREFIX(&info.super_prefix),
      		OPT__QUIET(&quiet, N_("suppress submodule status output")),
      		OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
      		OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
    -@@ builtin/submodule--helper.c: static int module_status(int argc, const char **argv, const char *prefix)
    - 		goto cleanup;
    - 
    - 	info.prefix = prefix;
    -+	info.super_prefix = super_prefix;
    - 	if (quiet)
    - 		info.flags |= OPT_QUIET;
    - 
     @@ builtin/submodule--helper.c: int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
      	subcmd = argv[0];
      
 7:  eaa73f5b1e4 !  7:  754a7489aa5 submodule--helper: convert "{update,clone}" to their own "--super-prefix"
    @@ Commit message
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## builtin/submodule--helper.c ##
    -@@ builtin/submodule--helper.c: static char *get_submodule_displaypath_sp(const char *path, const char *prefix,
    - 	}
    - }
    - 
    --static char *get_submodule_displaypath(const char *path, const char *prefix)
    --{
    --	const char *super_prefix = get_super_prefix();
    --
    --	return get_submodule_displaypath_sp(path, prefix, super_prefix);
    --}
    --
    - static char *compute_rev_name(const char *sub_path, const char* object_id)
    - {
    - 	struct strbuf sb = STRBUF_INIT;
     @@ builtin/submodule--helper.c: static int starts_with_dot_dot_slash(const char *const path)
      
      struct init_cb {
    @@ builtin/submodule--helper.c: static void init_submodule(const char *path, const
      	const char *upd;
      	char *url = NULL, *displaypath;
      
    --	displaypath = get_submodule_displaypath(path, prefix);
    -+	displaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);
    +-	displaypath = get_submodule_displaypath(path, prefix,
    +-						get_super_prefix());
    ++	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
      
      	sub = submodule_from_path(the_repository, null_oid(), path);
      
    @@ builtin/submodule--helper.c: struct summary_cb {
      	unsigned int for_status: 1;
      	unsigned int files: 1;
     @@ builtin/submodule--helper.c: static void generate_submodule_summary(struct summary_cb *info,
    - 		dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
      	}
      
    --	displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
    -+	displaypath = get_submodule_displaypath_sp(p->sm_path, info->prefix,
    -+						   info->super_prefix);
    + 	displaypath = get_submodule_displaypath(p->sm_path, info->prefix,
    +-						get_super_prefix());
    ++						info->super_prefix);
      
      	if (!missing_src && !missing_dst) {
      		struct child_process cp_rev_list = CHILD_PROCESS_INIT;
    @@ builtin/submodule--helper.c: static void submodule_update_clone_release(struct s
      	enum submodule_update_type update_default;
      	struct object_id suboid;
     @@ builtin/submodule--helper.c: static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
    - 	enum submodule_update_type update_type;
      	char *key;
      	const struct update_data *ud = suc->update_data;
    --	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
    -+	char *displaypath = get_submodule_displaypath_sp(ce->name, ud->prefix,
    -+							 ud->super_prefix);
    + 	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix,
    +-						      get_super_prefix());
    ++						      ud->super_prefix);
      	struct strbuf sb = STRBUF_INIT;
      	int needs_cloning = 0;
      	int need_free_url = 0;
    @@ builtin/submodule--helper.c: static void update_data_to_args(const struct update
      	if (update_data->quiet)
      		strvec_push(args, "--quiet");
     @@ builtin/submodule--helper.c: static int update_submodules(struct update_data *update_data)
    - 		if (code)
    - 			goto fail;
      
    --		update_data->displaypath = get_submodule_displaypath(
    --			update_data->sm_path, update_data->prefix);
    -+		update_data->displaypath = get_submodule_displaypath_sp(
    -+			update_data->sm_path, update_data->prefix,
    + 		update_data->displaypath = get_submodule_displaypath(
    + 			update_data->sm_path, update_data->prefix,
    +-			get_super_prefix());
     +			update_data->super_prefix);
      		code = update_submodule(update_data);
      		FREE_AND_NULL(update_data->displaypath);
      fail:
     @@ builtin/submodule--helper.c: static int module_update(int argc, const char **argv, const char *prefix)
    - 	struct list_objects_filter_options filter_options =
      		LIST_OBJECTS_FILTER_INIT;
      	int ret;
    -+	const char *super_prefix = NULL;
      	struct option module_update_options[] = {
    -+		OPT__SUPER_PREFIX(&super_prefix),
    ++		OPT__SUPER_PREFIX(&opt.super_prefix),
      		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
      		OPT_BOOL(0, "init", &opt.init,
      			 N_("initialize uninitialized submodules before update")),
     @@ builtin/submodule--helper.c: static int module_update(int argc, const char **argv, const char *prefix)
    - 
    - 	opt.filter_options = &filter_options;
    - 	opt.prefix = prefix;
    -+	opt.super_prefix = super_prefix;
    - 
    - 	if (opt.update_default)
    - 		opt.update_strategy.type = opt.update_default;
    -@@ builtin/submodule--helper.c: static int module_update(int argc, const char **argv, const char *prefix)
      			module_list_active(&list);
      
      		info.prefix = opt.prefix;
    -+		info.super_prefix = super_prefix;
    ++		info.super_prefix = opt.super_prefix;
      		if (opt.quiet)
      			info.flags |= OPT_QUIET;
      
 8:  172b5865811 <  -:  ----------- submodule tests: test "git branch -t" output and stderr
 9:  9fdeab60773 !  8:  f952fa3d01f read-tree: add "--super-prefix" option, eliminate global
    @@ submodule.c: static void submodule_reset_index(const char *path)
      {
      	int ret = 0;
      	struct child_process cp = CHILD_PROCESS_INIT;
    +@@ submodule.c: int submodule_move_head(const char *path,
    + 		if (old_head) {
    + 			if (!submodule_uses_gitfile(path))
    + 				absorb_git_dir_into_superproject(path,
    +-								 get_super_prefix());
    ++								 super_prefix);
    + 		} else {
    + 			struct strbuf gitdir = STRBUF_INIT;
    + 			submodule_name_to_gitdir(&gitdir, the_repository,
     @@ submodule.c: int submodule_move_head(const char *path,
      			strbuf_release(&gitdir);
      
10:  100ba36dfb7 =  9:  1aa4019527a fetch: rename "--submodule-prefix" to "--super-prefix"
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply	[flat|nested] 79+ messages in thread

* [PATCH v3 1/9] read-tree + fetch tests: test failing "--super-prefix" interaction
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
@ 2022-11-19 12:41       ` Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 2/9] submodule.c & submodule--helper: pass along "super_prefix" param Ævar Arnfjörð Bjarmason
                         ` (8 subsequent siblings)
  9 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

From: Glen Choo <chooglen@google.com>

Ever since "git fetch --refetch" was introduced in 0f5e8851737 (Merge
branch 'rc/fetch-refetch', 2022-04-04) the test being added here would
fail. This is because "restore" will "read-tree .. --reset <hash>",
which will in turn invoke "fetch". The "fetch" will then die with:

	fatal: fetch doesn't support --super-prefix

This edge case and other "--super-prefix" bugs will be fixed in
subsequent commits, but let's first add a "test_expect_failure" test
for it. It passes until the very last command in the test.

Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 037941b95d2..2846ec6629c 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '
 	grep "loosen_unused_packed_objects/loosened:0" trace
 '
 
+test_expect_failure 'lazy-fetch in submodule succeeds' '
+	# setup
+	test_config_global protocol.file.allow always &&
+
+	test_when_finished "rm -rf src-sub" &&
+	git init src-sub &&
+	git -C src-sub config uploadpack.allowfilter 1 &&
+	git -C src-sub config uploadpack.allowanysha1inwant 1 &&
+
+	# This blob must be missing in the subsequent commit.
+	echo foo >src-sub/file &&
+	git -C src-sub add file &&
+	git -C src-sub commit -m "submodule one" &&
+	SUB_ONE=$(git -C src-sub rev-parse HEAD) &&
+
+	echo bar >src-sub/file &&
+	git -C src-sub add file &&
+	git -C src-sub commit -m "submodule two" &&
+	SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
+
+	test_when_finished "rm -rf src-super" &&
+	git init src-super &&
+	git -C src-super config uploadpack.allowfilter 1 &&
+	git -C src-super config uploadpack.allowanysha1inwant 1 &&
+	git -C src-super submodule add ../src-sub src-sub &&
+
+	git -C src-super/src-sub checkout $SUB_ONE &&
+	git -C src-super add src-sub &&
+	git -C src-super commit -m "superproject one" &&
+
+	git -C src-super/src-sub checkout $SUB_TWO &&
+	git -C src-super add src-sub &&
+	git -C src-super commit -m "superproject two" &&
+
+	# the fetch
+	test_when_finished "rm -rf client" &&
+	git clone --filter=blob:none --also-filter-submodules \
+		--recurse-submodules "file://$(pwd)/src-super" client &&
+
+	# Trigger lazy-fetch from the superproject
+	git -C client restore --recurse-submodules --source=HEAD^ :/
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 2/9] submodule.c & submodule--helper: pass along "super_prefix" param
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 1/9] read-tree + fetch tests: test failing "--super-prefix" interaction Ævar Arnfjörð Bjarmason
@ 2022-11-19 12:41       ` Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 3/9] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
                         ` (7 subsequent siblings)
  9 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

Start passing the "super_prefix" along as a parameter to
get_submodule_displaypath() and absorb_git_dir_into_superproject(),
rather than get the value directly as a global.

This is in preparation for subsequent commits, where we'll gradually
phase out get_super_prefix() for an alternative way of getting the
"super_prefix".

Most of the users of this get a get_super_prefix() value, either
directly or by indirection. The exceptions are:

- builtin/rm.c: Doesn't declare SUPPORT_SUPER_PREFIX, so we'd have
  died if this was provided, so it's safe to passs "NULL".

- deinit_submodule(): The "deinit_submodule()" function has never been
  able to use the "git -super-prefix". It will call
  "absorb_git_dir_into_superproject()", but it will only do so from the
  top-level project.

  If "absorbgitdirs" recurses it will use the "path" passed to
  "absorb_git_dir_into_superproject()" in "deinit_submodule()" as its
  starting "--super-prefix". So we can safely remove the
  get_super_prefix() call here, and pass NULL instead.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/rm.c                |  2 +-
 builtin/submodule--helper.c | 35 ++++++++++++++++++++++-------------
 submodule.c                 | 15 +++++++++------
 submodule.h                 |  3 ++-
 4 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/builtin/rm.c b/builtin/rm.c
index 05bfe20a469..24e13f6e899 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -86,7 +86,7 @@ static void submodules_absorb_gitdir_if_needed(void)
 			continue;
 
 		if (!submodule_uses_gitfile(name))
-			absorb_git_dir_into_superproject(name);
+			absorb_git_dir_into_superproject(name, NULL);
 	}
 }
 
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c75e9e86b06..dc220d3348b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
 }
 
 /* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *get_submodule_displaypath(const char *path, const char *prefix,
+				       const char *super_prefix)
 {
-	const char *super_prefix = get_super_prefix();
-
 	if (prefix && super_prefix) {
 		BUG("cannot have prefix '%s' and superprefix '%s'",
 		    prefix, super_prefix);
@@ -294,7 +293,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 	struct child_process cp = CHILD_PROCESS_INIT;
 	char *displaypath;
 
-	displaypath = get_submodule_displaypath(path, info->prefix);
+	displaypath = get_submodule_displaypath(path, info->prefix,
+						get_super_prefix());
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -447,7 +447,8 @@ static void init_submodule(const char *path, const char *prefix,
 	const char *upd;
 	char *url = NULL, *displaypath;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath(path, prefix,
+						get_super_prefix());
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -624,7 +625,8 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		die(_("no submodule mapping found in .gitmodules for path '%s'"),
 		      path);
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath(path, prefix,
+						get_super_prefix());
 
 	if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
 		print_status(flags, 'U', path, null_oid(), displaypath);
@@ -948,7 +950,8 @@ static void generate_submodule_summary(struct summary_cb *info,
 		dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
 	}
 
-	displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+	displaypath = get_submodule_displaypath(p->sm_path, info->prefix,
+						get_super_prefix());
 
 	if (!missing_src && !missing_dst) {
 		struct child_process cp_rev_list = CHILD_PROCESS_INIT;
@@ -1239,7 +1242,8 @@ static void sync_submodule(const char *path, const char *prefix,
 		super_config_url = xstrdup("");
 	}
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath(path, prefix,
+						get_super_prefix());
 
 	if (!(flags & OPT_QUIET))
 		printf(_("Synchronizing submodule url for '%s'\n"),
@@ -1365,7 +1369,7 @@ static void deinit_submodule(const char *path, const char *prefix,
 	if (!sub || !sub->name)
 		goto cleanup;
 
-	displaypath = get_submodule_displaypath(path, prefix);
+	displaypath = get_submodule_displaypath(path, prefix, NULL);
 
 	/* remove the submodule work tree (unless the user already did it) */
 	if (is_directory(path)) {
@@ -1379,7 +1383,7 @@ static void deinit_submodule(const char *path, const char *prefix,
 					  ".git file by using absorbgitdirs."),
 					displaypath);
 
-			absorb_git_dir_into_superproject(path);
+			absorb_git_dir_into_superproject(path, NULL);
 
 		}
 
@@ -1958,7 +1962,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 	enum submodule_update_type update_type;
 	char *key;
 	const struct update_data *ud = suc->update_data;
-	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
+	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix,
+						      get_super_prefix());
 	struct strbuf sb = STRBUF_INIT;
 	int needs_cloning = 0;
 	int need_free_url = 0;
@@ -2608,7 +2613,8 @@ static int update_submodules(struct update_data *update_data)
 			goto fail;
 
 		update_data->displaypath = get_submodule_displaypath(
-			update_data->sm_path, update_data->prefix);
+			update_data->sm_path, update_data->prefix,
+			get_super_prefix());
 		code = update_submodule(update_data);
 		FREE_AND_NULL(update_data->displaypath);
 fail:
@@ -2828,6 +2834,7 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 	int i;
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
+	const char *super_prefix;
 	struct option embed_gitdir_options[] = {
 		OPT_END()
 	};
@@ -2843,8 +2850,10 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 	if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
 		goto cleanup;
 
+	super_prefix = get_super_prefix();
 	for (i = 0; i < list.nr; i++)
-		absorb_git_dir_into_superproject(list.entries[i]->name);
+		absorb_git_dir_into_superproject(list.entries[i]->name,
+						 super_prefix);
 
 	ret = 0;
 cleanup:
diff --git a/submodule.c b/submodule.c
index c47358097fd..d339ce3b62c 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2139,7 +2139,8 @@ int submodule_move_head(const char *path,
 	if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
 		if (old_head) {
 			if (!submodule_uses_gitfile(path))
-				absorb_git_dir_into_superproject(path);
+				absorb_git_dir_into_superproject(path,
+								 get_super_prefix());
 		} else {
 			struct strbuf gitdir = STRBUF_INIT;
 			submodule_name_to_gitdir(&gitdir, the_repository,
@@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)
 	strbuf_release(&new_gitdir);
 }
 
-static void absorb_git_dir_into_superproject_recurse(const char *path)
+static void absorb_git_dir_into_superproject_recurse(const char *path,
+						     const char *super_prefix)
 {
 
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2321,8 +2323,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
 	cp.dir = path;
 	cp.git_cmd = 1;
 	cp.no_stdin = 1;
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
+		     super_prefix : "", path);
 	strvec_pushl(&cp.args, "submodule--helper",
 		     "absorbgitdirs", NULL);
 	prepare_submodule_repo_env(&cp.env);
@@ -2335,7 +2337,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
  * having its git directory within the working tree to the git dir nested
  * in its superprojects git dir under modules/.
  */
-void absorb_git_dir_into_superproject(const char *path)
+void absorb_git_dir_into_superproject(const char *path,
+				      const char *super_prefix)
 {
 	int err_code;
 	const char *sub_git_dir;
@@ -2384,7 +2387,7 @@ void absorb_git_dir_into_superproject(const char *path)
 	}
 	strbuf_release(&gitdir);
 
-	absorb_git_dir_into_superproject_recurse(path);
+	absorb_git_dir_into_superproject_recurse(path, super_prefix);
 }
 
 int get_superproject_working_tree(struct strbuf *buf)
diff --git a/submodule.h b/submodule.h
index b52a4ff1e73..f90ee547d08 100644
--- a/submodule.h
+++ b/submodule.h
@@ -164,7 +164,8 @@ void submodule_unset_core_worktree(const struct submodule *sub);
  */
 void prepare_submodule_repo_env(struct strvec *env);
 
-void absorb_git_dir_into_superproject(const char *path);
+void absorb_git_dir_into_superproject(const char *path,
+				      const char *super_prefix);
 
 /*
  * Return the absolute path of the working tree of the superproject, which this
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 3/9] submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 1/9] read-tree + fetch tests: test failing "--super-prefix" interaction Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 2/9] submodule.c & submodule--helper: pass along "super_prefix" param Ævar Arnfjörð Bjarmason
@ 2022-11-19 12:41       ` Ævar Arnfjörð Bjarmason
  2022-11-22 19:53         ` Glen Choo
  2022-11-19 12:41       ` [PATCH v3 4/9] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
                         ` (6 subsequent siblings)
  9 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

The "--super-prefix" facility was introduced in [1] has always been a
transitory hack, which is why we've made it an error to supply it as
an option to "git" to commands that don't know about it.

That's been a good goal, as it has a global effect we haven't wanted
calls to get_super_prefix() from built-ins we didn't expect.

But it has meant that when we've had chains of different built-ins
using it all of the processes in that "chain" have needed to support
it, and worse processes that don't need it have needed to ask for
"SUPPORT_SUPER_PREFIX" because their parent process needs it.

That's how "fsmonitor--daemon" ended up with it, per [2] it's called
from (among other things) "submodule--helper absorbgitdirs", but as we
declared "submodule--helper" as "SUPPORT_SUPER_PREFIX" we needed to
declare "fsmonitor--daemon" as accepting it too, even though it
doesn't care about it.

But in the case of "absorbgitdirs" it only needed "--super-prefix" to
invoke itself recursively, and we'd never have another "in-between"
process in the chain. So we didn't need the bigger hammer of "git
--super-prefix", and the "setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)"
that it entails.

Let's instead accept a hidden "--super-prefix" option to
"submodule--helper absorbgitdirs" itself.

Eventually (as with all other "--super-prefix" users) we'll want to
clean this code up so that this all happens in-process. I.e. needing
any variant of "--super-prefix" is itself a hack around our various
global state, and implicit reliance on "the_repository". This stepping
stone makes such an eventual change easier, as we'll need to deal with
less global state at that point.

The "fsmonitor--daemon" test adjusted here was added in [3]. To assert
that it didn't run into the "--super-prefix" message it was asserting
the output it didn't have. Let's instead assert the full output that
we *do* have, which we can do here as this is based on a change[4] to
make it predictable (until [4] it contained absolute paths).

We could also remove the test entirely (as [5] did), but even though
the initial reason for having it is gone we're still getting some
marginal benefit from testing the "fsmonitor" and "submodule
absorbgitdirs" interaction, so let's keep it.

The change here to have either a NULL or non-"" string as a
"super_prefix" instead of the previous arrangement of "" or non-"" is
somewhat arbitrary. We could also decide to never have to check for
NULL.

As we'll be changing the rest of the "git --super-prefix" users to the
same pattern, leaving them all consistent makes sense. Why not pick ""
over NULL? Because that's how the "prefix" works[6], and having
"prefix" and "super_prefix" work the same way will be less
confusing. That "prefix" picked NULL instead of "" is itself
arbitrary, but as it's easy to make this small bit of our overall API
consistent, let's go with that.

1. 74866d75793 (git: make super-prefix option, 2016-10-07)
2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
   2022-05-26)
3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,
   2022-05-26)
4. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/
5. https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com/
6. 9725c8dda20 (built-ins: trust the "prefix" from run_builtin(),
   2022-02-16)

Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c  |  7 +++----
 git.c                        |  2 +-
 parse-options.h              |  4 ++++
 submodule.c                  | 12 +++++++-----
 t/t7527-builtin-fsmonitor.sh | 33 ++++++++-------------------------
 5 files changed, 23 insertions(+), 35 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index dc220d3348b..9f6ebc64140 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2834,8 +2834,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 	int i;
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
-	const char *super_prefix;
+	const char *super_prefix = NULL;
 	struct option embed_gitdir_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
 		OPT_END()
 	};
 	const char *const git_submodule_helper_usage[] = {
@@ -2850,7 +2851,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 	if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
 		goto cleanup;
 
-	super_prefix = get_super_prefix();
 	for (i = 0; i < list.nr; i++)
 		absorb_git_dir_into_superproject(list.entries[i]->name,
 						 super_prefix);
@@ -3391,8 +3391,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
 	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
-	    strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") &&
-	    get_super_prefix())
+	    strcmp(subcmd, "sync") && get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
diff --git a/git.c b/git.c
index 10202a7f126..b1b7e1a837e 100644
--- a/git.c
+++ b/git.c
@@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {
 	{ "format-patch", cmd_format_patch, RUN_SETUP },
 	{ "fsck", cmd_fsck, RUN_SETUP },
 	{ "fsck-objects", cmd_fsck, RUN_SETUP },
-	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
+	{ "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP },
 	{ "gc", cmd_gc, RUN_SETUP },
 	{ "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT },
 	{ "grep", cmd_grep, RUN_SETUP_GENTLY },
diff --git a/parse-options.h b/parse-options.h
index b6ef86e0d15..50d852f2991 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
 	{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"),	\
 	  N_("use <n> digits to display object names"),	\
 	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+#define OPT__SUPER_PREFIX(var) \
+	OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
+		N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
+
 #define OPT__COLOR(var, h) \
 	OPT_COLOR_FLAG(0, "color", (var), (h))
 #define OPT_COLUMN(s, l, v, h) \
diff --git a/submodule.c b/submodule.c
index d339ce3b62c..3383c47c719 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2269,7 +2269,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)
  * Embeds a single submodules git directory into the superprojects git dir,
  * non recursively.
  */
-static void relocate_single_git_dir_into_superproject(const char *path)
+static void relocate_single_git_dir_into_superproject(const char *path,
+						      const char *super_prefix)
 {
 	char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
 	struct strbuf new_gitdir = STRBUF_INIT;
@@ -2303,7 +2304,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
 	       real_old_git_dir[off] == real_new_git_dir[off])
 		off++;
 	fprintf(stderr, _("Migrating git directory of '%s%s' from '%s' to '%s'\n"),
-		get_super_prefix_or_empty(), path,
+		super_prefix ? super_prefix : "", path,
 		real_old_git_dir + off, real_new_git_dir + off);
 
 	relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
@@ -2323,10 +2324,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path,
 	cp.dir = path;
 	cp.git_cmd = 1;
 	cp.no_stdin = 1;
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
-		     super_prefix : "", path);
 	strvec_pushl(&cp.args, "submodule--helper",
 		     "absorbgitdirs", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
+		     super_prefix : "", path);
+
 	prepare_submodule_repo_env(&cp.env);
 	if (run_command(&cp))
 		die(_("could not recurse into submodule '%s'"), path);
@@ -2380,7 +2382,7 @@ void absorb_git_dir_into_superproject(const char *path,
 		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(path);
+			relocate_single_git_dir_into_superproject(path, super_prefix);
 
 		free(real_sub_git_dir);
 		free(real_common_git_dir);
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
index 4abc74db2bb..31526937d95 100755
--- a/t/t7527-builtin-fsmonitor.sh
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -866,30 +866,11 @@ test_expect_success 'submodule always visited' '
 # the submodule, and someone does a `git submodule absorbgitdirs`
 # in the super, Git will recursively invoke `git submodule--helper`
 # to do the work and this may try to read the index.  This will
-# try to start the daemon in the submodule *and* pass (either
-# directly or via inheritance) the `--super-prefix` arg to the
-# `git fsmonitor--daemon start` command inside the submodule.
-# This causes a warning because fsmonitor--daemon does take that
-# global arg (see the table in git.c)
-#
-# This causes a warning when trying to start the daemon that is
-# somewhat confusing.  It does not seem to hurt anything because
-# the fsmonitor code maps the query failure into a trivial response
-# and does the work anyway.
-#
-# It would be nice to silence the warning, however.
-
-have_t2_error_event () {
-	log=$1
-	msg="fsmonitor--daemon doesnQt support --super-prefix" &&
-
-	tr '\047' Q <$1 | grep -e "$msg"
-}
+# try to start the daemon in the submodule.
 
 test_expect_success "stray submodule super-prefix warning" '
 	test_when_finished "rm -rf super; \
-			    rm -rf sub;   \
-			    rm super-sub.trace" &&
+			    rm -rf sub" &&
 
 	create_super super &&
 	create_sub sub &&
@@ -904,10 +885,12 @@ test_expect_success "stray submodule super-prefix warning" '
 
 	test_path_is_dir super/dir_1/dir_2/sub/.git &&
 
-	GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
-		git -C super submodule absorbgitdirs &&
-
-	! have_t2_error_event super-sub.trace
+	cat >expect <<-\EOF &&
+	Migrating git directory of '\''dir_1/dir_2/sub'\'' from '\''dir_1/dir_2/sub/.git'\'' to '\''.git/modules/dir_1/dir_2/sub'\''
+	EOF
+	git -C super submodule absorbgitdirs >out 2>actual &&
+	test_cmp expect actual &&
+	test_must_be_empty out
 '
 
 # On a case-insensitive file system, confirm that the daemon
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 4/9] submodule--helper: convert "foreach" to its own "--super-prefix"
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
                         ` (2 preceding siblings ...)
  2022-11-19 12:41       ` [PATCH v3 3/9] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
@ 2022-11-19 12:41       ` Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 5/9] submodule--helper: convert "sync" " Ævar Arnfjörð Bjarmason
                         ` (5 subsequent siblings)
  9 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper foreach" to use its own "--super-prefix", instead
of relying on the global "--super-prefix" argument to "git"
itself. See that earlier commit for the rationale and background.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 9f6ebc64140..7c6f367fa00 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -278,6 +278,7 @@ struct foreach_cb {
 	int argc;
 	const char **argv;
 	const char *prefix;
+	const char *super_prefix;
 	int quiet;
 	int recursive;
 };
@@ -294,7 +295,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 	char *displaypath;
 
 	displaypath = get_submodule_displaypath(path, info->prefix,
-						get_super_prefix());
+						info->super_prefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -364,10 +365,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_pushl(&cpr.args, "--super-prefix", NULL);
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
 			     NULL);
+		strvec_pushl(&cpr.args, "--super-prefix", NULL);
+		strvec_pushf(&cpr.args, "%s/", displaypath);
 
 		if (info->quiet)
 			strvec_push(&cpr.args, "--quiet");
@@ -391,6 +392,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
 	struct option module_foreach_options[] = {
+		OPT__SUPER_PREFIX(&info.super_prefix),
 		OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
 		OPT_BOOL(0, "recursive", &info.recursive,
 			 N_("recurse into nested submodules")),
@@ -3390,8 +3392,8 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 	subcmd = argv[0];
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
-	    strcmp(subcmd, "sync") && get_super_prefix())
+	    strcmp(subcmd, "status") && strcmp(subcmd, "sync") &&
+	    get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 5/9] submodule--helper: convert "sync" to its own "--super-prefix"
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
                         ` (3 preceding siblings ...)
  2022-11-19 12:41       ` [PATCH v3 4/9] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-19 12:41       ` Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 6/9] submodule--helper: convert "status" " Ævar Arnfjörð Bjarmason
                         ` (4 subsequent siblings)
  9 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper sync" to use its own "--super-prefix", instead of
relying on the global "--super-prefix" argument to "git" itself. See
that earlier commit for the rationale and background.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 7c6f367fa00..7ac51c3506d 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1208,12 +1208,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)
 
 struct sync_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define SYNC_CB_INIT { 0 }
 
 static void sync_submodule(const char *path, const char *prefix,
-			   unsigned int flags)
+			   const char *super_prefix, unsigned int flags)
 {
 	const struct submodule *sub;
 	char *remote_key = NULL;
@@ -1244,8 +1245,7 @@ static void sync_submodule(const char *path, const char *prefix,
 		super_config_url = xstrdup("");
 	}
 
-	displaypath = get_submodule_displaypath(path, prefix,
-						get_super_prefix());
+	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
 
 	if (!(flags & OPT_QUIET))
 		printf(_("Synchronizing submodule url for '%s'\n"),
@@ -1282,10 +1282,11 @@ static void sync_submodule(const char *path, const char *prefix,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "sync",
 			     "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
+
 
 		if (flags & OPT_QUIET)
 			strvec_push(&cpr.args, "--quiet");
@@ -1308,7 +1309,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data
 {
 	struct sync_cb *info = cb_data;
 
-	sync_submodule(list_item->name, info->prefix, info->flags);
+	sync_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
 }
 
 static int module_sync(int argc, const char **argv, const char *prefix)
@@ -1319,6 +1321,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)
 	int quiet = 0;
 	int recursive = 0;
 	struct option module_sync_options[] = {
+		OPT__SUPER_PREFIX(&info.super_prefix),
 		OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
 		OPT_BOOL(0, "recursive", &recursive,
 			N_("recurse into nested submodules")),
@@ -2887,7 +2890,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
 	config_name = xstrfmt("submodule.%s.url", path);
 
 	config_set_in_gitmodules_file_gently(config_name, newurl);
-	sync_submodule(path, prefix, quiet ? OPT_QUIET : 0);
+	sync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);
 
 	free(config_name);
 
@@ -3392,8 +3395,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 	subcmd = argv[0];
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "status") && strcmp(subcmd, "sync") &&
-	    get_super_prefix())
+	    strcmp(subcmd, "status") && get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 6/9] submodule--helper: convert "status" to its own "--super-prefix"
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
                         ` (4 preceding siblings ...)
  2022-11-19 12:41       ` [PATCH v3 5/9] submodule--helper: convert "sync" " Ævar Arnfjörð Bjarmason
@ 2022-11-19 12:41       ` Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 7/9] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
                         ` (3 subsequent siblings)
  9 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper status" to use its own "--super-prefix", instead of
relying on the global "--super-prefix" argument to "git" itself. See
that earlier commit for the rationale and background.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 7ac51c3506d..8a186b61b9d 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -573,6 +573,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
 
 struct status_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define STATUS_CB_INIT { 0 }
@@ -611,7 +612,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,
 
 static void status_submodule(const char *path, const struct object_id *ce_oid,
 			     unsigned int ce_flags, const char *prefix,
-			     unsigned int flags)
+			     const char *super_prefix, unsigned int flags)
 {
 	char *displaypath;
 	struct strvec diff_files_args = STRVEC_INIT;
@@ -627,8 +628,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		die(_("no submodule mapping found in .gitmodules for path '%s'"),
 		      path);
 
-	displaypath = get_submodule_displaypath(path, prefix,
-						get_super_prefix());
+	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
 
 	if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
 		print_status(flags, 'U', path, null_oid(), displaypath);
@@ -686,10 +686,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
 		cpr.dir = path;
 		prepare_submodule_repo_env(&cpr.env);
 
-		strvec_push(&cpr.args, "--super-prefix");
-		strvec_pushf(&cpr.args, "%s/", displaypath);
 		strvec_pushl(&cpr.args, "submodule--helper", "status",
 			     "--recursive", NULL);
+		strvec_push(&cpr.args, "--super-prefix");
+		strvec_pushf(&cpr.args, "%s/", displaypath);
 
 		if (flags & OPT_CACHED)
 			strvec_push(&cpr.args, "--cached");
@@ -713,7 +713,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,
 	struct status_cb *info = cb_data;
 
 	status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
-			 info->prefix, info->flags);
+			 info->prefix, info->super_prefix, info->flags);
 }
 
 static int module_status(int argc, const char **argv, const char *prefix)
@@ -723,6 +723,7 @@ static int module_status(int argc, const char **argv, const char *prefix)
 	struct module_list list = MODULE_LIST_INIT;
 	int quiet = 0;
 	struct option module_status_options[] = {
+		OPT__SUPER_PREFIX(&info.super_prefix),
 		OPT__QUIET(&quiet, N_("suppress submodule status output")),
 		OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
 		OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
@@ -3395,7 +3396,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 	subcmd = argv[0];
 
 	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    strcmp(subcmd, "status") && get_super_prefix())
+	    get_super_prefix())
 		/*
 		 * xstrfmt() rather than "%s %s" to keep the translated
 		 * string identical to git.c's.
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 7/9] submodule--helper: convert "{update,clone}" to their own "--super-prefix"
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
                         ` (5 preceding siblings ...)
  2022-11-19 12:41       ` [PATCH v3 6/9] submodule--helper: convert "status" " Ævar Arnfjörð Bjarmason
@ 2022-11-19 12:41       ` Ævar Arnfjörð Bjarmason
  2022-11-19 12:41       ` [PATCH v3 8/9] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
                         ` (2 subsequent siblings)
  9 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

As with a preceding commit to convert "absorbgitdirs", we can convert
"submodule--helper status" to use its own "--super-prefix", instead of
relying on the global "--super-prefix" argument to "git".

We need to convert both of these away from the global "--super-prefix"
at the same time, because "update" will call "clone", but "clone"
itself didn't make use of the global "--super-prefix" for displaying
paths. It was only on the list of sub-commands that accepted it
because "update"'s use of it would set it in its environment.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/submodule--helper.c | 32 +++++++++++++-------------------
 git.c                       |  2 +-
 2 files changed, 14 insertions(+), 20 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 8a186b61b9d..b1945a06da1 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -437,11 +437,13 @@ static int starts_with_dot_dot_slash(const char *const path)
 
 struct init_cb {
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int flags;
 };
 #define INIT_CB_INIT { 0 }
 
 static void init_submodule(const char *path, const char *prefix,
+			   const char *super_prefix,
 			   unsigned int flags)
 {
 	const struct submodule *sub;
@@ -449,8 +451,7 @@ static void init_submodule(const char *path, const char *prefix,
 	const char *upd;
 	char *url = NULL, *displaypath;
 
-	displaypath = get_submodule_displaypath(path, prefix,
-						get_super_prefix());
+	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
 
 	sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -526,7 +527,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data
 {
 	struct init_cb *info = cb_data;
 
-	init_submodule(list_item->name, info->prefix, info->flags);
+	init_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
 }
 
 static int module_init(int argc, const char **argv, const char *prefix)
@@ -792,6 +794,7 @@ struct summary_cb {
 	int argc;
 	const char **argv;
 	const char *prefix;
+	const char *super_prefix;
 	unsigned int cached: 1;
 	unsigned int for_status: 1;
 	unsigned int files: 1;
@@ -954,7 +957,7 @@ static void generate_submodule_summary(struct summary_cb *info,
 	}
 
 	displaypath = get_submodule_displaypath(p->sm_path, info->prefix,
-						get_super_prefix());
+						info->super_prefix);
 
 	if (!missing_src && !missing_dst) {
 		struct child_process cp_rev_list = CHILD_PROCESS_INIT;
@@ -1893,6 +1896,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)
 
 struct update_data {
 	const char *prefix;
+	const char *super_prefix;
 	char *displaypath;
 	enum submodule_update_type update_default;
 	struct object_id suboid;
@@ -1969,7 +1973,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 	char *key;
 	const struct update_data *ud = suc->update_data;
 	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix,
-						      get_super_prefix());
+						      ud->super_prefix);
 	struct strbuf sb = STRBUF_INIT;
 	int needs_cloning = 0;
 	int need_free_url = 0;
@@ -2449,11 +2453,11 @@ static void update_data_to_args(const struct update_data *update_data,
 {
 	enum submodule_update_type update_type = update_data->update_default;
 
+	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
 	if (update_data->displaypath) {
 		strvec_push(args, "--super-prefix");
 		strvec_pushf(args, "%s/", update_data->displaypath);
 	}
-	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
 	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
 	if (update_data->quiet)
 		strvec_push(args, "--quiet");
@@ -2620,7 +2624,7 @@ static int update_submodules(struct update_data *update_data)
 
 		update_data->displaypath = get_submodule_displaypath(
 			update_data->sm_path, update_data->prefix,
-			get_super_prefix());
+			update_data->super_prefix);
 		code = update_submodule(update_data);
 		FREE_AND_NULL(update_data->displaypath);
 fail:
@@ -2646,6 +2650,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 		LIST_OBJECTS_FILTER_INIT;
 	int ret;
 	struct option module_update_options[] = {
+		OPT__SUPER_PREFIX(&opt.super_prefix),
 		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
 		OPT_BOOL(0, "init", &opt.init,
 			 N_("initialize uninitialized submodules before update")),
@@ -2742,6 +2747,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
 			module_list_active(&list);
 
 		info.prefix = opt.prefix;
+		info.super_prefix = opt.super_prefix;
 		if (opt.quiet)
 			info.flags |= OPT_QUIET;
 
@@ -3368,8 +3374,6 @@ static int module_add(int argc, const char **argv, const char *prefix)
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 {
-	const char *cmd = argv[0];
-	const char *subcmd;
 	parse_opt_subcommand_fn *fn = NULL;
 	const char *const usage[] = {
 		N_("git submodule--helper <command>"),
@@ -3393,16 +3397,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
-	subcmd = argv[0];
-
-	if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
-	    get_super_prefix())
-		/*
-		 * xstrfmt() rather than "%s %s" to keep the translated
-		 * string identical to git.c's.
-		 */
-		die(_("%s doesn't support --super-prefix"),
-		    xstrfmt("'%s %s'", cmd, subcmd));
 
 	return fn(argc, argv, prefix);
 }
diff --git a/git.c b/git.c
index b1b7e1a837e..2bca22cfd9a 100644
--- a/git.c
+++ b/git.c
@@ -610,7 +610,7 @@ static struct cmd_struct commands[] = {
 	{ "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
 	{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 	{ "stripspace", cmd_stripspace },
-	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },
+	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP },
 	{ "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
 	{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 	{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 8/9] read-tree: add "--super-prefix" option, eliminate global
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
                         ` (6 preceding siblings ...)
  2022-11-19 12:41       ` [PATCH v3 7/9] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
@ 2022-11-19 12:41       ` Ævar Arnfjörð Bjarmason
  2022-11-22 19:57         ` Glen Choo
  2022-11-19 12:41       ` [PATCH v3 9/9] fetch: rename "--submodule-prefix" to "--super-prefix" Ævar Arnfjörð Bjarmason
  2022-11-22 22:29       ` [PATCH v3 0/9] Get rid of "git --super-prefix" Glen Choo
  9 siblings, 1 reply; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

The "--super-prefix" option to "git" was initially added in [1] for
use with "ls-files"[2], and shortly thereafter "submodule--helper"[3]
and "grep"[4]. It wasn't until [5] that "read-tree" made use of it.

At the time [5] made sense, but since then we've made "ls-files"
recurse in-process in [6], "grep" in [7], and finally
"submodule--helper" in the preceding commits.

Let's also remove it from "read-tree", which allows us to remove the
option to "git" itself.

We can do this because the only remaining user of it is the submodule
API, which will now invoke "read-tree" with its new "--super-prefix"
option. It will only do so when the "submodule_move_head()" function
is called.

That "submodule_move_head()" function was then only invoked by
"read-tree" itself, but now rather than setting an environment
variable to pass "--super-prefix" between cmd_read_tree() we:

- Set a new "super_prefix" in "struct unpack_trees_options". The
  "super_prefixed()" function in "unpack-trees.c" added in [5] will now
  use this, rather than get_super_prefix() looking up the environment
  variable we set earlier in the same process.

- Add the same field to the "struct checkout", which is only needed to
  ferry the "super_prefix" in the "struct unpack_trees_options" all the
  way down to the "entry.c" callers of "submodule_move_head()".

  Those calls which used the super prefix all originated in
  "cmd_read_tree()". The only other caller is the "unlink_entry()"
  caller in "builtin/checkout.c", which now passes a "NULL".

1. 74866d75793 (git: make super-prefix option, 2016-10-07)
2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)
3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)
4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)
5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)
6. 188dce131fa (ls-files: use repository object, 2017-06-22)
7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 Documentation/git.txt       |  8 +-------
 builtin.h                   |  4 ----
 builtin/checkout.c          |  2 +-
 builtin/read-tree.c         |  1 +
 cache.h                     |  2 --
 entry.c                     | 12 ++++++------
 entry.h                     |  6 +++++-
 environment.c               | 13 -------------
 git.c                       | 37 +++++--------------------------------
 submodule.c                 | 29 ++++++++++-------------------
 submodule.h                 |  5 ++---
 t/t1001-read-tree-m-2way.sh |  2 +-
 t/t5616-partial-clone.sh    |  2 +-
 unpack-trees.c              | 23 +++++++++++++----------
 unpack-trees.h              |  1 +
 15 files changed, 47 insertions(+), 100 deletions(-)

diff --git a/Documentation/git.txt b/Documentation/git.txt
index 1d33e083ab8..f9a7a4554cd 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -13,8 +13,7 @@ SYNOPSIS
     [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
     [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
     [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
-    [--super-prefix=<path>] [--config-env=<name>=<envvar>]
-    <command> [<args>]
+    [--config-env=<name>=<envvar>] <command> [<args>]
 
 DESCRIPTION
 -----------
@@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use
 	details.  Equivalent to setting the `GIT_NAMESPACE` environment
 	variable.
 
---super-prefix=<path>::
-	Currently for internal use only.  Set a prefix which gives a path from
-	above a repository down to its root.  One use is to give submodules
-	context about the superproject that invoked it.
-
 --bare::
 	Treat the repository as a bare repository.  If GIT_DIR
 	environment is not set, it is set to the current working
diff --git a/builtin.h b/builtin.h
index 8901a34d6bf..8264b7e5241 100644
--- a/builtin.h
+++ b/builtin.h
@@ -51,10 +51,6 @@
  *	on bare repositories.
  *	This only makes sense when `RUN_SETUP` is also set.
  *
- * `SUPPORT_SUPER_PREFIX`:
- *
- *	The built-in supports `--super-prefix`.
- *
  * `DELAY_PAGER_CONFIG`:
  *
  *	If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2a132392fbe..dc008fb45e8 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -231,7 +231,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
 		pos++;
 	}
 	if (!overlay_mode) {
-		unlink_entry(ce);
+		unlink_entry(ce, NULL);
 		return 0;
 	}
 	if (stage == 2)
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index f4cbe460b97..4b6f22e58c1 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
 	int prefix_set = 0;
 	struct lock_file lock_file = LOCK_INIT;
 	const struct option read_tree_options[] = {
+		OPT__SUPER_PREFIX(&opts.super_prefix),
 		OPT_CALLBACK_F(0, "index-output", NULL, N_("file"),
 		  N_("write resulting index to <file>"),
 		  PARSE_OPT_NONEG, index_output_cb),
diff --git a/cache.h b/cache.h
index 26ed03bd6de..a4a0377b800 100644
--- a/cache.h
+++ b/cache.h
@@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)
 #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
-#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
 int get_common_dir(struct strbuf *sb, const char *gitdir);
 const char *get_git_namespace(void);
 const char *strip_namespace(const char *namespaced_ref);
-const char *get_super_prefix(void);
 const char *get_git_work_tree(void);
 
 /*
diff --git a/entry.c b/entry.c
index 616e4f073c1..971ab268714 100644
--- a/entry.c
+++ b/entry.c
@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
 			return error("cannot create submodule directory %s", path);
 		sub = submodule_from_ce(ce);
 		if (sub)
-			return submodule_move_head(ce->name,
+			return submodule_move_head(ce->name, state->super_prefix,
 				NULL, oid_to_hex(&ce->oid),
 				state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
 		break;
@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 			 * no pathname to return.
 			 */
 			BUG("Can't remove entry to a path");
-		unlink_entry(ce);
+		unlink_entry(ce, state->super_prefix);
 		return 0;
 	}
 
@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 				if (!(st.st_mode & S_IFDIR))
 					unlink_or_warn(ce->name);
 
-				return submodule_move_head(ce->name,
+				return submodule_move_head(ce->name, state->super_prefix,
 					NULL, oid_to_hex(&ce->oid), 0);
 			} else
-				return submodule_move_head(ce->name,
+				return submodule_move_head(ce->name, state->super_prefix,
 					"HEAD", oid_to_hex(&ce->oid),
 					state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
 		}
@@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
 	return write_entry(ce, path.buf, ca, state, 0, nr_checkouts);
 }
 
-void unlink_entry(const struct cache_entry *ce)
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)
 {
 	const struct submodule *sub = submodule_from_ce(ce);
 	if (sub) {
 		/* state.force is set at the caller. */
-		submodule_move_head(ce->name, "HEAD", NULL,
+		submodule_move_head(ce->name, super_prefix, "HEAD", NULL,
 				    SUBMODULE_MOVE_HEAD_FORCE);
 	}
 	if (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)
diff --git a/entry.h b/entry.h
index 9be4659881e..2d4fbb88c8f 100644
--- a/entry.h
+++ b/entry.h
@@ -8,6 +8,7 @@ struct checkout {
 	struct index_state *istate;
 	const char *base_dir;
 	int base_dir_len;
+	const char *super_prefix;
 	struct delayed_checkout *delayed_checkout;
 	struct checkout_metadata meta;
 	unsigned force:1,
@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);
 /*
  * Unlink the last component and schedule the leading directories for
  * removal, such that empty directories get removed.
+ *
+ * The "super_prefix" is either NULL, or the "--super-prefix" passed
+ * down from "read-tree" et al.
  */
-void unlink_entry(const struct cache_entry *ce);
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);
 
 void *read_blob_entry(const struct cache_entry *ce, size_t *size);
 int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);
diff --git a/environment.c b/environment.c
index 18d042b467d..1ee3686fd8a 100644
--- a/environment.c
+++ b/environment.c
@@ -102,8 +102,6 @@ char *git_work_tree_cfg;
 
 static char *git_namespace;
 
-static char *super_prefix;
-
 /*
  * Repository-local GIT_* environment variables; see cache.h for details.
  */
@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {
 	NO_REPLACE_OBJECTS_ENVIRONMENT,
 	GIT_REPLACE_REF_BASE_ENVIRONMENT,
 	GIT_PREFIX_ENVIRONMENT,
-	GIT_SUPER_PREFIX_ENVIRONMENT,
 	GIT_SHALLOW_FILE_ENVIRONMENT,
 	GIT_COMMON_DIR_ENVIRONMENT,
 	NULL
@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)
 	return NULL;
 }
 
-const char *get_super_prefix(void)
-{
-	static int initialized;
-	if (!initialized) {
-		super_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));
-		initialized = 1;
-	}
-	return super_prefix;
-}
-
 static int git_work_tree_initialized;
 
 /*
diff --git a/git.c b/git.c
index 2bca22cfd9a..00baaf23590 100644
--- a/git.c
+++ b/git.c
@@ -14,9 +14,8 @@
  * RUN_SETUP for reading from the configuration file.
  */
 #define NEED_WORK_TREE		(1<<3)
-#define SUPPORT_SUPER_PREFIX	(1<<4)
-#define DELAY_PAGER_CONFIG	(1<<5)
-#define NO_PARSEOPT		(1<<6) /* parse-options is not used */
+#define DELAY_PAGER_CONFIG	(1<<4)
+#define NO_PARSEOPT		(1<<5) /* parse-options is not used */
 
 struct cmd_struct {
 	const char *cmd;
@@ -29,8 +28,7 @@ const char git_usage_string[] =
 	   "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 	   "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
 	   "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-	   "           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-	   "           <command> [<args>]");
+	   "           [--config-env=<name>=<envvar>] <command> [<args>]");
 
 const char git_more_info_string[] =
 	N_("'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 			setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
 			if (envchanged)
 				*envchanged = 1;
-		} else if (!strcmp(cmd, "--super-prefix")) {
-			if (*argc < 2) {
-				fprintf(stderr, _("no prefix given for --super-prefix\n" ));
-				usage(git_usage_string);
-			}
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
-			if (envchanged)
-				*envchanged = 1;
-			(*argv)++;
-			(*argc)--;
-		} else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
-			setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
-			if (envchanged)
-				*envchanged = 1;
 		} else if (!strcmp(cmd, "--bare")) {
 			char *cwd = xgetcwd();
 			is_bare_repository_cfg = 1;
@@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 		trace_repo_setup(prefix);
 	commit_pager_choice();
 
-	if (!help && get_super_prefix()) {
-		if (!(p->option & SUPPORT_SUPER_PREFIX))
-			die(_("%s doesn't support --super-prefix"), p->cmd);
-	}
-
 	if (!help && p->option & NEED_WORK_TREE)
 		setup_work_tree();
 
@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {
 	{ "check-ref-format", cmd_check_ref_format, NO_PARSEOPT  },
 	{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout--worker", cmd_checkout__worker,
-		RUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },
+		RUN_SETUP | NEED_WORK_TREE },
 	{ "checkout-index", cmd_checkout_index,
 		RUN_SETUP | NEED_WORK_TREE},
 	{ "cherry", cmd_cherry, RUN_SETUP },
@@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {
 	{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
 	{ "push", cmd_push, RUN_SETUP },
 	{ "range-diff", cmd_range_diff, RUN_SETUP | USE_PAGER },
-	{ "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
+	{ "read-tree", cmd_read_tree, RUN_SETUP },
 	{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
 	{ "receive-pack", cmd_receive_pack },
 	{ "reflog", cmd_reflog, RUN_SETUP },
@@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)
 	struct child_process cmd = CHILD_PROCESS_INIT;
 	int status;
 
-	if (get_super_prefix())
-		die(_("%s doesn't support --super-prefix"), argv[0]);
-
 	if (use_pager == -1 && !is_builtin(argv[0]))
 		use_pager = check_pager_config(argv[0]);
 	commit_pager_choice();
@@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)
 			 */
 			trace2_cmd_name("_run_git_alias_");
 
-			if (get_super_prefix())
-				die("%s doesn't support --super-prefix", **argv);
-
 			commit_pager_choice();
 
 			strvec_push(&cmd.args, "git");
diff --git a/submodule.c b/submodule.c
index 3383c47c719..f8497793790 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2048,14 +2048,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)
 	strbuf_release(&config_path);
 }
 
-static const char *get_super_prefix_or_empty(void)
-{
-	const char *s = get_super_prefix();
-	if (!s)
-		s = "";
-	return s;
-}
-
 static int submodule_has_dirty_index(const struct submodule *sub)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2074,7 +2066,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)
 	return finish_command(&cp);
 }
 
-static void submodule_reset_index(const char *path)
+static void submodule_reset_index(const char *path, const char *super_prefix)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
 	prepare_submodule_repo_env(&cp.env);
@@ -2083,10 +2075,10 @@ static void submodule_reset_index(const char *path)
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	/* TODO: determine if this might overwright untracked files */
 	strvec_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+		     (super_prefix ? super_prefix : ""), path);
 
 	strvec_push(&cp.args, empty_tree_oid_hex());
 
@@ -2099,10 +2091,9 @@ static void submodule_reset_index(const char *path)
  * For edge cases (a submodule coming into existence or removing a submodule)
  * pass NULL for old or new respectively.
  */
-int submodule_move_head(const char *path,
-			 const char *old_head,
-			 const char *new_head,
-			 unsigned flags)
+int submodule_move_head(const char *path, const char *super_prefix,
+			const char *old_head, const char *new_head,
+			unsigned flags)
 {
 	int ret = 0;
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -2140,7 +2131,7 @@ int submodule_move_head(const char *path,
 		if (old_head) {
 			if (!submodule_uses_gitfile(path))
 				absorb_git_dir_into_superproject(path,
-								 get_super_prefix());
+								 super_prefix);
 		} else {
 			struct strbuf gitdir = STRBUF_INIT;
 			submodule_name_to_gitdir(&gitdir, the_repository,
@@ -2149,7 +2140,7 @@ int submodule_move_head(const char *path,
 			strbuf_release(&gitdir);
 
 			/* make sure the index is clean as well */
-			submodule_reset_index(path);
+			submodule_reset_index(path, NULL);
 		}
 
 		if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
@@ -2167,9 +2158,9 @@ int submodule_move_head(const char *path,
 	cp.no_stdin = 1;
 	cp.dir = path;
 
-	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
-		     get_super_prefix_or_empty(), path);
 	strvec_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
+	strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+		     (super_prefix ? super_prefix : ""), path);
 
 	if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
 		strvec_push(&cp.args, "-n");
diff --git a/submodule.h b/submodule.h
index f90ee547d08..c55a25ca37d 100644
--- a/submodule.h
+++ b/submodule.h
@@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);
 
 #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)
 #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)
-int submodule_move_head(const char *path,
-			const char *old,
-			const char *new_head,
+int submodule_move_head(const char *path, const char *super_prefix,
+			const char *old_head, const char *new_head,
 			unsigned flags);
 
 void submodule_unset_core_worktree(const struct submodule *sub);
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 516a6112fdc..3fb1b0c162d 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '
 	cat <<-EOF >expect &&
 		error: Updating '\''fictional/a'\'' would lose untracked files in it
 	EOF
-	test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual &&
+	test_must_fail git read-tree --super-prefix fictional/ -u -m "$treeH" "$treeM" 2>actual &&
 	test_cmp expect actual
 '
 
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 2846ec6629c..f519d2a87a7 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -644,7 +644,7 @@ test_expect_success 'repack does not loosen promisor objects' '
 	grep "loosen_unused_packed_objects/loosened:0" trace
 '
 
-test_expect_failure 'lazy-fetch in submodule succeeds' '
+test_expect_success 'lazy-fetch in submodule succeeds' '
 	# setup
 	test_config_global protocol.file.allow always &&
 
diff --git a/unpack-trees.c b/unpack-trees.c
index bae812156c4..61c02285454 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
 	  ? ((o)->msgs[(type)])      \
 	  : (unpack_plumbing_errors[(type)]) )
 
-static const char *super_prefixed(const char *path)
+static const char *super_prefixed(const char *path, const char *super_prefix)
 {
 	/*
 	 * It is necessary and sufficient to have two static buffers
@@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)
 	static unsigned idx = ARRAY_SIZE(buf) - 1;
 
 	if (super_prefix_len < 0) {
-		const char *super_prefix = get_super_prefix();
 		if (!super_prefix) {
 			super_prefix_len = 0;
 		} else {
@@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,
 		return -1;
 
 	if (!o->show_all_errors)
-		return error(ERRORMSG(o, e), super_prefixed(path));
+		return error(ERRORMSG(o, e), super_prefixed(path,
+							    o->super_prefix));
 
 	/*
 	 * Otherwise, insert in a list for future display by
@@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)
 			error_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			error(ERRORMSG(o, e), super_prefixed(path.buf));
+			error(ERRORMSG(o, e), super_prefixed(path.buf,
+							     o->super_prefix));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)
 			warning_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			warning(ERRORMSG(o, e), super_prefixed(path.buf));
+			warning(ERRORMSG(o, e), super_prefixed(path.buf,
+							       o->super_prefix));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,
 	if (o->reset)
 		flags |= SUBMODULE_MOVE_HEAD_FORCE;
 
-	if (submodule_move_head(ce->name, old_id, new_id, flags))
+	if (submodule_move_head(ce->name, NULL, old_id, new_id, flags))
 		return add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
 	return 0;
 }
@@ -415,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,
 	int i, pc_workers, pc_threshold;
 
 	trace_performance_enter();
+	state.super_prefix = o->super_prefix;
 	state.force = 1;
 	state.quiet = 1;
 	state.refresh_cache = 1;
@@ -445,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,
 
 		if (ce->ce_flags & CE_WT_REMOVE) {
 			display_progress(progress, ++cnt);
-			unlink_entry(ce);
+			unlink_entry(ce, o->super_prefix);
 		}
 	}
 
@@ -2958,8 +2961,8 @@ int bind_merge(const struct cache_entry * const *src,
 	if (a && old)
 		return o->quiet ? -1 :
 			error(ERRORMSG(o, ERROR_BIND_OVERLAP),
-			      super_prefixed(a->name),
-			      super_prefixed(old->name));
+			      super_prefixed(a->name, o->super_prefix),
+			      super_prefixed(old->name, o->super_prefix));
 	if (!a)
 		return keep_entry(old, o);
 	else
@@ -3020,7 +3023,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,
 
 	if (worktree && untracked)
 		return error(_("worktree and untracked commit have duplicate entries: %s"),
-			     super_prefixed(worktree->name));
+			     super_prefixed(worktree->name, o->super_prefix));
 
 	return merged_entry(worktree ? worktree : untracked, NULL, o);
 }
diff --git a/unpack-trees.h b/unpack-trees.h
index efb9edfbb27..9b81e284073 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -74,6 +74,7 @@ struct unpack_trees_options {
 		     dry_run;
 	enum unpack_trees_reset_type reset;
 	const char *prefix;
+	const char *super_prefix;
 	int cache_bottom;
 	struct pathspec *pathspec;
 	merge_fn_t fn;
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 9/9] fetch: rename "--submodule-prefix" to "--super-prefix"
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
                         ` (7 preceding siblings ...)
  2022-11-19 12:41       ` [PATCH v3 8/9] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
@ 2022-11-19 12:41       ` Ævar Arnfjörð Bjarmason
  2022-11-22 22:29       ` [PATCH v3 0/9] Get rid of "git --super-prefix" Glen Choo
  9 siblings, 0 replies; 79+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-11-19 12:41 UTC (permalink / raw)
  To: git
  Cc: Glen Choo, Taylor Blau, Robert Coup,
	Ævar Arnfjörð Bjarmason

In preceding commits we've introduced a command-level "--super-prefix"
option, which unlike the "git --super-prefix" it replaced doesn't rely
on setenv() or getenv(), it's just a normal command-line option that
the command passes down.

Since we've done that, let's rename the "--submodule-prefix" option
added in 7dce19d374a (fetch/pull: Add the --recurse-submodules option,
2010-11-12) to "--super-prefix" for consistency. This:

 * Allows us to use OPT__SUPER_PREFIX().
 * Leaves an unspecified "--super-prefix" with a "NULL" value, rather
   than an empty string, as is the case with the other "--super-prefix"
   users. We coerce the NULL to "" in submodule.c before using it.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 Documentation/fetch-options.txt |  5 -----
 builtin/fetch.c                 |  7 +++----
 submodule.c                     | 23 +++++++++++------------
 3 files changed, 14 insertions(+), 21 deletions(-)

diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 622bd84768b..20cbd2c2910 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -241,11 +241,6 @@ endif::git-pull[]
 	linkgit:git-config[1].
 
 ifndef::git-pull[]
---submodule-prefix=<path>::
-	Prepend <path> to paths printed in informative messages
-	such as "Fetching submodule foo".  This option is used
-	internally when recursing over submodules.
-
 --recurse-submodules-default=[yes|on-demand]::
 	This option is used internally to temporarily provide a
 	non-negative default value for the --recurse-submodules
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7378cafeec9..353bcd36d24 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -74,7 +74,7 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
 static struct strbuf default_rla = STRBUF_INIT;
 static struct transport *gtransport;
 static struct transport *gsecondary;
-static const char *submodule_prefix = "";
+static const char *super_prefix;
 static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
@@ -195,8 +195,7 @@ static struct option builtin_fetch_options[] = {
 	OPT_SET_INT_F(0, "refetch", &refetch,
 		      N_("re-fetch without negotiating common commits"),
 		      1, PARSE_OPT_NONEG),
-	{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
-		   N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
+	OPT__SUPER_PREFIX(&super_prefix),
 	OPT_CALLBACK_F(0, "recurse-submodules-default",
 		   &recurse_submodules_default, N_("on-demand"),
 		   N_("default for recursive fetching of submodules "
@@ -2300,7 +2299,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 		add_options_to_argv(&options);
 		result = fetch_submodules(the_repository,
 					  &options,
-					  submodule_prefix,
+					  super_prefix,
 					  recurse_submodules,
 					  recurse_submodules_default,
 					  verbosity < 0,
diff --git a/submodule.c b/submodule.c
index f8497793790..3e0aaaa2af0 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1376,7 +1376,7 @@ struct submodule_parallel_fetch {
 	int changed_count;
 	struct strvec args;
 	struct repository *r;
-	const char *prefix;
+	const char *super_prefix;
 	int command_line_option;
 	int default_option;
 	int quiet;
@@ -1567,7 +1567,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
 		if (task->repo) {
 			if (!spf->quiet)
 				strbuf_addf(err, _("Fetching submodule %s%s\n"),
-					    spf->prefix, ce->name);
+					    spf->super_prefix, ce->name);
 
 			spf->index_count++;
 			return task;
@@ -1629,7 +1629,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
 		if (!spf->quiet)
 			strbuf_addf(err,
 				    _("Fetching submodule %s%s at commit %s\n"),
-				    spf->prefix, task->sub->path,
+				    spf->super_prefix, task->sub->path,
 				    find_unique_abbrev(cs_data->super_oid,
 						       DEFAULT_ABBREV));
 
@@ -1687,11 +1687,10 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
 			strvec_pushv(&cp->args, task->git_args.v);
 		strvec_pushv(&cp->args, spf->args.v);
 		strvec_push(&cp->args, task->default_argv);
-		strvec_push(&cp->args, "--submodule-prefix");
+		strvec_push(&cp->args, "--super-prefix");
 
-		strbuf_addf(&submodule_prefix, "%s%s/",
-						spf->prefix,
-						task->sub->path);
+		strbuf_addf(&submodule_prefix, "%s%s/", spf->super_prefix,
+			    task->sub->path);
 		strvec_push(&cp->args, submodule_prefix.buf);
 		*task_cb = task;
 
@@ -1707,7 +1706,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
 		spf->oid_fetch_tasks_nr--;
 
 		strbuf_addf(&submodule_prefix, "%s%s/",
-			    spf->prefix, task->sub->path);
+			    spf->super_prefix, task->sub->path);
 
 		child_process_init(cp);
 		prepare_submodule_repo_env_in_gitdir(&cp->env);
@@ -1717,7 +1716,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,
 		strvec_init(&cp->args);
 		strvec_pushv(&cp->args, spf->args.v);
 		strvec_push(&cp->args, "on-demand");
-		strvec_push(&cp->args, "--submodule-prefix");
+		strvec_push(&cp->args, "--super-prefix");
 		strvec_push(&cp->args, submodule_prefix.buf);
 
 		/* NEEDSWORK: have get_default_remote from submodule--helper */
@@ -1813,7 +1812,7 @@ static int fetch_finish(int retvalue, struct strbuf *err,
 
 int fetch_submodules(struct repository *r,
 		     const struct strvec *options,
-		     const char *prefix, int command_line_option,
+		     const char *super_prefix, int command_line_option,
 		     int default_option,
 		     int quiet, int max_parallel_jobs)
 {
@@ -1835,7 +1834,7 @@ int fetch_submodules(struct repository *r,
 	spf.command_line_option = command_line_option;
 	spf.default_option = default_option;
 	spf.quiet = quiet;
-	spf.prefix = prefix;
+	spf.super_prefix = super_prefix ? super_prefix : "";
 
 	if (!r->worktree)
 		goto out;
@@ -1847,7 +1846,7 @@ int fetch_submodules(struct repository *r,
 	for (i = 0; i < options->nr; i++)
 		strvec_push(&spf.args, options->v[i]);
 	strvec_push(&spf.args, "--recurse-submodules-default");
-	/* default value, "--submodule-prefix" and its value are added later */
+	/* default value, "--super-prefix" and its value are added later */
 
 	calculate_changed_submodule_paths(r, &spf.changed_submodule_names);
 	string_list_sort(&spf.changed_submodule_names);
-- 
2.38.0.1509.g9445af83948


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [PATCH v2 00/10] Get rid of "git --super-prefix"
  2022-11-17 18:07           ` Ævar Arnfjörð Bjarmason
@ 2022-11-21 19:16             ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-21 19:16 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git, Taylor Blau, Robert Coup

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Wed, Nov 16 2022, Glen Choo wrote:
>
>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>>
>>> On Mon, Nov 14 2022, Glen Choo wrote:
>>>
>>>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>>>>
>>>>> It's also proposing to replace Glen's one-patch[6], which is working
>>>>> around the problem shown in the test added in 1/10 here. Per
>>>>> downthread of [7] I think Glen was aiming for getting a more narrow
>>>>> fix in case we split off 9/10 here into some later fix.
>>>>>
>>>>> As we're fixing an edge case in something that's always been broken
>>>>> (and thus wouldn't backport) I think it's better to just fix the
>>>>> problem directly, rather than introducing new "--super-prefix" use,
>>>>> just to take it away later.
>>>>
>>>> I still prefer that we take the one-patch to unbreak new releases,
>>>> because partial clone + submodules is absolutely broken (e.g. it's
>>>> already causing quite a lot of headaches at $DAYJOB) and the patch is
>>>> obviously harmless.
>>>>
>>>> And more importantly, it lets us take our time with this series and get
>>>> it right without time pressure. It's not as pressing as, e.g. a
>>>> regression fix, but it does render certain Git setups unusable.
>>>>
>>>> With regards to urgency and when to choose "small and harmless fixes vs
>>>> bigger and better fixes", I think Junio has generally made those calls
>>>> in the past. @Taylor if you have an opinion, I'd love to hear it.
>>>
>>> I feel like I'm missing something here. What's the regression? The test
>>> you're adding here didn't work at all until 0f5e8851737 (Merge branch
>>> 'rc/fetch-refetch', 2022-04-04), as the command didn't exist yet. That
>>> commit went out with v2.36.0.
>>>
>>> If it never worked there's no regression, and we wouldn't be merging
>>> down a fix for older point-releases.
>>>
>>> Or is there some case I've missed here which did work before, doesn't
>>> now, but just isn't captured in this test? If so what case is that, and
>>> when did it break?
>>
>> Right, this wasn't meant to be a regression fix at all. There's good
>> reason to believe that this was always broken, so I never went digging
>> to see if it ever worked.
>>
>> Even so, it doesn't change the fact that it's a use case that we've
>> expected to work, but doesn't due to some internal silliness, and that
>> we could fix it without invoking questions of the "--super-prefix"
>> design and dragging out the process (which is admittedly what I should
>> have done in the first place). Since we have such an easy fix in front
>> of us, I don't feel good about not fixing this before the next release.
>>
>> At any rate, I'm wiling to accept that I'm being overly cautious,
>> because it's quite likely that this series will make it into the next
>> release. (We could technically we unbreak 'next', though I don't know
>> who distributes that other than internally @ Google.) I'm ok to drop my
>> patch for now, but I'll revive it if it starts to look like this series
>> won't make it into the next release.
>
> Understood, I'm re-rolling this v2, will send it out soon.
>
> I'll keep that patch out for now, but if we're starting to run up
> against the next release how about we split it out? So it'll depend on
> how fast we can review & test this, and if/when Taylor is OK with
> merging it down.
>
> I really don't care if the fix comes first, but just thought I was
> missing something and it didn't seem urgent, as it was in the "never
> worked" and not "a regression" category AFAICT. But if you'd still like
> it shout, and I'll just stack it at the start...

That sounds good, thanks :) That's very helpful of you, and I appreciate
you making the way forward clear.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 3/9] submodule--helper: don't use global --super-prefix in "absorbgitdirs"
  2022-11-19 12:41       ` [PATCH v3 3/9] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
@ 2022-11-22 19:53         ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-22 19:53 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> The "fsmonitor--daemon" test adjusted here was added in [3]. To assert
> that it didn't run into the "--super-prefix" message it was asserting
> the output it didn't have. Let's instead assert the full output that
> we *do* have, which we can do here as this is based on a change[4] to
> make it predictable (until [4] it contained absolute paths).
>
> We could also remove the test entirely (as [5] did), but even though
> the initial reason for having it is gone we're still getting some
> marginal benefit from testing the "fsmonitor" and "submodule
> absorbgitdirs" interaction, so let's keep it.

I'm a bit ambivalent on this, especially since we're testing "submodule
absorbgitdirs" output in "fsmonitor" tests, but as you say, there is
some benefit in testing the interaction. I think we'll have to change
the test though...

> The change here to have either a NULL or non-"" string as a
> "super_prefix" instead of the previous arrangement of "" or non-"" is
> somewhat arbitrary. We could also decide to never have to check for
> NULL.
>
> As we'll be changing the rest of the "git --super-prefix" users to the
> same pattern, leaving them all consistent makes sense. Why not pick ""
> over NULL? Because that's how the "prefix" works[6], and having
> "prefix" and "super_prefix" work the same way will be less
> confusing. That "prefix" picked NULL instead of "" is itself
> arbitrary, but as it's easy to make this small bit of our overall API
> consistent, let's go with that.

Okay, I find consistency with "prefix" convincing, and I do hope that we
use "" someday :)

> index 4abc74db2bb..31526937d95 100755
> --- a/t/t7527-builtin-fsmonitor.sh
> +++ b/t/t7527-builtin-fsmonitor.sh
> @@ -866,30 +866,11 @@ test_expect_success 'submodule always visited' '
>  # the submodule, and someone does a `git submodule absorbgitdirs`
>  # in the super, Git will recursively invoke `git submodule--helper`
>  # to do the work and this may try to read the index.  This will
> -# try to start the daemon in the submodule *and* pass (either
> -# directly or via inheritance) the `--super-prefix` arg to the
> -# `git fsmonitor--daemon start` command inside the submodule.
> -# This causes a warning because fsmonitor--daemon does take that
> -# global arg (see the table in git.c)

We've removed mentions of the "--super-prefix", as we should, since
fsmonitor doesn't need to care about "--super-prefix" any more...

> @@ -904,10 +885,12 @@ test_expect_success "stray submodule super-prefix warning" '
>  
>  	test_path_is_dir super/dir_1/dir_2/sub/.git &&
>  
> -	GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
> -		git -C super submodule absorbgitdirs &&
> -
> -	! have_t2_error_event super-sub.trace
> +	cat >expect <<-\EOF &&
> +	Migrating git directory of '\''dir_1/dir_2/sub'\'' from '\''dir_1/dir_2/sub/.git'\'' to '\''.git/modules/dir_1/dir_2/sub'\''
> +	EOF
> +	git -C super submodule absorbgitdirs >out 2>actual &&
> +	test_cmp expect actual &&
> +	test_must_be_empty out
>  '

So let's adjust the test to match what we're testing. It's not the
--super-prefix any more, it's the interaction between "submodule
absorbgitdirs" and "fsmonitor--daemon", so perhaps something like:

  diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
  index 31526937d9..9f947341f5 100755
  --- a/t/t7527-builtin-fsmonitor.sh
  +++ b/t/t7527-builtin-fsmonitor.sh
  @@ -868,7 +868,7 @@ test_expect_success 'submodule always visited' '
  # to do the work and this may try to read the index.  This will
  # try to start the daemon in the submodule.

  -test_expect_success "stray submodule super-prefix warning" '
  +test_expect_success "submodule absorbgitdirs implicitly starts daemon" '
          test_when_finished "rm -rf super; \
                              rm -rf sub" &&

  @@ -888,9 +888,14 @@ test_expect_success "stray submodule super-prefix warning" '
          cat >expect <<-\EOF &&
          Migrating git directory of '\''dir_1/dir_2/sub'\'' from '\''dir_1/dir_2/sub/.git'\'' to '\''.git/modules/dir_1/dir_2/sub'\''
          EOF
  -       git -C super submodule absorbgitdirs >out 2>actual &&
  +       GIT_TRACE2_EVENT="$PWD/.git/trace_absorbgitdirs" \
  +               git -C super submodule absorbgitdirs >out 2>actual &&
          test_cmp expect actual &&
  -       test_must_be_empty out
  +       test_must_be_empty out &&
  +
  +       # Confirm that the trace2 log contains a record of the
  +       # daemon starting.
  +       test_subcommand git fsmonitor--daemon start <.git/trace_absorbgitdirs
  '

  # On a case-insensitive file system, confirm that the daemon

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 8/9] read-tree: add "--super-prefix" option, eliminate global
  2022-11-19 12:41       ` [PATCH v3 8/9] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
@ 2022-11-22 19:57         ` Glen Choo
  0 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-22 19:57 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> @@ -2149,7 +2140,7 @@ int submodule_move_head(const char *path,
>  			strbuf_release(&gitdir);
>  
>  			/* make sure the index is clean as well */
> -			submodule_reset_index(path);
> +			submodule_reset_index(path, NULL);
>  		}
>  
>  		if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {

Here, and..

> @@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,
>  	if (o->reset)
>  		flags |= SUBMODULE_MOVE_HEAD_FORCE;
>  
> -	if (submodule_move_head(ce->name, old_id, new_id, flags))
> +	if (submodule_move_head(ce->name, NULL, old_id, new_id, flags))
>  		return add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
>  	return 0;
>  }

here I think we should be passing a non-NULL value to super_prefix.

Perhaps this was missed when going through the v2 feedback [1]?

[1] https://lore.kernel.org/git/kl6lv8nhnpba.fsf@chooglen-macbookpro.roam.corp.google.com

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 0/9] Get rid of "git --super-prefix"
  2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
                         ` (8 preceding siblings ...)
  2022-11-19 12:41       ` [PATCH v3 9/9] fetch: rename "--submodule-prefix" to "--super-prefix" Ævar Arnfjörð Bjarmason
@ 2022-11-22 22:29       ` Glen Choo
  9 siblings, 0 replies; 79+ messages in thread
From: Glen Choo @ 2022-11-22 22:29 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, git
  Cc: Taylor Blau, Robert Coup, Ævar Arnfjörð Bjarmason

Thanks! I think we're close to getting this merged :)

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> = Changes since v2:
>
> * Fixes for test_when_finished() in test setup, and got rid of
>   redundant test_config_global.
>
> * There's a new 2/9, which passes along get_super_prefix() as a
>   parameter. This allows us to gradually replace it, and drop the
>   *_sp() variants of functions that the previous version introduced,
>   and it adds "super_prefix" to the absorb_git_dir_into_superproject()
>   call in submodule_move_head(), which as Glen noticed I'd missed
>
> * Squashed the "deinit" change into that 2/9.
>
> * Explain why we keep the "fsmonitor" test bits that we do.
>
> * Dropped the new "git branch" output tests, turns out I was just
>   wrong, and was conflating it with the subsequent read-tree
>   invocation...
>
> So, this should address all outstanding feedbakc, unless I've missed
> something.

As noted in [1], I think we might have missed some sites where we should
pass super_prefix.

[1] https://lore.kernel.org/git/kl6lcz9eep9k.fsf@chooglen-macbookpro.roam.corp.google.com,

> The one loose end here is that I still have no idea if you can invoke
> get "read-tree" to invoke that submodule_move_head() in such a way as
> to have the "super_prefix" used, I've failed to come up with a test
> case for that.
>
> But for the purposes of this topic it doesn't really matter. In 8/10
> we'll start passing the new "--super-prefix" that "read-tree" gets
> down to that function. At worst we're handing it to it redundantly,
> but that was the case before too.
>
> So we can leave potentially turning that into a "NULL" for some other
> time, for now providing the "super_prefix" is harmless, and guarantees
> that we avoid any regression in that area from not providing it, in
> case I've missed a way to have it matter in that case.

Yeah, I tried to do the same too, and it turned out to be harder than
expected. The "absorbgitdir during read-tree" code is definitely in use
(e.g. by t1013), so it's certainly possible, but as you noted, I don't
really think it matters as long as we avoid a regression for the time
being.


^ permalink raw reply	[flat|nested] 79+ messages in thread

end of thread, other threads:[~2022-11-22 22:29 UTC | newest]

Thread overview: 79+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-09  0:47 [RFC PATCH 0/4] git: remove --super-prefix Glen Choo
2022-11-09  0:47 ` [RFC PATCH 1/4] submodule--helper: teach --toplevel-cwd-prefix Glen Choo
2022-11-09  2:37   ` Ævar Arnfjörð Bjarmason
2022-11-09  0:47 ` [RFC PATCH 2/4] fetch: refactor --submodule-prefix Glen Choo
2022-11-09  3:06   ` Ævar Arnfjörð Bjarmason
2022-11-09  0:47 ` [RFC PATCH 3/4] read-tree: teach --submodule-prefix Glen Choo
2022-11-09  3:13   ` Ævar Arnfjörð Bjarmason
2022-11-09  0:47 ` [RFC PATCH 4/4] git: remove --super-prefix Glen Choo
2022-11-09 19:34 ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Ævar Arnfjörð Bjarmason
2022-11-09 19:34   ` [RFC PATCH 1/8] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
2022-11-11  0:12     ` Glen Choo
2022-11-09 19:34   ` [RFC PATCH 2/8] submodule--helper: "deinit" has never used "--super-prefix" Ævar Arnfjörð Bjarmason
2022-11-09 19:34   ` [RFC PATCH 3/8] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
2022-11-09 19:34   ` [RFC PATCH 4/8] submodule--helper: convert "sync" " Ævar Arnfjörð Bjarmason
2022-11-09 19:34   ` [RFC PATCH 5/8] submodule--helper: convert "status" " Ævar Arnfjörð Bjarmason
2022-11-09 19:34   ` [RFC PATCH 6/8] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
2022-11-09 19:34   ` [RFC PATCH 7/8] submodule tests: test "git branch -t" output and stderr Ævar Arnfjörð Bjarmason
2022-11-09 19:34   ` [RFC PATCH 8/8] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
2022-11-11  0:40     ` Glen Choo
2022-11-09 21:21   ` [RFC PATCH 0/8] Get rid of "git --super-prefix" Taylor Blau
2022-11-09 21:47     ` Ævar Arnfjörð Bjarmason
2022-11-09 22:27       ` Taylor Blau
2022-11-09 22:54         ` Ævar Arnfjörð Bjarmason
2022-11-10  0:45   ` Glen Choo
2022-11-10 10:51     ` Ævar Arnfjörð Bjarmason
2022-11-11  1:07       ` Glen Choo
2022-11-11 18:29         ` Glen Choo
2022-11-11 21:17           ` Ævar Arnfjörð Bjarmason
2022-11-11 21:51             ` Taylor Blau
2022-11-12  1:10             ` Glen Choo
2022-11-14 10:09               ` Ævar Arnfjörð Bjarmason
2022-11-14 23:33                 ` Glen Choo
2022-11-15  1:37                   ` Ævar Arnfjörð Bjarmason
2022-11-14 10:08   ` [PATCH v2 00/10] " Ævar Arnfjörð Bjarmason
2022-11-14 10:08     ` [PATCH v2 01/10] read-tree + fetch tests: test failing "--super-prefix" interaction Ævar Arnfjörð Bjarmason
2022-11-14 19:00       ` Glen Choo
2022-11-14 19:14         ` Ævar Arnfjörð Bjarmason
2022-11-14 19:49           ` Glen Choo
2022-11-14 10:08     ` [PATCH v2 02/10] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
2022-11-14 21:22       ` Glen Choo
2022-11-17 18:10         ` Ævar Arnfjörð Bjarmason
2022-11-14 10:08     ` [PATCH v2 03/10] submodule--helper: "deinit" has never used "--super-prefix" Ævar Arnfjörð Bjarmason
2022-11-14 10:08     ` [PATCH v2 04/10] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
2022-11-14 21:56       ` Glen Choo
2022-11-17 18:14         ` Ævar Arnfjörð Bjarmason
2022-11-14 10:08     ` [PATCH v2 05/10] submodule--helper: convert "sync" " Ævar Arnfjörð Bjarmason
2022-11-14 10:08     ` [PATCH v2 06/10] submodule--helper: convert "status" " Ævar Arnfjörð Bjarmason
2022-11-14 10:08     ` [PATCH v2 07/10] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
2022-11-14 22:04       ` Glen Choo
2022-11-14 10:08     ` [PATCH v2 08/10] submodule tests: test "git branch -t" output and stderr Ævar Arnfjörð Bjarmason
2022-11-14 22:20       ` Glen Choo
2022-11-14 10:08     ` [PATCH v2 09/10] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
2022-11-14 22:28       ` Glen Choo
2022-11-14 10:08     ` [PATCH v2 10/10] fetch: rename "--submodule-prefix" to "--super-prefix" Ævar Arnfjörð Bjarmason
2022-11-14 22:31       ` Glen Choo
2022-11-14 21:59     ` [PATCH v2 00/10] Get rid of "git --super-prefix" Taylor Blau
2022-11-14 23:20     ` Glen Choo
2022-11-14 23:39     ` Glen Choo
2022-11-15  1:27       ` Ævar Arnfjörð Bjarmason
2022-11-16 21:07         ` Glen Choo
2022-11-17 18:07           ` Ævar Arnfjörð Bjarmason
2022-11-21 19:16             ` Glen Choo
2022-11-19 12:41     ` [PATCH v3 0/9] " Ævar Arnfjörð Bjarmason
2022-11-19 12:41       ` [PATCH v3 1/9] read-tree + fetch tests: test failing "--super-prefix" interaction Ævar Arnfjörð Bjarmason
2022-11-19 12:41       ` [PATCH v3 2/9] submodule.c & submodule--helper: pass along "super_prefix" param Ævar Arnfjörð Bjarmason
2022-11-19 12:41       ` [PATCH v3 3/9] submodule--helper: don't use global --super-prefix in "absorbgitdirs" Ævar Arnfjörð Bjarmason
2022-11-22 19:53         ` Glen Choo
2022-11-19 12:41       ` [PATCH v3 4/9] submodule--helper: convert "foreach" to its own "--super-prefix" Ævar Arnfjörð Bjarmason
2022-11-19 12:41       ` [PATCH v3 5/9] submodule--helper: convert "sync" " Ævar Arnfjörð Bjarmason
2022-11-19 12:41       ` [PATCH v3 6/9] submodule--helper: convert "status" " Ævar Arnfjörð Bjarmason
2022-11-19 12:41       ` [PATCH v3 7/9] submodule--helper: convert "{update,clone}" to their " Ævar Arnfjörð Bjarmason
2022-11-19 12:41       ` [PATCH v3 8/9] read-tree: add "--super-prefix" option, eliminate global Ævar Arnfjörð Bjarmason
2022-11-22 19:57         ` Glen Choo
2022-11-19 12:41       ` [PATCH v3 9/9] fetch: rename "--submodule-prefix" to "--super-prefix" Ævar Arnfjörð Bjarmason
2022-11-22 22:29       ` [PATCH v3 0/9] Get rid of "git --super-prefix" Glen Choo
2022-11-09 21:16 ` [RFC PATCH 0/4] git: remove --super-prefix Taylor Blau
2022-11-09 23:55   ` Glen Choo
2022-11-10  2:14     ` Taylor Blau
2022-11-10 23:49       ` Glen Choo

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).