{"thread":{"id":"58773","subject":"[RFC PATCH 0/4] git: remove --super-prefix","startedAt":"2022-11-09T00:47:27Z","lastAt":"2022-12-20T12:44:23Z","messageCount":105,"participants":["Glen Choo","Ævar Arnfjörð Bjarmason","Taylor Blau","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"466923","messageId":"20221109004708.97668-1-chooglen@google.com","threadId":"58773","inReplyTo":null,"subject":"[RFC PATCH 0/4] git: remove --super-prefix","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-09T00:47:04Z","receivedAt":"2022-11-09T00:47:27Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"*Note to maintainer*: See \"Interactions with other series\".\n\nGiven the work on ab/submodule-helper-prep-only, I'm sending this early\nfor feedback, and to see if I can avoid blocking Ævar's follow-up work.\nThis is pretty much done, but I haven't scrutinized the patches too\nclosely to see if all of the relevant paths are tested.\n\nThe main motivation behind this is the partial clone bug demonstrated by\nthe test in Patch 3/4, but instead of just fixing that one issue, I'd\nprefer to get rid of this class of error once and for all.\n\n= Description\n\nWhen we introduced the internal-only \"--super-prefix\" in 74866d7579\n(git: make super-prefix option, 2016-10-07), we specified that commands\nmust prefix paths by it, and pathspecs must be parsed relative to it.\nThat commit also includes safeguards to ensure that \"--super-prefix\" is\nused correctly, namely:\n\n- Only commands marked SUPPORT_SUPER_PREFIX can be invoked with\n  \"--super-prefix\".\n- The super prefix is propagated via the GIT_INTERNAL_SUPER_PREFIX env\n  var, so a non-SUPPORT_SUPER_PREFIX command cannot be invoked by a\n  SUPPORT_SUPER_PREFIX one.\n\nHowever, its use is inconsistent, which is a strong reason to consider\nusing better-scoped flags instead. For example..\n\n- Of the 4 commands that are SUPPORT_SUPER_PREFIX, only \"read-tree\" and\n  \"submodule--helper\" do anything useful with it. \"fsmonitor--daemon\"\n  has it to avoid the SUPPORT_SUPER_PREFIX warning [1].\n  \"checkout--worker\" doesn't have a documented reason, but since it can\n  be invoked by \"read-tree\", it's presumably also a workaround.\n- \"read-tree\" and \"submodule--helper\" use different values for the super\n  prefix; \"read-tree\" passes the path from the root of the\n  superproject's tree to the submodule's gitlink, while\n  \"submodule--helper\" passes the relative path of the original CWD to\n  the submodule.\n- \"submodule--helper\" doesn't use \"--super-prefix\" to parse pathspecs,\n  only to display paths.\n\nThis series replaces the top-level \"--super-prefix\" with better-scoped,\nper-command flags.\n\n= Interactions with other series\n\nAs noted in the conversation starting at [2], the submodule--helper bits\nin this series have substantial overlap with\nab/submodule-helper-prep-only and the work that series is prep for. I've\nbased this series off ab/submodule-helper-prep-only, since the\nconversion of builtin/submodule--helper.c to use options parsing makes\npatch 1 much easier to reason about.\n\nÆvar: The patch of interest is 1/4, which removes the super prefix check\nfrom submodule--helper. Hopefully you find this useful, I strongly\nsuspect that it will save time and churn for us to move this series\nforward and to base your follow up work on this. But if this does end up\nstalling, however, I'm happy to rebase this on top of your follow up\nwork.\n\n= Patch summary\n\n- Patch 1/4 introduces a \"--toplevel-cwd-prefix\" flag for \"git\n  submodule--helper\" (replacing \"--super-prefix\" for \"git\n  submodule--helper\").\n- Patches 2-3/4 refactors \"--submodule-prefix\" for \"git fetch\" and\n  reuses that implementation for \"git read-tree\" (replacing\n  \"--super-prefix\" for \"git read-tree\").\n- Patch 4 drops \"--super-prefix\" and a now-defunct fsmonitor test.\n\n[1]: 53fcfbc84f (fsmonitor--daemon: allow --super-prefix argument, 2022-05-26)\n[2]: https://lore.kernel.org/git/221104.86wn8bzeus.gmgdl@evledraar.gmail.com\n\nGlen Choo (4):\n  submodule--helper: teach --toplevel-cwd-prefix\n  fetch: refactor --submodule-prefix\n  read-tree: teach --submodule-prefix\n  git: remove --super-prefix\n\n Documentation/fetch-options.txt    |  5 --\n Documentation/git.txt              |  7 +--\n builtin.h                          |  4 --\n builtin/fetch.c                    |  7 ++-\n builtin/read-tree.c                |  4 ++\n builtin/submodule--helper.c        | 52 ++++++++-----------\n cache.h                            |  2 -\n environment.c                      | 13 -----\n git.c                              | 40 +++-----------\n repository.c                       |  1 +\n repository.h                       |  9 +++-\n submodule.c                        | 83 ++++++++++++++++++------------\n submodule.h                        | 20 ++++++-\n t/t1001-read-tree-m-2way.sh        |  4 +-\n t/t5616-partial-clone.sh           | 43 ++++++++++++++++\n t/t7412-submodule-absorbgitdirs.sh | 13 ++++-\n t/t7527-builtin-fsmonitor.sh       | 50 ------------------\n unpack-trees.c                     | 32 ++++++------\n 18 files changed, 187 insertions(+), 202 deletions(-)\n\n\nbase-commit: 69d94464e14de859ff56bcde7ebe0132201eceb9\n-- \n2.38.1.431.g37b22c650d-goog\n\n"},{"id":"466924","messageId":"20221109004708.97668-2-chooglen@google.com","threadId":"58773","inReplyTo":"20221109004708.97668-1-chooglen@google.com","subject":"[RFC PATCH 1/4] submodule--helper: teach --toplevel-cwd-prefix","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-09T00:47:05Z","receivedAt":"2022-11-09T00:47:37Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"The top-level \"--super-prefix\" option (i.e. \"git --super-prefix\") is\noverloaded:\n\n- \"git submodule--helper\" passes the relative path between the top-level\n  \"git\" process's cwd and the current repository\n- \"git read-tree\" passes the path from the root of top-level\n  superproject's tree to the the current repository.\n\nIn both cases, \"--super-prefix\" is only used to display meaningful paths\nfrom the superproject to a nested submodule.\n\nLet's address this overloading by breaking it up into its constituent\nuse cases. Teach \"git submodule--helper\" the \"--toplevel-cwd-prefix\"\noption, which replaces its usage of \"git --super-prefix\". (A future\npatch will address the \"git read-tree\" use case.) This value is only\nused in builtin/submodule--helper.c, but it is stored in submodule.c,\nsince it may be needed by other builtins in the future.\n\nWhen \"--toplevel-cwd-prefix\" is provided, paths to submodules in the\nworking tree should be prefixed by it when they are printed, making the\npaths relative to the top-level process's cwd. This is the only way the\nprefix is used in \"git submodule--helper\", and all of its subcommands\nalready conform to this behavior (even the ones that weren't marked\nSUPPORT_SUPER_PREFIX) because they all use\nget_submodule_displaypath() when printing paths to submodules. As such,\nwe can say that all of \"git submodule--helper\" supports (and should\ncontinue to support) this flag, so we drop the constraint that\n\"--toplevel-cwd-prefix\" is only allowed for certain subcommands.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c        | 52 +++++++++++++-----------------\n submodule.c                        | 26 ++++++++++++---\n submodule.h                        | 10 ++++++\n t/t7412-submodule-absorbgitdirs.sh | 13 ++++++--\n 4 files changed, 64 insertions(+), 37 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c75e9e86b0..acb838e4d6 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -115,18 +115,18 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n /* the result should be freed by the caller. */\n static char *get_submodule_displaypath(const char *path, const char *prefix)\n {\n-\tconst char *super_prefix = get_super_prefix();\n+\tconst char *toplevel_cwd_prefix = get_toplevel_cwd_prefix();\n \n-\tif (prefix && super_prefix) {\n-\t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n-\t\t    prefix, super_prefix);\n+\tif (prefix && toplevel_cwd_prefix) {\n+\t\tBUG(\"cannot have prefix '%s' and toplevel_cwd_prefix '%s'\",\n+\t\t    prefix, toplevel_cwd_prefix);\n \t} else if (prefix) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n \t\tchar *displaypath = xstrdup(relative_path(path, prefix, &sb));\n \t\tstrbuf_release(&sb);\n \t\treturn displaypath;\n-\t} else if (super_prefix) {\n-\t\treturn xstrfmt(\"%s%s\", super_prefix, path);\n+\t} else if (toplevel_cwd_prefix) {\n+\t\treturn xstrfmt(\"%s%s\", toplevel_cwd_prefix, path);\n \t} else {\n \t\treturn xstrdup(path);\n \t}\n@@ -364,9 +364,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n+\t\tstrvec_pushl(&cpr.args, \"submodule--helper\",\n+\t\t\t     \"--toplevel-cwd-prefix\", NULL);\n \t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n-\t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"foreach\", \"--recursive\",\n+\t\tstrvec_pushl(&cpr.args, \"foreach\", \"--recursive\",\n \t\t\t     NULL);\n \n \t\tif (info->quiet)\n@@ -682,10 +683,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushl(&cpr.args, \"submodule--helper\",\n+\t\t\t     \"--toplevel-cwd-prefix\", NULL);\n \t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n-\t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"status\",\n-\t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_pushl(&cpr.args, \"status\", \"--recursive\", NULL);\n \n \t\tif (flags & OPT_CACHED)\n \t\t\tstrvec_push(&cpr.args, \"--cached\");\n@@ -1276,10 +1277,10 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushl(&cpr.args, \"submodule--helper\",\n+\t\t\t     \"--toplevel-cwd-prefix\", NULL);\n \t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n-\t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"sync\",\n-\t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_pushl(&cpr.args, \"sync\", \"--recursive\", NULL);\n \n \t\tif (flags & OPT_QUIET)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -2438,11 +2439,12 @@ static void update_data_to_args(const struct update_data *update_data,\n {\n \tenum submodule_update_type update_type = update_data->update_default;\n \n+\tstrvec_push(args, \"submodule--helper\");\n \tif (update_data->displaypath) {\n-\t\tstrvec_push(args, \"--super-prefix\");\n+\t\tstrvec_push(args, \"--toplevel-cwd-prefix\");\n \t\tstrvec_pushf(args, \"%s/\", update_data->displaypath);\n \t}\n-\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n+\tstrvec_pushl(args, \"update\", \"--recursive\", NULL);\n \tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n \tif (update_data->quiet)\n \t\tstrvec_push(args, \"--quiet\");\n@@ -3353,14 +3355,15 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n {\n-\tconst char *cmd = argv[0];\n-\tconst char *subcmd;\n \tparse_opt_subcommand_fn *fn = NULL;\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule--helper <command>\"),\n \t\tNULL\n \t};\n \tstruct option options[] = {\n+\t\tOPT_CALLBACK_F(0, \"toplevel-cwd-prefix\", NULL, \"path\",\n+\t\t\t       \"path from top level cwd to working tree root\",\n+\t\t\t       0, option_parse_toplevel_cwd_prefix),\n \t\tOPT_SUBCOMMAND(\"clone\", &fn, module_clone),\n \t\tOPT_SUBCOMMAND(\"add\", &fn, module_add),\n \t\tOPT_SUBCOMMAND(\"update\", &fn, module_update),\n@@ -3375,21 +3378,10 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_SUBCOMMAND(\"set-url\", &fn, module_set_url),\n \t\tOPT_SUBCOMMAND(\"set-branch\", &fn, module_set_branch),\n \t\tOPT_SUBCOMMAND(\"create-branch\", &fn, module_create_branch),\n+\n \t\tOPT_END()\n \t};\n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\tsubcmd = argv[0];\n-\n-\tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && strcmp(subcmd, \"absorbgitdirs\") &&\n-\t    get_super_prefix())\n-\t\t/*\n-\t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n-\t\t * string identical to git.c's.\n-\t\t */\n-\t\tdie(_(\"%s doesn't support --super-prefix\"),\n-\t\t    xstrfmt(\"'%s %s'\", cmd, subcmd));\n \n \treturn fn(argc, argv, prefix);\n }\ndiff --git a/submodule.c b/submodule.c\nindex 8fa2ad457b..a6db8c4bbe 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -28,6 +28,7 @@ static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n static int initialized_fetch_ref_tips;\n static struct oid_array ref_tips_before_fetch;\n static struct oid_array ref_tips_after_fetch;\n+static const char *toplevel_cwd_prefix;\n \n /*\n  * Check if the .gitmodules file is unmerged. Parsing of the .gitmodules file\n@@ -241,6 +242,21 @@ int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\n \treturn 0;\n }\n \n+int option_parse_toplevel_cwd_prefix(const struct option *opt,\n+\t\t\t\t     const char *arg, int unset)\n+{\n+\tif (arg)\n+\t\ttoplevel_cwd_prefix = arg;\n+\treturn 0;\n+}\n+\n+const char *get_toplevel_cwd_prefix(void)\n+{\n+\tif (!toplevel_cwd_prefix)\n+\t\treturn \"\";\n+\treturn toplevel_cwd_prefix;\n+}\n+\n /*\n  * Determine if a submodule has been initialized at a given 'path'\n  */\n@@ -2298,7 +2314,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \treal_new_git_dir = real_pathdup(new_gitdir.buf, 1);\n \n \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from\\n'%s' to\\n'%s'\\n\"),\n-\t\tget_super_prefix_or_empty(), path,\n+\t\tget_toplevel_cwd_prefix(), path,\n \t\treal_old_git_dir, real_new_git_dir);\n \n \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n@@ -2317,10 +2333,10 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n \tcp.dir = path;\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n-\tstrvec_pushl(&cp.args, \"submodule--helper\",\n-\t\t     \"absorbgitdirs\", NULL);\n+\tstrvec_push(&cp.args, \"submodule--helper\");\n+\tstrvec_pushf(&cp.args, \"--toplevel-cwd-prefix=%s%s/\",\n+\t\t     get_toplevel_cwd_prefix(), path);\n+\tstrvec_pushl(&cp.args, \"absorbgitdirs\", NULL);\n \tprepare_submodule_repo_env(&cp.env);\n \tif (run_command(&cp))\n \t\tdie(_(\"could not recurse into submodule '%s'\"), path);\ndiff --git a/submodule.h b/submodule.h\nindex b52a4ff1e7..436dbb2e11 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -54,6 +54,16 @@ int git_default_submodule_config(const char *var, const char *value, void *cb);\n struct option;\n int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\n \t\t\t\t\t\t     const char *arg, int unset);\n+int option_parse_toplevel_cwd_prefix(const struct option *opt,\n+\t\t\t\t   const char *arg, int unset);\n+/*\n+ * Return the relative path of the top-level process's cwd to the root of the\n+ * working tree. When printing paths to submodules in the working tree, this\n+ * value should be prepended to the path so that they appear relative to the\n+ * top-level process's cwd instead of this process's cwd.\n+ */\n+const char *get_toplevel_cwd_prefix(void);\n+\n int is_tree_submodule_active(struct repository *repo,\n \t\t\t     const struct object_id *treeish_name,\n \t\t\t     const char *path);\ndiff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\nindex 2859695c6d..a9efebc7ec 100755\n--- a/t/t7412-submodule-absorbgitdirs.sh\n+++ b/t/t7412-submodule-absorbgitdirs.sh\n@@ -54,15 +54,24 @@ test_expect_success 'setup nested submodule' '\n '\n \n test_expect_success 'absorb the git dir in a nested submodule' '\n+\t# Touch the files so that they show up in git status\n+\t>expect.err &&\n+\t>actual.err &&\n \tgit status >expect.1 &&\n \tgit -C sub1/nested rev-parse HEAD >expect.2 &&\n-\tgit submodule absorbgitdirs &&\n+\tgit submodule absorbgitdirs 2>actual.err &&\n \ttest -f sub1/nested/.git &&\n \ttest -d .git/modules/sub1/modules/nested &&\n \tgit status >actual.1 &&\n \tgit -C sub1/nested rev-parse HEAD >actual.2 &&\n \ttest_cmp expect.1 actual.1 &&\n-\ttest_cmp expect.2 actual.2\n+\ttest_cmp expect.2 actual.2 &&\n+\tcat >expect.err <<-EOF &&\n+\tMigrating git directory of ${SQ}sub1/nested${SQ} from\n+\t${SQ}/Users/chooglen/Code/git/t/trash directory.t7412-submodule-absorbgitdirs/sub1/nested/.git${SQ} to\n+\t${SQ}/Users/chooglen/Code/git/t/trash directory.t7412-submodule-absorbgitdirs/.git/modules/sub1/modules/nested${SQ}\n+\tEOF\n+\ttest_cmp expect.err actual.err\n '\n \n test_expect_success 're-setup nested submodule' '\n-- \n2.38.1.431.g37b22c650d-goog\n\n"},{"id":"466925","messageId":"20221109004708.97668-3-chooglen@google.com","threadId":"58773","inReplyTo":"20221109004708.97668-1-chooglen@google.com","subject":"[RFC PATCH 2/4] fetch: refactor --submodule-prefix","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-09T00:47:06Z","receivedAt":"2022-11-09T00:47:38Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Since \"git fetch\" learned to recurse into submodules [1], it has passed\n\"--submodule-prefix=<path from root of superproject tree to submodule>\"\nto print full paths to the submodules being fetched. This is the same\nvalue as \"--super-prefix\"'s when calling \"git read-tree\n--recurse-submodules\", as well as \"git (grep|ls-files)\n--recurse-submodules\" before they were implemented in-process [2] [3],\n(when they used repository.submodule_prefix to replace \"--super-prefix).\n\nLet's standardize the way we pass such prefixes. Having a per-command\n\"--submodule-prefix\" is preferable to a top-level \"--super-prefix\",\nsince it gives us fine-grained control over which commands support it\nand which don't, and we can preserve the effort-saving properties of the\ntop-level flag by sharing an implementation under the hood.\n\nRefactor \"git fetch\" so that \"--submodule-prefix\" is stored in\nrepository.submodule_prefix, and create functions in submodule.h for\nparsing and reading its value. Also, mark it with PARSE_OPT_HIDDEN and\ndrop it from our documentation. We will follow this pattern for \"git\nread-tree\" in the next commit.\n\nSince we've previously documented that repository.submodule_prefix is\nonly set for submodules, introduce repository.is_submodule for\ndistinguishing between the_repository and a submodule (although, this\nturns out to be unused, since no caller uses repository.submodule_prefix\nfor that purpose).\n\n[1] 7dce19d374 (fetch/pull: Add the --recurse-submodules option, 2010-11-12)\n[2] 188dce131f (ls-files: use repository object, 2017-06-22)\n[3] f9ee2fcdfa (grep: recurse in-process using 'struct repository', 2017-08-02)\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n Documentation/fetch-options.txt |  5 -----\n builtin/fetch.c                 |  7 +++----\n repository.c                    |  1 +\n repository.h                    |  9 +++++++--\n submodule.c                     | 35 +++++++++++++++++++++------------\n submodule.h                     | 12 +++++++++--\n 6 files changed, 43 insertions(+), 26 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 622bd84768..20cbd2c291 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -241,11 +241,6 @@ endif::git-pull[]\n \tlinkgit:git-config[1].\n \n ifndef::git-pull[]\n---submodule-prefix=<path>::\n-\tPrepend <path> to paths printed in informative messages\n-\tsuch as \"Fetching submodule foo\".  This option is used\n-\tinternally when recursing over submodules.\n-\n --recurse-submodules-default=[yes|on-demand]::\n \tThis option is used internally to temporarily provide a\n \tnon-negative default value for the --recurse-submodules\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex b06e454cbd..78a46389ff 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -74,7 +74,6 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;\n static struct strbuf default_rla = STRBUF_INIT;\n static struct transport *gtransport;\n static struct transport *gsecondary;\n-static const char *submodule_prefix = \"\";\n static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;\n static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;\n@@ -195,8 +194,9 @@ static struct option builtin_fetch_options[] = {\n \tOPT_SET_INT_F(0, \"refetch\", &refetch,\n \t\t      N_(\"re-fetch without negotiating common commits\"),\n \t\t      1, PARSE_OPT_NONEG),\n-\t{ OPTION_STRING, 0, \"submodule-prefix\", &submodule_prefix, N_(\"dir\"),\n-\t\t   N_(\"prepend this to submodule path output\"), PARSE_OPT_HIDDEN },\n+\tOPT_CALLBACK_F(0, \"submodule-prefix\", NULL, \"path\",\n+\t\t\t\"path from top-level superproject root to current repo root\",\n+\t\t\tPARSE_OPT_HIDDEN, option_parse_submodule_prefix),\n \tOPT_CALLBACK_F(0, \"recurse-submodules-default\",\n \t\t   &recurse_submodules_default, N_(\"on-demand\"),\n \t\t   N_(\"default for recursive fetching of submodules \"\n@@ -2297,7 +2297,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t\tadd_options_to_argv(&options);\n \t\tresult = fetch_submodules(the_repository,\n \t\t\t\t\t  &options,\n-\t\t\t\t\t  submodule_prefix,\n \t\t\t\t\t  recurse_submodules,\n \t\t\t\t\t  recurse_submodules_default,\n \t\t\t\t\t  verbosity < 0,\ndiff --git a/repository.c b/repository.c\nindex 5d166b692c..1d454a0ac4 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -229,6 +229,7 @@ int repo_submodule_init(struct repository *subrepo,\n \t\t}\n \t}\n \n+\tsubrepo->is_submodule = 1;\n \tsubrepo->submodule_prefix = xstrfmt(\"%s%s/\",\n \t\t\t\t\t    superproject->submodule_prefix ?\n \t\t\t\t\t    superproject->submodule_prefix :\ndiff --git a/repository.h b/repository.h\nindex 24316ac944..1bc4afc2b6 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -119,10 +119,15 @@ struct repository {\n \t */\n \tchar *worktree;\n \n+\t/*\n+\t * Whether this struct represents a submodule of this process's main\n+\t * repository.\n+\t */\n+\tint is_submodule;\n+\n \t/*\n \t * Path from the root of the top-level superproject down to this\n-\t * repository.  This is only non-NULL if the repository is initialized\n-\t * as a submodule of another repository.\n+\t * repository.\n \t */\n \tchar *submodule_prefix;\n \ndiff --git a/submodule.c b/submodule.c\nindex a6db8c4bbe..d84345a0b4 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -257,6 +257,21 @@ const char *get_toplevel_cwd_prefix(void)\n \treturn toplevel_cwd_prefix;\n }\n \n+int option_parse_submodule_prefix(const struct option *opt,\n+\t\t\t\t  const char *arg, int unset)\n+{\n+\tif (arg)\n+\t\tthe_repository->submodule_prefix = xstrdup(arg);\n+\treturn 0;\n+}\n+\n+const char *get_submodule_prefix(void)\n+{\n+\tif (!the_repository->submodule_prefix)\n+\t\treturn \"\";\n+\treturn the_repository->submodule_prefix;\n+}\n+\n /*\n  * Determine if a submodule has been initialized at a given 'path'\n  */\n@@ -1392,7 +1407,6 @@ struct submodule_parallel_fetch {\n \tint changed_count;\n \tstruct strvec args;\n \tstruct repository *r;\n-\tconst char *prefix;\n \tint command_line_option;\n \tint default_option;\n \tint quiet;\n@@ -1583,7 +1597,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,\n \t\tif (task->repo) {\n \t\t\tif (!spf->quiet)\n \t\t\t\tstrbuf_addf(err, _(\"Fetching submodule %s%s\\n\"),\n-\t\t\t\t\t    spf->prefix, ce->name);\n+\t\t\t\t\t    get_submodule_prefix(), ce->name);\n \n \t\t\tspf->index_count++;\n \t\t\treturn task;\n@@ -1645,7 +1659,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,\n \t\tif (!spf->quiet)\n \t\t\tstrbuf_addf(err,\n \t\t\t\t    _(\"Fetching submodule %s%s at commit %s\\n\"),\n-\t\t\t\t    spf->prefix, task->sub->path,\n+\t\t\t\t    get_submodule_prefix(), task->sub->path,\n \t\t\t\t    find_unique_abbrev(cs_data->super_oid,\n \t\t\t\t\t\t       DEFAULT_ABBREV));\n \n@@ -1692,8 +1706,6 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n \t\ttask = get_fetch_task_from_changed(spf, err);\n \n \tif (task) {\n-\t\tstruct strbuf submodule_prefix = STRBUF_INIT;\n-\n \t\tchild_process_init(cp);\n \t\tcp->dir = task->repo->gitdir;\n \t\tprepare_submodule_repo_env_in_gitdir(&cp->env);\n@@ -1705,13 +1717,11 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n \t\tstrvec_push(&cp->args, task->default_argv);\n \t\tstrvec_push(&cp->args, \"--submodule-prefix\");\n \n-\t\tstrbuf_addf(&submodule_prefix, \"%s%s/\",\n-\t\t\t\t\t\tspf->prefix,\n-\t\t\t\t\t\ttask->sub->path);\n-\t\tstrvec_push(&cp->args, submodule_prefix.buf);\n+\t\tstrvec_pushf(&cp->args, \"%s%s/\",\n+\t\t\t\t\tget_submodule_prefix(),\n+\t\t\t\t\ttask->sub->path);\n \t\t*task_cb = task;\n \n-\t\tstrbuf_release(&submodule_prefix);\n \t\tstring_list_insert(&spf->seen_submodule_names, task->sub->name);\n \t\treturn 1;\n \t}\n@@ -1723,7 +1733,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n \t\tspf->oid_fetch_tasks_nr--;\n \n \t\tstrbuf_addf(&submodule_prefix, \"%s%s/\",\n-\t\t\t    spf->prefix, task->sub->path);\n+\t\t\t    get_submodule_prefix(), task->sub->path);\n \n \t\tchild_process_init(cp);\n \t\tprepare_submodule_repo_env_in_gitdir(&cp->env);\n@@ -1829,7 +1839,7 @@ static int fetch_finish(int retvalue, struct strbuf *err,\n \n int fetch_submodules(struct repository *r,\n \t\t     const struct strvec *options,\n-\t\t     const char *prefix, int command_line_option,\n+\t\t     int command_line_option,\n \t\t     int default_option,\n \t\t     int quiet, int max_parallel_jobs)\n {\n@@ -1851,7 +1861,6 @@ int fetch_submodules(struct repository *r,\n \tspf.command_line_option = command_line_option;\n \tspf.default_option = default_option;\n \tspf.quiet = quiet;\n-\tspf.prefix = prefix;\n \n \tif (!r->worktree)\n \t\tgoto out;\ndiff --git a/submodule.h b/submodule.h\nindex 436dbb2e11..f2701c4869 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -55,7 +55,7 @@ struct option;\n int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\n \t\t\t\t\t\t     const char *arg, int unset);\n int option_parse_toplevel_cwd_prefix(const struct option *opt,\n-\t\t\t\t   const char *arg, int unset);\n+\t\t\t\t     const char *arg, int unset);\n /*\n  * Return the relative path of the top-level process's cwd to the root of the\n  * working tree. When printing paths to submodules in the working tree, this\n@@ -63,6 +63,15 @@ int option_parse_toplevel_cwd_prefix(const struct option *opt,\n  * top-level process's cwd instead of this process's cwd.\n  */\n const char *get_toplevel_cwd_prefix(void);\n+int option_parse_submodule_prefix(const struct option *opt,\n+\t\t\t\t      const char *arg, int unset);\n+/*\n+ * Return the path from the root of the top-level superproject to root of this\n+ * repository. When printing paths to submodules in a tree, this value should be\n+ * prepended to the path so that they originate from the top-level\n+ * superproject's tree instead of this repository's tree.\n+ */\n+const char *get_submodule_prefix(void);\n \n int is_tree_submodule_active(struct repository *repo,\n \t\t\t     const struct object_id *treeish_name,\n@@ -100,7 +109,6 @@ const struct submodule *submodule_from_ce(const struct cache_entry *ce);\n void check_for_new_submodule_commits(struct object_id *oid);\n int fetch_submodules(struct repository *r,\n \t\t     const struct strvec *options,\n-\t\t     const char *prefix,\n \t\t     int command_line_option,\n \t\t     int default_option,\n \t\t     int quiet, int max_parallel_jobs);\n-- \n2.38.1.431.g37b22c650d-goog\n\n"},{"id":"466926","messageId":"20221109004708.97668-4-chooglen@google.com","threadId":"58773","inReplyTo":"20221109004708.97668-1-chooglen@google.com","subject":"[RFC PATCH 3/4] read-tree: teach --submodule-prefix","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-09T00:47:07Z","receivedAt":"2022-11-09T00:47:42Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Following the precedent of previous commit, teach \"git read-tree\" the\n\"--submodule-prefix\" flag, replacing its use of the global\n\"--super-prefix\" flag.\n\nThis also fixes an existing bug where \"git --super-prefix=<path>\nread-tree\" (typically invoked by \"git restore\") in a partial clone with\nsubmodules could fail because we fetch promisor objects with \"git\nfetch\", but \"git fetch\" doesn't support \"--super-prefix\".\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/read-tree.c         |  4 ++++\n submodule.c                 | 22 +++++++------------\n t/t1001-read-tree-m-2way.sh |  4 ++--\n t/t5616-partial-clone.sh    | 43 +++++++++++++++++++++++++++++++++++++\n unpack-trees.c              | 32 +++++++++++++--------------\n 5 files changed, 73 insertions(+), 32 deletions(-)\n\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex f4cbe460b9..7aedab6951 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -148,6 +148,10 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)\n \t\tOPT_CALLBACK_F(0, \"recurse-submodules\", NULL,\n \t\t\t    \"checkout\", \"control recursive updating of submodules\",\n \t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),\n+\t\tOPT_CALLBACK_F(0, \"submodule-prefix\", NULL, \"path\",\n+\t\t\t       \"internal, path from root of top-level superproject tree to this repo\",\n+\t\t\t       PARSE_OPT_HIDDEN, option_parse_submodule_prefix),\n+\n \t\tOPT__QUIET(&opts.quiet, N_(\"suppress feedback messages\")),\n \t\tOPT_END()\n \t};\ndiff --git a/submodule.c b/submodule.c\nindex d84345a0b4..d3d6abc816 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2073,14 +2073,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)\n \tstrbuf_release(&config_path);\n }\n \n-static const char *get_super_prefix_or_empty(void)\n-{\n-\tconst char *s = get_super_prefix();\n-\tif (!s)\n-\t\ts = \"\";\n-\treturn s;\n-}\n-\n static int submodule_has_dirty_index(const struct submodule *sub)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2108,10 +2100,11 @@ static void submodule_reset_index(const char *path)\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \t/* TODO: determine if this might overwright untracked files */\n-\tstrvec_pushl(&cp.args, \"read-tree\", \"-u\", \"--reset\", NULL);\n+\tstrvec_push(&cp.args, \"read-tree\");\n+\tstrvec_pushf(&cp.args, \"--submodule-prefix=%s%s/\",\n+\t\t     get_submodule_prefix(), path);\n+\tstrvec_pushl(&cp.args, \"-u\", \"--reset\", NULL);\n \n \tstrvec_push(&cp.args, empty_tree_oid_hex());\n \n@@ -2191,9 +2184,10 @@ int submodule_move_head(const char *path,\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n-\tstrvec_pushl(&cp.args, \"read-tree\", \"--recurse-submodules\", NULL);\n+\tstrvec_push(&cp.args, \"read-tree\");\n+\tstrvec_pushf(&cp.args, \"--submodule-prefix=%s%s/\",\n+\t\t     get_submodule_prefix(), path);\n+\tstrvec_push(&cp.args, \"--recurse-submodules\");\n \n \tif (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)\n \t\tstrvec_push(&cp.args, \"-n\");\ndiff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh\nindex 516a6112fd..9cfba1a2af 100755\n--- a/t/t1001-read-tree-m-2way.sh\n+++ b/t/t1001-read-tree-m-2way.sh\n@@ -366,11 +366,11 @@ test_expect_success 'a/b (untracked) vs a, plus c/d case test.' '\n \ttest -f a/b\n '\n \n-test_expect_success 'read-tree supports the super-prefix' '\n+test_expect_success 'read-tree supports --submodule-prefix' '\n \tcat <<-EOF >expect &&\n \t\terror: Updating '\\''fictional/a'\\'' would lose untracked files in it\n \tEOF\n-\ttest_must_fail git --super-prefix fictional/ read-tree -u -m \"$treeH\" \"$treeM\" 2>actual &&\n+\ttest_must_fail git read-tree --submodule-prefix fictional/ -u -m \"$treeH\" \"$treeM\" 2>actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 037941b95d..9bec57a047 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '\n \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n '\n \n+test_expect_success 'setup src repo with submodules' '\n+\ttest_config_global protocol.file.allow always &&\n+\n+\tgit init src-sub &&\n+\tgit -C src-sub config uploadpack.allowfilter 1 &&\n+\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n+\n+\t# This blob must be missing in the subsequent commit.\n+\techo foo >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule one\" &&\n+\tSUB_ONE=$(git -C src-sub rev-parse HEAD) &&\n+\n+\techo bar >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule two\" &&\n+\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n+\n+\tgit init src-super &&\n+\tgit -C src-super config uploadpack.allowfilter 1 &&\n+\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n+\tgit -C src-super submodule add ../src-sub src-sub &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_ONE &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject one\" &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_TWO &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject two\"\n+'\n+\n+test_expect_success 'lazy-fetch in submodule succeeds' '\n+\ttest_when_finished \"rm -rf src-super src-sub client\" &&\n+\n+\ttest_config_global protocol.file.allow always &&\n+\tgit clone --filter=blob:none --also-filter-submodules \\\n+\t\t--recurse-submodules \"file://$(pwd)/src-super\" client &&\n+\n+\t# Trigger lazy-fetch from the superproject\n+\tgit -C client restore --recurse-submodules --source=HEAD^ :/\n+'\n+\n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n start_httpd\n \ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex bae812156c..930a2a46f1 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {\n \t  ? ((o)->msgs[(type)])      \\\n \t  : (unpack_plumbing_errors[(type)]) )\n \n-static const char *super_prefixed(const char *path)\n+static const char *submodule_prefixed(const char *path)\n {\n \t/*\n \t * It is necessary and sufficient to have two static buffers\n@@ -79,28 +79,28 @@ static const char *super_prefixed(const char *path)\n \t * error() using the unpack_*_errors[] templates we see above.\n \t */\n \tstatic struct strbuf buf[2] = {STRBUF_INIT, STRBUF_INIT};\n-\tstatic int super_prefix_len = -1;\n+\tstatic int submodule_prefix_len = -1;\n \tstatic unsigned idx = ARRAY_SIZE(buf) - 1;\n \n-\tif (super_prefix_len < 0) {\n-\t\tconst char *super_prefix = get_super_prefix();\n-\t\tif (!super_prefix) {\n-\t\t\tsuper_prefix_len = 0;\n+\tif (submodule_prefix_len < 0) {\n+\t\tconst char *submodule_prefix = get_submodule_prefix();\n+\t\tif (!submodule_prefix) {\n+\t\t\tsubmodule_prefix_len = 0;\n \t\t} else {\n \t\t\tint i;\n \t\t\tfor (i = 0; i < ARRAY_SIZE(buf); i++)\n-\t\t\t\tstrbuf_addstr(&buf[i], super_prefix);\n-\t\t\tsuper_prefix_len = buf[0].len;\n+\t\t\t\tstrbuf_addstr(&buf[i], submodule_prefix);\n+\t\t\tsubmodule_prefix_len = buf[0].len;\n \t\t}\n \t}\n \n-\tif (!super_prefix_len)\n+\tif (!submodule_prefix_len)\n \t\treturn path;\n \n \tif (++idx >= ARRAY_SIZE(buf))\n \t\tidx = 0;\n \n-\tstrbuf_setlen(&buf[idx], super_prefix_len);\n+\tstrbuf_setlen(&buf[idx], submodule_prefix_len);\n \tstrbuf_addstr(&buf[idx], path);\n \n \treturn buf[idx].buf;\n@@ -236,7 +236,7 @@ static int add_rejected_path(struct unpack_trees_options *o,\n \t\treturn -1;\n \n \tif (!o->show_all_errors)\n-\t\treturn error(ERRORMSG(o, e), super_prefixed(path));\n+\t\treturn error(ERRORMSG(o, e), submodule_prefixed(path));\n \n \t/*\n \t * Otherwise, insert in a list for future display by\n@@ -263,7 +263,7 @@ static void display_error_msgs(struct unpack_trees_options *o)\n \t\t\terror_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\terror(ERRORMSG(o, e), submodule_prefixed(path.buf));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -290,7 +290,7 @@ static void display_warning_msgs(struct unpack_trees_options *o)\n \t\t\twarning_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\twarning(ERRORMSG(o, e), submodule_prefixed(path.buf));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -2958,8 +2958,8 @@ int bind_merge(const struct cache_entry * const *src,\n \tif (a && old)\n \t\treturn o->quiet ? -1 :\n \t\t\terror(ERRORMSG(o, ERROR_BIND_OVERLAP),\n-\t\t\t      super_prefixed(a->name),\n-\t\t\t      super_prefixed(old->name));\n+\t\t\t      submodule_prefixed(a->name),\n+\t\t\t      submodule_prefixed(old->name));\n \tif (!a)\n \t\treturn keep_entry(old, o);\n \telse\n@@ -3020,7 +3020,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,\n \n \tif (worktree && untracked)\n \t\treturn error(_(\"worktree and untracked commit have duplicate entries: %s\"),\n-\t\t\t     super_prefixed(worktree->name));\n+\t\t\t     submodule_prefixed(worktree->name));\n \n \treturn merged_entry(worktree ? worktree : untracked, NULL, o);\n }\n-- \n2.38.1.431.g37b22c650d-goog\n\n"},{"id":"466927","messageId":"20221109004708.97668-5-chooglen@google.com","threadId":"58773","inReplyTo":"20221109004708.97668-1-chooglen@google.com","subject":"[RFC PATCH 4/4] git: remove --super-prefix","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-09T00:47:08Z","receivedAt":"2022-11-09T00:47:55Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"It has no more users, and prospective new users can use per-command\nflags instead, e.g. \"git fetch --submodule-prefix\" or \"git\nsubmodule--helper --toplevel-cwd-prefix\".\n\nNow that this flag is gone, also remove a now-defunct test from\nt/t7527-builtin-fsmonitor.sh.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n Documentation/git.txt        |  7 +----\n builtin.h                    |  4 ---\n cache.h                      |  2 --\n environment.c                | 13 ----------\n git.c                        | 40 +++++------------------------\n t/t7527-builtin-fsmonitor.sh | 50 ------------------------------------\n 6 files changed, 8 insertions(+), 108 deletions(-)\n\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 1d33e083ab..85c7d9500e 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -13,7 +13,7 @@ SYNOPSIS\n     [--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>]\n \n DESCRIPTION\n@@ -169,11 +169,6 @@ If you just want to run git as if it was started in `<path>` then use\n \tdetails.  Equivalent to setting the `GIT_NAMESPACE` environment\n \tvariable.\n \n---super-prefix=<path>::\n-\tCurrently for internal use only.  Set a prefix which gives a path from\n-\tabove a repository down to its root.  One use is to give submodules\n-\tcontext about the superproject that invoked it.\n-\n --bare::\n \tTreat the repository as a bare repository.  If GIT_DIR\n \tenvironment is not set, it is set to the current working\ndiff --git a/builtin.h b/builtin.h\nindex 8901a34d6b..8264b7e524 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -51,10 +51,6 @@\n  *\ton bare repositories.\n  *\tThis only makes sense when `RUN_SETUP` is also set.\n  *\n- * `SUPPORT_SUPER_PREFIX`:\n- *\n- *\tThe built-in supports `--super-prefix`.\n- *\n  * `DELAY_PAGER_CONFIG`:\n  *\n  *\tIf RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles\ndiff --git a/cache.h b/cache.h\nindex 26ed03bd6d..a4a0377b80 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)\n #define GIT_NAMESPACE_ENVIRONMENT \"GIT_NAMESPACE\"\n #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n #define GIT_PREFIX_ENVIRONMENT \"GIT_PREFIX\"\n-#define GIT_SUPER_PREFIX_ENVIRONMENT \"GIT_INTERNAL_SUPER_PREFIX\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n@@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n int get_common_dir(struct strbuf *sb, const char *gitdir);\n const char *get_git_namespace(void);\n const char *strip_namespace(const char *namespaced_ref);\n-const char *get_super_prefix(void);\n const char *get_git_work_tree(void);\n \n /*\ndiff --git a/environment.c b/environment.c\nindex 18d042b467..1ee3686fd8 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -102,8 +102,6 @@ char *git_work_tree_cfg;\n \n static char *git_namespace;\n \n-static char *super_prefix;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {\n \tNO_REPLACE_OBJECTS_ENVIRONMENT,\n \tGIT_REPLACE_REF_BASE_ENVIRONMENT,\n \tGIT_PREFIX_ENVIRONMENT,\n-\tGIT_SUPER_PREFIX_ENVIRONMENT,\n \tGIT_SHALLOW_FILE_ENVIRONMENT,\n \tGIT_COMMON_DIR_ENVIRONMENT,\n \tNULL\n@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)\n \treturn NULL;\n }\n \n-const char *get_super_prefix(void)\n-{\n-\tstatic int initialized;\n-\tif (!initialized) {\n-\t\tsuper_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));\n-\t\tinitialized = 1;\n-\t}\n-\treturn super_prefix;\n-}\n-\n static int git_work_tree_initialized;\n \n /*\ndiff --git a/git.c b/git.c\nindex fb69e60591..5548619aea 100644\n--- a/git.c\n+++ b/git.c\n@@ -14,9 +14,8 @@\n  * RUN_SETUP for reading from the configuration file.\n  */\n #define NEED_WORK_TREE\t\t(1<<3)\n-#define SUPPORT_SUPER_PREFIX\t(1<<4)\n-#define DELAY_PAGER_CONFIG\t(1<<5)\n-#define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n+#define DELAY_PAGER_CONFIG\t(1<<4)\n+#define NO_PARSEOPT\t\t(1<<5) /* parse-options is not used */\n \n struct cmd_struct {\n \tconst char *cmd;\n@@ -29,7 +28,7 @@ const char git_usage_string[] =\n \t   \"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\\n\"\n \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\\n\"\n \t   \"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\\n\"\n-\t   \"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\\n\"\n+\t   \"           [--config-env=<name>=<envvar>]\\n\"\n \t   \"           <command> [<args>]\");\n \n const char git_more_info_string[] =\n@@ -226,20 +225,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);\n \t\t\tif (envchanged)\n \t\t\t\t*envchanged = 1;\n-\t\t} else if (!strcmp(cmd, \"--super-prefix\")) {\n-\t\t\tif (*argc < 2) {\n-\t\t\t\tfprintf(stderr, _(\"no prefix given for --super-prefix\\n\" ));\n-\t\t\t\tusage(git_usage_string);\n-\t\t\t}\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n-\t\t\t(*argv)++;\n-\t\t\t(*argc)--;\n-\t\t} else if (skip_prefix(cmd, \"--super-prefix=\", &cmd)) {\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n \t\t} else if (!strcmp(cmd, \"--bare\")) {\n \t\t\tchar *cwd = xgetcwd();\n \t\t\tis_bare_repository_cfg = 1;\n@@ -449,11 +434,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\ttrace_repo_setup(prefix);\n \tcommit_pager_choice();\n \n-\tif (!help && get_super_prefix()) {\n-\t\tif (!(p->option & SUPPORT_SUPER_PREFIX))\n-\t\t\tdie(_(\"%s doesn't support --super-prefix\"), p->cmd);\n-\t}\n-\n \tif (!help && p->option & NEED_WORK_TREE)\n \t\tsetup_work_tree();\n \n@@ -504,7 +484,7 @@ static struct cmd_struct commands[] = {\n \t{ \"check-ref-format\", cmd_check_ref_format, NO_PARSEOPT  },\n \t{ \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout--worker\", cmd_checkout__worker,\n-\t\tRUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },\n+\t\tRUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout-index\", cmd_checkout_index,\n \t\tRUN_SETUP | NEED_WORK_TREE},\n \t{ \"cherry\", cmd_cherry, RUN_SETUP },\n@@ -539,7 +519,7 @@ static struct cmd_struct commands[] = {\n \t{ \"format-patch\", cmd_format_patch, RUN_SETUP },\n \t{ \"fsck\", cmd_fsck, RUN_SETUP },\n \t{ \"fsck-objects\", cmd_fsck, RUN_SETUP },\n-\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },\n+\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, RUN_SETUP },\n \t{ \"gc\", cmd_gc, RUN_SETUP },\n \t{ \"get-tar-commit-id\", cmd_get_tar_commit_id, NO_PARSEOPT },\n \t{ \"grep\", cmd_grep, RUN_SETUP_GENTLY },\n@@ -583,7 +563,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n-\t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n \t{ \"rebase\", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n@@ -610,7 +590,7 @@ static struct cmd_struct commands[] = {\n \t{ \"stash\", cmd_stash, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"stripspace\", cmd_stripspace },\n-\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP },\n \t{ \"switch\", cmd_switch, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"symbolic-ref\", cmd_symbolic_ref, RUN_SETUP },\n \t{ \"tag\", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },\n@@ -727,9 +707,6 @@ static void execv_dashed_external(const char **argv)\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tint status;\n \n-\tif (get_super_prefix())\n-\t\tdie(_(\"%s doesn't support --super-prefix\"), argv[0]);\n-\n \tif (use_pager == -1 && !is_builtin(argv[0]))\n \t\tuse_pager = check_pager_config(argv[0]);\n \tcommit_pager_choice();\n@@ -799,9 +776,6 @@ static int run_argv(int *argcp, const char ***argv)\n \t\t\t */\n \t\t\ttrace2_cmd_name(\"_run_git_alias_\");\n \n-\t\t\tif (get_super_prefix())\n-\t\t\t\tdie(\"%s doesn't support --super-prefix\", **argv);\n-\n \t\t\tcommit_pager_choice();\n \n \t\t\tstrvec_push(&args, \"git\");\ndiff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh\nindex 4abc74db2b..d11cb1854c 100755\n--- a/t/t7527-builtin-fsmonitor.sh\n+++ b/t/t7527-builtin-fsmonitor.sh\n@@ -860,56 +860,6 @@ test_expect_success 'submodule always visited' '\n \tmy_match_and_clean\n '\n \n-# If a submodule has a `sub/.git/` directory (rather than a file\n-# pointing to the super's `.git/modules/sub`) and `core.fsmonitor`\n-# turned on in the submodule and the daemon is not yet started in\n-# the submodule, and someone does a `git submodule absorbgitdirs`\n-# in the super, Git will recursively invoke `git submodule--helper`\n-# to do the work and this may try to read the index.  This will\n-# try to start the daemon in the submodule *and* pass (either\n-# directly or via inheritance) the `--super-prefix` arg to the\n-# `git fsmonitor--daemon start` command inside the submodule.\n-# This causes a warning because fsmonitor--daemon does take that\n-# global arg (see the table in git.c)\n-#\n-# This causes a warning when trying to start the daemon that is\n-# somewhat confusing.  It does not seem to hurt anything because\n-# the fsmonitor code maps the query failure into a trivial response\n-# and does the work anyway.\n-#\n-# It would be nice to silence the warning, however.\n-\n-have_t2_error_event () {\n-\tlog=$1\n-\tmsg=\"fsmonitor--daemon doesnQt support --super-prefix\" &&\n-\n-\ttr '\\047' Q <$1 | grep -e \"$msg\"\n-}\n-\n-test_expect_success \"stray submodule super-prefix warning\" '\n-\ttest_when_finished \"rm -rf super; \\\n-\t\t\t    rm -rf sub;   \\\n-\t\t\t    rm super-sub.trace\" &&\n-\n-\tcreate_super super &&\n-\tcreate_sub sub &&\n-\n-\t# Copy rather than submodule add so that we get a .git dir.\n-\tcp -R ./sub ./super/dir_1/dir_2/sub &&\n-\n-\tgit -C super/dir_1/dir_2/sub config core.fsmonitor true &&\n-\n-\tgit -C super submodule add ../sub ./dir_1/dir_2/sub &&\n-\tgit -C super commit -m \"add sub\" &&\n-\n-\ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n-\n-\tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n-\t\tgit -C super submodule absorbgitdirs &&\n-\n-\t! have_t2_error_event super-sub.trace\n-'\n-\n # On a case-insensitive file system, confirm that the daemon\n # notices when the .git directory is moved/renamed/deleted\n # regardless of how it is spelled in the the FS event.\n-- \n2.38.1.431.g37b22c650d-goog\n\n"},{"id":"466931","messageId":"221109.867d04rfnt.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"20221109004708.97668-2-chooglen@google.com","subject":"Re: [RFC PATCH 1/4] submodule--helper: teach --toplevel-cwd-prefix","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T02:37:27Z","receivedAt":"2022-11-09T03:05:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Nov 08 2022, Glen Choo wrote:\n\n> The top-level \"--super-prefix\" option (i.e. \"git --super-prefix\") is\n> overloaded:\n>\n> - \"git submodule--helper\" passes the relative path between the top-level\n>   \"git\" process's cwd and the current repository\n> - \"git read-tree\" passes the path from the root of top-level\n>   superproject's tree to the the current repository.\n>\n> In both cases, \"--super-prefix\" is only used to display meaningful paths\n> from the superproject to a nested submodule.\n\nThe \"overloaded\" here could really use some elaboration.\n\nYes, we have different built-in commands that use it, but their use is\nmostly mutually exclusive, i.e. when \"submodule status\" recurses into\nitself it using an option called \"--super-prefix\" doesn't impact \"git\nread-tree\", even though it uses the same option & env variable to\ncommunicate the same concept.\n\nBut I'm totally willing to buy that it's simpler to e.g. have \"git\nsubmodule--helper status\" or whatever use its own option to carry this\nforward, rather than some option to \"git\" itself. Or if some commands\njust need a --some-option, but not the environment variable.\n\nBut this doesn't really address that and ....\n\n> Let's address this overloading by breaking it up into its constituent\n> use cases. Teach \"git submodule--helper\" the \"--toplevel-cwd-prefix\"\n> option, which replaces its usage of \"git --super-prefix\". (A future\n> patch will address the \"git read-tree\" use case.) This value is only\n> used in builtin/submodule--helper.c, but it is stored in submodule.c,\n> since it may be needed by other builtins in the future.\n\n...Uh, other built-ins might use it in the future? :) Wouldn't we be\nright back to a --super-prefix then, which is a cross-built-in\nsemi-standard way to communicate this sort of information? So instead of\na hypothetical current:\n\n\tgit submodule some-subcommand\n\t\t=> git --super-prefix submodule/ submodule -C submodule/ some-subcommand\n\t\t\t=> git --super-prefix submodule/ fetch\n\nOr whatever, we'd do what? Have each of the now split-up commands take\ntheir own flag for this? E.g.:\n\n\tgit submodule some-subcommand\n\t\t=> git submodule -C submodule/ --toplevel-cwd-prefix submodule/ some-subcommand\n\t\t\t=> git fetch --submodule-prefix submodule/\n\nOr are you really trying to say that it was a hassle to pass down this\nthrough the various functions to all the callers, so emulating what we\ndid with the previous global was easier if it was a new global?\nI.e. it's not about passing it to other built-ins, but between\nsubmodule--helper itself?\n\nI think doing that and chipping away at this from the bottom-up would be\na much better approach, at least for some cases.\n\nE.g. just to have \"absorbgitdirs\" itself support a \"--super-prefix\"\noption, not \"git\" or \"git submodule--helper\".\n\nThen we just pass that down to absorb_git_dir_into_superproject(), which\nwill only invoke \"git submodule--helper absorbgitdirs\", which we'll then\ntell about the super-prefix with a \"--super-prefix\" option to that\nsubcommand.\n\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index c75e9e86b0..acb838e4d6 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -115,18 +115,18 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n>  /* the result should be freed by the caller. */\n>  static char *get_submodule_displaypath(const char *path, const char *prefix)\n>  {\n> -\tconst char *super_prefix = get_super_prefix();\n> +\tconst char *toplevel_cwd_prefix = get_toplevel_cwd_prefix();\n>  \n> -\tif (prefix && super_prefix) {\n> -\t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n> -\t\t    prefix, super_prefix);\n> +\tif (prefix && toplevel_cwd_prefix) {\n> +\t\tBUG(\"cannot have prefix '%s' and toplevel_cwd_prefix '%s'\",\n> +\t\t    prefix, toplevel_cwd_prefix);\n>  \t} else if (prefix) {\n>  \t\tstruct strbuf sb = STRBUF_INIT;\n>  \t\tchar *displaypath = xstrdup(relative_path(path, prefix, &sb));\n>  \t\tstrbuf_release(&sb);\n>  \t\treturn displaypath;\n> -\t} else if (super_prefix) {\n> -\t\treturn xstrfmt(\"%s%s\", super_prefix, path);\n> +\t} else if (toplevel_cwd_prefix) {\n> +\t\treturn xstrfmt(\"%s%s\", toplevel_cwd_prefix, path);\n>  \t} else {\n>  \t\treturn xstrdup(path);\n>  \t}\n\nAt the end of this series git.c has stopped knowing about\n\"--super-prefix\", so I don't see why we need the churn of renaming\nthis. Even if we just make built-in commands take it now, isn't that\nsufficient? We'd still need...\n\n> @@ -364,9 +364,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n>  \t\tcpr.dir = path;\n>  \t\tprepare_submodule_repo_env(&cpr.env);\n>  \n> -\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n> +\t\tstrvec_pushl(&cpr.args, \"submodule--helper\",\n> +\t\t\t     \"--toplevel-cwd-prefix\", NULL);\n>  \t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n> -\t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"foreach\", \"--recursive\",\n> +\t\tstrvec_pushl(&cpr.args, \"foreach\", \"--recursive\",\n>  \t\t\t     NULL);\n>  \n\n...to do this, but not all the function & variable renames.\n\n>  \tstruct option options[] = {\n> +\t\tOPT_CALLBACK_F(0, \"toplevel-cwd-prefix\", NULL, \"path\",\n> +\t\t\t       \"path from top level cwd to working tree root\",\n> +\t\t\t       0, option_parse_toplevel_cwd_prefix),\n>  \t\tOPT_SUBCOMMAND(\"clone\", &fn, module_clone),\n>  \t\tOPT_SUBCOMMAND(\"add\", &fn, module_add),\n>  \t\tOPT_SUBCOMMAND(\"update\", &fn, module_update),\n> @@ -3375,21 +3378,10 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n>  \t\tOPT_SUBCOMMAND(\"set-url\", &fn, module_set_url),\n>  \t\tOPT_SUBCOMMAND(\"set-branch\", &fn, module_set_branch),\n>  \t\tOPT_SUBCOMMAND(\"create-branch\", &fn, module_create_branch),\n> +\n>  \t\tOPT_END()\n>  \t};\n>  \targc = parse_options(argc, argv, prefix, options, usage, 0);\n> -\tsubcmd = argv[0];\n> -\n> -\tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n> -\t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n> -\t    strcmp(subcmd, \"sync\") && strcmp(subcmd, \"absorbgitdirs\") &&\n> -\t    get_super_prefix())\n> -\t\t/*\n> -\t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n> -\t\t * string identical to git.c's.\n> -\t\t */\n> -\t\tdie(_(\"%s doesn't support --super-prefix\"),\n> -\t\t    xstrfmt(\"'%s %s'\", cmd, subcmd));\n>  \n>  \treturn fn(argc, argv, prefix);\n>  }\n\nRe some of the things I was aiming for in the WIP submodule built-in\nseries by splitting up \"submodule--helper\", before this we'll only\naccept it for certain subcommands, e.g.:\n\n\t$ ./git --super-prefix=blah/ submodule--helper summary\n\tfatal: 'submodule--helper summary' doesn't support --super-prefix\n\nWhereas now we'll accept it:\n\n\t$ ./git submodule--helper --toplevel-cwd-prefix=blah/ summary\n\t$\n\nI'm not necessarily against that, but it does seem to run somewhat\ncounter to the divide-and-conquer of eventually getting rid of this\nsuper-prefix (or whatever we call it) business.\n\nAnd in any case, if that's what we're going to do let's loosen that up\nand justify that change in its own commit, separate from a\nrename/refactor. I.e. you could start by removing this strcmp(...) &&\nstrcmp(...), along with an explanation for why we won't need to care\nabout which \"submodule--helper\" subcommand needs it anymore.\n\n> diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\n> index 2859695c6d..a9efebc7ec 100755\n> --- a/t/t7412-submodule-absorbgitdirs.sh\n> +++ b/t/t7412-submodule-absorbgitdirs.sh\n> @@ -54,15 +54,24 @@ test_expect_success 'setup nested submodule' '\n>  '\n>  \n>  test_expect_success 'absorb the git dir in a nested submodule' '\n> +\t# Touch the files so that they show up in git status\n> +\t>expect.err &&\n> +\t>actual.err &&\n>  \tgit status >expect.1 &&\n>  \tgit -C sub1/nested rev-parse HEAD >expect.2 &&\n> -\tgit submodule absorbgitdirs &&\n> +\tgit submodule absorbgitdirs 2>actual.err &&\n>  \ttest -f sub1/nested/.git &&\n>  \ttest -d .git/modules/sub1/modules/nested &&\n>  \tgit status >actual.1 &&\n>  \tgit -C sub1/nested rev-parse HEAD >actual.2 &&\n>  \ttest_cmp expect.1 actual.1 &&\n> -\ttest_cmp expect.2 actual.2\n> +\ttest_cmp expect.2 actual.2 &&\n> +\tcat >expect.err <<-EOF &&\n> +\tMigrating git directory of ${SQ}sub1/nested${SQ} from\n> +\t${SQ}/Users/chooglen/Code/git/t/trash directory.t7412-submodule-absorbgitdirs/sub1/nested/.git${SQ} to\n> +\t${SQ}/Users/chooglen/Code/git/t/trash directory.t7412-submodule-absorbgitdirs/.git/modules/sub1/modules/nested${SQ}\n> +\tEOF\n> +\ttest_cmp expect.err actual.err\n\nI'm afraid I'll need to change my name & OS for that to pass for me :)\n\nThis reminded me to send in:\nhttps://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/\n; which fixes this message, & adds more tests for this output.\n"},{"id":"466932","messageId":"221109.8635asrfer.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"20221109004708.97668-3-chooglen@google.com","subject":"Re: [RFC PATCH 2/4] fetch: refactor --submodule-prefix","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T03:06:45Z","receivedAt":"2022-11-09T03:11:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Nov 08 2022, Glen Choo wrote:\n\n> Since we've previously documented that repository.submodule_prefix is\n> only set for submodules, introduce repository.is_submodule for\n> distinguishing between the_repository and a submodule (although, this\n> turns out to be unused, since no caller uses repository.submodule_prefix\n> for that purpose).\n\nThere's more to chew on here, but just briefly on this:\n\n> diff --git a/repository.c b/repository.c\n> index 5d166b692c..1d454a0ac4 100644\n> --- a/repository.c\n> +++ b/repository.c\n> @@ -229,6 +229,7 @@ int repo_submodule_init(struct repository *subrepo,\n>  \t\t}\n>  \t}\n>  \n> +\tsubrepo->is_submodule = 1;\n>  \tsubrepo->submodule_prefix = xstrfmt(\"%s%s/\",\n>  \t\t\t\t\t    superproject->submodule_prefix ?\n>  \t\t\t\t\t    superproject->submodule_prefix :\n> diff --git a/repository.h b/repository.h\n> index 24316ac944..1bc4afc2b6 100644\n> --- a/repository.h\n> +++ b/repository.h\n> @@ -119,10 +119,15 @@ struct repository {\n>  \t */\n>  \tchar *worktree;\n>  \n> +\t/*\n> +\t * Whether this struct represents a submodule of this process's main\n> +\t * repository.\n> +\t */\n> +\tint is_submodule;\n> +\n>  \t/*\n>  \t * Path from the root of the top-level superproject down to this\n> -\t * repository.  This is only non-NULL if the repository is initialized\n> -\t * as a submodule of another repository.\n> +\t * repository.\n>  \t */\n>  \tchar *submodule_prefix;\n>  \n\nJust deleting that \"is_submodule\" header addition and the assignment you\nadded on top of 4/4 has this series compile. So \"this turns out to be\nunused\" ... because it's added here, but never used? So why do we need\nto add it?\n"},{"id":"466933","messageId":"221109.86y1skq08e.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"20221109004708.97668-4-chooglen@google.com","subject":"Re: [RFC PATCH 3/4] read-tree: teach --submodule-prefix","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T03:13:05Z","receivedAt":"2022-11-09T03:24:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Nov 08 2022, Glen Choo wrote:\n\nOther things aside:\n\n> This also fixes an existing bug where \"git --super-prefix=<path>\n> read-tree\" (typically invoked by \"git restore\") in a partial clone with\n> submodules could fail because we fetch promisor objects with \"git\n> fetch\", but \"git fetch\" doesn't support \"--super-prefix\".\n> [...]\n> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\n> index 037941b95d..9bec57a047 100755\n> --- a/t/t5616-partial-clone.sh\n> +++ b/t/t5616-partial-clone.sh\n> @@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '\n>  \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n>  '\n>  \n> +test_expect_success 'setup src repo with submodules' '\n> +\ttest_config_global protocol.file.allow always &&\n> +\n> +\tgit init src-sub &&\n> +\tgit -C src-sub config uploadpack.allowfilter 1 &&\n> +\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n> +\n> +\t# This blob must be missing in the subsequent commit.\n> +\techo foo >src-sub/file &&\n> +\tgit -C src-sub add file &&\n> +\tgit -C src-sub commit -m \"submodule one\" &&\n> +\tSUB_ONE=$(git -C src-sub rev-parse HEAD) &&\n> +\n> +\techo bar >src-sub/file &&\n> +\tgit -C src-sub add file &&\n> +\tgit -C src-sub commit -m \"submodule two\" &&\n> +\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n> +\n> +\tgit init src-super &&\n> +\tgit -C src-super config uploadpack.allowfilter 1 &&\n> +\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n> +\tgit -C src-super submodule add ../src-sub src-sub &&\n> +\n> +\tgit -C src-super/src-sub checkout $SUB_ONE &&\n> +\tgit -C src-super add src-sub &&\n> +\tgit -C src-super commit -m \"superproject one\" &&\n> +\n> +\tgit -C src-super/src-sub checkout $SUB_TWO &&\n> +\tgit -C src-super add src-sub &&\n> +\tgit -C src-super commit -m \"superproject two\"\n> +'\n> +\n> +test_expect_success 'lazy-fetch in submodule succeeds' '\n> +\ttest_when_finished \"rm -rf src-super src-sub client\" &&\n> +\n> +\ttest_config_global protocol.file.allow always &&\n> +\tgit clone --filter=blob:none --also-filter-submodules \\\n> +\t\t--recurse-submodules \"file://$(pwd)/src-super\" client &&\n> +\n> +\t# Trigger lazy-fetch from the superproject\n> +\tgit -C client restore --recurse-submodules --source=HEAD^ :/\n> +'\n> +\n\nIf I take this test addition on top of \"master\", and don't apply any of\nthe C changes on this topic it'll fail in \"fetch\", and then in\n\"index-pack\"/\"unpack-objects\" etc., as \"fetch\" invokes those, due to us\nusing the --super-prefix.\n\nBut just this test addition and this code change would also \"fix it\":\n\t\n\tdiff --git a/builtin/fetch.c b/builtin/fetch.c\n\tindex 7378cafeec9..c5709a9e37b 100644\n\t--- a/builtin/fetch.c\n\t+++ b/builtin/fetch.c\n\t@@ -2114,6 +2114,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n\t \tint result = 0;\n\t \tint prune_tags_ok = 1;\n\t \n\t+\tunsetenv(GIT_SUPER_PREFIX_ENVIRONMENT);\n\t+\n\t \tpacket_trace_identity(\"fetch\");\n\t \n\t \t/* Record the command line for the reflog */\n\tdiff --git a/git.c b/git.c\n\tindex 10202a7f126..b5e63a0a57b 100644\n\t--- a/git.c\n\t+++ b/git.c\n\t@@ -531,7 +531,7 @@ static struct cmd_struct commands[] = {\n\t \t{ \"env--helper\", cmd_env__helper },\n\t \t{ \"fast-export\", cmd_fast_export, RUN_SETUP },\n\t \t{ \"fast-import\", cmd_fast_import, RUN_SETUP | NO_PARSEOPT },\n\t-\t{ \"fetch\", cmd_fetch, RUN_SETUP },\n\t+\t{ \"fetch\", cmd_fetch, RUN_SETUP | SUPPORT_SUPER_PREFIX /* not really* */ },\n\t \t{ \"fetch-pack\", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },\n\t \t{ \"fmt-merge-msg\", cmd_fmt_merge_msg, RUN_SETUP },\n\t \t{ \"for-each-ref\", cmd_for_each_ref, RUN_SETUP },\n\nDoesn't that do an end-run around the goals of this topic, but just in a\nmuch simpler way?\n\nI.e. I'm all for not propagating the --super-prefix any more than we\nneed to, but part of that is because once we start passing it, we set it\nin the environment, and then we'll *keep* passing it. So we've had some\ncommands \"accept\" it, when really they don't care, they're just being\ninvoked by other commands that needed it originally.\n\nBut maybe we can just unsetenv() the prefix before invoking any built-in\nthat doesn't have SUPPORT_SUPER_PREFIX, or not set it in the environment\nin the first place, but rather carry it forward more explicitly only\nwith the \"--super-prefix\" flag to \"git\" (adn then only to those specific\ncommands?\n\n"},{"id":"466979","messageId":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","threadId":"58773","inReplyTo":"20221109004708.97668-1-chooglen@google.com","subject":"[RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T19:34:28Z","receivedAt":"2022-11-09T19:34:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"An RFC alternative to Glen's [1], and what I *thought* he might be be\ngoing for in the earlier discussion[2].\n\nThe difference is that in Glen's there's no \"git --super-prefix\", but\nrather each set of commands still using it (\"submodule--helper\",\n\"read-tree\" etc.) geit their own command-level option.\n\nBut it still works substantially the same, in that we're juggling a\nglobal variable that we set, and read out later somewhere down the\nstack.\n\nWhereas here there's no renaming of the option, but:\n\n * For \"submodule--helper\" only the sub-commands that need it take the\n   option, it's not an option to \"submodule--helper\" itself.\n\n * There's no passing of the \"super_prefix\" as a global, instead we\n   pass it all the way along until we recurse to ourselves. For\n   \"submodule--helper\" this is quite straightforward.\n\n * Then in 8/8 we're left with just \"read-tree\" needing the remaining\n   \"--super-prefix\", and we likewise don't pass it as a global, but\n   instead add it to the \"struct unpack_trees_options\", which will\n   pass it all the way down into unpack-trees.c and entry.c, until\n   we're going to recursively invoke another \"read-tree\".\n\nThis is on top of my \"ab/submodule-helper-prep-only\" which is now in\n\"next\", and can make use of (but doesn't need) the better test\ncoverage for \"absorbgitdirs\" that I submitted in [3].\n\nA non-RFC version of this should really steal Glen's tests, in\nparticular the \"partial clone\" one from [4]. That test passes with\nthis series.\n\n1. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/\n2. https://lore.kernel.org/git/kl6l8rkqy7no.fsf@chooglen-macbookpro.roam.corp.google.com/\n3. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/\n4. https://lore.kernel.org/git/20221109004708.97668-4-chooglen@google.com/.\n\nÆvar Arnfjörð Bjarmason (8):\n  submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n  submodule--helper: \"deinit\" has never used \"--super-prefix\"\n  submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n  submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n  submodule--helper: convert \"status\" to its own \"--super-prefix\"\n  submodule--helper: convert \"{update,clone}\" to their own\n    \"--super-prefix\"\n  submodule tests: test \"git branch -t\" output and stderr\n  read-tree: add \"--super-prefix\" option, eliminate global\n\n Documentation/git.txt       |  8 +--\n builtin.h                   |  4 --\n builtin/checkout.c          |  2 +-\n builtin/read-tree.c         |  1 +\n builtin/submodule--helper.c | 95 ++++++++++++++++++++---------------\n cache.h                     |  2 -\n entry.c                     | 12 ++---\n entry.h                     |  6 ++-\n environment.c               | 13 -----\n git.c                       | 37 ++------------\n parse-options.h             |  4 ++\n submodule.c                 | 47 ++++++++----------\n submodule.h                 | 12 +++--\n t/lib-submodule-update.sh   | 98 +++++++++++++++++++++----------------\n t/t1001-read-tree-m-2way.sh |  2 +-\n unpack-trees.c              | 23 +++++----\n unpack-trees.h              |  1 +\n 17 files changed, 177 insertions(+), 190 deletions(-)\n\n-- \n2.38.0.1467.g709fbdff1a9\n\n"},{"id":"466980","messageId":"RFC-patch-1.8-ad0356b596f-20221109T192315Z-avarab@gmail.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"[RFC PATCH 1/8] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T19:34:29Z","receivedAt":"2022-11-09T19:34:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" facility was introduced in [1] has always been a\ntransitory hack, which is why we've made it an error to supply it as\nan option to \"git\" to commands that don't know about it.\n\nThat's been a good goal, as it has a global effect we haven't wanted\ncalls to get_super_prefix() from built-ins we didn't expect.\n\nBut it has meant that when we've had chains of different built-ins\nusing it all of the processes in that \"chain\" have needed to support\nit, and worse processes that don't need it have needed to ask for\n\"SUPPORT_SUPER_PREFIX\" because their parent process needs it.\n\nThat's how \"fsmonitor--daemon\" ended up with it, per [2] it's called\nfrom (among other things) \"submodule--helper absorbgitdirs\", but as we\ndeclared \"submodule--helper\" as \"SUPPORT_SUPER_PREFIX\" we needed to\ndeclare \"fsmonitor--daemon\" as accepting it too, even though it\ndoesn't care about it.\n\nThere's a parallel proposal to remove \"--super-prefix\" as an option to\n\"git\" in [3], and some of the approach might be the easiest route in\nsome cases.\n\nBut in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\ninvoke itself recursively, and we'd never have another \"in-between\"\nprocess in the chain. So we didn't need the bigger hammer of \"git\n--super-prefix\", and the \"setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)\"\nthat it entails.\n\nLet's instead accept a hidden \"--super-prefix\" option to\n\"submodule--helper absorbgitdirs\" itself.\n\nEventually (as with all other \"--super-prefix\" users) we'll want to\nclean this code up so that this all happens in-process. I.e. needing\nany variant of \"--super-prefix\" is itself a hack around our various\nglobal state, and implicit reliance on \"the_repository\". This stepping\nstone makes such an eventual change easier, as we'll need to deal with\nless global state at that point.\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n   2022-05-26)\n3. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c |  8 +++++---\n git.c                       |  2 +-\n parse-options.h             |  4 ++++\n submodule.c                 | 20 ++++++++++++--------\n submodule.h                 |  7 ++++++-\n 5 files changed, 28 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c75e9e86b06..427e793e204 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2828,7 +2828,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tconst char *super_prefix = NULL;\n \tstruct option embed_gitdir_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT_END()\n \t};\n \tconst char *const git_submodule_helper_usage[] = {\n@@ -2844,7 +2846,8 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \t\tgoto cleanup;\n \n \tfor (i = 0; i < list.nr; i++)\n-\t\tabsorb_git_dir_into_superproject(list.entries[i]->name);\n+\t\tabsorb_git_dir_into_superproject_sp(list.entries[i]->name,\n+\t\t\t\t\t\t    super_prefix);\n \n \tret = 0;\n cleanup:\n@@ -3382,8 +3385,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n \t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && strcmp(subcmd, \"absorbgitdirs\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\ndiff --git a/git.c b/git.c\nindex 10202a7f126..b1b7e1a837e 100644\n--- a/git.c\n+++ b/git.c\n@@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {\n \t{ \"format-patch\", cmd_format_patch, RUN_SETUP },\n \t{ \"fsck\", cmd_fsck, RUN_SETUP },\n \t{ \"fsck-objects\", cmd_fsck, RUN_SETUP },\n-\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },\n+\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, RUN_SETUP },\n \t{ \"gc\", cmd_gc, RUN_SETUP },\n \t{ \"get-tar-commit-id\", cmd_get_tar_commit_id, NO_PARSEOPT },\n \t{ \"grep\", cmd_grep, RUN_SETUP_GENTLY },\ndiff --git a/parse-options.h b/parse-options.h\nindex b6ef86e0d15..50d852f2991 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);\n \t{ OPTION_CALLBACK, 0, \"abbrev\", (var), N_(\"n\"),\t\\\n \t  N_(\"use <n> digits to display object names\"),\t\\\n \t  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }\n+#define OPT__SUPER_PREFIX(var) \\\n+\tOPT_STRING_F(0, \"super-prefix\", (var), N_(\"prefix\"), \\\n+\t\tN_(\"prefixed path to initial superproject\"), PARSE_OPT_HIDDEN)\n+\n #define OPT__COLOR(var, h) \\\n \tOPT_COLOR_FLAG(0, \"color\", (var), (h))\n #define OPT_COLUMN(s, l, v, h) \\\ndiff --git a/submodule.c b/submodule.c\nindex c47358097fd..d9fd0af81b6 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)\n  * Embeds a single submodules git directory into the superprojects git dir,\n  * non recursively.\n  */\n-static void relocate_single_git_dir_into_superproject(const char *path)\n+static void relocate_single_git_dir_into_superproject(const char *path,\n+\t\t\t\t\t\t      const char *super_prefix)\n {\n \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n \tstruct strbuf new_gitdir = STRBUF_INIT;\n@@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \t       real_old_git_dir[off] == real_new_git_dir[off])\n \t\toff++;\n \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from '%s' to '%s'\\n\"),\n-\t\tget_super_prefix_or_empty(), path,\n+\t\t(super_prefix ? super_prefix : \"\"), path,\n \t\treal_old_git_dir + off, real_new_git_dir + off);\n \n \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n@@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \tstrbuf_release(&new_gitdir);\n }\n \n-static void absorb_git_dir_into_superproject_recurse(const char *path)\n+static void absorb_git_dir_into_superproject_recurse(const char *path,\n+\t\t\t\t\t\t     const char *super_prefix)\n {\n \n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2321,10 +2323,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n \tcp.dir = path;\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \tstrvec_pushl(&cp.args, \"submodule--helper\",\n \t\t     \"absorbgitdirs\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n+\t\t     super_prefix : \"\", path);\n+\n \tprepare_submodule_repo_env(&cp.env);\n \tif (run_command(&cp))\n \t\tdie(_(\"could not recurse into submodule '%s'\"), path);\n@@ -2335,7 +2338,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n  * having its git directory within the working tree to the git dir nested\n  * in its superprojects git dir under modules/.\n  */\n-void absorb_git_dir_into_superproject(const char *path)\n+void absorb_git_dir_into_superproject_sp(const char *path,\n+\t\t\t\t\t const char *super_prefix)\n {\n \tint err_code;\n \tconst char *sub_git_dir;\n@@ -2377,14 +2381,14 @@ void absorb_git_dir_into_superproject(const char *path)\n \t\tchar *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);\n \n \t\tif (!starts_with(real_sub_git_dir, real_common_git_dir))\n-\t\t\trelocate_single_git_dir_into_superproject(path);\n+\t\t\trelocate_single_git_dir_into_superproject(path, super_prefix);\n \n \t\tfree(real_sub_git_dir);\n \t\tfree(real_common_git_dir);\n \t}\n \tstrbuf_release(&gitdir);\n \n-\tabsorb_git_dir_into_superproject_recurse(path);\n+\tabsorb_git_dir_into_superproject_recurse(path, super_prefix);\n }\n \n int get_superproject_working_tree(struct strbuf *buf)\ndiff --git a/submodule.h b/submodule.h\nindex b52a4ff1e73..e5ee13fb06a 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);\n  */\n void prepare_submodule_repo_env(struct strvec *env);\n \n-void absorb_git_dir_into_superproject(const char *path);\n+void absorb_git_dir_into_superproject_sp(const char *path,\n+\t\t\t\t\t const char *super_prefix);\n+static inline void absorb_git_dir_into_superproject(const char *path)\n+{\n+\tabsorb_git_dir_into_superproject_sp(path, NULL);\n+}\n \n /*\n  * Return the absolute path of the working tree of the superproject, which this\n-- \n2.38.0.1467.g709fbdff1a9\n\n"},{"id":"466981","messageId":"RFC-patch-2.8-87a780eb9bf-20221109T192315Z-avarab@gmail.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"[RFC PATCH 2/8] submodule--helper: \"deinit\" has never used \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T19:34:30Z","receivedAt":"2022-11-09T19:34:49Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"deinit_submodule()\" function has never been able to use the \"git\n--super-prefix\". It will call \"absorb_git_dir_into_superproject()\",\nbut it will only do so from the top-level project.\n\nIf \"absorbgitdirs\" recurses it will use the \"path\" passed to\n\"absorb_git_dir_into_superproject()\" in \"deinit_submodule()\" as its\nstarting \"--super-prefix\".\n\nSo, let's introduce a \"get_submodule_displaypath_sp()\" helper, and\nmake our existing \"get_submodule_displaypath()\" a wrapper for it. In a\nsubsequent commit the wrapper will be going away, as the rest of the\ncommands here will stop using the global \"get_super_prefix()\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 14 ++++++++++----\n 1 file changed, 10 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 427e793e204..c4d5e029b37 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n }\n \n /* the result should be freed by the caller. */\n-static char *get_submodule_displaypath(const char *path, const char *prefix)\n+static char *get_submodule_displaypath_sp(const char *path, const char *prefix,\n+\t\t\t\t\t  const char *super_prefix)\n {\n-\tconst char *super_prefix = get_super_prefix();\n-\n \tif (prefix && super_prefix) {\n \t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n \t\t    prefix, super_prefix);\n@@ -132,6 +131,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \n+static char *get_submodule_displaypath(const char *path, const char *prefix)\n+{\n+\tconst char *super_prefix = get_super_prefix();\n+\n+\treturn get_submodule_displaypath_sp(path, prefix, super_prefix);\n+}\n+\n static char *compute_rev_name(const char *sub_path, const char* object_id)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n@@ -1365,7 +1371,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \tif (!sub || !sub->name)\n \t\tgoto cleanup;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, NULL);\n \n \t/* remove the submodule work tree (unless the user already did it) */\n \tif (is_directory(path)) {\n-- \n2.38.0.1467.g709fbdff1a9\n\n"},{"id":"466982","messageId":"RFC-patch-3.8-4858e2ad0ed-20221109T192315Z-avarab@gmail.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"[RFC PATCH 3/8] submodule--helper: convert \"foreach\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T19:34:31Z","receivedAt":"2022-11-09T19:34:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper foreach\" to use its own \"--super-prefix\", instead\nof relying on the global \"--super-prefix\" argument to \"git\"\nitself. See that earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 15 ++++++++++-----\n 1 file changed, 10 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c4d5e029b37..989c75280af 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -285,6 +285,7 @@ struct foreach_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint quiet;\n \tint recursive;\n };\n@@ -300,7 +301,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, info->prefix,\n+\t\t\t\t\t\t   info->super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -370,10 +372,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"foreach\", \"--recursive\",\n \t\t\t     NULL);\n+\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (info->quiet)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -396,7 +398,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tstruct foreach_cb info = FOREACH_CB_INIT;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tconst char *super_prefix = NULL;\n \tstruct option module_foreach_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n \t\t\t N_(\"recurse into nested submodules\")),\n@@ -417,6 +421,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tinfo.argc = argc;\n \tinfo.argv = argv;\n \tinfo.prefix = prefix;\n+\tinfo.super_prefix = super_prefix;\n \n \tfor_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);\n \n@@ -3390,8 +3395,8 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.38.0.1467.g709fbdff1a9\n\n"},{"id":"466983","messageId":"RFC-patch-4.8-5ffe4407e46-20221109T192315Z-avarab@gmail.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"[RFC PATCH 4/8] submodule--helper: convert \"sync\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T19:34:32Z","receivedAt":"2022-11-09T19:35:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper sync\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 21 +++++++++++++--------\n 1 file changed, 13 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 989c75280af..db58fd5b2c4 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1214,12 +1214,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \n struct sync_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define SYNC_CB_INIT { 0 }\n \n static void sync_submodule(const char *path, const char *prefix,\n-\t\t\t   unsigned int flags)\n+\t\t\t   const char *super_prefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n@@ -1250,7 +1251,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tsuper_config_url = xstrdup(\"\");\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);\n \n \tif (!(flags & OPT_QUIET))\n \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n@@ -1287,10 +1288,11 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"sync\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n+\n \n \t\tif (flags & OPT_QUIET)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -1313,7 +1315,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct sync_cb *info = cb_data;\n \n-\tsync_submodule(list_item->name, info->prefix, info->flags);\n+\tsync_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_sync(int argc, const char **argv, const char *prefix)\n@@ -1323,7 +1326,9 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n \tint recursive = 0;\n+\tconst char *super_prefix = NULL;\n \tstruct option module_sync_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n \t\tOPT_BOOL(0, \"recursive\", &recursive,\n \t\t\tN_(\"recurse into nested submodules\")),\n@@ -1342,6 +1347,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \t\tgoto cleanup;\n \n \tinfo.prefix = prefix;\n+\tinfo.super_prefix = super_prefix;\n \tif (quiet)\n \t\tinfo.flags |= OPT_QUIET;\n \tif (recursive)\n@@ -2890,7 +2896,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)\n \tconfig_name = xstrfmt(\"submodule.%s.url\", path);\n \n \tconfig_set_in_gitmodules_file_gently(config_name, newurl);\n-\tsync_submodule(path, prefix, quiet ? OPT_QUIET : 0);\n+\tsync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);\n \n \tfree(config_name);\n \n@@ -3395,8 +3401,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.38.0.1467.g709fbdff1a9\n\n"},{"id":"466984","messageId":"RFC-patch-5.8-a46540b63c2-20221109T192315Z-avarab@gmail.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"[RFC PATCH 5/8] submodule--helper: convert \"status\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T19:34:33Z","receivedAt":"2022-11-09T19:35:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 16 ++++++++++------\n 1 file changed, 10 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex db58fd5b2c4..40939b0b18e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -581,6 +581,7 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \n struct status_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define STATUS_CB_INIT { 0 }\n@@ -619,7 +620,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,\n \n static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\t\t     unsigned int ce_flags, const char *prefix,\n-\t\t\t     unsigned int flags)\n+\t\t\t     const char *super_prefix, unsigned int flags)\n {\n \tchar *displaypath;\n \tstruct strvec diff_files_args = STRVEC_INIT;\n@@ -635,7 +636,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n \t\t      path);\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);\n \n \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n@@ -693,10 +694,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"status\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (flags & OPT_CACHED)\n \t\t\tstrvec_push(&cpr.args, \"--cached\");\n@@ -720,7 +721,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,\n \tstruct status_cb *info = cb_data;\n \n \tstatus_submodule(list_item->name, &list_item->oid, list_item->ce_flags,\n-\t\t\t info->prefix, info->flags);\n+\t\t\t info->prefix, info->super_prefix, info->flags);\n }\n \n static int module_status(int argc, const char **argv, const char *prefix)\n@@ -729,7 +730,9 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n+\tconst char *super_prefix = NULL;\n \tstruct option module_status_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n@@ -748,6 +751,7 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \t\tgoto cleanup;\n \n \tinfo.prefix = prefix;\n+\tinfo.super_prefix = super_prefix;\n \tif (quiet)\n \t\tinfo.flags |= OPT_QUIET;\n \n@@ -3401,7 +3405,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && get_super_prefix())\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.38.0.1467.g709fbdff1a9\n\n"},{"id":"466985","messageId":"RFC-patch-6.8-78ebf0e2abf-20221109T192315Z-avarab@gmail.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"[RFC PATCH 6/8] submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T19:34:34Z","receivedAt":"2022-11-09T19:35:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\".\n\nWe need to convert both of these away from the global \"--super-prefix\"\nat the same time, because \"update\" will call \"clone\", but \"clone\"\nitself didn't make use of the global \"--super-prefix\" for displaying\npaths. It was only on the list of sub-commands that accepted it\nbecause \"update\"'s use of it would set it in its environment.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 45 ++++++++++++++++---------------------\n git.c                       |  2 +-\n 2 files changed, 20 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 40939b0b18e..e13615eb939 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -131,13 +131,6 @@ static char *get_submodule_displaypath_sp(const char *path, const char *prefix,\n \t}\n }\n \n-static char *get_submodule_displaypath(const char *path, const char *prefix)\n-{\n-\tconst char *super_prefix = get_super_prefix();\n-\n-\treturn get_submodule_displaypath_sp(path, prefix, super_prefix);\n-}\n-\n static char *compute_rev_name(const char *sub_path, const char* object_id)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n@@ -446,11 +439,13 @@ static int starts_with_dot_dot_slash(const char *const path)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define INIT_CB_INIT { 0 }\n \n static void init_submodule(const char *path, const char *prefix,\n+\t\t\t   const char *super_prefix,\n \t\t\t   unsigned int flags)\n {\n \tconst struct submodule *sub;\n@@ -458,7 +453,7 @@ static void init_submodule(const char *path, const char *prefix,\n \tconst char *upd;\n \tchar *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -534,7 +529,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct init_cb *info = cb_data;\n \n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n@@ -802,6 +798,7 @@ struct summary_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int cached: 1;\n \tunsigned int for_status: 1;\n \tunsigned int files: 1;\n@@ -963,7 +960,8 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t\tdst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(p->sm_path, info->prefix,\n+\t\t\t\t\t\t   info->super_prefix);\n \n \tif (!missing_src && !missing_dst) {\n \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n@@ -1904,6 +1902,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)\n \n struct update_data {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tchar *displaypath;\n \tenum submodule_update_type update_default;\n \tstruct object_id suboid;\n@@ -1979,7 +1978,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tenum submodule_update_type update_type;\n \tchar *key;\n \tconst struct update_data *ud = suc->update_data;\n-\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n+\tchar *displaypath = get_submodule_displaypath_sp(ce->name, ud->prefix,\n+\t\t\t\t\t\t\t ud->super_prefix);\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n \tint need_free_url = 0;\n@@ -2459,11 +2459,11 @@ static void update_data_to_args(const struct update_data *update_data,\n {\n \tenum submodule_update_type update_type = update_data->update_default;\n \n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tif (update_data->displaypath) {\n \t\tstrvec_push(args, \"--super-prefix\");\n \t\tstrvec_pushf(args, \"%s/\", update_data->displaypath);\n \t}\n-\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n \tif (update_data->quiet)\n \t\tstrvec_push(args, \"--quiet\");\n@@ -2628,8 +2628,9 @@ static int update_submodules(struct update_data *update_data)\n \t\tif (code)\n \t\t\tgoto fail;\n \n-\t\tupdate_data->displaypath = get_submodule_displaypath(\n-\t\t\tupdate_data->sm_path, update_data->prefix);\n+\t\tupdate_data->displaypath = get_submodule_displaypath_sp(\n+\t\t\tupdate_data->sm_path, update_data->prefix,\n+\t\t\tupdate_data->super_prefix);\n \t\tcode = update_submodule(update_data);\n \t\tFREE_AND_NULL(update_data->displaypath);\n fail:\n@@ -2654,7 +2655,9 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tstruct list_objects_filter_options filter_options =\n \t\tLIST_OBJECTS_FILTER_INIT;\n \tint ret;\n+\tconst char *super_prefix = NULL;\n \tstruct option module_update_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n \t\tOPT_BOOL(0, \"init\", &opt.init,\n \t\t\t N_(\"initialize uninitialized submodules before update\")),\n@@ -2720,6 +2723,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \n \topt.filter_options = &filter_options;\n \topt.prefix = prefix;\n+\topt.super_prefix = super_prefix;\n \n \tif (opt.update_default)\n \t\topt.update_strategy.type = opt.update_default;\n@@ -2751,6 +2755,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\t\tmodule_list_active(&list);\n \n \t\tinfo.prefix = opt.prefix;\n+\t\tinfo.super_prefix = super_prefix;\n \t\tif (opt.quiet)\n \t\t\tinfo.flags |= OPT_QUIET;\n \n@@ -3377,8 +3382,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n {\n-\tconst char *cmd = argv[0];\n-\tconst char *subcmd;\n \tparse_opt_subcommand_fn *fn = NULL;\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule--helper <command>\"),\n@@ -3402,16 +3405,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\tsubcmd = argv[0];\n-\n-\tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    get_super_prefix())\n-\t\t/*\n-\t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n-\t\t * string identical to git.c's.\n-\t\t */\n-\t\tdie(_(\"%s doesn't support --super-prefix\"),\n-\t\t    xstrfmt(\"'%s %s'\", cmd, subcmd));\n \n \treturn fn(argc, argv, prefix);\n }\ndiff --git a/git.c b/git.c\nindex b1b7e1a837e..2bca22cfd9a 100644\n--- a/git.c\n+++ b/git.c\n@@ -610,7 +610,7 @@ static struct cmd_struct commands[] = {\n \t{ \"stash\", cmd_stash, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"stripspace\", cmd_stripspace },\n-\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP },\n \t{ \"switch\", cmd_switch, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"symbolic-ref\", cmd_symbolic_ref, RUN_SETUP },\n \t{ \"tag\", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },\n-- \n2.38.0.1467.g709fbdff1a9\n\n"},{"id":"466986","messageId":"RFC-patch-7.8-00a9e789be7-20221109T192315Z-avarab@gmail.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"[RFC PATCH 7/8] submodule tests: test \"git branch -t\" output and stderr","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T19:34:35Z","receivedAt":"2022-11-09T19:35:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"git branch\" command will currently make use of the\n\"--super-prefix\", as it will indirectly call submodule_move_head(),\nwhich will have access to the \"--super-prefix\".\n\nThe output could thus be affected by the \"--super-prefix\". Right now\nit isn't in this case, but let's exhaustively assert that that's the\ncase by testing the output of all of these \"git branch -t\" commands.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-submodule-update.sh | 98 ++++++++++++++++++++++-----------------\n 1 file changed, 55 insertions(+), 43 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 2d31fcfda1f..302d095ad9b 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -245,6 +245,17 @@ reset_work_tree_to_interested () {\n \tgit -C submodule_update/.git/modules/sub1 config submodule.sub2.url \"bogus\"\n }\n \n+test_branch_t_output () {\n+\tlocal branchname=\"$1\" &&\n+\tlocal start_point=\"$2\" &&\n+\tcat >expect <<-EOF &&\n+\tbranch '$branchname' set up to track '$start_point'.\n+\tEOF\n+\tgit branch -t \"$branchname\" \"$start_point\" >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp expect actual\n+}\n+\n # Test that the superproject contains the content according to commit \"$1\"\n # (the work tree must match the index for everything but submodules but the\n # index must exactly match the given commit including any submodule SHA-1s).\n@@ -323,7 +334,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -345,7 +356,7 @@ test_submodule_switch_common () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tmkdir sub1 &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -360,7 +371,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to replace_sub1_with_file &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\ttest_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&\n \t\t\t$command replace_file_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -384,7 +395,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to replace_sub1_with_directory &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\ttest_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n \t\t\t$command replace_directory_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -406,7 +417,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n \t\t\t$command remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -418,7 +429,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\t$command remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n@@ -447,7 +458,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -459,7 +470,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -474,7 +485,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -487,7 +498,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -512,7 +523,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\t$command modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n@@ -527,7 +538,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\ttest_branch_t_output invalid_sub1 origin/invalid_sub1 &&\n \t\t\t$command invalid_sub1 &&\n \t\t\ttest_superproject_content origin/invalid_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n@@ -542,7 +553,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to invalid_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\ttest_branch_t_output valid_sub1 origin/valid_sub1 &&\n \t\t\t$command valid_sub1 &&\n \t\t\ttest_superproject_content origin/valid_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -596,7 +607,7 @@ test_submodule_switch_func () {\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t>sub1 &&\n \t\t\t$command add_sub1 test_must_fail &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n@@ -635,7 +646,7 @@ test_submodule_forced_switch () {\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t>sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -675,7 +686,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -688,7 +699,7 @@ test_submodule_recursing_with_args_common () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tmkdir sub1 &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -701,7 +712,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested replace_sub1_with_file &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\ttest_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&\n \t\t\t$command replace_file_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n@@ -713,19 +724,20 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested replace_sub1_with_directory &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\ttest_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n \t\t\t$command replace_directory_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n \t\t)\n \t'\n+\n \t# Switching to a commit with nested submodules recursively checks them out\n \ttest_expect_success \"$command: nested submodules are checked out\" '\n \t\tprolog &&\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1_recursively origin/modify_sub1_recursively &&\n+\t\t\ttest_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&\n \t\t\t$command modify_sub1_recursively &&\n \t\t\ttest_superproject_content origin/modify_sub1_recursively &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1_recursively &&\n@@ -740,7 +752,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n \t\t\t$command remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\t! test -e sub1 &&\n@@ -753,7 +765,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\trm -rf .git/modules &&\n \t\t\t$command remove_sub1 &&\n@@ -769,7 +781,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\t$command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/replace_sub1_with_file &&\n \t\t\ttest -f sub1\n@@ -786,7 +798,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\t: >sub1/untrackedfile &&\n \t\t\ttest_must_fail $command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -801,7 +813,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_nested_sub &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t no_submodule origin/no_submodule &&\n+\t\t\ttest_branch_t_output no_submodule origin/no_submodule &&\n \t\t\t$command no_submodule &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n \t\t\t! test_path_is_dir sub1 &&\n@@ -817,7 +829,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\t$command modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1\n@@ -830,7 +842,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\ttest_branch_t_output invalid_sub1 origin/invalid_sub1 &&\n \t\t\ttest_must_fail $command invalid_sub1 2>err &&\n \t\t\ttest_i18ngrep sub1 err &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -844,13 +856,13 @@ test_submodule_recursing_with_args_common () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit -C sub1 checkout -b keep_branch &&\n-\t\t\tgit -C sub1 rev-parse HEAD >expect &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\tgit -C sub1 rev-parse HEAD >expect.rev-parse &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\t$command modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1 &&\n \t\t\tgit -C sub1 rev-parse keep_branch >actual &&\n-\t\t\ttest_cmp expect actual &&\n+\t\t\ttest_cmp expect.rev-parse actual &&\n \t\t\ttest_must_fail git -C sub1 symbolic-ref HEAD\n \t\t)\n \t'\n@@ -894,7 +906,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t: >sub1 &&\n \t\t\ttest_must_fail $command add_sub1 &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n@@ -908,7 +920,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t: >sub1 &&\n \t\t\tmkdir .git/info &&\n \t\t\techo sub1 >.git/info/exclude &&\n@@ -925,7 +937,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\t$command replace_sub1_with_directory &&\n \t\t\ttest_superproject_content origin/replace_sub1_with_directory &&\n \t\t\ttest_submodule_content sub1 origin/replace_sub1_with_directory\n@@ -937,7 +949,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\trm -rf .git/modules &&\n \t\t\t$command replace_sub1_with_directory &&\n@@ -954,7 +966,7 @@ test_submodule_switch_recursing_with_args () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\trm -rf .git/modules/sub1/info &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\tmkdir .git/modules/sub1/info &&\n \t\t\techo ignored >.git/modules/sub1/info/exclude &&\n \t\t\t: >sub1/ignored &&\n@@ -969,7 +981,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\tgit -c submodule.recurse=true $cmd_args modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1\n@@ -981,7 +993,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_nested_sub &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1_recursively origin/modify_sub1_recursively &&\n+\t\t\ttest_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&\n \t\t\t$command modify_sub1_recursively &&\n \t\t\ttest_superproject_content origin/modify_sub1_recursively &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1_recursively &&\n@@ -1009,7 +1021,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t>sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -1023,7 +1035,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\t$command replace_sub1_with_directory &&\n \t\t\ttest_superproject_content origin/replace_sub1_with_directory\n \t\t)\n@@ -1034,7 +1046,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\trm -rf .git/modules/sub1 &&\n \t\t\t$command replace_sub1_with_directory &&\n@@ -1049,7 +1061,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\t: >sub1/expect &&\n \t\t\t$command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/replace_sub1_with_file\n@@ -1062,7 +1074,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested invalid_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\ttest_branch_t_output valid_sub1 origin/valid_sub1 &&\n \t\t\t$command valid_sub1 &&\n \t\t\ttest_superproject_content origin/valid_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/valid_sub1\n@@ -1077,7 +1089,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\techo \"gitdir: bogus/path\" >sub1/.git &&\n \t\t\t$command modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n-- \n2.38.0.1467.g709fbdff1a9\n\n"},{"id":"466987","messageId":"RFC-patch-8.8-3ba894a6698-20221109T192315Z-avarab@gmail.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"[RFC PATCH 8/8] read-tree: add \"--super-prefix\" option, eliminate global","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T19:34:36Z","receivedAt":"2022-11-09T19:35:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" option to \"git\" was initially added in [1] for\nuse with \"ls-files\"[2], and shortly thereafter \"submodule--helper\"[3]\nand \"grep\"[4]. It wasn't until [5] that \"read-tree\" made use of it.\n\nAt the time [5] made sense, but since then we've made \"ls-files\"\nrecurse in-process in [6], \"grep\" in [7], and finally\n\"submodule--helper\" in the preceding commits.\n\nLet's also remove it from \"read-tree\", which allows us to remove the\noption to \"git\" itself.\n\nWe can do this because the only remaining user of it is the submodule\nAPI, which will now invoke \"read-tree\" with its new \"--super-prefix\"\noption. It will only do so when the \"submodule_move_head()\" function\nis called.\n\nThat \"submodule_move_head()\" function was then only invoked by\n\"read-tree\" itself, but now rather than setting an environment\nvariable to pass \"--super-prefix\" between cmd_read_tree() we:\n\n- Set a new \"super_prefix\" in \"struct unpack_trees_options\". The\n  \"super_prefixed()\" function in \"unpack-trees.c\" added in [5] will now\n  use this, rather than get_super_prefix() looking up the environment\n  variable we set earlier in the same process.\n\n- Add the same field to the \"struct checkout\", which is only needed to\n  ferry the \"super_prefix\" in the \"struct unpack_trees_options\" all the\n  way down to the \"entry.c\" callers of \"submodule_move_head()\".\n\n  Those calls which used the super prefix all originated in\n  \"cmd_read_tree()\". The only other caller is the \"unlink_entry()\"\n  caller in \"builtin/checkout.c\", which now passes a \"NULL\".\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)\n3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)\n4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)\n5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)\n6. 188dce131fa (ls-files: use repository object, 2017-06-22)\n7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git.txt       |  8 +-------\n builtin.h                   |  4 ----\n builtin/checkout.c          |  2 +-\n builtin/read-tree.c         |  1 +\n cache.h                     |  2 --\n entry.c                     | 12 ++++++------\n entry.h                     |  6 +++++-\n environment.c               | 13 -------------\n git.c                       | 33 +++------------------------------\n submodule.c                 | 27 +++++++++------------------\n submodule.h                 |  5 ++---\n t/t1001-read-tree-m-2way.sh |  2 +-\n unpack-trees.c              | 23 +++++++++++++----------\n unpack-trees.h              |  1 +\n 14 files changed, 43 insertions(+), 96 deletions(-)\n\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 1d33e083ab8..f9a7a4554cd 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -13,8 +13,7 @@ SYNOPSIS\n     [--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>]\n+    [--config-env=<name>=<envvar>] <command> [<args>]\n \n DESCRIPTION\n -----------\n@@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use\n \tdetails.  Equivalent to setting the `GIT_NAMESPACE` environment\n \tvariable.\n \n---super-prefix=<path>::\n-\tCurrently for internal use only.  Set a prefix which gives a path from\n-\tabove a repository down to its root.  One use is to give submodules\n-\tcontext about the superproject that invoked it.\n-\n --bare::\n \tTreat the repository as a bare repository.  If GIT_DIR\n \tenvironment is not set, it is set to the current working\ndiff --git a/builtin.h b/builtin.h\nindex 8901a34d6bf..8264b7e5241 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -51,10 +51,6 @@\n  *\ton bare repositories.\n  *\tThis only makes sense when `RUN_SETUP` is also set.\n  *\n- * `SUPPORT_SUPER_PREFIX`:\n- *\n- *\tThe built-in supports `--super-prefix`.\n- *\n  * `DELAY_PAGER_CONFIG`:\n  *\n  *\tIf RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2a132392fbe..dc008fb45e8 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -231,7 +231,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n \t\tpos++;\n \t}\n \tif (!overlay_mode) {\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, NULL);\n \t\treturn 0;\n \t}\n \tif (stage == 2)\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex f4cbe460b97..4b6f22e58c1 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)\n \tint prefix_set = 0;\n \tstruct lock_file lock_file = LOCK_INIT;\n \tconst struct option read_tree_options[] = {\n+\t\tOPT__SUPER_PREFIX(&opts.super_prefix),\n \t\tOPT_CALLBACK_F(0, \"index-output\", NULL, N_(\"file\"),\n \t\t  N_(\"write resulting index to <file>\"),\n \t\t  PARSE_OPT_NONEG, index_output_cb),\ndiff --git a/cache.h b/cache.h\nindex 26ed03bd6de..a4a0377b800 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)\n #define GIT_NAMESPACE_ENVIRONMENT \"GIT_NAMESPACE\"\n #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n #define GIT_PREFIX_ENVIRONMENT \"GIT_PREFIX\"\n-#define GIT_SUPER_PREFIX_ENVIRONMENT \"GIT_INTERNAL_SUPER_PREFIX\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n@@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n int get_common_dir(struct strbuf *sb, const char *gitdir);\n const char *get_git_namespace(void);\n const char *strip_namespace(const char *namespaced_ref);\n-const char *get_super_prefix(void);\n const char *get_git_work_tree(void);\n \n /*\ndiff --git a/entry.c b/entry.c\nindex 616e4f073c1..971ab268714 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca\n \t\t\treturn error(\"cannot create submodule directory %s\", path);\n \t\tsub = submodule_from_ce(ce);\n \t\tif (sub)\n-\t\t\treturn submodule_move_head(ce->name,\n+\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\tNULL, oid_to_hex(&ce->oid),\n \t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\tbreak;\n@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t * no pathname to return.\n \t\t\t */\n \t\t\tBUG(\"Can't remove entry to a path\");\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, state->super_prefix);\n \t\treturn 0;\n \t}\n \n@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t\tif (!(st.st_mode & S_IFDIR))\n \t\t\t\t\tunlink_or_warn(ce->name);\n \n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\tNULL, oid_to_hex(&ce->oid), 0);\n \t\t\t} else\n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\t\"HEAD\", oid_to_hex(&ce->oid),\n \t\t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\t}\n@@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \treturn write_entry(ce, path.buf, ca, state, 0, nr_checkouts);\n }\n \n-void unlink_entry(const struct cache_entry *ce)\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)\n {\n \tconst struct submodule *sub = submodule_from_ce(ce);\n \tif (sub) {\n \t\t/* state.force is set at the caller. */\n-\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n+\t\tsubmodule_move_head(ce->name, super_prefix, \"HEAD\", NULL,\n \t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n \t}\n \tif (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)\ndiff --git a/entry.h b/entry.h\nindex 9be4659881e..2d4fbb88c8f 100644\n--- a/entry.h\n+++ b/entry.h\n@@ -8,6 +8,7 @@ struct checkout {\n \tstruct index_state *istate;\n \tconst char *base_dir;\n \tint base_dir_len;\n+\tconst char *super_prefix;\n \tstruct delayed_checkout *delayed_checkout;\n \tstruct checkout_metadata meta;\n \tunsigned force:1,\n@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);\n /*\n  * Unlink the last component and schedule the leading directories for\n  * removal, such that empty directories get removed.\n+ *\n+ * The \"super_prefix\" is either NULL, or the \"--super-prefix\" passed\n+ * down from \"read-tree\" et al.\n  */\n-void unlink_entry(const struct cache_entry *ce);\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);\n \n void *read_blob_entry(const struct cache_entry *ce, size_t *size);\n int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);\ndiff --git a/environment.c b/environment.c\nindex 18d042b467d..1ee3686fd8a 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -102,8 +102,6 @@ char *git_work_tree_cfg;\n \n static char *git_namespace;\n \n-static char *super_prefix;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {\n \tNO_REPLACE_OBJECTS_ENVIRONMENT,\n \tGIT_REPLACE_REF_BASE_ENVIRONMENT,\n \tGIT_PREFIX_ENVIRONMENT,\n-\tGIT_SUPER_PREFIX_ENVIRONMENT,\n \tGIT_SHALLOW_FILE_ENVIRONMENT,\n \tGIT_COMMON_DIR_ENVIRONMENT,\n \tNULL\n@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)\n \treturn NULL;\n }\n \n-const char *get_super_prefix(void)\n-{\n-\tstatic int initialized;\n-\tif (!initialized) {\n-\t\tsuper_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));\n-\t\tinitialized = 1;\n-\t}\n-\treturn super_prefix;\n-}\n-\n static int git_work_tree_initialized;\n \n /*\ndiff --git a/git.c b/git.c\nindex 2bca22cfd9a..b848cd608ff 100644\n--- a/git.c\n+++ b/git.c\n@@ -14,7 +14,6 @@\n  * RUN_SETUP for reading from the configuration file.\n  */\n #define NEED_WORK_TREE\t\t(1<<3)\n-#define SUPPORT_SUPER_PREFIX\t(1<<4)\n #define DELAY_PAGER_CONFIG\t(1<<5)\n #define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n \n@@ -29,8 +28,7 @@ const char git_usage_string[] =\n \t   \"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\\n\"\n \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\\n\"\n \t   \"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\\n\"\n-\t   \"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\\n\"\n-\t   \"           <command> [<args>]\");\n+\t   \"           [--config-env=<name>=<envvar>] <command> [<args>]\");\n \n const char git_more_info_string[] =\n \tN_(\"'git help -a' and 'git help -g' list available subcommands and some\\n\"\n@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);\n \t\t\tif (envchanged)\n \t\t\t\t*envchanged = 1;\n-\t\t} else if (!strcmp(cmd, \"--super-prefix\")) {\n-\t\t\tif (*argc < 2) {\n-\t\t\t\tfprintf(stderr, _(\"no prefix given for --super-prefix\\n\" ));\n-\t\t\t\tusage(git_usage_string);\n-\t\t\t}\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n-\t\t\t(*argv)++;\n-\t\t\t(*argc)--;\n-\t\t} else if (skip_prefix(cmd, \"--super-prefix=\", &cmd)) {\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n \t\t} else if (!strcmp(cmd, \"--bare\")) {\n \t\t\tchar *cwd = xgetcwd();\n \t\t\tis_bare_repository_cfg = 1;\n@@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\ttrace_repo_setup(prefix);\n \tcommit_pager_choice();\n \n-\tif (!help && get_super_prefix()) {\n-\t\tif (!(p->option & SUPPORT_SUPER_PREFIX))\n-\t\t\tdie(_(\"%s doesn't support --super-prefix\"), p->cmd);\n-\t}\n-\n \tif (!help && p->option & NEED_WORK_TREE)\n \t\tsetup_work_tree();\n \n@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {\n \t{ \"check-ref-format\", cmd_check_ref_format, NO_PARSEOPT  },\n \t{ \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout--worker\", cmd_checkout__worker,\n-\t\tRUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },\n+\t\tRUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout-index\", cmd_checkout_index,\n \t\tRUN_SETUP | NEED_WORK_TREE},\n \t{ \"cherry\", cmd_cherry, RUN_SETUP },\n@@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n-\t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n \t{ \"rebase\", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n@@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tint status;\n \n-\tif (get_super_prefix())\n-\t\tdie(_(\"%s doesn't support --super-prefix\"), argv[0]);\n-\n \tif (use_pager == -1 && !is_builtin(argv[0]))\n \t\tuse_pager = check_pager_config(argv[0]);\n \tcommit_pager_choice();\n@@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)\n \t\t\t */\n \t\t\ttrace2_cmd_name(\"_run_git_alias_\");\n \n-\t\t\tif (get_super_prefix())\n-\t\t\t\tdie(\"%s doesn't support --super-prefix\", **argv);\n-\n \t\t\tcommit_pager_choice();\n \n \t\t\tstrvec_push(&cmd.args, \"git\");\ndiff --git a/submodule.c b/submodule.c\nindex d9fd0af81b6..5ac4e1b0568 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2048,14 +2048,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)\n \tstrbuf_release(&config_path);\n }\n \n-static const char *get_super_prefix_or_empty(void)\n-{\n-\tconst char *s = get_super_prefix();\n-\tif (!s)\n-\t\ts = \"\";\n-\treturn s;\n-}\n-\n static int submodule_has_dirty_index(const struct submodule *sub)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2074,7 +2066,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)\n \treturn finish_command(&cp);\n }\n \n-static void submodule_reset_index(const char *path)\n+static void submodule_reset_index(const char *path, const char *super_prefix)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tprepare_submodule_repo_env(&cp.env);\n@@ -2083,10 +2075,10 @@ static void submodule_reset_index(const char *path)\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \t/* TODO: determine if this might overwright untracked files */\n \tstrvec_pushl(&cp.args, \"read-tree\", \"-u\", \"--reset\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tstrvec_push(&cp.args, empty_tree_oid_hex());\n \n@@ -2099,10 +2091,9 @@ static void submodule_reset_index(const char *path)\n  * For edge cases (a submodule coming into existence or removing a submodule)\n  * pass NULL for old or new respectively.\n  */\n-int submodule_move_head(const char *path,\n-\t\t\t const char *old_head,\n-\t\t\t const char *new_head,\n-\t\t\t unsigned flags)\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n+\t\t\tunsigned flags)\n {\n \tint ret = 0;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2148,7 +2139,7 @@ int submodule_move_head(const char *path,\n \t\t\tstrbuf_release(&gitdir);\n \n \t\t\t/* make sure the index is clean as well */\n-\t\t\tsubmodule_reset_index(path);\n+\t\t\tsubmodule_reset_index(path, NULL);\n \t\t}\n \n \t\tif (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {\n@@ -2166,9 +2157,9 @@ int submodule_move_head(const char *path,\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \tstrvec_pushl(&cp.args, \"read-tree\", \"--recurse-submodules\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tif (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)\n \t\tstrvec_push(&cp.args, \"-n\");\ndiff --git a/submodule.h b/submodule.h\nindex e5ee13fb06a..36a7f7c5b32 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);\n \n #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)\n #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)\n-int submodule_move_head(const char *path,\n-\t\t\tconst char *old,\n-\t\t\tconst char *new_head,\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n \t\t\tunsigned flags);\n \n void submodule_unset_core_worktree(const struct submodule *sub);\ndiff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh\nindex 516a6112fdc..3fb1b0c162d 100755\n--- a/t/t1001-read-tree-m-2way.sh\n+++ b/t/t1001-read-tree-m-2way.sh\n@@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '\n \tcat <<-EOF >expect &&\n \t\terror: Updating '\\''fictional/a'\\'' would lose untracked files in it\n \tEOF\n-\ttest_must_fail git --super-prefix fictional/ read-tree -u -m \"$treeH\" \"$treeM\" 2>actual &&\n+\ttest_must_fail git read-tree --super-prefix fictional/ -u -m \"$treeH\" \"$treeM\" 2>actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex bae812156c4..61c02285454 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {\n \t  ? ((o)->msgs[(type)])      \\\n \t  : (unpack_plumbing_errors[(type)]) )\n \n-static const char *super_prefixed(const char *path)\n+static const char *super_prefixed(const char *path, const char *super_prefix)\n {\n \t/*\n \t * It is necessary and sufficient to have two static buffers\n@@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)\n \tstatic unsigned idx = ARRAY_SIZE(buf) - 1;\n \n \tif (super_prefix_len < 0) {\n-\t\tconst char *super_prefix = get_super_prefix();\n \t\tif (!super_prefix) {\n \t\t\tsuper_prefix_len = 0;\n \t\t} else {\n@@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,\n \t\treturn -1;\n \n \tif (!o->show_all_errors)\n-\t\treturn error(ERRORMSG(o, e), super_prefixed(path));\n+\t\treturn error(ERRORMSG(o, e), super_prefixed(path,\n+\t\t\t\t\t\t\t    o->super_prefix));\n \n \t/*\n \t * Otherwise, insert in a list for future display by\n@@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)\n \t\t\terror_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t     o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)\n \t\t\twarning_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t       o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,\n \tif (o->reset)\n \t\tflags |= SUBMODULE_MOVE_HEAD_FORCE;\n \n-\tif (submodule_move_head(ce->name, old_id, new_id, flags))\n+\tif (submodule_move_head(ce->name, NULL, old_id, new_id, flags))\n \t\treturn add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);\n \treturn 0;\n }\n@@ -415,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,\n \tint i, pc_workers, pc_threshold;\n \n \ttrace_performance_enter();\n+\tstate.super_prefix = o->super_prefix;\n \tstate.force = 1;\n \tstate.quiet = 1;\n \tstate.refresh_cache = 1;\n@@ -445,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,\n \n \t\tif (ce->ce_flags & CE_WT_REMOVE) {\n \t\t\tdisplay_progress(progress, ++cnt);\n-\t\t\tunlink_entry(ce);\n+\t\t\tunlink_entry(ce, o->super_prefix);\n \t\t}\n \t}\n \n@@ -2958,8 +2961,8 @@ int bind_merge(const struct cache_entry * const *src,\n \tif (a && old)\n \t\treturn o->quiet ? -1 :\n \t\t\terror(ERRORMSG(o, ERROR_BIND_OVERLAP),\n-\t\t\t      super_prefixed(a->name),\n-\t\t\t      super_prefixed(old->name));\n+\t\t\t      super_prefixed(a->name, o->super_prefix),\n+\t\t\t      super_prefixed(old->name, o->super_prefix));\n \tif (!a)\n \t\treturn keep_entry(old, o);\n \telse\n@@ -3020,7 +3023,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,\n \n \tif (worktree && untracked)\n \t\treturn error(_(\"worktree and untracked commit have duplicate entries: %s\"),\n-\t\t\t     super_prefixed(worktree->name));\n+\t\t\t     super_prefixed(worktree->name, o->super_prefix));\n \n \treturn merged_entry(worktree ? worktree : untracked, NULL, o);\n }\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex efb9edfbb27..9b81e284073 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -74,6 +74,7 @@ struct unpack_trees_options {\n \t\t     dry_run;\n \tenum unpack_trees_reset_type reset;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint cache_bottom;\n \tstruct pathspec *pathspec;\n \tmerge_fn_t fn;\n-- \n2.38.0.1467.g709fbdff1a9\n\n"},{"id":"466988","messageId":"Y2wYnpASncR2E0Ja@nand.local","threadId":"58773","inReplyTo":"20221109004708.97668-1-chooglen@google.com","subject":"Re: [RFC PATCH 0/4] git: remove --super-prefix","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-09T21:16:14Z","receivedAt":"2022-11-09T21:16:19Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Tue, Nov 08, 2022 at 04:47:04PM -0800, Glen Choo wrote:\n> *Note to maintainer*: See \"Interactions with other series\".\n\nThanks for the heads up ;-).\n\nIt looks like this series is broken, at least in my application of it.\nOn the first patch, running t7401, for example, I get:\n\n    BUG: builtin/submodule--helper.c:121: cannot have prefix 'sub/' and toplevel_cwd_prefix ''\n    Aborted\n\nafter running the first test (-x shows that it happens after running\n'git submodule summary', unsurprisingly).\n\nI pushed out the result of what I have to the 'gc/remove--super-prefix'\nbranch of git@github.com:ttaylorr/git.git. As you'll see, the base is\n'master' (as of 319605f8f0 (The eleventh batch, 2022-11-08)) with a\n--no-ff merge of 'ab/submodule-helper-prep-only'.\n\nLet me know if I'm holding it wrong.\n\nThanks,\nTaylor\n"},{"id":"466989","messageId":"Y2wZw3eYO4ykwtA8@nand.local","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-09T21:21:07Z","receivedAt":"2022-11-09T21:21:12Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Nov 09, 2022 at 08:34:28PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> An RFC alternative to Glen's [1], and what I *thought* he might be be\n> going for in the earlier discussion[2].\n\nI am a little puzzled with what to do with this series. For one, it\ndoesn't seem to apply cleanly on top of 'ab/remove--super-prefix':\n\n    $ git log --oneline -1\n    04e36effde (HEAD -> ab/remove--super-prefix) Merge branch 'ab/submodule-helper-prep-only' into ab/remove--super-prefix\n\n    $ git am -sc3 ~/patch\n    Applying: submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n    error: sha1 information is lacking or useless (submodule.c).\n    error: could not build fake ancestor\n    Patch failed at 0001 submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n    hint: Use 'git am --show-current-patch=diff' to see the failed patch\n    When you have resolved this problem, run \"git am --continue\".\n    If you prefer to skip this patch, run \"git am --skip\" instead.\n    To restore the original branch and stop patching, run \"git am --abort\".\n\nBut it would be nice to have a clearer path forward between this and\nGlen's series. I understand that they are both still RFCs, but I am\ncounting on you two working together to find a path forward that is\nsatisfactory to you both.\n\nIn the meantime, it would be nice to have a version of this series that\nI can apply to start playing around with.\n\nThanks,\nTaylor\n"},{"id":"466992","messageId":"221109.86h6z7pzdg.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"Y2wZw3eYO4ykwtA8@nand.local","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T21:47:40Z","receivedAt":"2022-11-09T21:55:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Nov 09 2022, Taylor Blau wrote:\n\n> On Wed, Nov 09, 2022 at 08:34:28PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>> An RFC alternative to Glen's [1], and what I *thought* he might be be\n>> going for in the earlier discussion[2].\n>\n> I am a little puzzled with what to do with this series. For one, it\n> doesn't seem to apply cleanly on top of 'ab/remove--super-prefix':\n>\n>     $ git log --oneline -1\n>     04e36effde (HEAD -> ab/remove--super-prefix) Merge branch 'ab/submodule-helper-prep-only' into ab/remove--super-prefix\n>\n>     $ git am -sc3 ~/patch\n>     Applying: submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n>     error: sha1 information is lacking or useless (submodule.c).\n>     error: could not build fake ancestor\n>     Patch failed at 0001 submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n>     hint: Use 'git am --show-current-patch=diff' to see the failed patch\n>     When you have resolved this problem, run \"git am --continue\".\n>     If you prefer to skip this patch, run \"git am --skip\" instead.\n>     To restore the original branch and stop patching, run \"git am --abort\".\n\nMy bad, the CL says:\n\n\tand can make use of (but doesn't need) the better test coverage\n\tfor \"absorbgitdirs\" that I submitted in [3]\n\t(https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/)\".\n\nBut it actually *does* need that, sorry. But with that, this works for me:\n\n\tgit checkout master\n\tgit reset --hard @{u}\n\tgit merge --no-edit ttaylorr/ab/submodule-helper-prep-only\n\t(apply https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/)\n\nThen apply this series. I've also got it at\nhttps://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local;\nbut that's a locally rebased version of ab/submodule-helper-prep-only,\nthen that [3], and finally this series.\n\nI figured I was just kicking ideas back & forth with Glen, so I didn't\ngo through my usual sanity checking :)\n\n> But it would be nice to have a clearer path forward between this and\n> Glen's series. I understand that they are both still RFCs, but I am\n> counting on you two working together to find a path forward that is\n> satisfactory to you both.\n\n*nod*, I'm sure we can manage that.\n"},{"id":"466996","messageId":"Y2wpYQ2x1Ghybqjo@nand.local","threadId":"58773","inReplyTo":"221109.86h6z7pzdg.gmgdl@evledraar.gmail.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-09T22:27:45Z","receivedAt":"2022-11-09T22:27:50Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Nov 09, 2022 at 10:47:40PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>\n> On Wed, Nov 09 2022, Taylor Blau wrote:\n>\n> > On Wed, Nov 09, 2022 at 08:34:28PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> >> An RFC alternative to Glen's [1], and what I *thought* he might be be\n> >> going for in the earlier discussion[2].\n> >\n> > I am a little puzzled with what to do with this series. For one, it\n> > doesn't seem to apply cleanly on top of 'ab/remove--super-prefix':\n> >\n> >     $ git log --oneline -1\n> >     04e36effde (HEAD -> ab/remove--super-prefix) Merge branch 'ab/submodule-helper-prep-only' into ab/remove--super-prefix\n> >\n> >     $ git am -sc3 ~/patch\n> >     Applying: submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n> >     error: sha1 information is lacking or useless (submodule.c).\n> >     error: could not build fake ancestor\n> >     Patch failed at 0001 submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n> >     hint: Use 'git am --show-current-patch=diff' to see the failed patch\n> >     When you have resolved this problem, run \"git am --continue\".\n> >     If you prefer to skip this patch, run \"git am --skip\" instead.\n> >     To restore the original branch and stop patching, run \"git am --abort\".\n>\n> My bad, the CL says:\n>\n> \tand can make use of (but doesn't need) the better test coverage\n> \tfor \"absorbgitdirs\" that I submitted in [3]\n> \t(https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/)\".\n>\n> But it actually *does* need that, sorry. But with that, this works for me:\n>\n> \tgit checkout master\n> \tgit reset --hard @{u}\n> \tgit merge --no-edit ttaylorr/ab/submodule-helper-prep-only\n> \t(apply https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/)\n>\n> Then apply this series. I've also got it at\n> https://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local;\n> but that's a locally rebased version of ab/submodule-helper-prep-only,\n> then that [3], and finally this series.\n\nYes, that works for me. I hadn't quite gotten to the later patch yet,\nbut I queued it as 'ab/remove--super-prefix' and then merged it into the\nnew branch (along with 'ab/submodule-helper-prep-only').\n\nThen everything applied as expected, so that is good.\n\n> I figured I was just kicking ideas back & forth with Glen, so I didn't\n> go through my usual sanity checking :)\n\nNo worries, I figured. It's helpful to know whether you intended to\nsupersede, build on top of, or propose an alternative direction for\nGlen's patch.\n\nFor what it's worth, I think it's totally fine to say: \"I have this\nalternative approach in a series, and here it is\", but it is also\nhelpful to add \"let's figure out a way to build these together instead\nof queuing this alternative approach as-is\".\n\n> > But it would be nice to have a clearer path forward between this and\n> > Glen's series. I understand that they are both still RFCs, but I am\n> > counting on you two working together to find a path forward that is\n> > satisfactory to you both.\n>\n> *nod*, I'm sure we can manage that.\n\nThanks very much.\n\nThanks,\nTaylor\n"},{"id":"467003","messageId":"221110.86cz9vpvqk.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"Y2wpYQ2x1Ghybqjo@nand.local","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-09T22:54:10Z","receivedAt":"2022-11-09T23:13:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Nov 09 2022, Taylor Blau wrote:\n\n> On Wed, Nov 09, 2022 at 10:47:40PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>> [...]\n>> I figured I was just kicking ideas back & forth with Glen, so I didn't\n>> go through my usual sanity checking :)\n>\n> No worries, I figured. It's helpful to know whether you intended to\n> supersede, build on top of, or propose an alternative direction for\n> Glen's patch.\n>\n> For what it's worth, I think it's totally fine to say: \"I have this\n> alternative approach in a series, and here it is\", but it is also\n> helpful to add \"let's figure out a way to build these together instead\n> of queuing this alternative approach as-is\".\n\nTo be clear: This is a proposed replacement for his, but I'm hoping\nhe'll also like it :)\n\nI don't think there's any disagreement about where we eventually want to\nend up.\n\nI.e. for stuff like \"read-tree\" we shouldn't be calling a sub-process\nrecursively, but should instead be able to handle this in-process, ditto\n\"branch\" having to invoke \"git submodule\" etc.\n\nBut getting there is a much longer journey. It doesn't just require\npassing a \"struct repository *r\" around, but also untangling some other\nglobal state & setup.\n\nThe \"--super-prefix\" feature was always something that was at least two\nsteps removed from that eventual goal. I.e. we didn't even have an easy\nway to connect two codepaths within our own built-ins, so we just set an\nenvironment variable at the start, and knew that if we spawned\nsub-processes we could carry things forward like that.\n\nGlen's RFC gets us about halfway past that state of affairs. It's not an\nenvironment variable anymore, or a single global, but a split up\nper-command global variable.\n\nWhereas what I went for was an \"all the way\" solution of not having the\nglobal at all. At least for submodule--helper I think 1-6/8 here shows\nthat that's pretty straightforward. We're usually only 1-3 function\ncalls away from the point at which we recurse to ourselves, so we can\njust pass that state along as a function parameter, or for \"foreach\",\n\"sync\" etc. via our own callback struct.\n\nThe 8/8 (and 7/8 prep test) then does that for \"read-tree\", which is\narguably a bit more gnarly (we need to ferry the state down two\ndifferent structs along the way), but even then it now becomes easy to\nfollow the full path to where we eventually recurse.\n\nIn terms of how this goes forward (and I'll wait for Glen to chime in,\nand depending on what he thinks): If we go forward with my version of\nthis I think probably doing 1-6/8 here as its own topic just for\n\"submodule--helper\" would make sense, as that's really quite\nstraightforward.\n\nWe could then do the somewhat tricker 8/8 separately.\n"},{"id":"467009","messageId":"kl6lwn833cp0.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"Y2wYnpASncR2E0Ja@nand.local","subject":"Re: [RFC PATCH 0/4] git: remove --super-prefix","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-09T23:55:39Z","receivedAt":"2022-11-09T23:55:56Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Taylor Blau <me@ttaylorr.com> writes:\n\n> On Tue, Nov 08, 2022 at 04:47:04PM -0800, Glen Choo wrote:\n>> *Note to maintainer*: See \"Interactions with other series\".\n>\n> Thanks for the heads up ;-).\n>\n> It looks like this series is broken, at least in my application of it.\n> On the first patch, running t7401, for example, I get:\n>\n>     BUG: builtin/submodule--helper.c:121: cannot have prefix 'sub/' and toplevel_cwd_prefix ''\n>     Aborted\n>\n> after running the first test (-x shows that it happens after running\n> 'git submodule summary', unsurprisingly).\n>\n> I pushed out the result of what I have to the 'gc/remove--super-prefix'\n> branch of git@github.com:ttaylorr/git.git. As you'll see, the base is\n> 'master' (as of 319605f8f0 (The eleventh batch, 2022-11-08)) with a\n> --no-ff merge of 'ab/submodule-helper-prep-only'.\n>\n> Let me know if I'm holding it wrong.\n\nNo, the problem seems to be entirely on my end. (I could've sworn I sent\nthis to CI..)\n\nGiven that we have another competing RFC, it doesn't seem like a great\nuse of time to reroll this just to unbreak \"seen\", but let me know if\nI'm missing somthing.\n\n>\n> Thanks,\n> Taylor\n"},{"id":"467011","messageId":"kl6ltu373ae5.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-10T00:45:22Z","receivedAt":"2022-11-10T00:46:23Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Thanks for the series! I haven't fully figured out where I stand on\nthis, but I can share some initial thoughts and comparisons to my RFC.\n\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> An RFC alternative to Glen's [1], and what I *thought* he might be be\n> going for in the earlier discussion[2].\n>\n> The difference is that in Glen's there's no \"git --super-prefix\", but\n> rather each set of commands still using it (\"submodule--helper\",\n> \"read-tree\" etc.) geit their own command-level option.\n\nYes, and a secondary intent was to give exact definitions and a shared\nimplementation to the command-level options instead of having each new\ncommand figure out what to do every time a similar use case pops up.\n\n>\n> But it still works substantially the same, in that we're juggling a\n> global variable that we set, and read out later somewhere down the\n> stack.\n\nYes, intentionally so. I was under the assumption that the various\nprefixes would still be used, and that adding them to commands will be a\nnecessary evil, so it was better to have them share a single\nimplementation.\n\n> Whereas here there's no renaming of the option, but:\n>\n>  * For \"submodule--helper\" only the sub-commands that need it take the\n>    option, it's not an option to \"submodule--helper\" itself.\n\nIn writing [1], I ended up convincing myself that it isn't just that all\nof \"submodule--helper\" _does_ support \"--super-prefix\", but that all of\nit _should_ support \"--super-prefix\". I'll have to take another look.\n\nAt the very least, the subcommands that are just entrypoints for\ngit-submodule.sh should support it, since they all need to print\nsubmodule paths in a semi-consistent way. I still think it would be nice\nfor these to take a top level flag.\n\nThere are other subcommands that are implementation details of other\ncommands that need to run in a submodule because of assumptions\nthe_repository, e.g. create-branch, push-check. Maybe these don't need\n\"--super-prefix\", I'll take another look.\n\nI'm not sure if there are others.\n\n(As an aside, when you remove git-submodule.sh, I wonder if we should\nsplit up submodule--helper along this dual-use line? e.g. the ones that\nare entrypoints could be moved to \"builtin/submodule.c\", and the\nimplementation details can stay in \"builtin/submodule--helper.c\". Or\nmaybe you're already one step ahead of me here :))\n\nAs you noted (somewhere) in the series, only commands called recursively\nneed \"--super-prefix\", because otherwise \"submodule--helper\" is called\nfrom the root of the superproject and the 'prefix' is already\nwell-known. I didn't make this argument because it was hard to word, so\nI'm glad you mentioned it.\n\n[1] https://lore.kernel.org/git/20221109004708.97668-2-chooglen@google.com/\n\n>  * There's no passing of the \"super_prefix\" as a global, instead we\n>    pass it all the way along until we recurse to ourselves. For\n>    \"submodule--helper\" this is quite straightforward.\n>\n>  * Then in 8/8 we're left with just \"read-tree\" needing the remaining\n>    \"--super-prefix\", and we likewise don't pass it as a global, but\n>    instead add it to the \"struct unpack_trees_options\", which will\n>    pass it all the way down into unpack-trees.c and entry.c, until\n>    we're going to recursively invoke another \"read-tree\".\n\nI worry a little about two \"necessary evils\":\n\n- (As stated earlier) we may have to add \"--super-prefix\" or similar to\n  more commands\n- We may need to read \"--super-prefix\" from many parts of the code,\n  since many parts might print paths.\n\nHaving globals makes both of these cases easier, and is quite a bit\ncloser to the original implementation of \"--super-prefix\" (so your\ncharacterization of only getting to a halfway point is accurate). This\nwas mostly to stave off opposition that it would tedious to add new\nper-command \"--super-prefix\"-es, but if nobody else cares, maybe it's ok\nto get of the globals.\n\nIf we do want to pass a context object around, we probably have to be\nmore principled about it (e.g. in 8/8 I notice that checkout_stage()\ndoesn't receive the context object and we resort to passing NULL\ninstead), but we'd want that anyway if we want Git to move towards being\nmore library-like.\n\nIt's quite likely that if any new \"--super-prefix\"-es are added, they\nwould be added by a Googler (even the original ones were ;)), so I can\nprobably go through the roadmap and figure out how costly these extra\n\"--super-prefix\"-es might be.\n"},{"id":"467019","messageId":"Y2xebII98xXBZqPq@nand.local","threadId":"58773","inReplyTo":"kl6lwn833cp0.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [RFC PATCH 0/4] git: remove --super-prefix","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-10T02:14:04Z","receivedAt":"2022-11-10T02:14:12Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Nov 09, 2022 at 03:55:39PM -0800, Glen Choo wrote:\n> > It looks like this series is broken, at least in my application of it.\n> > On the first patch, running t7401, for example, I get:\n> >\n> >     BUG: builtin/submodule--helper.c:121: cannot have prefix 'sub/' and toplevel_cwd_prefix ''\n> >     Aborted\n> >\n> > after running the first test (-x shows that it happens after running\n> > 'git submodule summary', unsurprisingly).\n> >\n> > I pushed out the result of what I have to the 'gc/remove--super-prefix'\n> > branch of git@github.com:ttaylorr/git.git. As you'll see, the base is\n> > 'master' (as of 319605f8f0 (The eleventh batch, 2022-11-08)) with a\n> > --no-ff merge of 'ab/submodule-helper-prep-only'.\n> >\n> > Let me know if I'm holding it wrong.\n>\n> No, the problem seems to be entirely on my end. (I could've sworn I sent\n> this to CI..)\n>\n> Given that we have another competing RFC, it doesn't seem like a great\n> use of time to reroll this just to unbreak \"seen\", but let me know if\n> I'm missing somthing.\n\nNo problem. Let's drop this one for now, unless you have strong\nobjections.\n\nThanks,\nTaylor\n"},{"id":"467040","messageId":"221110.86zgcznjah.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6ltu373ae5.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-10T10:51:07Z","receivedAt":"2022-11-10T11:25:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Nov 09 2022, Glen Choo wrote:\n\n> Thanks for the series! I haven't fully figured out where I stand on\n> this, but I can share some initial thoughts and comparisons to my RFC.\n>\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> An RFC alternative to Glen's [1], and what I *thought* he might be be\n>> going for in the earlier discussion[2].\n>>\n>> The difference is that in Glen's there's no \"git --super-prefix\", but\n>> rather each set of commands still using it (\"submodule--helper\",\n>> \"read-tree\" etc.) geit their own command-level option.\n>\n> Yes, and a secondary intent was to give exact definitions and a shared\n> implementation to the command-level options instead of having each new\n> command figure out what to do every time a similar use case pops up.\n\n... (more below)...\n\n>>\n>> But it still works substantially the same, in that we're juggling a\n>> global variable that we set, and read out later somewhere down the\n>> stack.\n>\n> Yes, intentionally so. I was under the assumption that the various\n> prefixes would still be used, and that adding them to commands will be a\n> necessary evil, so it was better to have them share a single\n> implementation.\n\nI'm not sure I understand what you mean here exactly, but as an example\nthat might clarify things: In my \"foreach\" patch:\nhttps://lore.kernel.org/git/RFC-patch-3.8-4858e2ad0ed-20221109T192315Z-avarab@gmail.com/\n\nI'm making use of \"OPT__SUPER_PREFIX()\" to share the things that need to\nbe shared, and after that we ferry the \"super_prefix\" from\nmodule_foreach() down through \"struct foreach_cb\" to\n\"runcommand_in_submodule_cb()\", and that's all the places we need it.\n\nWith how OPT_SUBCOMMAND() works we'd need a file-level static variable\n(or similar) if we took the \"--super-prefix\" in the\ncmd_submodule__helper() instead, which we could do, and it would have\npretty much the same effect.\n\nBut I don't really see the advantage in any one individiual case. Isn't\nit just trading that one repeated \"OPT__SUPER_PREFIX()\" line for more\nclarity about who needs what?\n\n>> Whereas here there's no renaming of the option, but:\n>>\n>>  * For \"submodule--helper\" only the sub-commands that need it take the\n>>    option, it's not an option to \"submodule--helper\" itself.\n>\n> In writing [1], I ended up convincing myself that it isn't just that all\n> of \"submodule--helper\" _does_ support \"--super-prefix\", but that all of\n> it _should_ support \"--super-prefix\". I'll have to take another look.\n\nI agree with your:\n\n\t\"[...]\"This is the only way the prefix is used in \"git\n\tsubmodule--helper\", and all of its subcommands already conform\n\tto this behavior (even the ones that weren't marked\n\tSUPPORT_SUPER_PREFIX) because they all use\n\tget_submodule_displaypath() when printing paths to\n\tsubmodules.[...]\"\n\nIn that it's clear that e.g. if \"add\" were added to the list of\nsub-commands that used \"git --super-prefix\" *and* we started calling\nthat recursively with the same method that \"get_submodule_displaypath()\"\nmakes it easier to construct such paths (which is also the case after my\nseries, just with the *_sp() variant).\n\nBut I don't see how that extends to an argument that we should be\nblurring the lines about what does and doesn't need it *now*, which as I\npointed out in my \"now we'll accept it\" is what that commit is doing:\nhttps://lore.kernel.org/git/221109.867d04rfnt.gmgdl@evledraar.gmail.com/\n\n> At the very least, the subcommands that are just entrypoints for\n> git-submodule.sh should support it, since they all need to print\n> submodule paths in a semi-consistent way. I still think it would be nice\n> for these to take a top level flag.\n\nBut they don't need it, and some of them will never need it. E.g. I\ndon't see how it would make sense for \"set-url\" and \"get-url\" ever to\nget a \"--recursive\" option, those are inherently non-recursive (if\nthey're going to make any sense, you *could* set all your submodule URLs\nto the same thing, but what's the use in that?).\n\nBut also re my:\nhttps://lore.kernel.org/git/221110.86cz9vpvqk.gmgdl@evledraar.gmail.com/;\nI think that *if* we add new recursion we're just as likely to not use\nany \"--submodule-prefix\"-like functionality, but to instead just walk\nthe tree, constructing repo objects along the way. As my 8/8 summarizes\nthat's what we're doing in \"grep\", \"ls-files\" etc.\n\nStill, if it was easier etc. to just provide this for the entire\ncommand, even if all subcommands wouldn't need it I wouldn't mind\nit. But as noted above it's trivial to add it on demand with\n\"OPT__SUPER_PREFIX()\", you don't need to reason about globals etc. So I\njust don't see the benefit...\n\n> There are other subcommands that are implementation details of other\n> commands that need to run in a submodule because of assumptions\n> the_repository, e.g. create-branch, push-check. Maybe these don't need\n> \"--super-prefix\", I'll take another look.\n\nI you don't need to take much of a look, because on \"master\" they don't\nhave a \"SUPPORT_SUPER_PREFIX\" next to their listing at the bottom of\nsubmodule--helper.c, ditto for the \"if\" chain I have in\n\"next\". I.e. none of the ones listed in the \"struct option options\" as\nOPT_SUBCOMMAND() use \"git --super-prefix\", except if they're listed in\nthe \"if\" chain below.\n\n> I'm not sure if there are others.\n\nWe can be sure it's just clone/update/foreach/status/sync/absorbgitdirs,\nbecause if the others are invoked with the --super-prefix they'll die().\n\nWhich aside from the specific approaches in either of our topics is, I\nthink, a really nice thing to have. I.e. it makes reasoning about the\ncode easier if we can confidently say \"this is a feature with global\neffect, but it only has an impact on this subset of stuff\".\n\nWhich is an aspect of your proposed RFC that I don't like in\nisolation. I.e. if/when we're going to do the eventual refactoring that\nI've done in my RFC we'd need to reason that we need to change \"foreach\"\nand not \"create-branch\" or whatever, which the current whitelisting\nreally helps us with.\n\n> (As an aside, when you remove git-submodule.sh, I wonder if we should\n> split up submodule--helper along this dual-use line? e.g. the ones that\n> are entrypoints could be moved to \"builtin/submodule.c\", and the\n> implementation details can stay in \"builtin/submodule--helper.c\". Or\n> maybe you're already one step ahead of me here :))\n\nYes, I'm ahead of you there.\n\nThe ones that are purely internal, such as \"push-check\" etc. are still\ngoing to be invoked as \"submodule--helper push-check\".\n\nBefore my RFC topic here I was planning on having both a \"foreach\" and\n\"submodule--helper-foreach\", as seen in:\nhttps://lore.kernel.org/git/221104.86wn8bzeus.gmgdl@evledraar.gmail.com/\n\nThat was because I:\n\n 1. Didn't want to make \"foreach\"'s \"--super-prefix\" interface \"public\",\n    which it isn't now, as it's a purely internal thing we're trying to\n    eventually get rid of.\n 2. Didn't want to list all of \"submodule--helper\" as accepting it, as\n    some of it doesn't need it (e.g. \"push-check\").\n\nSo having a \"git submodule foreach\" *not* accept it and it then\nrecursing to an internal \"git submodule--helper-foreach\" which did\naccept it seemed like the least sucky thing to do.\n\nBut if I rebase those patches on my RFC topic here we can invoke both as\njust \"git submodule foreach\".\n\nPedantically, that's also exposing a \"private\" interface to the\npublic. But:\n\n * I'm listing it as OPT_HIDDEN, so we're not showing it outside fo\n   --help-all.\n\n * More importantly, you need to provide that specific flag, it's not\n   accepting it \"at a distance\" via an env variable, which was the main\n   thing I was being paranod about.\n\n   Or rather. Even if *I knew* that \"read-tree\" or whatever wasn't\n   invoking a hook, which then invoked \"submodule foreach\" down the\n   line, and that \"foreach\" was slurping up the env var, I wanted to\n   leave it in a state where the next maintainer of this code didn't\n   have to worry about that.\n\n> As you noted (somewhere) in the series, only commands called recursively\n> need \"--super-prefix\", because otherwise \"submodule--helper\" is called\n> from the root of the superproject and the 'prefix' is already\n> well-known. I didn't make this argument because it was hard to word, so\n> I'm glad you mentioned it.\n\nRight, and just to add to that: This is the super_prefix==NULL case in\nget_submodule_displaypath() on \"master\" (i.e. aside from either of our\ntopics here).\n\n> [1] https://lore.kernel.org/git/20221109004708.97668-2-chooglen@google.com/\n>\n>>  * There's no passing of the \"super_prefix\" as a global, instead we\n>>    pass it all the way along until we recurse to ourselves. For\n>>    \"submodule--helper\" this is quite straightforward.\n>>\n>>  * Then in 8/8 we're left with just \"read-tree\" needing the remaining\n>>    \"--super-prefix\", and we likewise don't pass it as a global, but\n>>    instead add it to the \"struct unpack_trees_options\", which will\n>>    pass it all the way down into unpack-trees.c and entry.c, until\n>>    we're going to recursively invoke another \"read-tree\".\n>\n> I worry a little about two \"necessary evils\":\n>\n> - (As stated earlier) we may have to add \"--super-prefix\" or similar to\n>   more commands\n> - We may need to read \"--super-prefix\" from many parts of the code,\n>   since many parts might print paths.\n>\n> Having globals makes both of these cases easier, and is quite a bit\n> closer to the original implementation of \"--super-prefix\" (so your\n> characterization of only getting to a halfway point is accurate). This\n> was mostly to stave off opposition that it would tedious to add new\n> per-command \"--super-prefix\"-es, but if nobody else cares, maybe it's ok\n> to get of the globals.\n>\n> If we do want to pass a context object around, we probably have to be\n> more principled about it (e.g. in 8/8 I notice that checkout_stage()\n> doesn't receive the context object and we resort to passing NULL\n> instead), but we'd want that anyway if we want Git to move towards being\n> more library-like.\n\nQuick aside: Yes, that unlink_entry(ce) in builtin/checkout.c is now\nunlink_entry(ce, NULL).\n\nThe API had only 3 users, and two potentially cared about the\nsuper_prefix. So I just amended the existing function, we could also add\na unlink_entry_sp() or whatever.\n\n> It's quite likely that if any new \"--super-prefix\"-es are added, they\n> would be added by a Googler (even the original ones were ;)), so I can\n> probably go through the roadmap and figure out how costly these extra\n> \"--super-prefix\"-es might be.\n\nI don't really see that happening, but let me just grant that point for\nthe sake of argument: \n\nNext month we're going to add a new \"--super-prefix\"-like use, and we're\ngoing to want some combinatino of a global, setenv()/getenv() etc. back,\nbecause it's the \"sparse\" code or whatever, and it'll be daunting to\npass the state through 30 levels of callstack, we'll want to bypass it.\n\nI still don't see how it follows that we'd want to keep any of structure\nfor this, which I think my series shows none of the current code needs.\n\nWe can easily add such functionality back, adding a global variable\nisn't hard, and I think if anything such a future future would benefit\nfrom having to explain why it needs global state to do this sort of\nthing, when these other commands and sub-commands don't.\n"},{"id":"467101","messageId":"kl6lfseq2wuy.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"Y2xebII98xXBZqPq@nand.local","subject":"Re: [RFC PATCH 0/4] git: remove --super-prefix","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-10T23:49:57Z","receivedAt":"2022-11-10T23:50:02Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Taylor Blau <me@ttaylorr.com> writes:\n\n> On Wed, Nov 09, 2022 at 03:55:39PM -0800, Glen Choo wrote:\n>> > It looks like this series is broken, at least in my application of it.\n>> > On the first patch, running t7401, for example, I get:\n>> >\n>> >     BUG: builtin/submodule--helper.c:121: cannot have prefix 'sub/' and toplevel_cwd_prefix ''\n>> >     Aborted\n>> >\n>> > after running the first test (-x shows that it happens after running\n>> > 'git submodule summary', unsurprisingly).\n>> >\n>> > I pushed out the result of what I have to the 'gc/remove--super-prefix'\n>> > branch of git@github.com:ttaylorr/git.git. As you'll see, the base is\n>> > 'master' (as of 319605f8f0 (The eleventh batch, 2022-11-08)) with a\n>> > --no-ff merge of 'ab/submodule-helper-prep-only'.\n>> >\n>> > Let me know if I'm holding it wrong.\n>>\n>> No, the problem seems to be entirely on my end. (I could've sworn I sent\n>> this to CI..)\n>>\n>> Given that we have another competing RFC, it doesn't seem like a great\n>> use of time to reroll this just to unbreak \"seen\", but let me know if\n>> I'm missing somthing.\n>\n> No problem. Let's drop this one for now, unless you have strong\n> objections.\n\nYes let's drop my RFC for now, thanks.\n\n>\n> Thanks,\n> Taylor\n"},{"id":"467102","messageId":"kl6ledua2vtw.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"RFC-patch-1.8-ad0356b596f-20221109T192315Z-avarab@gmail.com","subject":"Re: [RFC PATCH 1/8] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-11T00:12:11Z","receivedAt":"2022-11-11T00:12:18Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> But in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\n> invoke itself recursively, and we'd never have another \"in-between\"\n> process in the chain. So we didn't need the bigger hammer of \"git\n> --super-prefix\", and the \"setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)\"\n> that it entails.\n\nI also thought this was the case, but in the proces of reviewing this, I\nI'm not sure any more. More below..\n\n> Eventually (as with all other \"--super-prefix\" users) we'll want to\n> clean this code up so that this all happens in-process. I.e. needing\n> any variant of \"--super-prefix\" is itself a hack around our various\n> global state, and implicit reliance on \"the_repository\". This stepping\n> stone makes such an eventual change easier, as we'll need to deal with\n> less global state at that point.\n\nYes, I 100% agree. I am not optimistic that we can clean all of these up\nany time soon, but I can buy the argument that we will have to remove\nthe extra global state at some point, so we should just bite the bullet\nnow.\n\n> diff --git a/parse-options.h b/parse-options.h\n> index b6ef86e0d15..50d852f2991 100644\n> --- a/parse-options.h\n> +++ b/parse-options.h\n> @@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);\n>  \t{ OPTION_CALLBACK, 0, \"abbrev\", (var), N_(\"n\"),\t\\\n>  \t  N_(\"use <n> digits to display object names\"),\t\\\n>  \t  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }\n> +#define OPT__SUPER_PREFIX(var) \\\n> +\tOPT_STRING_F(0, \"super-prefix\", (var), N_(\"prefix\"), \\\n> +\t\tN_(\"prefixed path to initial superproject\"), PARSE_OPT_HIDDEN)\n> +\n>  #define OPT__COLOR(var, h) \\\n>  \tOPT_COLOR_FLAG(0, \"color\", (var), (h))\n>  #define OPT_COLUMN(s, l, v, h) \\\n> diff --git a/submodule.c b/submodule.c\n> index c47358097fd..d9fd0af81b6 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)\n>   * Embeds a single submodules git directory into the superprojects git dir,\n>   * non recursively.\n>   */\n> -static void relocate_single_git_dir_into_superproject(const char *path)\n> +static void relocate_single_git_dir_into_superproject(const char *path,\n> +\t\t\t\t\t\t      const char *super_prefix)\n>  {\n>  \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n>  \tstruct strbuf new_gitdir = STRBUF_INIT;\n> @@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n>  \t       real_old_git_dir[off] == real_new_git_dir[off])\n>  \t\toff++;\n>  \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from '%s' to '%s'\\n\"),\n> -\t\tget_super_prefix_or_empty(), path,\n> +\t\t(super_prefix ? super_prefix : \"\"), path,\n>  \t\treal_old_git_dir + off, real_new_git_dir + off);\n>  \n>  \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n\nWhen this gets cleaned up post-RFC, I think we should have\nOPT__SUPER_PREFIX handle this \"default to empty\" behavior for us.\n\n> diff --git a/submodule.h b/submodule.h\n> index b52a4ff1e73..e5ee13fb06a 100644\n> --- a/submodule.h\n> +++ b/submodule.h\n> @@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);\n>   */\n>  void prepare_submodule_repo_env(struct strvec *env);\n>  \n> -void absorb_git_dir_into_superproject(const char *path);\n> +void absorb_git_dir_into_superproject_sp(const char *path,\n> +\t\t\t\t\t const char *super_prefix);\n> +static inline void absorb_git_dir_into_superproject(const char *path)\n> +{\n> +\tabsorb_git_dir_into_superproject_sp(path, NULL);\n> +}\n\nSince absorb_git_dir_into_superproject() is called by\nsubmodule_move_head() (the function that handles submodule changes in\nunpack_trees()), it can be called from \"git read-tree\".\n\nSo we really do end up mixing the different values of --super-prefix;\ninvoking \"absorbgitdirs\" directly would print the relative path from\ncwd, but invoking it indirectly via \"read-tree\" would print the path\nfrom the root of the superproject tree. I guess that result makes sense,\nsince \"read-tree\" and friends print paths from the root of the tree, but\nit feels a bit odd.\n\nI'll propose a test for this after I finish reading through the series.\nTo avoid masking this behavior, I think we'll have to avoid going down\nthe *_sp() path and just plumb super_prefix everywhere.\n\n>  \n>  /*\n>   * Return the absolute path of the working tree of the superproject, which this\n> -- \n> 2.38.0.1467.g709fbdff1a9\n"},{"id":"467103","messageId":"kl6l8rki2uii.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"RFC-patch-8.8-3ba894a6698-20221109T192315Z-avarab@gmail.com","subject":"Re: [RFC PATCH 8/8] read-tree: add \"--super-prefix\" option, eliminate global","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-11T00:40:37Z","receivedAt":"2022-11-11T00:40:45Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> That \"submodule_move_head()\" function was then only invoked by\n> \"read-tree\" itself, but now rather than setting an environment\n> variable to pass \"--super-prefix\" between cmd_read_tree() we:\n>\n> - Set a new \"super_prefix\" in \"struct unpack_trees_options\". The\n>   \"super_prefixed()\" function in \"unpack-trees.c\" added in [5] will now\n>   use this, rather than get_super_prefix() looking up the environment\n>   variable we set earlier in the same process.\n>\n> - Add the same field to the \"struct checkout\", which is only needed to\n>   ferry the \"super_prefix\" in the \"struct unpack_trees_options\" all the\n>   way down to the \"entry.c\" callers of \"submodule_move_head()\".\n>\n>   Those calls which used the super prefix all originated in\n>   \"cmd_read_tree()\". The only other caller is the \"unlink_entry()\"\n>   caller in \"builtin/checkout.c\", which now passes a \"NULL\".\n>\n> 1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n> 2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)\n> 3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)\n> 4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)\n> 5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)\n> 6. 188dce131fa (ls-files: use repository object, 2017-06-22)\n> 7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\n[...]\n\n> diff --git a/submodule.h b/submodule.h\n> index e5ee13fb06a..36a7f7c5b32 100644\n> --- a/submodule.h\n> +++ b/submodule.h\n> @@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);\n>  \n>  #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)\n>  #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)\n> -int submodule_move_head(const char *path,\n> -\t\t\tconst char *old,\n> -\t\t\tconst char *new_head,\n> +int submodule_move_head(const char *path, const char *super_prefix,\n> +\t\t\tconst char *old_head, const char *new_head,\n>  \t\t\tunsigned flags);\n>  \n>  void submodule_unset_core_worktree(const struct submodule *sub);\n\nThis signature change turned out to be far less disruptive than I\nexpected, nice. It helps that we already had a natural home for these,\ni.e. \"struct checkout\" and \"struct unpack_trees_options\".\n"},{"id":"467104","messageId":"kl6l5yfm2taf.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"221110.86zgcznjah.gmgdl@evledraar.gmail.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-11T01:07:04Z","receivedAt":"2022-11-11T01:10:07Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Rereading this series and thinking about this some more, let's go with\nyour approach, primarily because it avoids global state.\n\nFrom this series, it seems that it's not that hard to make this change\nand support whatever use cases we currently have.\n\nThis does make it more tedious to add more \"--super-prefix\" in the\nfuture, but that's a good push for us to do more things in-process\nand/or be more principled about passing context objects through the call\nstack instead of relying on globals.\n\nLet me know what I can add to this effort besides reviewing :)\n\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Wed, Nov 09 2022, Glen Choo wrote:\n>\n>> Thanks for the series! I haven't fully figured out where I stand on\n>> this, but I can share some initial thoughts and comparisons to my RFC.\n>>\n>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>\n>>> An RFC alternative to Glen's [1], and what I *thought* he might be be\n>>> going for in the earlier discussion[2].\n>>>\n>>> The difference is that in Glen's there's no \"git --super-prefix\", but\n>>> rather each set of commands still using it (\"submodule--helper\",\n>>> \"read-tree\" etc.) geit their own command-level option.\n>>\n>> Yes, and a secondary intent was to give exact definitions and a shared\n>> implementation to the command-level options instead of having each new\n>> command figure out what to do every time a similar use case pops up.\n>\n> ... (more below)...\n>\n>>>\n>>> But it still works substantially the same, in that we're juggling a\n>>> global variable that we set, and read out later somewhere down the\n>>> stack.\n>>\n>> Yes, intentionally so. I was under the assumption that the various\n>> prefixes would still be used, and that adding them to commands will be a\n>> necessary evil, so it was better to have them share a single\n>> implementation.\n>\n> I'm not sure I understand what you mean here exactly, but as an example\n> that might clarify things: In my \"foreach\" patch:\n> https://lore.kernel.org/git/RFC-patch-3.8-4858e2ad0ed-20221109T192315Z-avarab@gmail.com/\n>\n> I'm making use of \"OPT__SUPER_PREFIX()\" to share the things that need to\n> be shared, and after that we ferry the \"super_prefix\" from\n> module_foreach() down through \"struct foreach_cb\" to\n> \"runcommand_in_submodule_cb()\", and that's all the places we need it.\n>\n> With how OPT_SUBCOMMAND() works we'd need a file-level static variable\n> (or similar) if we took the \"--super-prefix\" in the\n> cmd_submodule__helper() instead, which we could do, and it would have\n> pretty much the same effect.\n>\n> But I don't really see the advantage in any one individiual case. Isn't\n> it just trading that one repeated \"OPT__SUPER_PREFIX()\" line for more\n> clarity about who needs what?\n\nThe other concern I had was that we'd have to repeat the \"super_prefix\"\nfield in all of the command options structs, and then pass them down\nthrough all of the call chain that would need it. Or even worse, create\nnew structs for call chains that didn't have them.\n\nBut, since want to move away from global state altogether, the \"effort\nsaving\" of having a global will end up causing more headache for us in\nthe future, so we should just bite the bullet now, especially since this\nseries shows thats it's not _that_ hard.\n\n> We can be sure it's just clone/update/foreach/status/sync/absorbgitdirs,\n> because if the others are invoked with the --super-prefix they'll die().\n>\n> Which aside from the specific approaches in either of our topics is, I\n> think, a really nice thing to have. I.e. it makes reasoning about the\n> code easier if we can confidently say \"this is a feature with global\n> effect, but it only has an impact on this subset of stuff\".\n>\n> Which is an aspect of your proposed RFC that I don't like in\n> isolation. I.e. if/when we're going to do the eventual refactoring that\n> I've done in my RFC we'd need to reason that we need to change \"foreach\"\n> and not \"create-branch\" or whatever, which the current whitelisting\n> really helps us with.\n\nFair. I also had the same worries, which is probably a sign of smelly\ncode.\n\n>\n>> (As an aside, when you remove git-submodule.sh, I wonder if we should\n>> split up submodule--helper along this dual-use line? e.g. the ones that\n>> are entrypoints could be moved to \"builtin/submodule.c\", and the\n>> implementation details can stay in \"builtin/submodule--helper.c\". Or\n>> maybe you're already one step ahead of me here :))\n>\n> Yes, I'm ahead of you there.\n>\n> The ones that are purely internal, such as \"push-check\" etc. are still\n> going to be invoked as \"submodule--helper push-check\".\n>\n> Before my RFC topic here I was planning on having both a \"foreach\" and\n> \"submodule--helper-foreach\", as seen in:\n> https://lore.kernel.org/git/221104.86wn8bzeus.gmgdl@evledraar.gmail.com/\n>\n> That was because I:\n>\n>  1. Didn't want to make \"foreach\"'s \"--super-prefix\" interface \"public\",\n>     which it isn't now, as it's a purely internal thing we're trying to\n>     eventually get rid of.\n>  2. Didn't want to list all of \"submodule--helper\" as accepting it, as\n>     some of it doesn't need it (e.g. \"push-check\").\n>\n> So having a \"git submodule foreach\" *not* accept it and it then\n> recursing to an internal \"git submodule--helper-foreach\" which did\n> accept it seemed like the least sucky thing to do.\n>\n> But if I rebase those patches on my RFC topic here we can invoke both as\n> just \"git submodule foreach\".\n>\n> Pedantically, that's also exposing a \"private\" interface to the\n> public. But:\n>\n>  * I'm listing it as OPT_HIDDEN, so we're not showing it outside fo\n>    --help-all.\n\nIMO I think OPT_HIDDEN is good enough, so yes, let's avoid having\n\"submodule foo\" and \"submodule--helper foo\".\n\n>  * More importantly, you need to provide that specific flag, it's not\n>    accepting it \"at a distance\" via an env variable, which was the main\n>    thing I was being paranod about.\n>\n>    Or rather. Even if *I knew* that \"read-tree\" or whatever wasn't\n>    invoking a hook, which then invoked \"submodule foreach\" down the\n>    line, and that \"foreach\" was slurping up the env var, I wanted to\n>    leave it in a state where the next maintainer of this code didn't\n>    have to worry about that.\n\nAgree.\n\n>> [1] https://lore.kernel.org/git/20221109004708.97668-2-chooglen@google.com/\n>>\n>>>  * There's no passing of the \"super_prefix\" as a global, instead we\n>>>    pass it all the way along until we recurse to ourselves. For\n>>>    \"submodule--helper\" this is quite straightforward.\n>>>\n>>>  * Then in 8/8 we're left with just \"read-tree\" needing the remaining\n>>>    \"--super-prefix\", and we likewise don't pass it as a global, but\n>>>    instead add it to the \"struct unpack_trees_options\", which will\n>>>    pass it all the way down into unpack-trees.c and entry.c, until\n>>>    we're going to recursively invoke another \"read-tree\".\n>>\n>> I worry a little about two \"necessary evils\":\n>>\n>> - (As stated earlier) we may have to add \"--super-prefix\" or similar to\n>>   more commands\n>> - We may need to read \"--super-prefix\" from many parts of the code,\n>>   since many parts might print paths.\n>>\n>> Having globals makes both of these cases easier, and is quite a bit\n>> closer to the original implementation of \"--super-prefix\" (so your\n>> characterization of only getting to a halfway point is accurate). This\n>> was mostly to stave off opposition that it would tedious to add new\n>> per-command \"--super-prefix\"-es, but if nobody else cares, maybe it's ok\n>> to get of the globals.\n>>\n>> If we do want to pass a context object around, we probably have to be\n>> more principled about it (e.g. in 8/8 I notice that checkout_stage()\n>> doesn't receive the context object and we resort to passing NULL\n>> instead), but we'd want that anyway if we want Git to move towards being\n>> more library-like.\n>\n> Quick aside: Yes, that unlink_entry(ce) in builtin/checkout.c is now\n> unlink_entry(ce, NULL).\n>\n> The API had only 3 users, and two potentially cared about the\n> super_prefix. So I just amended the existing function, we could also add\n> a unlink_entry_sp() or whatever.\n\nI definitely prefer modifying the existing function in place since it\navoids accidental omissions of the super prefix.\n\nMy original diagnosis is wrong though, that checkout_stage() caller\nis passed \"struct checkout\", so there is a super_prefix available.\n\n>\n>> It's quite likely that if any new \"--super-prefix\"-es are added, they\n>> would be added by a Googler (even the original ones were ;)), so I can\n>> probably go through the roadmap and figure out how costly these extra\n>> \"--super-prefix\"-es might be.\n>\n> I don't really see that happening, but let me just grant that point for\n> the sake of argument: \n>\n> Next month we're going to add a new \"--super-prefix\"-like use, and we're\n> going to want some combinatino of a global, setenv()/getenv() etc. back,\n> because it's the \"sparse\" code or whatever, and it'll be daunting to\n> pass the state through 30 levels of callstack, we'll want to bypass it.\n>\n> I still don't see how it follows that we'd want to keep any of structure\n> for this, which I think my series shows none of the current code needs.\n>\n> We can easily add such functionality back, adding a global variable\n> isn't hard, and I think if anything such a future future would benefit\n> from having to explain why it needs global state to do this sort of\n> thing, when these other commands and sub-commands don't.\n\nYeah, I think the stakes of removing the global variable weren't as\nhigh as I originally thought.\n"},{"id":"467152","messageId":"kl6lv8nl1h19.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"kl6l5yfm2taf.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-11T18:29:22Z","receivedAt":"2022-11-11T18:30:09Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Glen Choo <chooglen@google.com> writes:\n\n> Rereading this series and thinking about this some more, let's go with\n> your approach, primarily because it avoids global state.\n>\n> From this series, it seems that it's not that hard to make this change\n> and support whatever use cases we currently have.\n>\n> This does make it more tedious to add more \"--super-prefix\" in the\n> future, but that's a good push for us to do more things in-process\n> and/or be more principled about passing context objects through the call\n> stack instead of relying on globals.\n>\n> Let me know what I can add to this effort besides reviewing :)\n\nSpecifically, if you have other things on your plate, I'd be happy to\npick up where where this RFC has left off.\n"},{"id":"467161","messageId":"221111.86fsepmbhe.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6lv8nl1h19.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-11T21:17:44Z","receivedAt":"2022-11-11T21:24:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Nov 11 2022, Glen Choo wrote:\n\n> Glen Choo <chooglen@google.com> writes:\n>\n>> Rereading this series and thinking about this some more, let's go with\n>> your approach, primarily because it avoids global state.\n>>\n>> From this series, it seems that it's not that hard to make this change\n>> and support whatever use cases we currently have.\n>>\n>> This does make it more tedious to add more \"--super-prefix\" in the\n>> future, but that's a good push for us to do more things in-process\n>> and/or be more principled about passing context objects through the call\n>> stack instead of relying on globals.\n>>\n>> Let me know what I can add to this effort besides reviewing :)\n>\n> Specifically, if you have other things on your plate, I'd be happy to\n> pick up where where this RFC has left off.\n\nI was going to get around to re-rolling this in the next few days, but\nI'd also be happy to have you beat me to it.\n\nMy plan was basically:\n\n * Steal the test from your series, put them at the beginning, and for\n   those that fail make them \"test_expect_failure\", then\n   \"test_expect_success\" later when they pass.\n\n * Pretty much my RFC as-is. If you're re-rolling it I'll leave to you\n   whether it makes sense to do it with the \"read-tree\" included (I\n   think probably yes, but \"just the submodule--helper\" is smaller).\n\n   Rewording the commit message referring to \"the other approach\"\n   (i.e. your series) probably makes sense in light of later discussion\n   (probably just dropping it).\n\n * Right now I can't remember if that one test failed until the\n   \"read-tree\" patch, or if the \"submodule--helper\" was sufficient, so\n   maybe we need the \"read-tree\" one to flip the\n   \"test_expect_failure\"...\n\n * The 8/8 has a wart where I just removed \"SUPPORT_SUPER_PREFIX\" from\n   git.c, but didn't adjust the rest of the bitfields, i.e. it should be\n   1<<0..6, not 1<<0..3,5..9 at the end (having removed \"1<<4\". You got\n   that right in your version...\n\nIf you can do that and address any other nits/issues you find that would\nbe great. I don't think I'd get to it before next week otherwise, but\nit's earlier in the -0800 TZ :)\n"},{"id":"467162","messageId":"Y27D8QUl3I2d4xNe@nand.local","threadId":"58773","inReplyTo":"221111.86fsepmbhe.gmgdl@evledraar.gmail.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-11T21:51:45Z","receivedAt":"2022-11-11T21:52:03Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Fri, Nov 11, 2022 at 10:17:44PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> If you can do that and address any other nits/issues you find that would\n> be great. I don't think I'd get to it before next week otherwise, but\n> it's earlier in the -0800 TZ :)\n\nThanks, both.\n\n\nThanks,\nTaylor\n"},{"id":"467184","messageId":"kl6lsfip0yfx.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"221111.86fsepmbhe.gmgdl@evledraar.gmail.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-12T01:10:58Z","receivedAt":"2022-11-12T01:12:08Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Fri, Nov 11 2022, Glen Choo wrote:\n>\n>> Glen Choo <chooglen@google.com> writes:\n>>\n>>> Rereading this series and thinking about this some more, let's go with\n>>> your approach, primarily because it avoids global state.\n>>>\n>>> From this series, it seems that it's not that hard to make this change\n>>> and support whatever use cases we currently have.\n>>>\n>>> This does make it more tedious to add more \"--super-prefix\" in the\n>>> future, but that's a good push for us to do more things in-process\n>>> and/or be more principled about passing context objects through the call\n>>> stack instead of relying on globals.\n>>>\n>>> Let me know what I can add to this effort besides reviewing :)\n>>\n>> Specifically, if you have other things on your plate, I'd be happy to\n>> pick up where where this RFC has left off.\n>\n> I was going to get around to re-rolling this in the next few days, but\n> I'd also be happy to have you beat me to it.\n\nAh, well, I didn't mean that I was planning to work on this over the\nweekend, but I can certainly get to it on Monday. I meant something\ncloser to \"If you didn't want to think about git-submodule.sh for the\nnext week or so, I can pick this up\".\n\nAlternatively, I think it also makes sense if you want to reroll only\nthe submodule--helper bits (1-7/8) to unblock your git-submodule.sh\nwork, and I can prepare the rest of the \"nuke --super-prefix\" stuff on\ntop of that. That should save you a context switch, and since I sent out\n[1], nuking --super-prefix shouldn't be urgent.\n\nIf you don't really care any which way, I'll just re-roll this :)\n\n[1] https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com\n\n>\n> My plan was basically:\n>\n>  * Steal the test from your series, put them at the beginning, and for\n>    those that fail make them \"test_expect_failure\", then\n>    \"test_expect_success\" later when they pass.\n>\n>  * Pretty much my RFC as-is. If you're re-rolling it I'll leave to you\n>    whether it makes sense to do it with the \"read-tree\" included (I\n>    think probably yes, but \"just the submodule--helper\" is smaller).\n>\n>    Rewording the commit message referring to \"the other approach\"\n>    (i.e. your series) probably makes sense in light of later discussion\n>    (probably just dropping it).\n>\n>  * Right now I can't remember if that one test failed until the\n>    \"read-tree\" patch, or if the \"submodule--helper\" was sufficient, so\n>    maybe we need the \"read-tree\" one to flip the\n>    \"test_expect_failure\"...\n>\n>  * The 8/8 has a wart where I just removed \"SUPPORT_SUPER_PREFIX\" from\n>    git.c, but didn't adjust the rest of the bitfields, i.e. it should be\n>    1<<0..6, not 1<<0..3,5..9 at the end (having removed \"1<<4\". You got\n>    that right in your version...\n\nYeah, this plan makes sense. One thing I'd add is that I'd also use\nOPT__SUPER_PREFIX to handle \"git fetch --submodule-prefix\".\n\n>\n> If you can do that and address any other nits/issues you find that would\n> be great. I don't think I'd get to it before next week otherwise, but\n> it's earlier in the -0800 TZ :)\n"},{"id":"467234","messageId":"patch-v2-01.10-1114a4ff666-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 01/10] read-tree + fetch tests: test failing \"--super-prefix\" interaction","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:41Z","receivedAt":"2022-11-14T10:09:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nEver since \"git fetch --refetch\" was introduced in 0f5e8851737 (Merge\nbranch 'rc/fetch-refetch', 2022-04-04) the test being added here would\nfail. This is because \"restore\" will \"read-tree .. --reset <hash>\",\nwhich will in turn invoke \"fetch\". The \"fetch\" will then die with:\n\n\tfatal: fetch doesn't support --super-prefix\n\nThis edge case and other \"--super-prefix\" bugs will be fixed in\nsubsequent commits, but let's first add a \"test_expect_failure\" test\nfor it. It passes until the very last command in the test.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 43 insertions(+)\n\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 037941b95d2..e56466580cf 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '\n \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n '\n \n+test_expect_failure 'lazy-fetch in submodule succeeds' '\n+\t# setup\n+\ttest_config_global protocol.file.allow always &&\n+\n+\tgit init src-sub &&\n+\tgit -C src-sub config uploadpack.allowfilter 1 &&\n+\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n+\n+\t# This blob must be missing in the subsequent commit.\n+\techo foo >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule one\" &&\n+\tSUB_ONE=$(git -C src-sub rev-parse HEAD) &&\n+\n+\techo bar >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule two\" &&\n+\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n+\n+\tgit init src-super &&\n+\tgit -C src-super config uploadpack.allowfilter 1 &&\n+\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n+\tgit -C src-super submodule add ../src-sub src-sub &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_ONE &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject one\" &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_TWO &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject two\" &&\n+\n+\t# the fetch\n+\ttest_when_finished \"rm -rf src-super src-sub client\" &&\n+\n+\ttest_config_global protocol.file.allow always &&\n+\tgit clone --filter=blob:none --also-filter-submodules \\\n+\t\t--recurse-submodules \"file://$(pwd)/src-super\" client &&\n+\n+\t# Trigger lazy-fetch from the superproject\n+\tgit -C client restore --recurse-submodules --source=HEAD^ :/\n+'\n+\n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n start_httpd\n \n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467235","messageId":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com","subject":"[PATCH v2 00/10] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:40Z","receivedAt":"2022-11-14T10:09:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"= Summary\n\nWhat's \"--super-prefix\"? The \"git\" command takes an \"internal use\nonly\" \"--super-prefix\" option, which is used to inform processes\ninvoked in submodules what the path prefix to the invoking\nsuperproject is.\n\nThis is so so that e.g. \"git submodule absorbgitdirs\" can report\n\"sub-1/sub-2\", instead of \"sub-2\" when being invoked in the \"sub-1\"\nsubmodule.\n\nFor this the \"--super-prefix\" facility has been doing a\nsetenv(\"GIT_INTERNAL_SUPER_PREFIX\", \"sub-1/\") as soon as it got the\n\"--supre-prefix=sub-1/\". We'd then pass that along via the environment\nwhen invoking the sub-process.\n\nAs this series shows we don't need such a hands-off global facility to\ndo this, we can instead just pass the relevant context directly in\neach command. E.g. \"git submodule absorbgitdirs\" can pass the path to\nthe \"git submodule absorbgitdirs\" sub-process it's about to invoke.\n\n= Relation to other submissions\n\nThis is a non-RFC version of my earlier RFC to get rid of\n\"--super-prefix\"[1], which itself was an alternate proposal to Glen's\n[2]. Per [3] he's agreed to go with this approach.\n\nThis is on top of \"ab/submodule-helper-prep-only\" (currently in\n\"next\"[4]) and \"ab/submodule-no-abspath\" (currently in \"seen\"[5]).\n\nIt's also proposing to replace Glen's one-patch[6], which is working\naround the problem shown in the test added in 1/10 here. Per\ndownthread of [7] I think Glen was aiming for getting a more narrow\nfix in case we split off 9/10 here into some later fix.\n\nAs we're fixing an edge case in something that's always been broken\n(and thus wouldn't backport) I think it's better to just fix the\nproblem directly, rather than introducing new \"--super-prefix\" use,\njust to take it away later.\n\n= Changes since the RFC\n\n* Added Glen's \"git fetch\" test as a 1/10, with an updated commit message\n* Updated 2/10's commit message for the non-RFC, and adjusted and\n  incorporated a variant of Glen's fsmonitor test change.\n* 9/10: Correctly re-arrange bitfield define's when removing one, make\n  the test added in 1/10 pass.\n\n* 10/10: New commit to make \"git fetch\" use our own \"--super-prefix\"\n  instead of its \"--submodule-prefix\", which makes it consistent with\n  the other command-level \"--super-prefix\" introduced here.\n\n  Personally I'm rather \"meh\" on this. It's not actually needed by the\n  main body of the series, but Glen seems to prefer it in[9], and\n  doing it is easy enough.\n\n  That change is a pure refactoring clean-up for consistency. The only\n  reason it's 10/10 and not 1/10 is because it uses the\n  \"OPT__SUPER_PREFIX()\" introduced in 2/10.\n\n= CI & fetch URL\n\nPassing at: https://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local-2\n\n1. https://lore.kernel.org/git/RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/\n3. https://lore.kernel.org/git/kl6l5yfm2taf.fsf@chooglen-macbookpro.roam.corp.google.com/\n4. c0c4f4d1c33 (Merge branch 'ab/submodule-helper-prep-only' into next, 2022-11-08)\n5. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/\n6. https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com/\n7. https://lore.kernel.org/git/221111.86fsepmbhe.gmgdl@evledraar.gmail.com/\n8. https://lore.kernel.org/git/20221109004708.97668-3-chooglen@google.com/\n9. https://lore.kernel.org/git/kl6lsfip0yfx.fsf@chooglen-macbookpro.roam.corp.google.com/\n\nGlen Choo (1):\n  read-tree + fetch tests: test failing \"--super-prefix\" interaction\n\nÆvar Arnfjörð Bjarmason (9):\n  submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n  submodule--helper: \"deinit\" has never used \"--super-prefix\"\n  submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n  submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n  submodule--helper: convert \"status\" to its own \"--super-prefix\"\n  submodule--helper: convert \"{update,clone}\" to their own\n    \"--super-prefix\"\n  submodule tests: test \"git branch -t\" output and stderr\n  read-tree: add \"--super-prefix\" option, eliminate global\n  fetch: rename \"--submodule-prefix\" to \"--super-prefix\"\n\n Documentation/fetch-options.txt |  5 --\n Documentation/git.txt           |  8 +--\n builtin.h                       |  4 --\n builtin/checkout.c              |  2 +-\n builtin/fetch.c                 |  7 +--\n builtin/read-tree.c             |  1 +\n builtin/submodule--helper.c     | 95 ++++++++++++++++++--------------\n cache.h                         |  2 -\n entry.c                         | 12 ++--\n entry.h                         |  6 +-\n environment.c                   | 13 -----\n git.c                           | 41 +++-----------\n parse-options.h                 |  4 ++\n submodule.c                     | 70 +++++++++++------------\n submodule.h                     | 12 ++--\n t/lib-submodule-update.sh       | 98 ++++++++++++++++++---------------\n t/t1001-read-tree-m-2way.sh     |  2 +-\n t/t5616-partial-clone.sh        | 43 +++++++++++++++\n t/t7527-builtin-fsmonitor.sh    | 33 +++--------\n unpack-trees.c                  | 23 ++++----\n unpack-trees.h                  |  1 +\n 21 files changed, 244 insertions(+), 238 deletions(-)\n\nRange-diff against v1:\n -:  ----------- >  1:  1114a4ff666 read-tree + fetch tests: test failing \"--super-prefix\" interaction\n 1:  ad0356b596f !  2:  5a35f7b75b3 submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n    @@ Commit message\n         declare \"fsmonitor--daemon\" as accepting it too, even though it\n         doesn't care about it.\n     \n    -    There's a parallel proposal to remove \"--super-prefix\" as an option to\n    -    \"git\" in [3], and some of the approach might be the easiest route in\n    -    some cases.\n    -\n         But in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\n         invoke itself recursively, and we'd never have another \"in-between\"\n         process in the chain. So we didn't need the bigger hammer of \"git\n    @@ Commit message\n         stone makes such an eventual change easier, as we'll need to deal with\n         less global state at that point.\n     \n    +    The \"fsmonitor--daemon\" test adjusted here was added in [3]. The\n    +    comment added in that commit has been out-of-date from the beginning,\n    +    and the \"have_t2_error_event()\" was being overly specific in testing\n    +    for a bug that we *don't* have. Let's instead test for the stdout and\n    +    stderr that we *do have*.\n    +\n         1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n         2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n            2022-05-26)\n    -    3. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/\n    +    3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n    +       2022-05-26)\n     \n    +    Signed-off-by: Glen Choo <chooglen@google.com>\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    @@ submodule.h: void submodule_unset_core_worktree(const struct submodule *sub);\n      \n      /*\n       * Return the absolute path of the working tree of the superproject, which this\n    +\n    + ## t/t7527-builtin-fsmonitor.sh ##\n    +@@ t/t7527-builtin-fsmonitor.sh: test_expect_success 'submodule always visited' '\n    + # the submodule, and someone does a `git submodule absorbgitdirs`\n    + # in the super, Git will recursively invoke `git submodule--helper`\n    + # to do the work and this may try to read the index.  This will\n    +-# try to start the daemon in the submodule *and* pass (either\n    +-# directly or via inheritance) the `--super-prefix` arg to the\n    +-# `git fsmonitor--daemon start` command inside the submodule.\n    +-# This causes a warning because fsmonitor--daemon does take that\n    +-# global arg (see the table in git.c)\n    +-#\n    +-# This causes a warning when trying to start the daemon that is\n    +-# somewhat confusing.  It does not seem to hurt anything because\n    +-# the fsmonitor code maps the query failure into a trivial response\n    +-# and does the work anyway.\n    +-#\n    +-# It would be nice to silence the warning, however.\n    +-\n    +-have_t2_error_event () {\n    +-\tlog=$1\n    +-\tmsg=\"fsmonitor--daemon doesnQt support --super-prefix\" &&\n    +-\n    +-\ttr '\\047' Q <$1 | grep -e \"$msg\"\n    +-}\n    ++# try to start the daemon in the submodule.\n    + \n    + test_expect_success \"stray submodule super-prefix warning\" '\n    + \ttest_when_finished \"rm -rf super; \\\n    +-\t\t\t    rm -rf sub;   \\\n    +-\t\t\t    rm super-sub.trace\" &&\n    ++\t\t\t    rm -rf sub\" &&\n    + \n    + \tcreate_super super &&\n    + \tcreate_sub sub &&\n    +@@ t/t7527-builtin-fsmonitor.sh: test_expect_success \"stray submodule super-prefix warning\" '\n    + \n    + \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n    + \n    +-\tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n    +-\t\tgit -C super submodule absorbgitdirs &&\n    +-\n    +-\t! have_t2_error_event super-sub.trace\n    ++\tcat >expect <<-\\EOF &&\n    ++\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from '\\''dir_1/dir_2/sub/.git'\\'' to '\\''.git/modules/dir_1/dir_2/sub'\\''\n    ++\tEOF\n    ++\tgit -C super submodule absorbgitdirs >out 2>actual &&\n    ++\ttest_cmp expect actual &&\n    ++\ttest_must_be_empty out\n    + '\n    + \n    + # On a case-insensitive file system, confirm that the daemon\n 2:  87a780eb9bf =  3:  a7a1f9487dc submodule--helper: \"deinit\" has never used \"--super-prefix\"\n 3:  4858e2ad0ed =  4:  935d8070834 submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n 4:  5ffe4407e46 =  5:  933c752513d submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n 5:  a46540b63c2 =  6:  67273f729e0 submodule--helper: convert \"status\" to its own \"--super-prefix\"\n 6:  78ebf0e2abf =  7:  eaa73f5b1e4 submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"\n 7:  00a9e789be7 =  8:  172b5865811 submodule tests: test \"git branch -t\" output and stderr\n 8:  3ba894a6698 !  9:  9fdeab60773 read-tree: add \"--super-prefix\" option, eliminate global\n    @@ git.c\n       */\n      #define NEED_WORK_TREE\t\t(1<<3)\n     -#define SUPPORT_SUPER_PREFIX\t(1<<4)\n    - #define DELAY_PAGER_CONFIG\t(1<<5)\n    - #define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n    +-#define DELAY_PAGER_CONFIG\t(1<<5)\n    +-#define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n    ++#define DELAY_PAGER_CONFIG\t(1<<4)\n    ++#define NO_PARSEOPT\t\t(1<<5) /* parse-options is not used */\n      \n    + struct cmd_struct {\n    + \tconst char *cmd;\n     @@ git.c: const char git_usage_string[] =\n      \t   \"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\\n\"\n      \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\\n\"\n    @@ t/t1001-read-tree-m-2way.sh: test_expect_success 'read-tree supports the super-p\n      '\n      \n     \n    + ## t/t5616-partial-clone.sh ##\n    +@@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor objects' '\n    + \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n    + '\n    + \n    +-test_expect_failure 'lazy-fetch in submodule succeeds' '\n    ++test_expect_success 'lazy-fetch in submodule succeeds' '\n    + \t# setup\n    + \ttest_config_global protocol.file.allow always &&\n    + \n    +\n      ## unpack-trees.c ##\n     @@ unpack-trees.c: static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {\n      \t  ? ((o)->msgs[(type)])      \\\n -:  ----------- > 10:  100ba36dfb7 fetch: rename \"--submodule-prefix\" to \"--super-prefix\"\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467236","messageId":"patch-v2-02.10-5a35f7b75b3-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 02/10] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:42Z","receivedAt":"2022-11-14T10:09:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" facility was introduced in [1] has always been a\ntransitory hack, which is why we've made it an error to supply it as\nan option to \"git\" to commands that don't know about it.\n\nThat's been a good goal, as it has a global effect we haven't wanted\ncalls to get_super_prefix() from built-ins we didn't expect.\n\nBut it has meant that when we've had chains of different built-ins\nusing it all of the processes in that \"chain\" have needed to support\nit, and worse processes that don't need it have needed to ask for\n\"SUPPORT_SUPER_PREFIX\" because their parent process needs it.\n\nThat's how \"fsmonitor--daemon\" ended up with it, per [2] it's called\nfrom (among other things) \"submodule--helper absorbgitdirs\", but as we\ndeclared \"submodule--helper\" as \"SUPPORT_SUPER_PREFIX\" we needed to\ndeclare \"fsmonitor--daemon\" as accepting it too, even though it\ndoesn't care about it.\n\nBut in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\ninvoke itself recursively, and we'd never have another \"in-between\"\nprocess in the chain. So we didn't need the bigger hammer of \"git\n--super-prefix\", and the \"setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)\"\nthat it entails.\n\nLet's instead accept a hidden \"--super-prefix\" option to\n\"submodule--helper absorbgitdirs\" itself.\n\nEventually (as with all other \"--super-prefix\" users) we'll want to\nclean this code up so that this all happens in-process. I.e. needing\nany variant of \"--super-prefix\" is itself a hack around our various\nglobal state, and implicit reliance on \"the_repository\". This stepping\nstone makes such an eventual change easier, as we'll need to deal with\nless global state at that point.\n\nThe \"fsmonitor--daemon\" test adjusted here was added in [3]. The\ncomment added in that commit has been out-of-date from the beginning,\nand the \"have_t2_error_event()\" was being overly specific in testing\nfor a bug that we *don't* have. Let's instead test for the stdout and\nstderr that we *do have*.\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n   2022-05-26)\n3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n   2022-05-26)\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c  |  8 +++++---\n git.c                        |  2 +-\n parse-options.h              |  4 ++++\n submodule.c                  | 20 ++++++++++++--------\n submodule.h                  |  7 ++++++-\n t/t7527-builtin-fsmonitor.sh | 33 ++++++++-------------------------\n 6 files changed, 36 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c75e9e86b06..427e793e204 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2828,7 +2828,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tconst char *super_prefix = NULL;\n \tstruct option embed_gitdir_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT_END()\n \t};\n \tconst char *const git_submodule_helper_usage[] = {\n@@ -2844,7 +2846,8 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \t\tgoto cleanup;\n \n \tfor (i = 0; i < list.nr; i++)\n-\t\tabsorb_git_dir_into_superproject(list.entries[i]->name);\n+\t\tabsorb_git_dir_into_superproject_sp(list.entries[i]->name,\n+\t\t\t\t\t\t    super_prefix);\n \n \tret = 0;\n cleanup:\n@@ -3382,8 +3385,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n \t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && strcmp(subcmd, \"absorbgitdirs\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\ndiff --git a/git.c b/git.c\nindex 10202a7f126..b1b7e1a837e 100644\n--- a/git.c\n+++ b/git.c\n@@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {\n \t{ \"format-patch\", cmd_format_patch, RUN_SETUP },\n \t{ \"fsck\", cmd_fsck, RUN_SETUP },\n \t{ \"fsck-objects\", cmd_fsck, RUN_SETUP },\n-\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },\n+\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, RUN_SETUP },\n \t{ \"gc\", cmd_gc, RUN_SETUP },\n \t{ \"get-tar-commit-id\", cmd_get_tar_commit_id, NO_PARSEOPT },\n \t{ \"grep\", cmd_grep, RUN_SETUP_GENTLY },\ndiff --git a/parse-options.h b/parse-options.h\nindex b6ef86e0d15..50d852f2991 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);\n \t{ OPTION_CALLBACK, 0, \"abbrev\", (var), N_(\"n\"),\t\\\n \t  N_(\"use <n> digits to display object names\"),\t\\\n \t  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }\n+#define OPT__SUPER_PREFIX(var) \\\n+\tOPT_STRING_F(0, \"super-prefix\", (var), N_(\"prefix\"), \\\n+\t\tN_(\"prefixed path to initial superproject\"), PARSE_OPT_HIDDEN)\n+\n #define OPT__COLOR(var, h) \\\n \tOPT_COLOR_FLAG(0, \"color\", (var), (h))\n #define OPT_COLUMN(s, l, v, h) \\\ndiff --git a/submodule.c b/submodule.c\nindex c47358097fd..d9fd0af81b6 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)\n  * Embeds a single submodules git directory into the superprojects git dir,\n  * non recursively.\n  */\n-static void relocate_single_git_dir_into_superproject(const char *path)\n+static void relocate_single_git_dir_into_superproject(const char *path,\n+\t\t\t\t\t\t      const char *super_prefix)\n {\n \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n \tstruct strbuf new_gitdir = STRBUF_INIT;\n@@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \t       real_old_git_dir[off] == real_new_git_dir[off])\n \t\toff++;\n \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from '%s' to '%s'\\n\"),\n-\t\tget_super_prefix_or_empty(), path,\n+\t\t(super_prefix ? super_prefix : \"\"), path,\n \t\treal_old_git_dir + off, real_new_git_dir + off);\n \n \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n@@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \tstrbuf_release(&new_gitdir);\n }\n \n-static void absorb_git_dir_into_superproject_recurse(const char *path)\n+static void absorb_git_dir_into_superproject_recurse(const char *path,\n+\t\t\t\t\t\t     const char *super_prefix)\n {\n \n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2321,10 +2323,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n \tcp.dir = path;\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \tstrvec_pushl(&cp.args, \"submodule--helper\",\n \t\t     \"absorbgitdirs\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n+\t\t     super_prefix : \"\", path);\n+\n \tprepare_submodule_repo_env(&cp.env);\n \tif (run_command(&cp))\n \t\tdie(_(\"could not recurse into submodule '%s'\"), path);\n@@ -2335,7 +2338,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n  * having its git directory within the working tree to the git dir nested\n  * in its superprojects git dir under modules/.\n  */\n-void absorb_git_dir_into_superproject(const char *path)\n+void absorb_git_dir_into_superproject_sp(const char *path,\n+\t\t\t\t\t const char *super_prefix)\n {\n \tint err_code;\n \tconst char *sub_git_dir;\n@@ -2377,14 +2381,14 @@ void absorb_git_dir_into_superproject(const char *path)\n \t\tchar *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);\n \n \t\tif (!starts_with(real_sub_git_dir, real_common_git_dir))\n-\t\t\trelocate_single_git_dir_into_superproject(path);\n+\t\t\trelocate_single_git_dir_into_superproject(path, super_prefix);\n \n \t\tfree(real_sub_git_dir);\n \t\tfree(real_common_git_dir);\n \t}\n \tstrbuf_release(&gitdir);\n \n-\tabsorb_git_dir_into_superproject_recurse(path);\n+\tabsorb_git_dir_into_superproject_recurse(path, super_prefix);\n }\n \n int get_superproject_working_tree(struct strbuf *buf)\ndiff --git a/submodule.h b/submodule.h\nindex b52a4ff1e73..e5ee13fb06a 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);\n  */\n void prepare_submodule_repo_env(struct strvec *env);\n \n-void absorb_git_dir_into_superproject(const char *path);\n+void absorb_git_dir_into_superproject_sp(const char *path,\n+\t\t\t\t\t const char *super_prefix);\n+static inline void absorb_git_dir_into_superproject(const char *path)\n+{\n+\tabsorb_git_dir_into_superproject_sp(path, NULL);\n+}\n \n /*\n  * Return the absolute path of the working tree of the superproject, which this\ndiff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh\nindex 4abc74db2bb..31526937d95 100755\n--- a/t/t7527-builtin-fsmonitor.sh\n+++ b/t/t7527-builtin-fsmonitor.sh\n@@ -866,30 +866,11 @@ test_expect_success 'submodule always visited' '\n # the submodule, and someone does a `git submodule absorbgitdirs`\n # in the super, Git will recursively invoke `git submodule--helper`\n # to do the work and this may try to read the index.  This will\n-# try to start the daemon in the submodule *and* pass (either\n-# directly or via inheritance) the `--super-prefix` arg to the\n-# `git fsmonitor--daemon start` command inside the submodule.\n-# This causes a warning because fsmonitor--daemon does take that\n-# global arg (see the table in git.c)\n-#\n-# This causes a warning when trying to start the daemon that is\n-# somewhat confusing.  It does not seem to hurt anything because\n-# the fsmonitor code maps the query failure into a trivial response\n-# and does the work anyway.\n-#\n-# It would be nice to silence the warning, however.\n-\n-have_t2_error_event () {\n-\tlog=$1\n-\tmsg=\"fsmonitor--daemon doesnQt support --super-prefix\" &&\n-\n-\ttr '\\047' Q <$1 | grep -e \"$msg\"\n-}\n+# try to start the daemon in the submodule.\n \n test_expect_success \"stray submodule super-prefix warning\" '\n \ttest_when_finished \"rm -rf super; \\\n-\t\t\t    rm -rf sub;   \\\n-\t\t\t    rm super-sub.trace\" &&\n+\t\t\t    rm -rf sub\" &&\n \n \tcreate_super super &&\n \tcreate_sub sub &&\n@@ -904,10 +885,12 @@ test_expect_success \"stray submodule super-prefix warning\" '\n \n \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n \n-\tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n-\t\tgit -C super submodule absorbgitdirs &&\n-\n-\t! have_t2_error_event super-sub.trace\n+\tcat >expect <<-\\EOF &&\n+\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from '\\''dir_1/dir_2/sub/.git'\\'' to '\\''.git/modules/dir_1/dir_2/sub'\\''\n+\tEOF\n+\tgit -C super submodule absorbgitdirs >out 2>actual &&\n+\ttest_cmp expect actual &&\n+\ttest_must_be_empty out\n '\n \n # On a case-insensitive file system, confirm that the daemon\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467237","messageId":"patch-v2-03.10-a7a1f9487dc-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 03/10] submodule--helper: \"deinit\" has never used \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:43Z","receivedAt":"2022-11-14T10:09:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"deinit_submodule()\" function has never been able to use the \"git\n--super-prefix\". It will call \"absorb_git_dir_into_superproject()\",\nbut it will only do so from the top-level project.\n\nIf \"absorbgitdirs\" recurses it will use the \"path\" passed to\n\"absorb_git_dir_into_superproject()\" in \"deinit_submodule()\" as its\nstarting \"--super-prefix\".\n\nSo, let's introduce a \"get_submodule_displaypath_sp()\" helper, and\nmake our existing \"get_submodule_displaypath()\" a wrapper for it. In a\nsubsequent commit the wrapper will be going away, as the rest of the\ncommands here will stop using the global \"get_super_prefix()\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 14 ++++++++++----\n 1 file changed, 10 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 427e793e204..c4d5e029b37 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n }\n \n /* the result should be freed by the caller. */\n-static char *get_submodule_displaypath(const char *path, const char *prefix)\n+static char *get_submodule_displaypath_sp(const char *path, const char *prefix,\n+\t\t\t\t\t  const char *super_prefix)\n {\n-\tconst char *super_prefix = get_super_prefix();\n-\n \tif (prefix && super_prefix) {\n \t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n \t\t    prefix, super_prefix);\n@@ -132,6 +131,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \n+static char *get_submodule_displaypath(const char *path, const char *prefix)\n+{\n+\tconst char *super_prefix = get_super_prefix();\n+\n+\treturn get_submodule_displaypath_sp(path, prefix, super_prefix);\n+}\n+\n static char *compute_rev_name(const char *sub_path, const char* object_id)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n@@ -1365,7 +1371,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \tif (!sub || !sub->name)\n \t\tgoto cleanup;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, NULL);\n \n \t/* remove the submodule work tree (unless the user already did it) */\n \tif (is_directory(path)) {\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467238","messageId":"patch-v2-04.10-935d8070834-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 04/10] submodule--helper: convert \"foreach\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:44Z","receivedAt":"2022-11-14T10:09:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper foreach\" to use its own \"--super-prefix\", instead\nof relying on the global \"--super-prefix\" argument to \"git\"\nitself. See that earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 15 ++++++++++-----\n 1 file changed, 10 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c4d5e029b37..989c75280af 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -285,6 +285,7 @@ struct foreach_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint quiet;\n \tint recursive;\n };\n@@ -300,7 +301,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, info->prefix,\n+\t\t\t\t\t\t   info->super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -370,10 +372,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"foreach\", \"--recursive\",\n \t\t\t     NULL);\n+\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (info->quiet)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -396,7 +398,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tstruct foreach_cb info = FOREACH_CB_INIT;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tconst char *super_prefix = NULL;\n \tstruct option module_foreach_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n \t\t\t N_(\"recurse into nested submodules\")),\n@@ -417,6 +421,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tinfo.argc = argc;\n \tinfo.argv = argv;\n \tinfo.prefix = prefix;\n+\tinfo.super_prefix = super_prefix;\n \n \tfor_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);\n \n@@ -3390,8 +3395,8 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467239","messageId":"patch-v2-05.10-933c752513d-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 05/10] submodule--helper: convert \"sync\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:45Z","receivedAt":"2022-11-14T10:10:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper sync\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 21 +++++++++++++--------\n 1 file changed, 13 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 989c75280af..db58fd5b2c4 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1214,12 +1214,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \n struct sync_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define SYNC_CB_INIT { 0 }\n \n static void sync_submodule(const char *path, const char *prefix,\n-\t\t\t   unsigned int flags)\n+\t\t\t   const char *super_prefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n@@ -1250,7 +1251,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tsuper_config_url = xstrdup(\"\");\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);\n \n \tif (!(flags & OPT_QUIET))\n \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n@@ -1287,10 +1288,11 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"sync\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n+\n \n \t\tif (flags & OPT_QUIET)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -1313,7 +1315,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct sync_cb *info = cb_data;\n \n-\tsync_submodule(list_item->name, info->prefix, info->flags);\n+\tsync_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_sync(int argc, const char **argv, const char *prefix)\n@@ -1323,7 +1326,9 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n \tint recursive = 0;\n+\tconst char *super_prefix = NULL;\n \tstruct option module_sync_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n \t\tOPT_BOOL(0, \"recursive\", &recursive,\n \t\t\tN_(\"recurse into nested submodules\")),\n@@ -1342,6 +1347,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \t\tgoto cleanup;\n \n \tinfo.prefix = prefix;\n+\tinfo.super_prefix = super_prefix;\n \tif (quiet)\n \t\tinfo.flags |= OPT_QUIET;\n \tif (recursive)\n@@ -2890,7 +2896,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)\n \tconfig_name = xstrfmt(\"submodule.%s.url\", path);\n \n \tconfig_set_in_gitmodules_file_gently(config_name, newurl);\n-\tsync_submodule(path, prefix, quiet ? OPT_QUIET : 0);\n+\tsync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);\n \n \tfree(config_name);\n \n@@ -3395,8 +3401,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467240","messageId":"patch-v2-06.10-67273f729e0-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 06/10] submodule--helper: convert \"status\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:46Z","receivedAt":"2022-11-14T10:10:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 16 ++++++++++------\n 1 file changed, 10 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex db58fd5b2c4..40939b0b18e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -581,6 +581,7 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \n struct status_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define STATUS_CB_INIT { 0 }\n@@ -619,7 +620,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,\n \n static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\t\t     unsigned int ce_flags, const char *prefix,\n-\t\t\t     unsigned int flags)\n+\t\t\t     const char *super_prefix, unsigned int flags)\n {\n \tchar *displaypath;\n \tstruct strvec diff_files_args = STRVEC_INIT;\n@@ -635,7 +636,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n \t\t      path);\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);\n \n \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n@@ -693,10 +694,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"status\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (flags & OPT_CACHED)\n \t\t\tstrvec_push(&cpr.args, \"--cached\");\n@@ -720,7 +721,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,\n \tstruct status_cb *info = cb_data;\n \n \tstatus_submodule(list_item->name, &list_item->oid, list_item->ce_flags,\n-\t\t\t info->prefix, info->flags);\n+\t\t\t info->prefix, info->super_prefix, info->flags);\n }\n \n static int module_status(int argc, const char **argv, const char *prefix)\n@@ -729,7 +730,9 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n+\tconst char *super_prefix = NULL;\n \tstruct option module_status_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n@@ -748,6 +751,7 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \t\tgoto cleanup;\n \n \tinfo.prefix = prefix;\n+\tinfo.super_prefix = super_prefix;\n \tif (quiet)\n \t\tinfo.flags |= OPT_QUIET;\n \n@@ -3401,7 +3405,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && get_super_prefix())\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467241","messageId":"patch-v2-07.10-eaa73f5b1e4-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 07/10] submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:47Z","receivedAt":"2022-11-14T10:10:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\".\n\nWe need to convert both of these away from the global \"--super-prefix\"\nat the same time, because \"update\" will call \"clone\", but \"clone\"\nitself didn't make use of the global \"--super-prefix\" for displaying\npaths. It was only on the list of sub-commands that accepted it\nbecause \"update\"'s use of it would set it in its environment.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 45 ++++++++++++++++---------------------\n git.c                       |  2 +-\n 2 files changed, 20 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 40939b0b18e..e13615eb939 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -131,13 +131,6 @@ static char *get_submodule_displaypath_sp(const char *path, const char *prefix,\n \t}\n }\n \n-static char *get_submodule_displaypath(const char *path, const char *prefix)\n-{\n-\tconst char *super_prefix = get_super_prefix();\n-\n-\treturn get_submodule_displaypath_sp(path, prefix, super_prefix);\n-}\n-\n static char *compute_rev_name(const char *sub_path, const char* object_id)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n@@ -446,11 +439,13 @@ static int starts_with_dot_dot_slash(const char *const path)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define INIT_CB_INIT { 0 }\n \n static void init_submodule(const char *path, const char *prefix,\n+\t\t\t   const char *super_prefix,\n \t\t\t   unsigned int flags)\n {\n \tconst struct submodule *sub;\n@@ -458,7 +453,7 @@ static void init_submodule(const char *path, const char *prefix,\n \tconst char *upd;\n \tchar *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -534,7 +529,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct init_cb *info = cb_data;\n \n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n@@ -802,6 +798,7 @@ struct summary_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int cached: 1;\n \tunsigned int for_status: 1;\n \tunsigned int files: 1;\n@@ -963,7 +960,8 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t\tdst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath_sp(p->sm_path, info->prefix,\n+\t\t\t\t\t\t   info->super_prefix);\n \n \tif (!missing_src && !missing_dst) {\n \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n@@ -1904,6 +1902,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)\n \n struct update_data {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tchar *displaypath;\n \tenum submodule_update_type update_default;\n \tstruct object_id suboid;\n@@ -1979,7 +1978,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tenum submodule_update_type update_type;\n \tchar *key;\n \tconst struct update_data *ud = suc->update_data;\n-\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n+\tchar *displaypath = get_submodule_displaypath_sp(ce->name, ud->prefix,\n+\t\t\t\t\t\t\t ud->super_prefix);\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n \tint need_free_url = 0;\n@@ -2459,11 +2459,11 @@ static void update_data_to_args(const struct update_data *update_data,\n {\n \tenum submodule_update_type update_type = update_data->update_default;\n \n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tif (update_data->displaypath) {\n \t\tstrvec_push(args, \"--super-prefix\");\n \t\tstrvec_pushf(args, \"%s/\", update_data->displaypath);\n \t}\n-\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n \tif (update_data->quiet)\n \t\tstrvec_push(args, \"--quiet\");\n@@ -2628,8 +2628,9 @@ static int update_submodules(struct update_data *update_data)\n \t\tif (code)\n \t\t\tgoto fail;\n \n-\t\tupdate_data->displaypath = get_submodule_displaypath(\n-\t\t\tupdate_data->sm_path, update_data->prefix);\n+\t\tupdate_data->displaypath = get_submodule_displaypath_sp(\n+\t\t\tupdate_data->sm_path, update_data->prefix,\n+\t\t\tupdate_data->super_prefix);\n \t\tcode = update_submodule(update_data);\n \t\tFREE_AND_NULL(update_data->displaypath);\n fail:\n@@ -2654,7 +2655,9 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tstruct list_objects_filter_options filter_options =\n \t\tLIST_OBJECTS_FILTER_INIT;\n \tint ret;\n+\tconst char *super_prefix = NULL;\n \tstruct option module_update_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n \t\tOPT_BOOL(0, \"init\", &opt.init,\n \t\t\t N_(\"initialize uninitialized submodules before update\")),\n@@ -2720,6 +2723,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \n \topt.filter_options = &filter_options;\n \topt.prefix = prefix;\n+\topt.super_prefix = super_prefix;\n \n \tif (opt.update_default)\n \t\topt.update_strategy.type = opt.update_default;\n@@ -2751,6 +2755,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\t\tmodule_list_active(&list);\n \n \t\tinfo.prefix = opt.prefix;\n+\t\tinfo.super_prefix = super_prefix;\n \t\tif (opt.quiet)\n \t\t\tinfo.flags |= OPT_QUIET;\n \n@@ -3377,8 +3382,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n {\n-\tconst char *cmd = argv[0];\n-\tconst char *subcmd;\n \tparse_opt_subcommand_fn *fn = NULL;\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule--helper <command>\"),\n@@ -3402,16 +3405,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\tsubcmd = argv[0];\n-\n-\tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    get_super_prefix())\n-\t\t/*\n-\t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n-\t\t * string identical to git.c's.\n-\t\t */\n-\t\tdie(_(\"%s doesn't support --super-prefix\"),\n-\t\t    xstrfmt(\"'%s %s'\", cmd, subcmd));\n \n \treturn fn(argc, argv, prefix);\n }\ndiff --git a/git.c b/git.c\nindex b1b7e1a837e..2bca22cfd9a 100644\n--- a/git.c\n+++ b/git.c\n@@ -610,7 +610,7 @@ static struct cmd_struct commands[] = {\n \t{ \"stash\", cmd_stash, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"stripspace\", cmd_stripspace },\n-\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP },\n \t{ \"switch\", cmd_switch, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"symbolic-ref\", cmd_symbolic_ref, RUN_SETUP },\n \t{ \"tag\", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467242","messageId":"patch-v2-08.10-172b5865811-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 08/10] submodule tests: test \"git branch -t\" output and stderr","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:48Z","receivedAt":"2022-11-14T10:10:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"git branch\" command will currently make use of the\n\"--super-prefix\", as it will indirectly call submodule_move_head(),\nwhich will have access to the \"--super-prefix\".\n\nThe output could thus be affected by the \"--super-prefix\". Right now\nit isn't in this case, but let's exhaustively assert that that's the\ncase by testing the output of all of these \"git branch -t\" commands.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-submodule-update.sh | 98 ++++++++++++++++++++++-----------------\n 1 file changed, 55 insertions(+), 43 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 2d31fcfda1f..302d095ad9b 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -245,6 +245,17 @@ reset_work_tree_to_interested () {\n \tgit -C submodule_update/.git/modules/sub1 config submodule.sub2.url \"bogus\"\n }\n \n+test_branch_t_output () {\n+\tlocal branchname=\"$1\" &&\n+\tlocal start_point=\"$2\" &&\n+\tcat >expect <<-EOF &&\n+\tbranch '$branchname' set up to track '$start_point'.\n+\tEOF\n+\tgit branch -t \"$branchname\" \"$start_point\" >actual 2>err &&\n+\ttest_must_be_empty err &&\n+\ttest_cmp expect actual\n+}\n+\n # Test that the superproject contains the content according to commit \"$1\"\n # (the work tree must match the index for everything but submodules but the\n # index must exactly match the given commit including any submodule SHA-1s).\n@@ -323,7 +334,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -345,7 +356,7 @@ test_submodule_switch_common () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tmkdir sub1 &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -360,7 +371,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to replace_sub1_with_file &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\ttest_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&\n \t\t\t$command replace_file_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -384,7 +395,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to replace_sub1_with_directory &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\ttest_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n \t\t\t$command replace_directory_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -406,7 +417,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n \t\t\t$command remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -418,7 +429,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\t$command remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n@@ -447,7 +458,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -459,7 +470,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\t$command replace_sub1_with_directory test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -474,7 +485,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -487,7 +498,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\t$command replace_sub1_with_file test_must_fail &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -512,7 +523,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\t$command modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n@@ -527,7 +538,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\ttest_branch_t_output invalid_sub1 origin/invalid_sub1 &&\n \t\t\t$command invalid_sub1 &&\n \t\t\ttest_superproject_content origin/invalid_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n@@ -542,7 +553,7 @@ test_submodule_switch_common () {\n \t\treset_work_tree_to invalid_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\ttest_branch_t_output valid_sub1 origin/valid_sub1 &&\n \t\t\t$command valid_sub1 &&\n \t\t\ttest_superproject_content origin/valid_sub1 &&\n \t\t\ttest_dir_is_empty sub1 &&\n@@ -596,7 +607,7 @@ test_submodule_switch_func () {\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t>sub1 &&\n \t\t\t$command add_sub1 test_must_fail &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n@@ -635,7 +646,7 @@ test_submodule_forced_switch () {\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t>sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -675,7 +686,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -688,7 +699,7 @@ test_submodule_recursing_with_args_common () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tmkdir sub1 &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/add_sub1\n@@ -701,7 +712,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested replace_sub1_with_file &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\ttest_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&\n \t\t\t$command replace_file_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n@@ -713,19 +724,20 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested replace_sub1_with_directory &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\ttest_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n \t\t\t$command replace_directory_with_sub1 &&\n \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n \t\t)\n \t'\n+\n \t# Switching to a commit with nested submodules recursively checks them out\n \ttest_expect_success \"$command: nested submodules are checked out\" '\n \t\tprolog &&\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1_recursively origin/modify_sub1_recursively &&\n+\t\t\ttest_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&\n \t\t\t$command modify_sub1_recursively &&\n \t\t\ttest_superproject_content origin/modify_sub1_recursively &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1_recursively &&\n@@ -740,7 +752,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n \t\t\t$command remove_sub1 &&\n \t\t\ttest_superproject_content origin/remove_sub1 &&\n \t\t\t! test -e sub1 &&\n@@ -753,7 +765,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\trm -rf .git/modules &&\n \t\t\t$command remove_sub1 &&\n@@ -769,7 +781,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\t$command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/replace_sub1_with_file &&\n \t\t\ttest -f sub1\n@@ -786,7 +798,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\t: >sub1/untrackedfile &&\n \t\t\ttest_must_fail $command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -801,7 +813,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_nested_sub &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t no_submodule origin/no_submodule &&\n+\t\t\ttest_branch_t_output no_submodule origin/no_submodule &&\n \t\t\t$command no_submodule &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n \t\t\t! test_path_is_dir sub1 &&\n@@ -817,7 +829,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\t$command modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1\n@@ -830,7 +842,7 @@ test_submodule_recursing_with_args_common () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\ttest_branch_t_output invalid_sub1 origin/invalid_sub1 &&\n \t\t\ttest_must_fail $command invalid_sub1 2>err &&\n \t\t\ttest_i18ngrep sub1 err &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -844,13 +856,13 @@ test_submodule_recursing_with_args_common () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit -C sub1 checkout -b keep_branch &&\n-\t\t\tgit -C sub1 rev-parse HEAD >expect &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\tgit -C sub1 rev-parse HEAD >expect.rev-parse &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\t$command modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1 &&\n \t\t\tgit -C sub1 rev-parse keep_branch >actual &&\n-\t\t\ttest_cmp expect actual &&\n+\t\t\ttest_cmp expect.rev-parse actual &&\n \t\t\ttest_must_fail git -C sub1 symbolic-ref HEAD\n \t\t)\n \t'\n@@ -894,7 +906,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t: >sub1 &&\n \t\t\ttest_must_fail $command add_sub1 &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n@@ -908,7 +920,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t: >sub1 &&\n \t\t\tmkdir .git/info &&\n \t\t\techo sub1 >.git/info/exclude &&\n@@ -925,7 +937,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\t$command replace_sub1_with_directory &&\n \t\t\ttest_superproject_content origin/replace_sub1_with_directory &&\n \t\t\ttest_submodule_content sub1 origin/replace_sub1_with_directory\n@@ -937,7 +949,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\trm -rf .git/modules &&\n \t\t\t$command replace_sub1_with_directory &&\n@@ -954,7 +966,7 @@ test_submodule_switch_recursing_with_args () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\trm -rf .git/modules/sub1/info &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\tmkdir .git/modules/sub1/info &&\n \t\t\techo ignored >.git/modules/sub1/info/exclude &&\n \t\t\t: >sub1/ignored &&\n@@ -969,7 +981,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\tgit -c submodule.recurse=true $cmd_args modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1\n@@ -981,7 +993,7 @@ test_submodule_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_nested_sub &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1_recursively origin/modify_sub1_recursively &&\n+\t\t\ttest_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&\n \t\t\t$command modify_sub1_recursively &&\n \t\t\ttest_superproject_content origin/modify_sub1_recursively &&\n \t\t\ttest_submodule_content sub1 origin/modify_sub1_recursively &&\n@@ -1009,7 +1021,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested no_submodule &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n \t\t\t>sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n@@ -1023,7 +1035,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\t$command replace_sub1_with_directory &&\n \t\t\ttest_superproject_content origin/replace_sub1_with_directory\n \t\t)\n@@ -1034,7 +1046,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n \t\t\treplace_gitfile_with_git_dir sub1 &&\n \t\t\trm -rf .git/modules/sub1 &&\n \t\t\t$command replace_sub1_with_directory &&\n@@ -1049,7 +1061,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n \t\t\t: >sub1/expect &&\n \t\t\t$command replace_sub1_with_file &&\n \t\t\ttest_superproject_content origin/replace_sub1_with_file\n@@ -1062,7 +1074,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested invalid_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\ttest_branch_t_output valid_sub1 origin/valid_sub1 &&\n \t\t\t$command valid_sub1 &&\n \t\t\ttest_superproject_content origin/valid_sub1 &&\n \t\t\ttest_submodule_content sub1 origin/valid_sub1\n@@ -1077,7 +1089,7 @@ test_submodule_forced_switch_recursing_with_args () {\n \t\treset_work_tree_to_interested add_sub1 &&\n \t\t(\n \t\t\tcd submodule_update &&\n-\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n \t\t\techo \"gitdir: bogus/path\" >sub1/.git &&\n \t\t\t$command modify_sub1 &&\n \t\t\ttest_superproject_content origin/modify_sub1 &&\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467243","messageId":"patch-v2-10.10-100ba36dfb7-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 10/10] fetch: rename \"--submodule-prefix\" to \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:50Z","receivedAt":"2022-11-14T10:10:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In preceding commits we've introduced a command-level \"--super-prefix\"\noption, which unlike the \"git --super-prefix\" it replaced doesn't rely\non setenv() or getenv(), it's just a normal command-line option that\nthe command passes down.\n\nSince we've done that, let's rename the \"--submodule-prefix\" option\nadded in 7dce19d374a (fetch/pull: Add the --recurse-submodules option,\n2010-11-12) to \"--super-prefix\" for consistency. This:\n\n * Allows us to use OPT__SUPER_PREFIX().\n * Leaves an unspecified \"--super-prefix\" with a \"NULL\" value, rather\n   than an empty string, as is the case with the other \"--super-prefix\"\n   users. We coerce the NULL to \"\" in submodule.c before using it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/fetch-options.txt |  5 -----\n builtin/fetch.c                 |  7 +++----\n submodule.c                     | 23 +++++++++++------------\n 3 files changed, 14 insertions(+), 21 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 622bd84768b..20cbd2c2910 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -241,11 +241,6 @@ endif::git-pull[]\n \tlinkgit:git-config[1].\n \n ifndef::git-pull[]\n---submodule-prefix=<path>::\n-\tPrepend <path> to paths printed in informative messages\n-\tsuch as \"Fetching submodule foo\".  This option is used\n-\tinternally when recursing over submodules.\n-\n --recurse-submodules-default=[yes|on-demand]::\n \tThis option is used internally to temporarily provide a\n \tnon-negative default value for the --recurse-submodules\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 7378cafeec9..353bcd36d24 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -74,7 +74,7 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;\n static struct strbuf default_rla = STRBUF_INIT;\n static struct transport *gtransport;\n static struct transport *gsecondary;\n-static const char *submodule_prefix = \"\";\n+static const char *super_prefix;\n static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;\n static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;\n@@ -195,8 +195,7 @@ static struct option builtin_fetch_options[] = {\n \tOPT_SET_INT_F(0, \"refetch\", &refetch,\n \t\t      N_(\"re-fetch without negotiating common commits\"),\n \t\t      1, PARSE_OPT_NONEG),\n-\t{ OPTION_STRING, 0, \"submodule-prefix\", &submodule_prefix, N_(\"dir\"),\n-\t\t   N_(\"prepend this to submodule path output\"), PARSE_OPT_HIDDEN },\n+\tOPT__SUPER_PREFIX(&super_prefix),\n \tOPT_CALLBACK_F(0, \"recurse-submodules-default\",\n \t\t   &recurse_submodules_default, N_(\"on-demand\"),\n \t\t   N_(\"default for recursive fetching of submodules \"\n@@ -2300,7 +2299,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t\tadd_options_to_argv(&options);\n \t\tresult = fetch_submodules(the_repository,\n \t\t\t\t\t  &options,\n-\t\t\t\t\t  submodule_prefix,\n+\t\t\t\t\t  super_prefix,\n \t\t\t\t\t  recurse_submodules,\n \t\t\t\t\t  recurse_submodules_default,\n \t\t\t\t\t  verbosity < 0,\ndiff --git a/submodule.c b/submodule.c\nindex 5ac4e1b0568..1e4eee3492b 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1376,7 +1376,7 @@ struct submodule_parallel_fetch {\n \tint changed_count;\n \tstruct strvec args;\n \tstruct repository *r;\n-\tconst char *prefix;\n+\tconst char *super_prefix;\n \tint command_line_option;\n \tint default_option;\n \tint quiet;\n@@ -1567,7 +1567,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,\n \t\tif (task->repo) {\n \t\t\tif (!spf->quiet)\n \t\t\t\tstrbuf_addf(err, _(\"Fetching submodule %s%s\\n\"),\n-\t\t\t\t\t    spf->prefix, ce->name);\n+\t\t\t\t\t    spf->super_prefix, ce->name);\n \n \t\t\tspf->index_count++;\n \t\t\treturn task;\n@@ -1629,7 +1629,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,\n \t\tif (!spf->quiet)\n \t\t\tstrbuf_addf(err,\n \t\t\t\t    _(\"Fetching submodule %s%s at commit %s\\n\"),\n-\t\t\t\t    spf->prefix, task->sub->path,\n+\t\t\t\t    spf->super_prefix, task->sub->path,\n \t\t\t\t    find_unique_abbrev(cs_data->super_oid,\n \t\t\t\t\t\t       DEFAULT_ABBREV));\n \n@@ -1687,11 +1687,10 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n \t\t\tstrvec_pushv(&cp->args, task->git_args.v);\n \t\tstrvec_pushv(&cp->args, spf->args.v);\n \t\tstrvec_push(&cp->args, task->default_argv);\n-\t\tstrvec_push(&cp->args, \"--submodule-prefix\");\n+\t\tstrvec_push(&cp->args, \"--super-prefix\");\n \n-\t\tstrbuf_addf(&submodule_prefix, \"%s%s/\",\n-\t\t\t\t\t\tspf->prefix,\n-\t\t\t\t\t\ttask->sub->path);\n+\t\tstrbuf_addf(&submodule_prefix, \"%s%s/\", spf->super_prefix,\n+\t\t\t    task->sub->path);\n \t\tstrvec_push(&cp->args, submodule_prefix.buf);\n \t\t*task_cb = task;\n \n@@ -1707,7 +1706,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n \t\tspf->oid_fetch_tasks_nr--;\n \n \t\tstrbuf_addf(&submodule_prefix, \"%s%s/\",\n-\t\t\t    spf->prefix, task->sub->path);\n+\t\t\t    spf->super_prefix, task->sub->path);\n \n \t\tchild_process_init(cp);\n \t\tprepare_submodule_repo_env_in_gitdir(&cp->env);\n@@ -1717,7 +1716,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n \t\tstrvec_init(&cp->args);\n \t\tstrvec_pushv(&cp->args, spf->args.v);\n \t\tstrvec_push(&cp->args, \"on-demand\");\n-\t\tstrvec_push(&cp->args, \"--submodule-prefix\");\n+\t\tstrvec_push(&cp->args, \"--super-prefix\");\n \t\tstrvec_push(&cp->args, submodule_prefix.buf);\n \n \t\t/* NEEDSWORK: have get_default_remote from submodule--helper */\n@@ -1813,7 +1812,7 @@ static int fetch_finish(int retvalue, struct strbuf *err,\n \n int fetch_submodules(struct repository *r,\n \t\t     const struct strvec *options,\n-\t\t     const char *prefix, int command_line_option,\n+\t\t     const char *super_prefix, int command_line_option,\n \t\t     int default_option,\n \t\t     int quiet, int max_parallel_jobs)\n {\n@@ -1835,7 +1834,7 @@ int fetch_submodules(struct repository *r,\n \tspf.command_line_option = command_line_option;\n \tspf.default_option = default_option;\n \tspf.quiet = quiet;\n-\tspf.prefix = prefix;\n+\tspf.super_prefix = super_prefix ? super_prefix : \"\";\n \n \tif (!r->worktree)\n \t\tgoto out;\n@@ -1847,7 +1846,7 @@ int fetch_submodules(struct repository *r,\n \tfor (i = 0; i < options->nr; i++)\n \t\tstrvec_push(&spf.args, options->v[i]);\n \tstrvec_push(&spf.args, \"--recurse-submodules-default\");\n-\t/* default value, \"--submodule-prefix\" and its value are added later */\n+\t/* default value, \"--super-prefix\" and its value are added later */\n \n \tcalculate_changed_submodule_paths(r, &spf.changed_submodule_names);\n \tstring_list_sort(&spf.changed_submodule_names);\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467244","messageId":"patch-v2-09.10-9fdeab60773-20221114T100803Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v2 09/10] read-tree: add \"--super-prefix\" option, eliminate global","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:08:49Z","receivedAt":"2022-11-14T10:10:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" option to \"git\" was initially added in [1] for\nuse with \"ls-files\"[2], and shortly thereafter \"submodule--helper\"[3]\nand \"grep\"[4]. It wasn't until [5] that \"read-tree\" made use of it.\n\nAt the time [5] made sense, but since then we've made \"ls-files\"\nrecurse in-process in [6], \"grep\" in [7], and finally\n\"submodule--helper\" in the preceding commits.\n\nLet's also remove it from \"read-tree\", which allows us to remove the\noption to \"git\" itself.\n\nWe can do this because the only remaining user of it is the submodule\nAPI, which will now invoke \"read-tree\" with its new \"--super-prefix\"\noption. It will only do so when the \"submodule_move_head()\" function\nis called.\n\nThat \"submodule_move_head()\" function was then only invoked by\n\"read-tree\" itself, but now rather than setting an environment\nvariable to pass \"--super-prefix\" between cmd_read_tree() we:\n\n- Set a new \"super_prefix\" in \"struct unpack_trees_options\". The\n  \"super_prefixed()\" function in \"unpack-trees.c\" added in [5] will now\n  use this, rather than get_super_prefix() looking up the environment\n  variable we set earlier in the same process.\n\n- Add the same field to the \"struct checkout\", which is only needed to\n  ferry the \"super_prefix\" in the \"struct unpack_trees_options\" all the\n  way down to the \"entry.c\" callers of \"submodule_move_head()\".\n\n  Those calls which used the super prefix all originated in\n  \"cmd_read_tree()\". The only other caller is the \"unlink_entry()\"\n  caller in \"builtin/checkout.c\", which now passes a \"NULL\".\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)\n3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)\n4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)\n5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)\n6. 188dce131fa (ls-files: use repository object, 2017-06-22)\n7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git.txt       |  8 +-------\n builtin.h                   |  4 ----\n builtin/checkout.c          |  2 +-\n builtin/read-tree.c         |  1 +\n cache.h                     |  2 --\n entry.c                     | 12 ++++++------\n entry.h                     |  6 +++++-\n environment.c               | 13 -------------\n git.c                       | 37 +++++--------------------------------\n submodule.c                 | 27 +++++++++------------------\n submodule.h                 |  5 ++---\n t/t1001-read-tree-m-2way.sh |  2 +-\n t/t5616-partial-clone.sh    |  2 +-\n unpack-trees.c              | 23 +++++++++++++----------\n unpack-trees.h              |  1 +\n 15 files changed, 46 insertions(+), 99 deletions(-)\n\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 1d33e083ab8..f9a7a4554cd 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -13,8 +13,7 @@ SYNOPSIS\n     [--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>]\n+    [--config-env=<name>=<envvar>] <command> [<args>]\n \n DESCRIPTION\n -----------\n@@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use\n \tdetails.  Equivalent to setting the `GIT_NAMESPACE` environment\n \tvariable.\n \n---super-prefix=<path>::\n-\tCurrently for internal use only.  Set a prefix which gives a path from\n-\tabove a repository down to its root.  One use is to give submodules\n-\tcontext about the superproject that invoked it.\n-\n --bare::\n \tTreat the repository as a bare repository.  If GIT_DIR\n \tenvironment is not set, it is set to the current working\ndiff --git a/builtin.h b/builtin.h\nindex 8901a34d6bf..8264b7e5241 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -51,10 +51,6 @@\n  *\ton bare repositories.\n  *\tThis only makes sense when `RUN_SETUP` is also set.\n  *\n- * `SUPPORT_SUPER_PREFIX`:\n- *\n- *\tThe built-in supports `--super-prefix`.\n- *\n  * `DELAY_PAGER_CONFIG`:\n  *\n  *\tIf RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2a132392fbe..dc008fb45e8 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -231,7 +231,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n \t\tpos++;\n \t}\n \tif (!overlay_mode) {\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, NULL);\n \t\treturn 0;\n \t}\n \tif (stage == 2)\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex f4cbe460b97..4b6f22e58c1 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)\n \tint prefix_set = 0;\n \tstruct lock_file lock_file = LOCK_INIT;\n \tconst struct option read_tree_options[] = {\n+\t\tOPT__SUPER_PREFIX(&opts.super_prefix),\n \t\tOPT_CALLBACK_F(0, \"index-output\", NULL, N_(\"file\"),\n \t\t  N_(\"write resulting index to <file>\"),\n \t\t  PARSE_OPT_NONEG, index_output_cb),\ndiff --git a/cache.h b/cache.h\nindex 26ed03bd6de..a4a0377b800 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)\n #define GIT_NAMESPACE_ENVIRONMENT \"GIT_NAMESPACE\"\n #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n #define GIT_PREFIX_ENVIRONMENT \"GIT_PREFIX\"\n-#define GIT_SUPER_PREFIX_ENVIRONMENT \"GIT_INTERNAL_SUPER_PREFIX\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n@@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n int get_common_dir(struct strbuf *sb, const char *gitdir);\n const char *get_git_namespace(void);\n const char *strip_namespace(const char *namespaced_ref);\n-const char *get_super_prefix(void);\n const char *get_git_work_tree(void);\n \n /*\ndiff --git a/entry.c b/entry.c\nindex 616e4f073c1..971ab268714 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca\n \t\t\treturn error(\"cannot create submodule directory %s\", path);\n \t\tsub = submodule_from_ce(ce);\n \t\tif (sub)\n-\t\t\treturn submodule_move_head(ce->name,\n+\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\tNULL, oid_to_hex(&ce->oid),\n \t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\tbreak;\n@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t * no pathname to return.\n \t\t\t */\n \t\t\tBUG(\"Can't remove entry to a path\");\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, state->super_prefix);\n \t\treturn 0;\n \t}\n \n@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t\tif (!(st.st_mode & S_IFDIR))\n \t\t\t\t\tunlink_or_warn(ce->name);\n \n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\tNULL, oid_to_hex(&ce->oid), 0);\n \t\t\t} else\n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\t\"HEAD\", oid_to_hex(&ce->oid),\n \t\t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\t}\n@@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \treturn write_entry(ce, path.buf, ca, state, 0, nr_checkouts);\n }\n \n-void unlink_entry(const struct cache_entry *ce)\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)\n {\n \tconst struct submodule *sub = submodule_from_ce(ce);\n \tif (sub) {\n \t\t/* state.force is set at the caller. */\n-\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n+\t\tsubmodule_move_head(ce->name, super_prefix, \"HEAD\", NULL,\n \t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n \t}\n \tif (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)\ndiff --git a/entry.h b/entry.h\nindex 9be4659881e..2d4fbb88c8f 100644\n--- a/entry.h\n+++ b/entry.h\n@@ -8,6 +8,7 @@ struct checkout {\n \tstruct index_state *istate;\n \tconst char *base_dir;\n \tint base_dir_len;\n+\tconst char *super_prefix;\n \tstruct delayed_checkout *delayed_checkout;\n \tstruct checkout_metadata meta;\n \tunsigned force:1,\n@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);\n /*\n  * Unlink the last component and schedule the leading directories for\n  * removal, such that empty directories get removed.\n+ *\n+ * The \"super_prefix\" is either NULL, or the \"--super-prefix\" passed\n+ * down from \"read-tree\" et al.\n  */\n-void unlink_entry(const struct cache_entry *ce);\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);\n \n void *read_blob_entry(const struct cache_entry *ce, size_t *size);\n int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);\ndiff --git a/environment.c b/environment.c\nindex 18d042b467d..1ee3686fd8a 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -102,8 +102,6 @@ char *git_work_tree_cfg;\n \n static char *git_namespace;\n \n-static char *super_prefix;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {\n \tNO_REPLACE_OBJECTS_ENVIRONMENT,\n \tGIT_REPLACE_REF_BASE_ENVIRONMENT,\n \tGIT_PREFIX_ENVIRONMENT,\n-\tGIT_SUPER_PREFIX_ENVIRONMENT,\n \tGIT_SHALLOW_FILE_ENVIRONMENT,\n \tGIT_COMMON_DIR_ENVIRONMENT,\n \tNULL\n@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)\n \treturn NULL;\n }\n \n-const char *get_super_prefix(void)\n-{\n-\tstatic int initialized;\n-\tif (!initialized) {\n-\t\tsuper_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));\n-\t\tinitialized = 1;\n-\t}\n-\treturn super_prefix;\n-}\n-\n static int git_work_tree_initialized;\n \n /*\ndiff --git a/git.c b/git.c\nindex 2bca22cfd9a..00baaf23590 100644\n--- a/git.c\n+++ b/git.c\n@@ -14,9 +14,8 @@\n  * RUN_SETUP for reading from the configuration file.\n  */\n #define NEED_WORK_TREE\t\t(1<<3)\n-#define SUPPORT_SUPER_PREFIX\t(1<<4)\n-#define DELAY_PAGER_CONFIG\t(1<<5)\n-#define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n+#define DELAY_PAGER_CONFIG\t(1<<4)\n+#define NO_PARSEOPT\t\t(1<<5) /* parse-options is not used */\n \n struct cmd_struct {\n \tconst char *cmd;\n@@ -29,8 +28,7 @@ const char git_usage_string[] =\n \t   \"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\\n\"\n \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\\n\"\n \t   \"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\\n\"\n-\t   \"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\\n\"\n-\t   \"           <command> [<args>]\");\n+\t   \"           [--config-env=<name>=<envvar>] <command> [<args>]\");\n \n const char git_more_info_string[] =\n \tN_(\"'git help -a' and 'git help -g' list available subcommands and some\\n\"\n@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);\n \t\t\tif (envchanged)\n \t\t\t\t*envchanged = 1;\n-\t\t} else if (!strcmp(cmd, \"--super-prefix\")) {\n-\t\t\tif (*argc < 2) {\n-\t\t\t\tfprintf(stderr, _(\"no prefix given for --super-prefix\\n\" ));\n-\t\t\t\tusage(git_usage_string);\n-\t\t\t}\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n-\t\t\t(*argv)++;\n-\t\t\t(*argc)--;\n-\t\t} else if (skip_prefix(cmd, \"--super-prefix=\", &cmd)) {\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n \t\t} else if (!strcmp(cmd, \"--bare\")) {\n \t\t\tchar *cwd = xgetcwd();\n \t\t\tis_bare_repository_cfg = 1;\n@@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\ttrace_repo_setup(prefix);\n \tcommit_pager_choice();\n \n-\tif (!help && get_super_prefix()) {\n-\t\tif (!(p->option & SUPPORT_SUPER_PREFIX))\n-\t\t\tdie(_(\"%s doesn't support --super-prefix\"), p->cmd);\n-\t}\n-\n \tif (!help && p->option & NEED_WORK_TREE)\n \t\tsetup_work_tree();\n \n@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {\n \t{ \"check-ref-format\", cmd_check_ref_format, NO_PARSEOPT  },\n \t{ \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout--worker\", cmd_checkout__worker,\n-\t\tRUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },\n+\t\tRUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout-index\", cmd_checkout_index,\n \t\tRUN_SETUP | NEED_WORK_TREE},\n \t{ \"cherry\", cmd_cherry, RUN_SETUP },\n@@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n-\t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n \t{ \"rebase\", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n@@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tint status;\n \n-\tif (get_super_prefix())\n-\t\tdie(_(\"%s doesn't support --super-prefix\"), argv[0]);\n-\n \tif (use_pager == -1 && !is_builtin(argv[0]))\n \t\tuse_pager = check_pager_config(argv[0]);\n \tcommit_pager_choice();\n@@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)\n \t\t\t */\n \t\t\ttrace2_cmd_name(\"_run_git_alias_\");\n \n-\t\t\tif (get_super_prefix())\n-\t\t\t\tdie(\"%s doesn't support --super-prefix\", **argv);\n-\n \t\t\tcommit_pager_choice();\n \n \t\t\tstrvec_push(&cmd.args, \"git\");\ndiff --git a/submodule.c b/submodule.c\nindex d9fd0af81b6..5ac4e1b0568 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2048,14 +2048,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)\n \tstrbuf_release(&config_path);\n }\n \n-static const char *get_super_prefix_or_empty(void)\n-{\n-\tconst char *s = get_super_prefix();\n-\tif (!s)\n-\t\ts = \"\";\n-\treturn s;\n-}\n-\n static int submodule_has_dirty_index(const struct submodule *sub)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2074,7 +2066,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)\n \treturn finish_command(&cp);\n }\n \n-static void submodule_reset_index(const char *path)\n+static void submodule_reset_index(const char *path, const char *super_prefix)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tprepare_submodule_repo_env(&cp.env);\n@@ -2083,10 +2075,10 @@ static void submodule_reset_index(const char *path)\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \t/* TODO: determine if this might overwright untracked files */\n \tstrvec_pushl(&cp.args, \"read-tree\", \"-u\", \"--reset\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tstrvec_push(&cp.args, empty_tree_oid_hex());\n \n@@ -2099,10 +2091,9 @@ static void submodule_reset_index(const char *path)\n  * For edge cases (a submodule coming into existence or removing a submodule)\n  * pass NULL for old or new respectively.\n  */\n-int submodule_move_head(const char *path,\n-\t\t\t const char *old_head,\n-\t\t\t const char *new_head,\n-\t\t\t unsigned flags)\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n+\t\t\tunsigned flags)\n {\n \tint ret = 0;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2148,7 +2139,7 @@ int submodule_move_head(const char *path,\n \t\t\tstrbuf_release(&gitdir);\n \n \t\t\t/* make sure the index is clean as well */\n-\t\t\tsubmodule_reset_index(path);\n+\t\t\tsubmodule_reset_index(path, NULL);\n \t\t}\n \n \t\tif (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {\n@@ -2166,9 +2157,9 @@ int submodule_move_head(const char *path,\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \tstrvec_pushl(&cp.args, \"read-tree\", \"--recurse-submodules\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tif (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)\n \t\tstrvec_push(&cp.args, \"-n\");\ndiff --git a/submodule.h b/submodule.h\nindex e5ee13fb06a..36a7f7c5b32 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);\n \n #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)\n #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)\n-int submodule_move_head(const char *path,\n-\t\t\tconst char *old,\n-\t\t\tconst char *new_head,\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n \t\t\tunsigned flags);\n \n void submodule_unset_core_worktree(const struct submodule *sub);\ndiff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh\nindex 516a6112fdc..3fb1b0c162d 100755\n--- a/t/t1001-read-tree-m-2way.sh\n+++ b/t/t1001-read-tree-m-2way.sh\n@@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '\n \tcat <<-EOF >expect &&\n \t\terror: Updating '\\''fictional/a'\\'' would lose untracked files in it\n \tEOF\n-\ttest_must_fail git --super-prefix fictional/ read-tree -u -m \"$treeH\" \"$treeM\" 2>actual &&\n+\ttest_must_fail git read-tree --super-prefix fictional/ -u -m \"$treeH\" \"$treeM\" 2>actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex e56466580cf..18375bff535 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -644,7 +644,7 @@ test_expect_success 'repack does not loosen promisor objects' '\n \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n '\n \n-test_expect_failure 'lazy-fetch in submodule succeeds' '\n+test_expect_success 'lazy-fetch in submodule succeeds' '\n \t# setup\n \ttest_config_global protocol.file.allow always &&\n \ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex bae812156c4..61c02285454 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {\n \t  ? ((o)->msgs[(type)])      \\\n \t  : (unpack_plumbing_errors[(type)]) )\n \n-static const char *super_prefixed(const char *path)\n+static const char *super_prefixed(const char *path, const char *super_prefix)\n {\n \t/*\n \t * It is necessary and sufficient to have two static buffers\n@@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)\n \tstatic unsigned idx = ARRAY_SIZE(buf) - 1;\n \n \tif (super_prefix_len < 0) {\n-\t\tconst char *super_prefix = get_super_prefix();\n \t\tif (!super_prefix) {\n \t\t\tsuper_prefix_len = 0;\n \t\t} else {\n@@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,\n \t\treturn -1;\n \n \tif (!o->show_all_errors)\n-\t\treturn error(ERRORMSG(o, e), super_prefixed(path));\n+\t\treturn error(ERRORMSG(o, e), super_prefixed(path,\n+\t\t\t\t\t\t\t    o->super_prefix));\n \n \t/*\n \t * Otherwise, insert in a list for future display by\n@@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)\n \t\t\terror_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t     o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)\n \t\t\twarning_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t       o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,\n \tif (o->reset)\n \t\tflags |= SUBMODULE_MOVE_HEAD_FORCE;\n \n-\tif (submodule_move_head(ce->name, old_id, new_id, flags))\n+\tif (submodule_move_head(ce->name, NULL, old_id, new_id, flags))\n \t\treturn add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);\n \treturn 0;\n }\n@@ -415,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,\n \tint i, pc_workers, pc_threshold;\n \n \ttrace_performance_enter();\n+\tstate.super_prefix = o->super_prefix;\n \tstate.force = 1;\n \tstate.quiet = 1;\n \tstate.refresh_cache = 1;\n@@ -445,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,\n \n \t\tif (ce->ce_flags & CE_WT_REMOVE) {\n \t\t\tdisplay_progress(progress, ++cnt);\n-\t\t\tunlink_entry(ce);\n+\t\t\tunlink_entry(ce, o->super_prefix);\n \t\t}\n \t}\n \n@@ -2958,8 +2961,8 @@ int bind_merge(const struct cache_entry * const *src,\n \tif (a && old)\n \t\treturn o->quiet ? -1 :\n \t\t\terror(ERRORMSG(o, ERROR_BIND_OVERLAP),\n-\t\t\t      super_prefixed(a->name),\n-\t\t\t      super_prefixed(old->name));\n+\t\t\t      super_prefixed(a->name, o->super_prefix),\n+\t\t\t      super_prefixed(old->name, o->super_prefix));\n \tif (!a)\n \t\treturn keep_entry(old, o);\n \telse\n@@ -3020,7 +3023,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,\n \n \tif (worktree && untracked)\n \t\treturn error(_(\"worktree and untracked commit have duplicate entries: %s\"),\n-\t\t\t     super_prefixed(worktree->name));\n+\t\t\t     super_prefixed(worktree->name, o->super_prefix));\n \n \treturn merged_entry(worktree ? worktree : untracked, NULL, o);\n }\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex efb9edfbb27..9b81e284073 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -74,6 +74,7 @@ struct unpack_trees_options {\n \t\t     dry_run;\n \tenum unpack_trees_reset_type reset;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint cache_bottom;\n \tstruct pathspec *pathspec;\n \tmerge_fn_t fn;\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467245","messageId":"221114.86y1sdlq2d.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6lsfip0yfx.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T10:09:18Z","receivedAt":"2022-11-14T11:43:14Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Nov 11 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> On Fri, Nov 11 2022, Glen Choo wrote:\n>>\n>>> Glen Choo <chooglen@google.com> writes:\n>>>\n>>>> Rereading this series and thinking about this some more, let's go with\n>>>> your approach, primarily because it avoids global state.\n>>>>\n>>>> From this series, it seems that it's not that hard to make this change\n>>>> and support whatever use cases we currently have.\n>>>>\n>>>> This does make it more tedious to add more \"--super-prefix\" in the\n>>>> future, but that's a good push for us to do more things in-process\n>>>> and/or be more principled about passing context objects through the call\n>>>> stack instead of relying on globals.\n>>>>\n>>>> Let me know what I can add to this effort besides reviewing :)\n>>>\n>>> Specifically, if you have other things on your plate, I'd be happy to\n>>> pick up where where this RFC has left off.\n>>\n>> I was going to get around to re-rolling this in the next few days, but\n>> I'd also be happy to have you beat me to it.\n>\n> Ah, well, I didn't mean that I was planning to work on this over the\n> weekend, but I can certainly get to it on Monday. I meant something\n> closer to \"If you didn't want to think about git-submodule.sh for the\n> next week or so, I can pick this up\".\n>\n> Alternatively, I think it also makes sense if you want to reroll only\n> the submodule--helper bits (1-7/8) to unblock your git-submodule.sh\n> work, and I can prepare the rest of the \"nuke --super-prefix\" stuff on\n> top of that. That should save you a context switch, and since I sent out\n> [1], nuking --super-prefix shouldn't be urgent.\n>\n> If you don't really care any which way, I'll just re-roll this :)\n>\n> [1] https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com\n\nI just re-rolled it at\nhttps://lore.kernel.org/git/cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com/;\nMainly because I think just going for the \"read-tree\" fix directly instead of:\n\n 1. Adding --super-prefix to \"fetch\" first, and reviewing any new\n    side-effects that may have (i.e. your PR above).\n 2. Concurrently, just the \"submodule--helper\" part of this RFC\n 3. Finally, the \"read-tree\" part, and getting rid of \"git\n    --super-prefix\", which would need to depend on both #1 and #2 above.\n\nWill involve too much avoidable juggling, when getting rid of the global\ndirectly isn't too hard to reason about, in which case we can skip #1\nentirely.\n\nLet me know what you think...\n\n> Yeah, this plan makes sense. One thing I'd add is that I'd also use\n> OPT__SUPER_PREFIX to handle \"git fetch --submodule-prefix\".\n\nAs noted in the CL above I included this because I see you're keen to\ninclude it, but I'm personally a bit \"meh\" on it. I.e. it's just\nrenaming an existing unrelated option, although being able to use\nOPT__SUPER_PREFIX() makes it slightly nicer.\n\nAs post-cleanups go I think removing the \"submodule_prefix\" from the\n\"struct repository\" would make more sense, and maybe it's worth peeling\noff the 10/10 to include in such a post-cleanup series? I.e. the below\non top of all of this works, and reduces allocations and cargo-culting\naround the submodule API.\n\n-- >8 --\nSubject: [PATCH] repo & submodule API: stop carrying \"repo->submodule_prefix\"\n\nAs this change shows the \"submodule_prefix\" field to \"struct\nrepository\" added in 96dc883b3cd (repository: enable initialization of\nsubmodules, 2017-06-22) was only used by \"ls-files\" and \"grep\". Let's\nhave those two carry forward the \"super_prefix\" instead.\n\nHaving every user of \"struct repository\" needing to worry about this\ncreated a mismatch in the API where e.g. \"grep\" would re-compute a\n\"name_base_len\" which we knew before. Now we use a \"struct strbuf\" in\nthe \"struct grep_opt\" there instead, so we'll know the length\nalready. This simplifies \"grep_cache()\" and \"grep_tree()\".\n\nWe're also deleting cargo-culted code that the previous API foisted\nupon us. In 605f0ec1350 (submodule: use submodule repos for object\nlookup, 2018-12-14) the \"Mark it as a submodule\" code was added to\n\"open_submodule()\", but the resulting xstrdup()'d \"submodule_prefix\"\nwas never used by anything.\n\nStill, removing this field might not be a good move, as the\n\"super_prefix\" might be a common enough case in the future, e.g. when\neventually migrating the \"submodule--helper\" users[1] to run\nin-process.\n\nAs the \"grep\" example demonstrates I don't think that's the\ncase. There instead of xstrdup()-ing all the way down we're now\ncarrying a single \"super_prefix\" in the form of a \"struct strbuf\". As\nwe recurse we then append to it, and strbuf_setlen() it back when we\nwe recurse out of that submodule. This is similar to how e.g. the\n\"read_tree_at()\" API works.\n\nDoing it that way means that we have just one allocation, which in the\ncommon case we might realloc() if we don't have enough room in the\n\"struct strbuf\".\n\n1. https://lore.kernel.org/git/cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com/\n2. https://github.com/avar/git/tree/avar/grep-post-drop-prefix-cleanup\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c     | 18 ++++++++----------\n builtin/ls-files.c | 40 +++++++++++++++++++++++++---------------\n grep.c             |  6 +++---\n grep.h             |  2 ++\n repository.c       |  7 -------\n repository.h       |  7 -------\n submodule.c        |  3 ---\n 7 files changed, 38 insertions(+), 45 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5fa927d4e22..69826daba26 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -437,6 +437,7 @@ static int grep_submodule(struct grep_opt *opt,\n \tstruct repository *superproject = opt->repo;\n \tstruct grep_opt subopt;\n \tint hit = 0;\n+\tsize_t oldlen = opt->super_prefix.len;\n \n \tif (!is_submodule_active(superproject, path))\n \t\treturn 0;\n@@ -497,6 +498,7 @@ static int grep_submodule(struct grep_opt *opt,\n \tadd_submodule_odb_by_path(subrepo->objects->odb->path);\n \tobj_read_unlock();\n \n+\tstrbuf_addf(&opt->super_prefix, \"%s/\", path);\n \tmemcpy(&subopt, opt, sizeof(subopt));\n \tsubopt.repo = subrepo;\n \n@@ -527,6 +529,7 @@ static int grep_submodule(struct grep_opt *opt,\n \t} else {\n \t\thit = grep_cache(&subopt, pathspec, cached);\n \t}\n+\tstrbuf_setlen(&opt->super_prefix, oldlen);\n \n \treturn hit;\n }\n@@ -538,11 +541,8 @@ static int grep_cache(struct grep_opt *opt,\n \tint hit = 0;\n \tint nr;\n \tstruct strbuf name = STRBUF_INIT;\n-\tint name_base_len = 0;\n-\tif (repo->submodule_prefix) {\n-\t\tname_base_len = strlen(repo->submodule_prefix);\n-\t\tstrbuf_addstr(&name, repo->submodule_prefix);\n-\t}\n+\tsize_t name_base_len = opt->super_prefix.len;\n+\tstrbuf_addbuf(&name, &opt->super_prefix);\n \n \tif (repo_read_index(repo) < 0)\n \t\tdie(_(\"index file corrupt\"));\n@@ -618,11 +618,9 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \tstruct name_entry entry;\n \tint old_baselen = base->len;\n \tstruct strbuf name = STRBUF_INIT;\n-\tint name_base_len = 0;\n-\tif (repo->submodule_prefix) {\n-\t\tstrbuf_addstr(&name, repo->submodule_prefix);\n-\t\tname_base_len = name.len;\n-\t}\n+\tsize_t name_base_len = opt->super_prefix.len;\n+\n+\tstrbuf_addbuf(&name, &opt->super_prefix);\n \n \twhile (tree_entry(tree, &entry)) {\n \t\tint te_len = tree_entry_len(&entry);\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 4cf8a236483..c76a6be2fbe 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -216,10 +216,12 @@ static void show_killed_files(struct index_state *istate,\n \t}\n }\n \n-static void show_files(struct repository *repo, struct dir_struct *dir);\n+static void show_files(struct repository *repo, struct dir_struct *dir,\n+\t\t       const char *super_prefix);\n \n static void show_submodule(struct repository *superproject,\n-\t\t\t   struct dir_struct *dir, const char *path)\n+\t\t\t   struct dir_struct *dir, const char *path,\n+\t\t\t   const char *super_prefix)\n {\n \tstruct repository subrepo;\n \n@@ -229,7 +231,7 @@ static void show_submodule(struct repository *superproject,\n \tif (repo_read_index(&subrepo) < 0)\n \t\tdie(\"index file corrupt\");\n \n-\tshow_files(&subrepo, dir);\n+\tshow_files(&subrepo, dir, super_prefix);\n \n \trepo_clear(&subrepo);\n }\n@@ -303,14 +305,19 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,\n \n static void show_ce(struct repository *repo, struct dir_struct *dir,\n \t\t    const struct cache_entry *ce, const char *fullname,\n-\t\t    const char *tag)\n+\t\t    const char *tag, const char *super_prefix)\n {\n \tif (max_prefix_len > strlen(fullname))\n \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n \n \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n \t    is_submodule_active(repo, ce->name)) {\n-\t\tshow_submodule(repo, dir, ce->name);\n+\t\tstruct strbuf sp = STRBUF_INIT;\n+\n+\t\tstrbuf_addf(&sp, \"%s%s/\", super_prefix ? super_prefix : \"\",\n+\t\t\t    ce->name);\n+\t\tshow_submodule(repo, dir, ce->name, sp.buf);\n+\t\tstrbuf_release(&sp);\n \t} else if (match_pathspec(repo->index, &pathspec, fullname, strlen(fullname),\n \t\t\t\t  max_prefix_len, ps_matched,\n \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n@@ -374,16 +381,17 @@ static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n \treturn is_excluded(dir, istate, fullname, &dtype);\n }\n \n-static void construct_fullname(struct strbuf *out, const struct repository *repo,\n-\t\t\t       const struct cache_entry *ce)\n+static void construct_fullname(struct strbuf *out, const struct cache_entry *ce,\n+\t\t\t       const char *super_prefix)\n {\n \tstrbuf_reset(out);\n-\tif (repo->submodule_prefix)\n-\t\tstrbuf_addstr(out, repo->submodule_prefix);\n+\tif (super_prefix)\n+\t\tstrbuf_addstr(out, super_prefix);\n \tstrbuf_addstr(out, ce->name);\n }\n \n-static void show_files(struct repository *repo, struct dir_struct *dir)\n+static void show_files(struct repository *repo, struct dir_struct *dir,\n+\t\t       const char *super_prefix)\n {\n \tint i;\n \tstruct strbuf fullname = STRBUF_INIT;\n@@ -410,7 +418,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir)\n \t\tstruct stat st;\n \t\tint stat_err;\n \n-\t\tconstruct_fullname(&fullname, repo, ce);\n+\t\tconstruct_fullname(&fullname, ce, super_prefix);\n \n \t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n \t\t\t!ce_excluded(dir, repo->index, fullname.buf, ce))\n@@ -422,7 +430,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir)\n \t\t\tshow_ce(repo, dir, ce, fullname.buf,\n \t\t\t\tce_stage(ce) ? tag_unmerged :\n \t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree :\n-\t\t\t\t tag_cached));\n+\t\t\t\t tag_cached), super_prefix);\n \t\t\tif (skipping_duplicates)\n \t\t\t\tgoto skip_to_next_name;\n \t\t}\n@@ -435,13 +443,15 @@ static void show_files(struct repository *repo, struct dir_struct *dir)\n \t\tif (stat_err && (errno != ENOENT && errno != ENOTDIR))\n \t\t\terror_errno(\"cannot lstat '%s'\", fullname.buf);\n \t\tif (stat_err && show_deleted) {\n-\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed);\n+\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed,\n+\t\t\t\tsuper_prefix);\n \t\t\tif (skipping_duplicates)\n \t\t\t\tgoto skip_to_next_name;\n \t\t}\n \t\tif (show_modified &&\n \t\t    (stat_err || ie_modified(repo->index, ce, &st, 0))) {\n-\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified);\n+\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified,\n+\t\t\t\tsuper_prefix);\n \t\t\tif (skipping_duplicates)\n \t\t\t\tgoto skip_to_next_name;\n \t\t}\n@@ -874,7 +884,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\toverlay_tree_on_index(the_repository->index, with_tree, max_prefix);\n \t}\n \n-\tshow_files(the_repository, &dir);\n+\tshow_files(the_repository, &dir, NULL);\n \n \tif (show_resolve_undo)\n \t\tshow_ru_info(the_repository->index);\ndiff --git a/grep.c b/grep.c\nindex 06eed694936..10d52219229 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -791,9 +791,9 @@ void free_grep_patterns(struct grep_opt *opt)\n \t\tfree(p);\n \t}\n \n-\tif (!opt->pattern_expression)\n-\t\treturn;\n-\tfree_pattern_expr(opt->pattern_expression);\n+\tif (opt->pattern_expression)\n+\t\tfree_pattern_expr(opt->pattern_expression);\n+\tstrbuf_release(&opt->super_prefix);\n }\n \n static const char *end_of_line(const char *cp, unsigned long *left)\ndiff --git a/grep.h b/grep.h\nindex 6075f997e68..d353bfa21ce 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -133,6 +133,7 @@ struct grep_opt {\n \t * t7814-grep-recurse-submodules.sh for more information.\n \t */\n \tstruct repository *repo;\n+\tstruct strbuf super_prefix;\n \n \tint linenum;\n \tint columnnum;\n@@ -178,6 +179,7 @@ struct grep_opt {\n };\n \n #define GREP_OPT_INIT { \\\n+\t.super_prefix = STRBUF_INIT, \\\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\ndiff --git a/repository.c b/repository.c\nindex 5d166b692c8..2f8581c517d 100644\n--- a/repository.c\n+++ b/repository.c\n@@ -228,12 +228,6 @@ int repo_submodule_init(struct repository *subrepo,\n \t\t\tgoto out;\n \t\t}\n \t}\n-\n-\tsubrepo->submodule_prefix = xstrfmt(\"%s%s/\",\n-\t\t\t\t\t    superproject->submodule_prefix ?\n-\t\t\t\t\t    superproject->submodule_prefix :\n-\t\t\t\t\t    \"\", path);\n-\n out:\n \tstrbuf_release(&gitdir);\n \tstrbuf_release(&worktree);\n@@ -261,7 +255,6 @@ void repo_clear(struct repository *repo)\n \tFREE_AND_NULL(repo->graft_file);\n \tFREE_AND_NULL(repo->index_file);\n \tFREE_AND_NULL(repo->worktree);\n-\tFREE_AND_NULL(repo->submodule_prefix);\n \n \traw_object_store_clear(repo->objects);\n \tFREE_AND_NULL(repo->objects);\ndiff --git a/repository.h b/repository.h\nindex 6c461c5b9de..a08da26133c 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -120,13 +120,6 @@ struct repository {\n \t */\n \tchar *worktree;\n \n-\t/*\n-\t * Path from the root of the top-level superproject down to this\n-\t * repository.  This is only non-NULL if the repository is initialized\n-\t * as a submodule of another repository.\n-\t */\n-\tchar *submodule_prefix;\n-\n \tstruct repo_settings settings;\n \n \t/* Subsystems */\ndiff --git a/submodule.c b/submodule.c\nindex 1e4eee3492b..1c5ef904a03 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -528,9 +528,6 @@ static struct repository *open_submodule(const char *path)\n \t\treturn NULL;\n \t}\n \n-\t/* Mark it as a submodule */\n-\tout->submodule_prefix = xstrdup(path);\n-\n \tstrbuf_release(&sb);\n \treturn out;\n }\n-- \n2.38.0.1471.ge4d8947e7aa\n\n"},{"id":"467258","messageId":"kl6lo7t91hvd.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v2-01.10-1114a4ff666-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 01/10] read-tree + fetch tests: test failing \"--super-prefix\" interaction","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T19:00:22Z","receivedAt":"2022-11-14T19:00:31Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> From: Glen Choo <chooglen@google.com>\n>\n> Ever since \"git fetch --refetch\" was introduced in 0f5e8851737 (Merge\n> branch 'rc/fetch-refetch', 2022-04-04) the test being added here would\n> fail. This is because \"restore\" will \"read-tree .. --reset <hash>\",\n> which will in turn invoke \"fetch\". The \"fetch\" will then die with:\n>\n> \tfatal: fetch doesn't support --super-prefix\n>\n> This edge case and other \"--super-prefix\" bugs will be fixed in\n> subsequent commits, but let's first add a \"test_expect_failure\" test\n> for it. It passes until the very last command in the test.\n>\n> Signed-off-by: Glen Choo <chooglen@google.com>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++\n>  1 file changed, 43 insertions(+)\n>\n> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\n> index 037941b95d2..e56466580cf 100755\n> --- a/t/t5616-partial-clone.sh\n> +++ b/t/t5616-partial-clone.sh\n> @@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '\n>  \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n>  '\n>  \n> +test_expect_failure 'lazy-fetch in submodule succeeds' '\n> +\t# setup\n> +\ttest_config_global protocol.file.allow always &&\n> +\n> +\tgit init src-sub &&\n> +\tgit -C src-sub config uploadpack.allowfilter 1 &&\n> +\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n> +\n> +\t# This blob must be missing in the subsequent commit.\n> +\techo foo >src-sub/file &&\n> +\tgit -C src-sub add file &&\n> +\tgit -C src-sub commit -m \"submodule one\" &&\n> +\tSUB_ONE=$(git -C src-sub rev-parse HEAD) &&\n> +\n> +\techo bar >src-sub/file &&\n> +\tgit -C src-sub add file &&\n> +\tgit -C src-sub commit -m \"submodule two\" &&\n> +\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n> +\n> +\tgit init src-super &&\n> +\tgit -C src-super config uploadpack.allowfilter 1 &&\n> +\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n> +\tgit -C src-super submodule add ../src-sub src-sub &&\n> +\n> +\tgit -C src-super/src-sub checkout $SUB_ONE &&\n> +\tgit -C src-super add src-sub &&\n> +\tgit -C src-super commit -m \"superproject one\" &&\n> +\n> +\tgit -C src-super/src-sub checkout $SUB_TWO &&\n> +\tgit -C src-super add src-sub &&\n> +\tgit -C src-super commit -m \"superproject two\" &&\n> +\n> +\t# the fetch\n> +\ttest_when_finished \"rm -rf src-super src-sub client\" &&\n\n(Genuinely curious) are we okay with test_when_finished in the middle of\nthe test body instead of at the top?\n\n> +\n> +\ttest_config_global protocol.file.allow always &&\n\nWe have this exact same test_config_global line at the top of this test,\nso we can drop this one.\n\n> +\tgit clone --filter=blob:none --also-filter-submodules \\\n> +\t\t--recurse-submodules \"file://$(pwd)/src-super\" client &&\n> +\n> +\t# Trigger lazy-fetch from the superproject\n> +\tgit -C client restore --recurse-submodules --source=HEAD^ :/\n> +'\n> +\n>  . \"$TEST_DIRECTORY\"/lib-httpd.sh\n>  start_httpd\n>  \n> -- \n> 2.38.0.1471.ge4d8947e7aa\n"},{"id":"467259","messageId":"221114.86cz9pl4vn.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6lo7t91hvd.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v2 01/10] read-tree + fetch tests: test failing \"--super-prefix\" interaction","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-14T19:14:55Z","receivedAt":"2022-11-14T19:20:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Nov 14 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> From: Glen Choo <chooglen@google.com>\n>>\n>> Ever since \"git fetch --refetch\" was introduced in 0f5e8851737 (Merge\n>> branch 'rc/fetch-refetch', 2022-04-04) the test being added here would\n>> fail. This is because \"restore\" will \"read-tree .. --reset <hash>\",\n>> which will in turn invoke \"fetch\". The \"fetch\" will then die with:\n>>\n>> \tfatal: fetch doesn't support --super-prefix\n>>\n>> This edge case and other \"--super-prefix\" bugs will be fixed in\n>> subsequent commits, but let's first add a \"test_expect_failure\" test\n>> for it. It passes until the very last command in the test.\n>>\n>> Signed-off-by: Glen Choo <chooglen@google.com>\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> ---\n>>  t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++\n>>  1 file changed, 43 insertions(+)\n>>\n>> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\n>> index 037941b95d2..e56466580cf 100755\n>> --- a/t/t5616-partial-clone.sh\n>> +++ b/t/t5616-partial-clone.sh\n>> @@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '\n>>  \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n>>  '\n>>  \n>> +test_expect_failure 'lazy-fetch in submodule succeeds' '\n>> +\t# setup\n>> +\ttest_config_global protocol.file.allow always &&\n>> +\n>> +\tgit init src-sub &&\n>> +\tgit -C src-sub config uploadpack.allowfilter 1 &&\n>> +\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n>> +\n>> +\t# This blob must be missing in the subsequent commit.\n>> +\techo foo >src-sub/file &&\n>> +\tgit -C src-sub add file &&\n>> +\tgit -C src-sub commit -m \"submodule one\" &&\n>> +\tSUB_ONE=$(git -C src-sub rev-parse HEAD) &&\n>> +\n>> +\techo bar >src-sub/file &&\n>> +\tgit -C src-sub add file &&\n>> +\tgit -C src-sub commit -m \"submodule two\" &&\n>> +\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n>> +\n>> +\tgit init src-super &&\n>> +\tgit -C src-super config uploadpack.allowfilter 1 &&\n>> +\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n>> +\tgit -C src-super submodule add ../src-sub src-sub &&\n>> +\n>> +\tgit -C src-super/src-sub checkout $SUB_ONE &&\n>> +\tgit -C src-super add src-sub &&\n>> +\tgit -C src-super commit -m \"superproject one\" &&\n>> +\n>> +\tgit -C src-super/src-sub checkout $SUB_TWO &&\n>> +\tgit -C src-super add src-sub &&\n>> +\tgit -C src-super commit -m \"superproject two\" &&\n>> +\n>> +\t# the fetch\n>> +\ttest_when_finished \"rm -rf src-super src-sub client\" &&\n>\n> (Genuinely curious) are we okay with test_when_finished in the middle of\n> the test body instead of at the top?\n\nYeah, and it's not just supported, but preferred, usually we do:\n\n\ttest_when_finished \"rm -rf repo\" &&\n\tgit init repo &&\n\nSo at the top makes sense, but if there's a bunch of stuff we might fail\non first it makes sense not to attempt the cleanup.\n\nBut I see in this case the \"src-super\" part of it should be earlier, and\n\"src-sub\", but the \"client\" should be just before the clone below, don't\nknow how I missed that. Will fix.\n\n>> +\n>> +\ttest_config_global protocol.file.allow always &&\n>\n> We have this exact same test_config_global line at the top of this test,\n> so we can drop this one.\n\nDitto, thanks, I'll fix that. A mistake when combining the tests.\n\nYou had these as two tests, but one was mandatory setup for the other,\nand when making it test_expect_failure I wanted to have it atomic..\n"},{"id":"467260","messageId":"kl6lk03x1fld.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"221114.86cz9pl4vn.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v2 01/10] read-tree + fetch tests: test failing \"--super-prefix\" interaction","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T19:49:34Z","receivedAt":"2022-11-14T19:50:02Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Mon, Nov 14 2022, Glen Choo wrote:\n>\n>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>\n>>> From: Glen Choo <chooglen@google.com>\n>>>\n>>> Ever since \"git fetch --refetch\" was introduced in 0f5e8851737 (Merge\n>>> branch 'rc/fetch-refetch', 2022-04-04) the test being added here would\n>>> fail. This is because \"restore\" will \"read-tree .. --reset <hash>\",\n>>> which will in turn invoke \"fetch\". The \"fetch\" will then die with:\n>>>\n>>> \tfatal: fetch doesn't support --super-prefix\n>>>\n>>> This edge case and other \"--super-prefix\" bugs will be fixed in\n>>> subsequent commits, but let's first add a \"test_expect_failure\" test\n>>> for it. It passes until the very last command in the test.\n>>>\n>>> Signed-off-by: Glen Choo <chooglen@google.com>\n>>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>>> ---\n>>>  t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++\n>>>  1 file changed, 43 insertions(+)\n>>>\n>>> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\n>>> index 037941b95d2..e56466580cf 100755\n>>> --- a/t/t5616-partial-clone.sh\n>>> +++ b/t/t5616-partial-clone.sh\n>>> @@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '\n>>>  \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n>>>  '\n>>>  \n>>> +test_expect_failure 'lazy-fetch in submodule succeeds' '\n>>> +\t# setup\n>>> +\ttest_config_global protocol.file.allow always &&\n>>> +\n>>> +\tgit init src-sub &&\n>>> +\tgit -C src-sub config uploadpack.allowfilter 1 &&\n>>> +\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n>>> +\n>>> +\t# This blob must be missing in the subsequent commit.\n>>> +\techo foo >src-sub/file &&\n>>> +\tgit -C src-sub add file &&\n>>> +\tgit -C src-sub commit -m \"submodule one\" &&\n>>> +\tSUB_ONE=$(git -C src-sub rev-parse HEAD) &&\n>>> +\n>>> +\techo bar >src-sub/file &&\n>>> +\tgit -C src-sub add file &&\n>>> +\tgit -C src-sub commit -m \"submodule two\" &&\n>>> +\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n>>> +\n>>> +\tgit init src-super &&\n>>> +\tgit -C src-super config uploadpack.allowfilter 1 &&\n>>> +\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n>>> +\tgit -C src-super submodule add ../src-sub src-sub &&\n>>> +\n>>> +\tgit -C src-super/src-sub checkout $SUB_ONE &&\n>>> +\tgit -C src-super add src-sub &&\n>>> +\tgit -C src-super commit -m \"superproject one\" &&\n>>> +\n>>> +\tgit -C src-super/src-sub checkout $SUB_TWO &&\n>>> +\tgit -C src-super add src-sub &&\n>>> +\tgit -C src-super commit -m \"superproject two\" &&\n>>> +\n>>> +\t# the fetch\n>>> +\ttest_when_finished \"rm -rf src-super src-sub client\" &&\n>>\n>> (Genuinely curious) are we okay with test_when_finished in the middle of\n>> the test body instead of at the top?\n>\n> Yeah, and it's not just supported, but preferred, usually we do:\n>\n> \ttest_when_finished \"rm -rf repo\" &&\n> \tgit init repo &&\n>\n> So at the top makes sense, but if there's a bunch of stuff we might fail\n> on first it makes sense not to attempt the cleanup.\n>\n> But I see in this case the \"src-super\" part of it should be earlier, and\n> \"src-sub\", but the \"client\" should be just before the clone below, don't\n> know how I missed that. Will fix.\n\nAh, I see. Yeah that makes sense.\n\n>\n>>> +\n>>> +\ttest_config_global protocol.file.allow always &&\n>>\n>> We have this exact same test_config_global line at the top of this test,\n>> so we can drop this one.\n>\n> Ditto, thanks, I'll fix that. A mistake when combining the tests.\n>\n> You had these as two tests, but one was mandatory setup for the other,\n> and when making it test_expect_failure I wanted to have it atomic..\n\nMakes sense too. I initially had them separate for readability purposes,\nbut the inline comments work too.\n"},{"id":"467262","messageId":"kl6la64tp6xc.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v2-02.10-5a35f7b75b3-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 02/10] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T21:22:55Z","receivedAt":"2022-11-14T21:23:08Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> The \"--super-prefix\" facility was introduced in [1] has always been a\n> transitory hack, which is why we've made it an error to supply it as\n> an option to \"git\" to commands that don't know about it.\n>\n> That's been a good goal, as it has a global effect we haven't wanted\n> calls to get_super_prefix() from built-ins we didn't expect.\n>\n> But it has meant that when we've had chains of different built-ins\n> using it all of the processes in that \"chain\" have needed to support\n> it, and worse processes that don't need it have needed to ask for\n> \"SUPPORT_SUPER_PREFIX\" because their parent process needs it.\n>\n> That's how \"fsmonitor--daemon\" ended up with it, per [2] it's called\n> from (among other things) \"submodule--helper absorbgitdirs\", but as we\n> declared \"submodule--helper\" as \"SUPPORT_SUPER_PREFIX\" we needed to\n> declare \"fsmonitor--daemon\" as accepting it too, even though it\n> doesn't care about it.\n>\n> But in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\n> invoke itself recursively, and we'd never have another \"in-between\"\n> process in the chain. So we didn't need the bigger hammer of \"git\n> --super-prefix\", and the \"setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)\"\n> that it entails.\n>\n> Let's instead accept a hidden \"--super-prefix\" option to\n> \"submodule--helper absorbgitdirs\" itself.\n>\n> Eventually (as with all other \"--super-prefix\" users) we'll want to\n> clean this code up so that this all happens in-process. I.e. needing\n> any variant of \"--super-prefix\" is itself a hack around our various\n> global state, and implicit reliance on \"the_repository\". This stepping\n> stone makes such an eventual change easier, as we'll need to deal with\n> less global state at that point.\n>\n> The \"fsmonitor--daemon\" test adjusted here was added in [3]. The\n> comment added in that commit has been out-of-date from the beginning,\n> and the \"have_t2_error_event()\" was being overly specific in testing\n> for a bug that we *don't* have. Let's instead test for the stdout and\n> stderr that we *do have*.\n\nI didn't understand this bit initially, because I read this as\n\"have_t2_error_event() isn't catching bugs\", which isn't true. But I see\nwhat you mean after inspecting the test_cmp output:\n\n  @@ -1 +1,2 @@\n  Migrating git directory of 'dir_1/dir_2/sub' from 'dir_1/dir_2/sub/.git' to '.git/modules/dir_1/dir_2/sub'\n  +fatal: fsmonitor--daemon doesn't support --super-prefix\n\nIOW, it doesn't make sense to inspecting the tr2 output for stray\nwarnings when our stderr is so obviously broken. But at the end of the\nseries, I don't think we even need this test at all because if we don't\nhave a global \"--super-prefix\", there's literally no reason for\nfsmonitor--daemon to worry about absorbgitdirs or \"supporting\" the super\nprefix. That's why I removed it in [1].\n\nWondering aloud, that stderr suggests that the \"git submodule absorbgitdirs\"\ninvocation failed. I wonder why the test didn't catch a bad exit code\n(and resulting in us inspecting stderr unnecessarily). I think it's not\nworth looking too closely at right now, but we could revisit this after\nwe get builtin/submodule.c.\n\n[1] https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com\n\n>\n> 1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n> 2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n>    2022-05-26)\n> 3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n>    2022-05-26)\n>\n> Signed-off-by: Glen Choo <chooglen@google.com>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c  |  8 +++++---\n>  git.c                        |  2 +-\n>  parse-options.h              |  4 ++++\n>  submodule.c                  | 20 ++++++++++++--------\n>  submodule.h                  |  7 ++++++-\n>  t/t7527-builtin-fsmonitor.sh | 33 ++++++++-------------------------\n>  6 files changed, 36 insertions(+), 38 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index c75e9e86b06..427e793e204 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2828,7 +2828,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n>  \tint i;\n>  \tstruct pathspec pathspec = { 0 };\n>  \tstruct module_list list = MODULE_LIST_INIT;\n> +\tconst char *super_prefix = NULL;\n>  \tstruct option embed_gitdir_options[] = {\n> +\t\tOPT__SUPER_PREFIX(&super_prefix),\n>  \t\tOPT_END()\n>  \t};\n>  \tconst char *const git_submodule_helper_usage[] = {\n> @@ -2844,7 +2846,8 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n>  \t\tgoto cleanup;\n>  \n>  \tfor (i = 0; i < list.nr; i++)\n> -\t\tabsorb_git_dir_into_superproject(list.entries[i]->name);\n> +\t\tabsorb_git_dir_into_superproject_sp(list.entries[i]->name,\n> +\t\t\t\t\t\t    super_prefix);\n>  \n>  \tret = 0;\n>  cleanup:\n> @@ -3382,8 +3385,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n>  \n>  \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n>  \t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n> -\t    strcmp(subcmd, \"sync\") && strcmp(subcmd, \"absorbgitdirs\") &&\n> -\t    get_super_prefix())\n> +\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n>  \t\t/*\n>  \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n>  \t\t * string identical to git.c's.\n> diff --git a/git.c b/git.c\n> index 10202a7f126..b1b7e1a837e 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {\n>  \t{ \"format-patch\", cmd_format_patch, RUN_SETUP },\n>  \t{ \"fsck\", cmd_fsck, RUN_SETUP },\n>  \t{ \"fsck-objects\", cmd_fsck, RUN_SETUP },\n> -\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },\n> +\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, RUN_SETUP },\n>  \t{ \"gc\", cmd_gc, RUN_SETUP },\n>  \t{ \"get-tar-commit-id\", cmd_get_tar_commit_id, NO_PARSEOPT },\n>  \t{ \"grep\", cmd_grep, RUN_SETUP_GENTLY },\n> diff --git a/parse-options.h b/parse-options.h\n> index b6ef86e0d15..50d852f2991 100644\n> --- a/parse-options.h\n> +++ b/parse-options.h\n> @@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);\n>  \t{ OPTION_CALLBACK, 0, \"abbrev\", (var), N_(\"n\"),\t\\\n>  \t  N_(\"use <n> digits to display object names\"),\t\\\n>  \t  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }\n> +#define OPT__SUPER_PREFIX(var) \\\n> +\tOPT_STRING_F(0, \"super-prefix\", (var), N_(\"prefix\"), \\\n> +\t\tN_(\"prefixed path to initial superproject\"), PARSE_OPT_HIDDEN)\n> +\n\nCould we default to \"\" instead of NULL? (possibly via a callback). I\nthink there's never any good reason to have NULL instead of \"\", e.g.\nsince this is internal, we don't care to distinguish between\n\"--super-prefix=''\" and not passing \"--super-prefix\" at all...\n\n>  #define OPT__COLOR(var, h) \\\n>  \tOPT_COLOR_FLAG(0, \"color\", (var), (h))\n>  #define OPT_COLUMN(s, l, v, h) \\\n> diff --git a/submodule.c b/submodule.c\n> index c47358097fd..d9fd0af81b6 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)\n>   * Embeds a single submodules git directory into the superprojects git dir,\n>   * non recursively.\n>   */\n> -static void relocate_single_git_dir_into_superproject(const char *path)\n> +static void relocate_single_git_dir_into_superproject(const char *path,\n> +\t\t\t\t\t\t      const char *super_prefix)\n>  {\n>  \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n>  \tstruct strbuf new_gitdir = STRBUF_INIT;\n> @@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n>  \t       real_old_git_dir[off] == real_new_git_dir[off])\n>  \t\toff++;\n>  \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from '%s' to '%s'\\n\"),\n> -\t\tget_super_prefix_or_empty(), path,\n> +\t\t(super_prefix ? super_prefix : \"\"), path,\n>  \t\treal_old_git_dir + off, real_new_git_dir + off);\n\n\nWhich would make sites like these a bit cleaner.\n\nTangentially, 'default to \"\" if NULL' sounds like a common pattern. Is\nthere a good reason not to have a macro or inline function to do that?\ne.g. we think the ternary expression is good enough?)\n\n>  \n>  \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n> @@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n>  \tstrbuf_release(&new_gitdir);\n>  }\n>  \n> -static void absorb_git_dir_into_superproject_recurse(const char *path)\n> +static void absorb_git_dir_into_superproject_recurse(const char *path,\n> +\t\t\t\t\t\t     const char *super_prefix)\n>  {\n>  \n>  \tstruct child_process cp = CHILD_PROCESS_INIT;\n> @@ -2321,10 +2323,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n>  \tcp.dir = path;\n>  \tcp.git_cmd = 1;\n>  \tcp.no_stdin = 1;\n> -\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n> -\t\t     get_super_prefix_or_empty(), path);\n>  \tstrvec_pushl(&cp.args, \"submodule--helper\",\n>  \t\t     \"absorbgitdirs\", NULL);\n> +\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n> +\t\t     super_prefix : \"\", path);\n> +\n>  \tprepare_submodule_repo_env(&cp.env);\n>  \tif (run_command(&cp))\n>  \t\tdie(_(\"could not recurse into submodule '%s'\"), path);\n> @@ -2335,7 +2338,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n>   * having its git directory within the working tree to the git dir nested\n>   * in its superprojects git dir under modules/.\n>   */\n> -void absorb_git_dir_into_superproject(const char *path)\n> +void absorb_git_dir_into_superproject_sp(const char *path,\n> +\t\t\t\t\t const char *super_prefix)\n>  {\n>  \tint err_code;\n>  \tconst char *sub_git_dir;\n> @@ -2377,14 +2381,14 @@ void absorb_git_dir_into_superproject(const char *path)\n>  \t\tchar *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);\n>  \n>  \t\tif (!starts_with(real_sub_git_dir, real_common_git_dir))\n> -\t\t\trelocate_single_git_dir_into_superproject(path);\n> +\t\t\trelocate_single_git_dir_into_superproject(path, super_prefix);\n>  \n>  \t\tfree(real_sub_git_dir);\n>  \t\tfree(real_common_git_dir);\n>  \t}\n>  \tstrbuf_release(&gitdir);\n>  \n> -\tabsorb_git_dir_into_superproject_recurse(path);\n> +\tabsorb_git_dir_into_superproject_recurse(path, super_prefix);\n>  }\n>  \n>  int get_superproject_working_tree(struct strbuf *buf)\n> diff --git a/submodule.h b/submodule.h\n> index b52a4ff1e73..e5ee13fb06a 100644\n> --- a/submodule.h\n> +++ b/submodule.h\n> @@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);\n>   */\n>  void prepare_submodule_repo_env(struct strvec *env);\n>  \n> -void absorb_git_dir_into_superproject(const char *path);\n> +void absorb_git_dir_into_superproject_sp(const char *path,\n> +\t\t\t\t\t const char *super_prefix);\n> +static inline void absorb_git_dir_into_superproject(const char *path)\n> +{\n> +\tabsorb_git_dir_into_superproject_sp(path, NULL);\n> +}\n\nIs there a reason you chose to go with _sp() instead of changing the\noriginal function signature? I tested out that change, and it seems\nrather small (absorb_git_dir_into_superproject() only has 4 call sites).\n\nCrucially, changing the signature catches a \"git read-tree\" call site:\n\n  diff --git a/submodule.c b/submodule.c\n  index d9fd0af81b..e79a04d3e3 100644\n  --- a/submodule.c\n  +++ b/submodule.c\n  @@ -2139,7 +2139,9 @@ int submodule_move_head(const char *path,\n          if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {\n                  if (old_head) {\n                          if (!submodule_uses_gitfile(path))\n  -                               absorb_git_dir_into_superproject(path);\n  +                               /* Pass super_prefix properly later. */\n  +                               absorb_git_dir_into_superproject(path,\n  +                                                                get_super_prefix());\n                  } else {\n                          struct strbuf gitdir = STRBUF_INIT;\n                          submodule_name_to_gitdir(&gitdir, the_repository,\n\nwhich would otherwise be broken since we used to read the global super\nprefix, but we don't do that in this patch. This has no test coverage\n(bleh), but it shouldn't be too hard, something like:\n\n  git init super &&\n  cd super &&\n  # Create an unabsorbed submodule right in the worktree\n  git init sub &&\n  test_commit -C sub \"foo\" &&\n  git add sub &&\n  git commit -m \"Add submodule\" &&\n  test_commit \"bar\" &&\n  # This should invoke \"git read-tree\" and absorb the git dir.\n  # Or maybe we should invoke \"git read-tree\" directly?\n  git checkout --recurse-submodules HEAD^ 2>err &&\n  # Search for the shortened message\n  grep \"Migrating submodule sub from sub to .git/modules/....\" err\n\n>  /*\n>   * Return the absolute path of the working tree of the superproject, which this\n> diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh\n> index 4abc74db2bb..31526937d95 100755\n> --- a/t/t7527-builtin-fsmonitor.sh\n> +++ b/t/t7527-builtin-fsmonitor.sh\n> @@ -866,30 +866,11 @@ test_expect_success 'submodule always visited' '\n>  # the submodule, and someone does a `git submodule absorbgitdirs`\n>  # in the super, Git will recursively invoke `git submodule--helper`\n>  # to do the work and this may try to read the index.  This will\n> -# try to start the daemon in the submodule *and* pass (either\n> -# directly or via inheritance) the `--super-prefix` arg to the\n> -# `git fsmonitor--daemon start` command inside the submodule.\n> -# This causes a warning because fsmonitor--daemon does take that\n> -# global arg (see the table in git.c)\n> -#\n> -# This causes a warning when trying to start the daemon that is\n> -# somewhat confusing.  It does not seem to hurt anything because\n> -# the fsmonitor code maps the query failure into a trivial response\n> -# and does the work anyway.\n> -#\n> -# It would be nice to silence the warning, however.\n> -\n> -have_t2_error_event () {\n> -\tlog=$1\n> -\tmsg=\"fsmonitor--daemon doesnQt support --super-prefix\" &&\n> -\n> -\ttr '\\047' Q <$1 | grep -e \"$msg\"\n> -}\n> +# try to start the daemon in the submodule.\n>  \n>  test_expect_success \"stray submodule super-prefix warning\" '\n>  \ttest_when_finished \"rm -rf super; \\\n> -\t\t\t    rm -rf sub;   \\\n> -\t\t\t    rm super-sub.trace\" &&\n> +\t\t\t    rm -rf sub\" &&\n>  \n>  \tcreate_super super &&\n>  \tcreate_sub sub &&\n> @@ -904,10 +885,12 @@ test_expect_success \"stray submodule super-prefix warning\" '\n>  \n>  \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n>  \n> -\tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n> -\t\tgit -C super submodule absorbgitdirs &&\n> -\n> -\t! have_t2_error_event super-sub.trace\n> +\tcat >expect <<-\\EOF &&\n> +\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from '\\''dir_1/dir_2/sub/.git'\\'' to '\\''.git/modules/dir_1/dir_2/sub'\\''\n> +\tEOF\n> +\tgit -C super submodule absorbgitdirs >out 2>actual &&\n> +\ttest_cmp expect actual &&\n> +\ttest_must_be_empty out\n>  '\n>  \n>  # On a case-insensitive file system, confirm that the daemon\n> -- \n> 2.38.0.1471.ge4d8947e7aa\n"},{"id":"467264","messageId":"kl6l7czxp5dd.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v2-04.10-935d8070834-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 04/10] submodule--helper: convert \"foreach\" to its own \"--super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T21:56:30Z","receivedAt":"2022-11-14T21:56:40Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> As with a preceding commit to convert \"absorbgitdirs\", we can convert\n> \"submodule--helper foreach\" to use its own \"--super-prefix\", instead\n> of relying on the global \"--super-prefix\" argument to \"git\"\n> itself. See that earlier commit for the rationale and background.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 15 ++++++++++-----\n>  1 file changed, 10 insertions(+), 5 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index c4d5e029b37..989c75280af 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -396,7 +398,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n>  \tstruct foreach_cb info = FOREACH_CB_INIT;\n>  \tstruct pathspec pathspec = { 0 };\n>  \tstruct module_list list = MODULE_LIST_INIT;\n> +\tconst char *super_prefix = NULL;\n>  \tstruct option module_foreach_options[] = {\n> +\t\tOPT__SUPER_PREFIX(&super_prefix),\n>  \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n>  \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n>  \t\t\t N_(\"recurse into nested submodules\")),\n> @@ -417,6 +421,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n>  \tinfo.argc = argc;\n>  \tinfo.argv = argv;\n>  \tinfo.prefix = prefix;\n> +\tinfo.super_prefix = super_prefix;\n\n(Also applies to subsequent patches) Why don't we assign the super\nprefix directly to the struct's field? e.g.\n\n\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n\n>  \n>  \tfor_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);\n>  \n"},{"id":"467266","messageId":"Y3K6VM4Ciwv7ytcw@nand.local","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 00/10] Get rid of \"git --super-prefix\"","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2022-11-14T21:59:48Z","receivedAt":"2022-11-14T21:59:54Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Nov 14, 2022 at 11:08:40AM +0100, Ævar Arnfjörð Bjarmason wrote:\n> = Relation to other submissions\n>\n> This is a non-RFC version of my earlier RFC to get rid of\n> \"--super-prefix\"[1], which itself was an alternate proposal to Glen's\n> [2]. Per [3] he's agreed to go with this approach.\n\nThanks for working it out together, and for a clear summary of how this\nseries interacts with and depends on others in-flight.\n\nThanks,\nTaylor\n"},{"id":"467268","messageId":"kl6l1qq5p4zy.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v2-07.10-eaa73f5b1e4-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 07/10] submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T22:04:33Z","receivedAt":"2022-11-14T22:04:40Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 40939b0b18e..e13615eb939 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -131,13 +131,6 @@ static char *get_submodule_displaypath_sp(const char *path, const char *prefix,\n>  \t}\n>  }\n>  \n> -static char *get_submodule_displaypath(const char *path, const char *prefix)\n> -{\n> -\tconst char *super_prefix = get_super_prefix();\n> -\n> -\treturn get_submodule_displaypath_sp(path, prefix, super_prefix);\n> -}\n> -\n\nIt feels a bit odd that the function we keep is the one with _sp,\nespecially since the \"original\" is gone. FWIW, I wouldn't mind if we\njust changed the signature of get_submodule_displaypath() instead of\nintroducing the _sp helper.\n\n"},{"id":"467270","messageId":"kl6ly1sdnpp9.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v2-08.10-172b5865811-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 08/10] submodule tests: test \"git branch -t\" output and stderr","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T22:20:18Z","receivedAt":"2022-11-14T22:20:55Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> The \"git branch\" command will currently make use of the\n> \"--super-prefix\", as it will indirectly call submodule_move_head(),\n> which will have access to the \"--super-prefix\".\n\nI couldn't figure out how \"git branch\" ends up calling\nsubmodule_move_head(), could you include the call chain?\n\nI find it very odd because AFAICT we only call submodule_move_head()\nwhen we are modifying the working tree (or checking if it is safe to\nmodify), and \"git branch\" shouldn't touch the working tree.\n\n> The output could thus be affected by the \"--super-prefix\". Right now\n> it isn't in this case, but let's exhaustively assert that that's the\n> case by testing the output of all of these \"git branch -t\" commands.\n\nIt's reasonable to be worried if the output contained paths to the\nworking tree, but...\n\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/lib-submodule-update.sh | 98 ++++++++++++++++++++++-----------------\n>  1 file changed, 55 insertions(+), 43 deletions(-)\n>\n> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> index 2d31fcfda1f..302d095ad9b 100644\n> --- a/t/lib-submodule-update.sh\n> +++ b/t/lib-submodule-update.sh\n> @@ -245,6 +245,17 @@ reset_work_tree_to_interested () {\n>  \tgit -C submodule_update/.git/modules/sub1 config submodule.sub2.url \"bogus\"\n>  }\n>  \n> +test_branch_t_output () {\n> +\tlocal branchname=\"$1\" &&\n> +\tlocal start_point=\"$2\" &&\n> +\tcat >expect <<-EOF &&\n> +\tbranch '$branchname' set up to track '$start_point'.\n> +\tEOF\n> +\tgit branch -t \"$branchname\" \"$start_point\" >actual 2>err &&\n> +\ttest_must_be_empty err &&\n> +\ttest_cmp expect actual\n> +}\n> +\n\nit looks like the output is based entirely on the ref store, which has\nno reason to use the super prefix. Based on the commit message in\n74866d7579 (git: make super-prefix option, 2016-10-07):\n\n  When such a super-prefix is specified, the paths reported by Git\n  are prefixed with it to make them relative to that directory \"above\".\n  The paths given by the user on the command line\n  (e.g. \"git subcmd --output-file=path/to/a/file\" and pathspecs) are taken\n  relative to the directory \"above\" to match.\n\nand the fact that the super prefix has never been used for anything\nother than the working tree, I don't think this level of paranoia is\nnecessary.\n\n>  # Test that the superproject contains the content according to commit \"$1\"\n>  # (the work tree must match the index for everything but submodules but the\n>  # index must exactly match the given commit including any submodule SHA-1s).\n> @@ -323,7 +334,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to no_submodule &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> +\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n>  \t\t\t$command add_sub1 &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n> @@ -345,7 +356,7 @@ test_submodule_switch_common () {\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n>  \t\t\tmkdir sub1 &&\n> -\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> +\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n>  \t\t\t$command add_sub1 &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n> @@ -360,7 +371,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to replace_sub1_with_file &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n> +\t\t\ttest_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&\n>  \t\t\t$command replace_file_with_sub1 &&\n>  \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n> @@ -384,7 +395,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to replace_sub1_with_directory &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n> +\t\t\ttest_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n>  \t\t\t$command replace_directory_with_sub1 &&\n>  \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n> @@ -406,7 +417,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n> +\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n>  \t\t\t$command remove_sub1 &&\n>  \t\t\ttest_superproject_content origin/remove_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n> @@ -418,7 +429,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n> +\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n>  \t\t\treplace_gitfile_with_git_dir sub1 &&\n>  \t\t\t$command remove_sub1 &&\n>  \t\t\ttest_superproject_content origin/remove_sub1 &&\n> @@ -447,7 +458,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n>  \t\t\t$command replace_sub1_with_directory test_must_fail &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n> @@ -459,7 +470,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n>  \t\t\treplace_gitfile_with_git_dir sub1 &&\n>  \t\t\t$command replace_sub1_with_directory test_must_fail &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n> @@ -474,7 +485,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n>  \t\t\t$command replace_sub1_with_file test_must_fail &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n> @@ -487,7 +498,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n>  \t\t\treplace_gitfile_with_git_dir sub1 &&\n>  \t\t\t$command replace_sub1_with_file test_must_fail &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n> @@ -512,7 +523,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n> +\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n>  \t\t\t$command modify_sub1 &&\n>  \t\t\ttest_superproject_content origin/modify_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n> @@ -527,7 +538,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n> +\t\t\ttest_branch_t_output invalid_sub1 origin/invalid_sub1 &&\n>  \t\t\t$command invalid_sub1 &&\n>  \t\t\ttest_superproject_content origin/invalid_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n> @@ -542,7 +553,7 @@ test_submodule_switch_common () {\n>  \t\treset_work_tree_to invalid_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n> +\t\t\ttest_branch_t_output valid_sub1 origin/valid_sub1 &&\n>  \t\t\t$command valid_sub1 &&\n>  \t\t\ttest_superproject_content origin/valid_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1 &&\n> @@ -596,7 +607,7 @@ test_submodule_switch_func () {\n>  \t\treset_work_tree_to no_submodule &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> +\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n>  \t\t\t>sub1 &&\n>  \t\t\t$command add_sub1 test_must_fail &&\n>  \t\t\ttest_superproject_content origin/no_submodule &&\n> @@ -635,7 +646,7 @@ test_submodule_forced_switch () {\n>  \t\treset_work_tree_to no_submodule &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> +\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n>  \t\t\t>sub1 &&\n>  \t\t\t$command add_sub1 &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n> @@ -675,7 +686,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested no_submodule &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> +\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n>  \t\t\t$command add_sub1 &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n> @@ -688,7 +699,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n>  \t\t\tmkdir sub1 &&\n> -\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> +\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n>  \t\t\t$command add_sub1 &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/add_sub1\n> @@ -701,7 +712,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested replace_sub1_with_file &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n> +\t\t\ttest_branch_t_output replace_file_with_sub1 origin/replace_file_with_sub1 &&\n>  \t\t\t$command replace_file_with_sub1 &&\n>  \t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n> @@ -713,19 +724,20 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested replace_sub1_with_directory &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n> +\t\t\ttest_branch_t_output replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n>  \t\t\t$command replace_directory_with_sub1 &&\n>  \t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n>  \t\t)\n>  \t'\n> +\n>  \t# Switching to a commit with nested submodules recursively checks them out\n>  \ttest_expect_success \"$command: nested submodules are checked out\" '\n>  \t\tprolog &&\n>  \t\treset_work_tree_to_interested no_submodule &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t modify_sub1_recursively origin/modify_sub1_recursively &&\n> +\t\t\ttest_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&\n>  \t\t\t$command modify_sub1_recursively &&\n>  \t\t\ttest_superproject_content origin/modify_sub1_recursively &&\n>  \t\t\ttest_submodule_content sub1 origin/modify_sub1_recursively &&\n> @@ -740,7 +752,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n> +\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n>  \t\t\t$command remove_sub1 &&\n>  \t\t\ttest_superproject_content origin/remove_sub1 &&\n>  \t\t\t! test -e sub1 &&\n> @@ -753,7 +765,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n> +\t\t\ttest_branch_t_output remove_sub1 origin/remove_sub1 &&\n>  \t\t\treplace_gitfile_with_git_dir sub1 &&\n>  \t\t\trm -rf .git/modules &&\n>  \t\t\t$command remove_sub1 &&\n> @@ -769,7 +781,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n>  \t\t\t$command replace_sub1_with_file &&\n>  \t\t\ttest_superproject_content origin/replace_sub1_with_file &&\n>  \t\t\ttest -f sub1\n> @@ -786,7 +798,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n>  \t\t\t: >sub1/untrackedfile &&\n>  \t\t\ttest_must_fail $command replace_sub1_with_file &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n> @@ -801,7 +813,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested add_nested_sub &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t no_submodule origin/no_submodule &&\n> +\t\t\ttest_branch_t_output no_submodule origin/no_submodule &&\n>  \t\t\t$command no_submodule &&\n>  \t\t\ttest_superproject_content origin/no_submodule &&\n>  \t\t\t! test_path_is_dir sub1 &&\n> @@ -817,7 +829,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n> +\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n>  \t\t\t$command modify_sub1 &&\n>  \t\t\ttest_superproject_content origin/modify_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/modify_sub1\n> @@ -830,7 +842,7 @@ test_submodule_recursing_with_args_common () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n> +\t\t\ttest_branch_t_output invalid_sub1 origin/invalid_sub1 &&\n>  \t\t\ttest_must_fail $command invalid_sub1 2>err &&\n>  \t\t\ttest_i18ngrep sub1 err &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n> @@ -844,13 +856,13 @@ test_submodule_recursing_with_args_common () {\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n>  \t\t\tgit -C sub1 checkout -b keep_branch &&\n> -\t\t\tgit -C sub1 rev-parse HEAD >expect &&\n> -\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n> +\t\t\tgit -C sub1 rev-parse HEAD >expect.rev-parse &&\n> +\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n>  \t\t\t$command modify_sub1 &&\n>  \t\t\ttest_superproject_content origin/modify_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/modify_sub1 &&\n>  \t\t\tgit -C sub1 rev-parse keep_branch >actual &&\n> -\t\t\ttest_cmp expect actual &&\n> +\t\t\ttest_cmp expect.rev-parse actual &&\n>  \t\t\ttest_must_fail git -C sub1 symbolic-ref HEAD\n>  \t\t)\n>  \t'\n> @@ -894,7 +906,7 @@ test_submodule_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested no_submodule &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> +\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n>  \t\t\t: >sub1 &&\n>  \t\t\ttest_must_fail $command add_sub1 &&\n>  \t\t\ttest_superproject_content origin/no_submodule &&\n> @@ -908,7 +920,7 @@ test_submodule_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested no_submodule &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> +\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n>  \t\t\t: >sub1 &&\n>  \t\t\tmkdir .git/info &&\n>  \t\t\techo sub1 >.git/info/exclude &&\n> @@ -925,7 +937,7 @@ test_submodule_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n>  \t\t\t$command replace_sub1_with_directory &&\n>  \t\t\ttest_superproject_content origin/replace_sub1_with_directory &&\n>  \t\t\ttest_submodule_content sub1 origin/replace_sub1_with_directory\n> @@ -937,7 +949,7 @@ test_submodule_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n>  \t\t\treplace_gitfile_with_git_dir sub1 &&\n>  \t\t\trm -rf .git/modules &&\n>  \t\t\t$command replace_sub1_with_directory &&\n> @@ -954,7 +966,7 @@ test_submodule_switch_recursing_with_args () {\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n>  \t\t\trm -rf .git/modules/sub1/info &&\n> -\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n>  \t\t\tmkdir .git/modules/sub1/info &&\n>  \t\t\techo ignored >.git/modules/sub1/info/exclude &&\n>  \t\t\t: >sub1/ignored &&\n> @@ -969,7 +981,7 @@ test_submodule_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n> +\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n>  \t\t\tgit -c submodule.recurse=true $cmd_args modify_sub1 &&\n>  \t\t\ttest_superproject_content origin/modify_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/modify_sub1\n> @@ -981,7 +993,7 @@ test_submodule_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested add_nested_sub &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t modify_sub1_recursively origin/modify_sub1_recursively &&\n> +\t\t\ttest_branch_t_output modify_sub1_recursively origin/modify_sub1_recursively &&\n>  \t\t\t$command modify_sub1_recursively &&\n>  \t\t\ttest_superproject_content origin/modify_sub1_recursively &&\n>  \t\t\ttest_submodule_content sub1 origin/modify_sub1_recursively &&\n> @@ -1009,7 +1021,7 @@ test_submodule_forced_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested no_submodule &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> +\t\t\ttest_branch_t_output add_sub1 origin/add_sub1 &&\n>  \t\t\t>sub1 &&\n>  \t\t\t$command add_sub1 &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n> @@ -1023,7 +1035,7 @@ test_submodule_forced_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n>  \t\t\t$command replace_sub1_with_directory &&\n>  \t\t\ttest_superproject_content origin/replace_sub1_with_directory\n>  \t\t)\n> @@ -1034,7 +1046,7 @@ test_submodule_forced_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_directory origin/replace_sub1_with_directory &&\n>  \t\t\treplace_gitfile_with_git_dir sub1 &&\n>  \t\t\trm -rf .git/modules/sub1 &&\n>  \t\t\t$command replace_sub1_with_directory &&\n> @@ -1049,7 +1061,7 @@ test_submodule_forced_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n> +\t\t\ttest_branch_t_output replace_sub1_with_file origin/replace_sub1_with_file &&\n>  \t\t\t: >sub1/expect &&\n>  \t\t\t$command replace_sub1_with_file &&\n>  \t\t\ttest_superproject_content origin/replace_sub1_with_file\n> @@ -1062,7 +1074,7 @@ test_submodule_forced_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested invalid_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n> +\t\t\ttest_branch_t_output valid_sub1 origin/valid_sub1 &&\n>  \t\t\t$command valid_sub1 &&\n>  \t\t\ttest_superproject_content origin/valid_sub1 &&\n>  \t\t\ttest_submodule_content sub1 origin/valid_sub1\n> @@ -1077,7 +1089,7 @@ test_submodule_forced_switch_recursing_with_args () {\n>  \t\treset_work_tree_to_interested add_sub1 &&\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n> -\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n> +\t\t\ttest_branch_t_output modify_sub1 origin/modify_sub1 &&\n>  \t\t\techo \"gitdir: bogus/path\" >sub1/.git &&\n>  \t\t\t$command modify_sub1 &&\n>  \t\t\ttest_superproject_content origin/modify_sub1 &&\n> -- \n> 2.38.0.1471.ge4d8947e7aa\n"},{"id":"467272","messageId":"kl6lv8nhnpba.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v2-09.10-9fdeab60773-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 09/10] read-tree: add \"--super-prefix\" option, eliminate global","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T22:28:41Z","receivedAt":"2022-11-14T22:28:49Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> The \"--super-prefix\" option to \"git\" was initially added in [1] for\n> use with \"ls-files\"[2], and shortly thereafter \"submodule--helper\"[3]\n> and \"grep\"[4]. It wasn't until [5] that \"read-tree\" made use of it.\n>\n> At the time [5] made sense, but since then we've made \"ls-files\"\n> recurse in-process in [6], \"grep\" in [7], and finally\n> \"submodule--helper\" in the preceding commits.\n>\n> Let's also remove it from \"read-tree\", which allows us to remove the\n> option to \"git\" itself.\n>\n> We can do this because the only remaining user of it is the submodule\n> API, which will now invoke \"read-tree\" with its new \"--super-prefix\"\n> option. It will only do so when the \"submodule_move_head()\" function\n> is called.\n>\n> That \"submodule_move_head()\" function was then only invoked by\n> \"read-tree\" itself, but now rather than setting an environment\n> variable to pass \"--super-prefix\" between cmd_read_tree() we:\n>\n> - Set a new \"super_prefix\" in \"struct unpack_trees_options\". The\n>   \"super_prefixed()\" function in \"unpack-trees.c\" added in [5] will now\n>   use this, rather than get_super_prefix() looking up the environment\n>   variable we set earlier in the same process.\n>\n> - Add the same field to the \"struct checkout\", which is only needed to\n>   ferry the \"super_prefix\" in the \"struct unpack_trees_options\" all the\n>   way down to the \"entry.c\" callers of \"submodule_move_head()\".\n>\n>   Those calls which used the super prefix all originated in\n>   \"cmd_read_tree()\". The only other caller is the \"unlink_entry()\"\n>   caller in \"builtin/checkout.c\", which now passes a \"NULL\".\n>\n> 1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n> 2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)\n> 3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)\n> 4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)\n> 5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)\n> 6. 188dce131fa (ls-files: use repository object, 2017-06-22)\n> 7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  Documentation/git.txt       |  8 +-------\n>  builtin.h                   |  4 ----\n>  builtin/checkout.c          |  2 +-\n>  builtin/read-tree.c         |  1 +\n>  cache.h                     |  2 --\n>  entry.c                     | 12 ++++++------\n>  entry.h                     |  6 +++++-\n>  environment.c               | 13 -------------\n>  git.c                       | 37 +++++--------------------------------\n>  submodule.c                 | 27 +++++++++------------------\n>  submodule.h                 |  5 ++---\n>  t/t1001-read-tree-m-2way.sh |  2 +-\n>  t/t5616-partial-clone.sh    |  2 +-\n>  unpack-trees.c              | 23 +++++++++++++----------\n>  unpack-trees.h              |  1 +\n>  15 files changed, 46 insertions(+), 99 deletions(-)\n>\n> diff --git a/Documentation/git.txt b/Documentation/git.txt\n> index 1d33e083ab8..f9a7a4554cd 100644\n> --- a/Documentation/git.txt\n> +++ b/Documentation/git.txt\n> @@ -13,8 +13,7 @@ SYNOPSIS\n>      [--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>]\n> +    [--config-env=<name>=<envvar>] <command> [<args>]\n>  \n>  DESCRIPTION\n>  -----------\n> @@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use\n>  \tdetails.  Equivalent to setting the `GIT_NAMESPACE` environment\n>  \tvariable.\n>  \n> ---super-prefix=<path>::\n> -\tCurrently for internal use only.  Set a prefix which gives a path from\n> -\tabove a repository down to its root.  One use is to give submodules\n> -\tcontext about the superproject that invoked it.\n> -\n>  --bare::\n>  \tTreat the repository as a bare repository.  If GIT_DIR\n>  \tenvironment is not set, it is set to the current working\n> diff --git a/builtin.h b/builtin.h\n> index 8901a34d6bf..8264b7e5241 100644\n> --- a/builtin.h\n> +++ b/builtin.h\n> @@ -51,10 +51,6 @@\n>   *\ton bare repositories.\n>   *\tThis only makes sense when `RUN_SETUP` is also set.\n>   *\n> - * `SUPPORT_SUPER_PREFIX`:\n> - *\n> - *\tThe built-in supports `--super-prefix`.\n> - *\n>   * `DELAY_PAGER_CONFIG`:\n>   *\n>   *\tIf RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 2a132392fbe..dc008fb45e8 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -231,7 +231,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n>  \t\tpos++;\n>  \t}\n>  \tif (!overlay_mode) {\n> -\t\tunlink_entry(ce);\n> +\t\tunlink_entry(ce, NULL);\n>  \t\treturn 0;\n>  \t}\n>  \tif (stage == 2)\n> diff --git a/builtin/read-tree.c b/builtin/read-tree.c\n> index f4cbe460b97..4b6f22e58c1 100644\n> --- a/builtin/read-tree.c\n> +++ b/builtin/read-tree.c\n> @@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)\n>  \tint prefix_set = 0;\n>  \tstruct lock_file lock_file = LOCK_INIT;\n>  \tconst struct option read_tree_options[] = {\n> +\t\tOPT__SUPER_PREFIX(&opts.super_prefix),\n>  \t\tOPT_CALLBACK_F(0, \"index-output\", NULL, N_(\"file\"),\n>  \t\t  N_(\"write resulting index to <file>\"),\n>  \t\t  PARSE_OPT_NONEG, index_output_cb),\n> diff --git a/cache.h b/cache.h\n> index 26ed03bd6de..a4a0377b800 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)\n>  #define GIT_NAMESPACE_ENVIRONMENT \"GIT_NAMESPACE\"\n>  #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n>  #define GIT_PREFIX_ENVIRONMENT \"GIT_PREFIX\"\n> -#define GIT_SUPER_PREFIX_ENVIRONMENT \"GIT_INTERNAL_SUPER_PREFIX\"\n>  #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n>  #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n>  #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n> @@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n>  int get_common_dir(struct strbuf *sb, const char *gitdir);\n>  const char *get_git_namespace(void);\n>  const char *strip_namespace(const char *namespaced_ref);\n> -const char *get_super_prefix(void);\n>  const char *get_git_work_tree(void);\n>  \n>  /*\n> diff --git a/entry.c b/entry.c\n> index 616e4f073c1..971ab268714 100644\n> --- a/entry.c\n> +++ b/entry.c\n> @@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca\n>  \t\t\treturn error(\"cannot create submodule directory %s\", path);\n>  \t\tsub = submodule_from_ce(ce);\n>  \t\tif (sub)\n> -\t\t\treturn submodule_move_head(ce->name,\n> +\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n>  \t\t\t\tNULL, oid_to_hex(&ce->oid),\n>  \t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n>  \t\tbreak;\n> @@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n>  \t\t\t * no pathname to return.\n>  \t\t\t */\n>  \t\t\tBUG(\"Can't remove entry to a path\");\n> -\t\tunlink_entry(ce);\n> +\t\tunlink_entry(ce, state->super_prefix);\n>  \t\treturn 0;\n>  \t}\n>  \n> @@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n>  \t\t\t\tif (!(st.st_mode & S_IFDIR))\n>  \t\t\t\t\tunlink_or_warn(ce->name);\n>  \n> -\t\t\t\treturn submodule_move_head(ce->name,\n> +\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n>  \t\t\t\t\tNULL, oid_to_hex(&ce->oid), 0);\n>  \t\t\t} else\n> -\t\t\t\treturn submodule_move_head(ce->name,\n> +\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n>  \t\t\t\t\t\"HEAD\", oid_to_hex(&ce->oid),\n>  \t\t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n>  \t\t}\n> @@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n>  \treturn write_entry(ce, path.buf, ca, state, 0, nr_checkouts);\n>  }\n>  \n> -void unlink_entry(const struct cache_entry *ce)\n> +void unlink_entry(const struct cache_entry *ce, const char *super_prefix)\n>  {\n>  \tconst struct submodule *sub = submodule_from_ce(ce);\n>  \tif (sub) {\n>  \t\t/* state.force is set at the caller. */\n> -\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n> +\t\tsubmodule_move_head(ce->name, super_prefix, \"HEAD\", NULL,\n>  \t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n>  \t}\n>  \tif (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)\n> diff --git a/entry.h b/entry.h\n> index 9be4659881e..2d4fbb88c8f 100644\n> --- a/entry.h\n> +++ b/entry.h\n> @@ -8,6 +8,7 @@ struct checkout {\n>  \tstruct index_state *istate;\n>  \tconst char *base_dir;\n>  \tint base_dir_len;\n> +\tconst char *super_prefix;\n>  \tstruct delayed_checkout *delayed_checkout;\n>  \tstruct checkout_metadata meta;\n>  \tunsigned force:1,\n> @@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);\n>  /*\n>   * Unlink the last component and schedule the leading directories for\n>   * removal, such that empty directories get removed.\n> + *\n> + * The \"super_prefix\" is either NULL, or the \"--super-prefix\" passed\n> + * down from \"read-tree\" et al.\n>   */\n> -void unlink_entry(const struct cache_entry *ce);\n> +void unlink_entry(const struct cache_entry *ce, const char *super_prefix);\n>  \n>  void *read_blob_entry(const struct cache_entry *ce, size_t *size);\n>  int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);\n> diff --git a/environment.c b/environment.c\n> index 18d042b467d..1ee3686fd8a 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -102,8 +102,6 @@ char *git_work_tree_cfg;\n>  \n>  static char *git_namespace;\n>  \n> -static char *super_prefix;\n> -\n>  /*\n>   * Repository-local GIT_* environment variables; see cache.h for details.\n>   */\n> @@ -121,7 +119,6 @@ const char * const local_repo_env[] = {\n>  \tNO_REPLACE_OBJECTS_ENVIRONMENT,\n>  \tGIT_REPLACE_REF_BASE_ENVIRONMENT,\n>  \tGIT_PREFIX_ENVIRONMENT,\n> -\tGIT_SUPER_PREFIX_ENVIRONMENT,\n>  \tGIT_SHALLOW_FILE_ENVIRONMENT,\n>  \tGIT_COMMON_DIR_ENVIRONMENT,\n>  \tNULL\n> @@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)\n>  \treturn NULL;\n>  }\n>  \n> -const char *get_super_prefix(void)\n> -{\n> -\tstatic int initialized;\n> -\tif (!initialized) {\n> -\t\tsuper_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));\n> -\t\tinitialized = 1;\n> -\t}\n> -\treturn super_prefix;\n> -}\n> -\n>  static int git_work_tree_initialized;\n>  \n>  /*\n> diff --git a/git.c b/git.c\n> index 2bca22cfd9a..00baaf23590 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -14,9 +14,8 @@\n>   * RUN_SETUP for reading from the configuration file.\n>   */\n>  #define NEED_WORK_TREE\t\t(1<<3)\n> -#define SUPPORT_SUPER_PREFIX\t(1<<4)\n> -#define DELAY_PAGER_CONFIG\t(1<<5)\n> -#define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n> +#define DELAY_PAGER_CONFIG\t(1<<4)\n> +#define NO_PARSEOPT\t\t(1<<5) /* parse-options is not used */\n>  \n>  struct cmd_struct {\n>  \tconst char *cmd;\n> @@ -29,8 +28,7 @@ const char git_usage_string[] =\n>  \t   \"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\\n\"\n>  \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\\n\"\n>  \t   \"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\\n\"\n> -\t   \"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\\n\"\n> -\t   \"           <command> [<args>]\");\n> +\t   \"           [--config-env=<name>=<envvar>] <command> [<args>]\");\n>  \n>  const char git_more_info_string[] =\n>  \tN_(\"'git help -a' and 'git help -g' list available subcommands and some\\n\"\n> @@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n>  \t\t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);\n>  \t\t\tif (envchanged)\n>  \t\t\t\t*envchanged = 1;\n> -\t\t} else if (!strcmp(cmd, \"--super-prefix\")) {\n> -\t\t\tif (*argc < 2) {\n> -\t\t\t\tfprintf(stderr, _(\"no prefix given for --super-prefix\\n\" ));\n> -\t\t\t\tusage(git_usage_string);\n> -\t\t\t}\n> -\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);\n> -\t\t\tif (envchanged)\n> -\t\t\t\t*envchanged = 1;\n> -\t\t\t(*argv)++;\n> -\t\t\t(*argc)--;\n> -\t\t} else if (skip_prefix(cmd, \"--super-prefix=\", &cmd)) {\n> -\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);\n> -\t\t\tif (envchanged)\n> -\t\t\t\t*envchanged = 1;\n>  \t\t} else if (!strcmp(cmd, \"--bare\")) {\n>  \t\t\tchar *cwd = xgetcwd();\n>  \t\t\tis_bare_repository_cfg = 1;\n> @@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n>  \t\ttrace_repo_setup(prefix);\n>  \tcommit_pager_choice();\n>  \n> -\tif (!help && get_super_prefix()) {\n> -\t\tif (!(p->option & SUPPORT_SUPER_PREFIX))\n> -\t\t\tdie(_(\"%s doesn't support --super-prefix\"), p->cmd);\n> -\t}\n> -\n>  \tif (!help && p->option & NEED_WORK_TREE)\n>  \t\tsetup_work_tree();\n>  \n> @@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {\n>  \t{ \"check-ref-format\", cmd_check_ref_format, NO_PARSEOPT  },\n>  \t{ \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n>  \t{ \"checkout--worker\", cmd_checkout__worker,\n> -\t\tRUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },\n> +\t\tRUN_SETUP | NEED_WORK_TREE },\n>  \t{ \"checkout-index\", cmd_checkout_index,\n>  \t\tRUN_SETUP | NEED_WORK_TREE},\n>  \t{ \"cherry\", cmd_cherry, RUN_SETUP },\n> @@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {\n>  \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n>  \t{ \"push\", cmd_push, RUN_SETUP },\n>  \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n> -\t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n> +\t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n>  \t{ \"rebase\", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },\n>  \t{ \"receive-pack\", cmd_receive_pack },\n>  \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n> @@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)\n>  \tstruct child_process cmd = CHILD_PROCESS_INIT;\n>  \tint status;\n>  \n> -\tif (get_super_prefix())\n> -\t\tdie(_(\"%s doesn't support --super-prefix\"), argv[0]);\n> -\n>  \tif (use_pager == -1 && !is_builtin(argv[0]))\n>  \t\tuse_pager = check_pager_config(argv[0]);\n>  \tcommit_pager_choice();\n> @@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)\n>  \t\t\t */\n>  \t\t\ttrace2_cmd_name(\"_run_git_alias_\");\n>  \n> -\t\t\tif (get_super_prefix())\n> -\t\t\t\tdie(\"%s doesn't support --super-prefix\", **argv);\n> -\n>  \t\t\tcommit_pager_choice();\n>  \n>  \t\t\tstrvec_push(&cmd.args, \"git\");\n> diff --git a/submodule.c b/submodule.c\n> index d9fd0af81b6..5ac4e1b0568 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -2048,14 +2048,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)\n>  \tstrbuf_release(&config_path);\n>  }\n>  \n> -static const char *get_super_prefix_or_empty(void)\n> -{\n> -\tconst char *s = get_super_prefix();\n> -\tif (!s)\n> -\t\ts = \"\";\n> -\treturn s;\n> -}\n> -\n>  static int submodule_has_dirty_index(const struct submodule *sub)\n>  {\n>  \tstruct child_process cp = CHILD_PROCESS_INIT;\n> @@ -2074,7 +2066,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)\n>  \treturn finish_command(&cp);\n>  }\n>  \n> -static void submodule_reset_index(const char *path)\n> +static void submodule_reset_index(const char *path, const char *super_prefix)\n>  {\n>  \tstruct child_process cp = CHILD_PROCESS_INIT;\n>  \tprepare_submodule_repo_env(&cp.env);\n> @@ -2083,10 +2075,10 @@ static void submodule_reset_index(const char *path)\n>  \tcp.no_stdin = 1;\n>  \tcp.dir = path;\n>  \n> -\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n> -\t\t     get_super_prefix_or_empty(), path);\n>  \t/* TODO: determine if this might overwright untracked files */\n>  \tstrvec_pushl(&cp.args, \"read-tree\", \"-u\", \"--reset\", NULL);\n> +\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n> +\t\t     (super_prefix ? super_prefix : \"\"), path);\n>  \n>  \tstrvec_push(&cp.args, empty_tree_oid_hex());\n>  \n> @@ -2099,10 +2091,9 @@ static void submodule_reset_index(const char *path)\n>   * For edge cases (a submodule coming into existence or removing a submodule)\n>   * pass NULL for old or new respectively.\n>   */\n> -int submodule_move_head(const char *path,\n> -\t\t\t const char *old_head,\n> -\t\t\t const char *new_head,\n> -\t\t\t unsigned flags)\n> +int submodule_move_head(const char *path, const char *super_prefix,\n> +\t\t\tconst char *old_head, const char *new_head,\n> +\t\t\tunsigned flags)\n>  {\n>  \tint ret = 0;\n>  \tstruct child_process cp = CHILD_PROCESS_INIT;\n> @@ -2148,7 +2139,7 @@ int submodule_move_head(const char *path,\n>  \t\t\tstrbuf_release(&gitdir);\n>  \n>  \t\t\t/* make sure the index is clean as well */\n> -\t\t\tsubmodule_reset_index(path);\n> +\t\t\tsubmodule_reset_index(path, NULL);\n\nShouldn't we be passing the super prefix? i.e.\n\n  submodule_reset_index(path, super_prefix)\n\n>  \t\t}\n>  \n>  \t\tif (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {\n> @@ -2166,9 +2157,9 @@ int submodule_move_head(const char *path,\n>  \tcp.no_stdin = 1;\n>  \tcp.dir = path;\n>  \n> -\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n> -\t\t     get_super_prefix_or_empty(), path);\n>  \tstrvec_pushl(&cp.args, \"read-tree\", \"--recurse-submodules\", NULL);\n> +\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n> +\t\t     (super_prefix ? super_prefix : \"\"), path);\n>  \n>  \tif (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)\n>  \t\tstrvec_push(&cp.args, \"-n\");\n> diff --git a/submodule.h b/submodule.h\n> index e5ee13fb06a..36a7f7c5b32 100644\n> --- a/submodule.h\n> +++ b/submodule.h\n> @@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);\n>  \n>  #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)\n>  #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)\n> -int submodule_move_head(const char *path,\n> -\t\t\tconst char *old,\n> -\t\t\tconst char *new_head,\n> +int submodule_move_head(const char *path, const char *super_prefix,\n> +\t\t\tconst char *old_head, const char *new_head,\n>  \t\t\tunsigned flags);\n>  \n>  void submodule_unset_core_worktree(const struct submodule *sub);\n> diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh\n> index 516a6112fdc..3fb1b0c162d 100755\n> --- a/t/t1001-read-tree-m-2way.sh\n> +++ b/t/t1001-read-tree-m-2way.sh\n> @@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '\n>  \tcat <<-EOF >expect &&\n>  \t\terror: Updating '\\''fictional/a'\\'' would lose untracked files in it\n>  \tEOF\n> -\ttest_must_fail git --super-prefix fictional/ read-tree -u -m \"$treeH\" \"$treeM\" 2>actual &&\n> +\ttest_must_fail git read-tree --super-prefix fictional/ -u -m \"$treeH\" \"$treeM\" 2>actual &&\n>  \ttest_cmp expect actual\n>  '\n>  \n> diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\n> index e56466580cf..18375bff535 100755\n> --- a/t/t5616-partial-clone.sh\n> +++ b/t/t5616-partial-clone.sh\n> @@ -644,7 +644,7 @@ test_expect_success 'repack does not loosen promisor objects' '\n>  \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n>  '\n>  \n> -test_expect_failure 'lazy-fetch in submodule succeeds' '\n> +test_expect_success 'lazy-fetch in submodule succeeds' '\n>  \t# setup\n>  \ttest_config_global protocol.file.allow always &&\n>  \n> diff --git a/unpack-trees.c b/unpack-trees.c\n> index bae812156c4..61c02285454 100644\n> --- a/unpack-trees.c\n> +++ b/unpack-trees.c\n> @@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {\n>  \t  ? ((o)->msgs[(type)])      \\\n>  \t  : (unpack_plumbing_errors[(type)]) )\n>  \n> -static const char *super_prefixed(const char *path)\n> +static const char *super_prefixed(const char *path, const char *super_prefix)\n>  {\n>  \t/*\n>  \t * It is necessary and sufficient to have two static buffers\n> @@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)\n>  \tstatic unsigned idx = ARRAY_SIZE(buf) - 1;\n>  \n>  \tif (super_prefix_len < 0) {\n> -\t\tconst char *super_prefix = get_super_prefix();\n>  \t\tif (!super_prefix) {\n>  \t\t\tsuper_prefix_len = 0;\n>  \t\t} else {\n> @@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,\n>  \t\treturn -1;\n>  \n>  \tif (!o->show_all_errors)\n> -\t\treturn error(ERRORMSG(o, e), super_prefixed(path));\n> +\t\treturn error(ERRORMSG(o, e), super_prefixed(path,\n> +\t\t\t\t\t\t\t    o->super_prefix));\n>  \n>  \t/*\n>  \t * Otherwise, insert in a list for future display by\n> @@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)\n>  \t\t\terror_displayed = 1;\n>  \t\t\tfor (i = 0; i < rejects->nr; i++)\n>  \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n> -\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf));\n> +\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf,\n> +\t\t\t\t\t\t\t     o->super_prefix));\n>  \t\t\tstrbuf_release(&path);\n>  \t\t}\n>  \t\tstring_list_clear(rejects, 0);\n> @@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)\n>  \t\t\twarning_displayed = 1;\n>  \t\t\tfor (i = 0; i < rejects->nr; i++)\n>  \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n> -\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf));\n> +\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf,\n> +\t\t\t\t\t\t\t       o->super_prefix));\n>  \t\t\tstrbuf_release(&path);\n>  \t\t}\n>  \t\tstring_list_clear(rejects, 0);\n> @@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,\n>  \tif (o->reset)\n>  \t\tflags |= SUBMODULE_MOVE_HEAD_FORCE;\n>  \n> -\tif (submodule_move_head(ce->name, old_id, new_id, flags))\n> +\tif (submodule_move_head(ce->name, NULL, old_id, new_id, flags))\n\nSimilarly, shouldn't this be\n\n  - submodule_move_head(ce->name, NULL, old_id, new_id, flags)\n  + submodule_move_head(ce->name, o->super_prefix, old_id, new_id, flags)\n\n>  \t\treturn add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);\n>  \treturn 0;\n>  }\n> @@ -415,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,\n>  \tint i, pc_workers, pc_threshold;\n>  \n>  \ttrace_performance_enter();\n> +\tstate.super_prefix = o->super_prefix;\n>  \tstate.force = 1;\n>  \tstate.quiet = 1;\n>  \tstate.refresh_cache = 1;\n> @@ -445,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,\n>  \n>  \t\tif (ce->ce_flags & CE_WT_REMOVE) {\n>  \t\t\tdisplay_progress(progress, ++cnt);\n> -\t\t\tunlink_entry(ce);\n> +\t\t\tunlink_entry(ce, o->super_prefix);\n>  \t\t}\n>  \t}\n>  \n> @@ -2958,8 +2961,8 @@ int bind_merge(const struct cache_entry * const *src,\n>  \tif (a && old)\n>  \t\treturn o->quiet ? -1 :\n>  \t\t\terror(ERRORMSG(o, ERROR_BIND_OVERLAP),\n> -\t\t\t      super_prefixed(a->name),\n> -\t\t\t      super_prefixed(old->name));\n> +\t\t\t      super_prefixed(a->name, o->super_prefix),\n> +\t\t\t      super_prefixed(old->name, o->super_prefix));\n>  \tif (!a)\n>  \t\treturn keep_entry(old, o);\n>  \telse\n> @@ -3020,7 +3023,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,\n>  \n>  \tif (worktree && untracked)\n>  \t\treturn error(_(\"worktree and untracked commit have duplicate entries: %s\"),\n> -\t\t\t     super_prefixed(worktree->name));\n> +\t\t\t     super_prefixed(worktree->name, o->super_prefix));\n>  \n>  \treturn merged_entry(worktree ? worktree : untracked, NULL, o);\n>  }\n> diff --git a/unpack-trees.h b/unpack-trees.h\n> index efb9edfbb27..9b81e284073 100644\n> --- a/unpack-trees.h\n> +++ b/unpack-trees.h\n> @@ -74,6 +74,7 @@ struct unpack_trees_options {\n>  \t\t     dry_run;\n>  \tenum unpack_trees_reset_type reset;\n>  \tconst char *prefix;\n> +\tconst char *super_prefix;\n>  \tint cache_bottom;\n>  \tstruct pathspec *pathspec;\n>  \tmerge_fn_t fn;\n> -- \n> 2.38.0.1471.ge4d8947e7aa\n"},{"id":"467275","messageId":"kl6lsfilnp6t.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v2-10.10-100ba36dfb7-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 10/10] fetch: rename \"--submodule-prefix\" to \"--super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T22:31:22Z","receivedAt":"2022-11-14T22:31:31Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Thanks for picking this up, especially since you feel \"meh\" about it :)\n\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> In preceding commits we've introduced a command-level \"--super-prefix\"\n> option, which unlike the \"git --super-prefix\" it replaced doesn't rely\n> on setenv() or getenv(), it's just a normal command-line option that\n> the command passes down.\n>\n> Since we've done that, let's rename the \"--submodule-prefix\" option\n> added in 7dce19d374a (fetch/pull: Add the --recurse-submodules option,\n> 2010-11-12) to \"--super-prefix\" for consistency. This:\n>\n>  * Allows us to use OPT__SUPER_PREFIX().\n>  * Leaves an unspecified \"--super-prefix\" with a \"NULL\" value, rather\n>    than an empty string, as is the case with the other \"--super-prefix\"\n>    users. We coerce the NULL to \"\" in submodule.c before using it.\n\n[...]\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  Documentation/fetch-options.txt |  5 -----\n>  builtin/fetch.c                 |  7 +++----\n>  submodule.c                     | 23 +++++++++++------------\n>  3 files changed, 14 insertions(+), 21 deletions(-)\n>\n> diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\n> index 622bd84768b..20cbd2c2910 100644\n> --- a/Documentation/fetch-options.txt\n> +++ b/Documentation/fetch-options.txt\n> @@ -241,11 +241,6 @@ endif::git-pull[]\n>  \tlinkgit:git-config[1].\n>  \n>  ifndef::git-pull[]\n> ---submodule-prefix=<path>::\n> -\tPrepend <path> to paths printed in informative messages\n> -\tsuch as \"Fetching submodule foo\".  This option is used\n> -\tinternally when recursing over submodules.\n> -\n>  --recurse-submodules-default=[yes|on-demand]::\n>  \tThis option is used internally to temporarily provide a\n>  \tnon-negative default value for the --recurse-submodules\n> diff --git a/builtin/fetch.c b/builtin/fetch.c\n> index 7378cafeec9..353bcd36d24 100644\n> --- a/builtin/fetch.c\n> +++ b/builtin/fetch.c\n> @@ -74,7 +74,7 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;\n>  static struct strbuf default_rla = STRBUF_INIT;\n>  static struct transport *gtransport;\n>  static struct transport *gsecondary;\n> -static const char *submodule_prefix = \"\";\n> +static const char *super_prefix;\n\nIs there a reason we can't keep the '= \"\"'?\n\n>  static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n>  static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;\n>  static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;\n> @@ -195,8 +195,7 @@ static struct option builtin_fetch_options[] = {\n>  \tOPT_SET_INT_F(0, \"refetch\", &refetch,\n>  \t\t      N_(\"re-fetch without negotiating common commits\"),\n>  \t\t      1, PARSE_OPT_NONEG),\n> -\t{ OPTION_STRING, 0, \"submodule-prefix\", &submodule_prefix, N_(\"dir\"),\n> -\t\t   N_(\"prepend this to submodule path output\"), PARSE_OPT_HIDDEN },\n> +\tOPT__SUPER_PREFIX(&super_prefix),\n>  \tOPT_CALLBACK_F(0, \"recurse-submodules-default\",\n>  \t\t   &recurse_submodules_default, N_(\"on-demand\"),\n>  \t\t   N_(\"default for recursive fetching of submodules \"\n> @@ -2300,7 +2299,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n>  \t\tadd_options_to_argv(&options);\n>  \t\tresult = fetch_submodules(the_repository,\n>  \t\t\t\t\t  &options,\n> -\t\t\t\t\t  submodule_prefix,\n> +\t\t\t\t\t  super_prefix,\n>  \t\t\t\t\t  recurse_submodules,\n>  \t\t\t\t\t  recurse_submodules_default,\n>  \t\t\t\t\t  verbosity < 0,\n> diff --git a/submodule.c b/submodule.c\n> index 5ac4e1b0568..1e4eee3492b 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -1376,7 +1376,7 @@ struct submodule_parallel_fetch {\n>  \tint changed_count;\n>  \tstruct strvec args;\n>  \tstruct repository *r;\n> -\tconst char *prefix;\n> +\tconst char *super_prefix;\n>  \tint command_line_option;\n>  \tint default_option;\n>  \tint quiet;\n> @@ -1567,7 +1567,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,\n>  \t\tif (task->repo) {\n>  \t\t\tif (!spf->quiet)\n>  \t\t\t\tstrbuf_addf(err, _(\"Fetching submodule %s%s\\n\"),\n> -\t\t\t\t\t    spf->prefix, ce->name);\n> +\t\t\t\t\t    spf->super_prefix, ce->name);\n>  \n>  \t\t\tspf->index_count++;\n>  \t\t\treturn task;\n> @@ -1629,7 +1629,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,\n>  \t\tif (!spf->quiet)\n>  \t\t\tstrbuf_addf(err,\n>  \t\t\t\t    _(\"Fetching submodule %s%s at commit %s\\n\"),\n> -\t\t\t\t    spf->prefix, task->sub->path,\n> +\t\t\t\t    spf->super_prefix, task->sub->path,\n>  \t\t\t\t    find_unique_abbrev(cs_data->super_oid,\n>  \t\t\t\t\t\t       DEFAULT_ABBREV));\n>  \n> @@ -1687,11 +1687,10 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n>  \t\t\tstrvec_pushv(&cp->args, task->git_args.v);\n>  \t\tstrvec_pushv(&cp->args, spf->args.v);\n>  \t\tstrvec_push(&cp->args, task->default_argv);\n> -\t\tstrvec_push(&cp->args, \"--submodule-prefix\");\n> +\t\tstrvec_push(&cp->args, \"--super-prefix\");\n>  \n> -\t\tstrbuf_addf(&submodule_prefix, \"%s%s/\",\n> -\t\t\t\t\t\tspf->prefix,\n> -\t\t\t\t\t\ttask->sub->path);\n> +\t\tstrbuf_addf(&submodule_prefix, \"%s%s/\", spf->super_prefix,\n> +\t\t\t    task->sub->path);\n>  \t\tstrvec_push(&cp->args, submodule_prefix.buf);\n>  \t\t*task_cb = task;\n>  \n> @@ -1707,7 +1706,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n>  \t\tspf->oid_fetch_tasks_nr--;\n>  \n>  \t\tstrbuf_addf(&submodule_prefix, \"%s%s/\",\n> -\t\t\t    spf->prefix, task->sub->path);\n> +\t\t\t    spf->super_prefix, task->sub->path);\n>  \n>  \t\tchild_process_init(cp);\n>  \t\tprepare_submodule_repo_env_in_gitdir(&cp->env);\n> @@ -1717,7 +1716,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n>  \t\tstrvec_init(&cp->args);\n>  \t\tstrvec_pushv(&cp->args, spf->args.v);\n>  \t\tstrvec_push(&cp->args, \"on-demand\");\n> -\t\tstrvec_push(&cp->args, \"--submodule-prefix\");\n> +\t\tstrvec_push(&cp->args, \"--super-prefix\");\n>  \t\tstrvec_push(&cp->args, submodule_prefix.buf);\n>  \n>  \t\t/* NEEDSWORK: have get_default_remote from submodule--helper */\n> @@ -1813,7 +1812,7 @@ static int fetch_finish(int retvalue, struct strbuf *err,\n>  \n>  int fetch_submodules(struct repository *r,\n>  \t\t     const struct strvec *options,\n> -\t\t     const char *prefix, int command_line_option,\n> +\t\t     const char *super_prefix, int command_line_option,\n>  \t\t     int default_option,\n>  \t\t     int quiet, int max_parallel_jobs)\n>  {\n> @@ -1835,7 +1834,7 @@ int fetch_submodules(struct repository *r,\n>  \tspf.command_line_option = command_line_option;\n>  \tspf.default_option = default_option;\n>  \tspf.quiet = quiet;\n> -\tspf.prefix = prefix;\n> +\tspf.super_prefix = super_prefix ? super_prefix : \"\";\n>  \n>  \tif (!r->worktree)\n>  \t\tgoto out;\n> @@ -1847,7 +1846,7 @@ int fetch_submodules(struct repository *r,\n>  \tfor (i = 0; i < options->nr; i++)\n>  \t\tstrvec_push(&spf.args, options->v[i]);\n>  \tstrvec_push(&spf.args, \"--recurse-submodules-default\");\n> -\t/* default value, \"--submodule-prefix\" and its value are added later */\n> +\t/* default value, \"--super-prefix\" and its value are added later */\n>  \n>  \tcalculate_changed_submodule_paths(r, &spf.changed_submodule_names);\n>  \tstring_list_sort(&spf.changed_submodule_names);\n> -- \n> 2.38.0.1471.ge4d8947e7aa\n"},{"id":"467287","messageId":"kl6lpmdpnmwo.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 00/10] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T23:20:39Z","receivedAt":"2022-11-14T23:20:47Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Thanks for taking this forward as a non-RFC (and sorry for the\ncoordinating confusion last week). I'm really happy to see this go\nforward.\n\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> = Summary\n>\n> What's \"--super-prefix\"? The \"git\" command takes an \"internal use\n> only\" \"--super-prefix\" option, which is used to inform processes\n> invoked in submodules what the path prefix to the invoking\n> superproject is.\n>\n> This is so so that e.g. \"git submodule absorbgitdirs\" can report\n> \"sub-1/sub-2\", instead of \"sub-2\" when being invoked in the \"sub-1\"\n> submodule.\n>\n> For this the \"--super-prefix\" facility has been doing a\n> setenv(\"GIT_INTERNAL_SUPER_PREFIX\", \"sub-1/\") as soon as it got the\n> \"--supre-prefix=sub-1/\". We'd then pass that along via the environment\n> when invoking the sub-process.\n>\n> As this series shows we don't need such a hands-off global facility to\n> do this, we can instead just pass the relevant context directly in\n> each command. E.g. \"git submodule absorbgitdirs\" can pass the path to\n> the \"git submodule absorbgitdirs\" sub-process it's about to invoke.\n>\n\nTo play devil's advocate, we don't need it now, but one could argue that\nwe'll need it in the future, and having some global facility for this\nwould continue to be helpful. In [1], I mentioned that it is \"helpful\"\nin this way, but that this \"helpfulness\" is a trap, because we want to\nbe moving more things in-process anyway (and we're making pretty good\nstrides in that direction), and adding more global state makes it harder\nto reason about who should own the variables when we libify the\ninternals (do we move the state into per-process struct?\nthe_repository? something else?)\n\nIn addition, you also mentioned earlier in the [1] thread that this\nglobal state also makes it possible accidentally affect commands we\ndidn't mean to, and having less global state makes behavior easier to\nreason about.\n\nSo I think the argument I find most convincing isn't just \"We don't need\nit now.\", but also \"Global state is the wrong way to do this, so let's\nstop.\".\n\n[1] https://lore.kernel.org/git/kl6l5yfm2taf.fsf@chooglen-macbookpro.roam.corp.google.com\n\n> It's also proposing to replace Glen's one-patch[6], which is working\n> around the problem shown in the test added in 1/10 here. Per\n> downthread of [7] I think Glen was aiming for getting a more narrow\n> fix in case we split off 9/10 here into some later fix.\n>\n> As we're fixing an edge case in something that's always been broken\n> (and thus wouldn't backport) I think it's better to just fix the\n> problem directly, rather than introducing new \"--super-prefix\" use,\n> just to take it away later.\n\n(I'll share my thoughts on this on another email).\n\n> = Changes since the RFC\n>\n> * Added Glen's \"git fetch\" test as a 1/10, with an updated commit message\n> * Updated 2/10's commit message for the non-RFC, and adjusted and\n>   incorporated a variant of Glen's fsmonitor test change.\n> * 9/10: Correctly re-arrange bitfield define's when removing one, make\n>   the test added in 1/10 pass.\n>\n> * 10/10: New commit to make \"git fetch\" use our own \"--super-prefix\"\n>   instead of its \"--submodule-prefix\", which makes it consistent with\n>   the other command-level \"--super-prefix\" introduced here.\n>\n>   Personally I'm rather \"meh\" on this. It's not actually needed by the\n>   main body of the series, but Glen seems to prefer it in[9], and\n>   doing it is easy enough.\n>\n>   That change is a pure refactoring clean-up for consistency. The only\n>   reason it's 10/10 and not 1/10 is because it uses the\n>   \"OPT__SUPER_PREFIX()\" introduced in 2/10.\n\nThanks for this, I really appreciate it :)\n\n> = CI & fetch URL\n>\n> Passing at: https://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local-2\n>\n> 1. https://lore.kernel.org/git/RFC-cover-0.8-00000000000-20221109T192315Z-avarab@gmail.com/\n> 2. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/\n> 3. https://lore.kernel.org/git/kl6l5yfm2taf.fsf@chooglen-macbookpro.roam.corp.google.com/\n> 4. c0c4f4d1c33 (Merge branch 'ab/submodule-helper-prep-only' into next, 2022-11-08)\n> 5. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/\n> 6. https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com/\n> 7. https://lore.kernel.org/git/221111.86fsepmbhe.gmgdl@evledraar.gmail.com/\n> 8. https://lore.kernel.org/git/20221109004708.97668-3-chooglen@google.com/\n> 9. https://lore.kernel.org/git/kl6lsfip0yfx.fsf@chooglen-macbookpro.roam.corp.google.com/\n>\n> Glen Choo (1):\n>   read-tree + fetch tests: test failing \"--super-prefix\" interaction\n>\n> Ævar Arnfjörð Bjarmason (9):\n>   submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n>   submodule--helper: \"deinit\" has never used \"--super-prefix\"\n>   submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n>   submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n>   submodule--helper: convert \"status\" to its own \"--super-prefix\"\n>   submodule--helper: convert \"{update,clone}\" to their own\n>     \"--super-prefix\"\n>   submodule tests: test \"git branch -t\" output and stderr\n>   read-tree: add \"--super-prefix\" option, eliminate global\n>   fetch: rename \"--submodule-prefix\" to \"--super-prefix\"\n>\n>  Documentation/fetch-options.txt |  5 --\n>  Documentation/git.txt           |  8 +--\n>  builtin.h                       |  4 --\n>  builtin/checkout.c              |  2 +-\n>  builtin/fetch.c                 |  7 +--\n>  builtin/read-tree.c             |  1 +\n>  builtin/submodule--helper.c     | 95 ++++++++++++++++++--------------\n>  cache.h                         |  2 -\n>  entry.c                         | 12 ++--\n>  entry.h                         |  6 +-\n>  environment.c                   | 13 -----\n>  git.c                           | 41 +++-----------\n>  parse-options.h                 |  4 ++\n>  submodule.c                     | 70 +++++++++++------------\n>  submodule.h                     | 12 ++--\n>  t/lib-submodule-update.sh       | 98 ++++++++++++++++++---------------\n>  t/t1001-read-tree-m-2way.sh     |  2 +-\n>  t/t5616-partial-clone.sh        | 43 +++++++++++++++\n>  t/t7527-builtin-fsmonitor.sh    | 33 +++--------\n>  unpack-trees.c                  | 23 ++++----\n>  unpack-trees.h                  |  1 +\n>  21 files changed, 244 insertions(+), 238 deletions(-)\n>\n> Range-diff against v1:\n>  -:  ----------- >  1:  1114a4ff666 read-tree + fetch tests: test failing \"--super-prefix\" interaction\n>  1:  ad0356b596f !  2:  5a35f7b75b3 submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n>     @@ Commit message\n>          declare \"fsmonitor--daemon\" as accepting it too, even though it\n>          doesn't care about it.\n>      \n>     -    There's a parallel proposal to remove \"--super-prefix\" as an option to\n>     -    \"git\" in [3], and some of the approach might be the easiest route in\n>     -    some cases.\n>     -\n>          But in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\n>          invoke itself recursively, and we'd never have another \"in-between\"\n>          process in the chain. So we didn't need the bigger hammer of \"git\n>     @@ Commit message\n>          stone makes such an eventual change easier, as we'll need to deal with\n>          less global state at that point.\n>      \n>     +    The \"fsmonitor--daemon\" test adjusted here was added in [3]. The\n>     +    comment added in that commit has been out-of-date from the beginning,\n>     +    and the \"have_t2_error_event()\" was being overly specific in testing\n>     +    for a bug that we *don't* have. Let's instead test for the stdout and\n>     +    stderr that we *do have*.\n>     +\n>          1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n>          2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n>             2022-05-26)\n>     -    3. https://lore.kernel.org/git/20221109004708.97668-1-chooglen@google.com/\n>     +    3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n>     +       2022-05-26)\n>      \n>     +    Signed-off-by: Glen Choo <chooglen@google.com>\n>          Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>      \n>       ## builtin/submodule--helper.c ##\n>     @@ submodule.h: void submodule_unset_core_worktree(const struct submodule *sub);\n>       \n>       /*\n>        * Return the absolute path of the working tree of the superproject, which this\n>     +\n>     + ## t/t7527-builtin-fsmonitor.sh ##\n>     +@@ t/t7527-builtin-fsmonitor.sh: test_expect_success 'submodule always visited' '\n>     + # the submodule, and someone does a `git submodule absorbgitdirs`\n>     + # in the super, Git will recursively invoke `git submodule--helper`\n>     + # to do the work and this may try to read the index.  This will\n>     +-# try to start the daemon in the submodule *and* pass (either\n>     +-# directly or via inheritance) the `--super-prefix` arg to the\n>     +-# `git fsmonitor--daemon start` command inside the submodule.\n>     +-# This causes a warning because fsmonitor--daemon does take that\n>     +-# global arg (see the table in git.c)\n>     +-#\n>     +-# This causes a warning when trying to start the daemon that is\n>     +-# somewhat confusing.  It does not seem to hurt anything because\n>     +-# the fsmonitor code maps the query failure into a trivial response\n>     +-# and does the work anyway.\n>     +-#\n>     +-# It would be nice to silence the warning, however.\n>     +-\n>     +-have_t2_error_event () {\n>     +-\tlog=$1\n>     +-\tmsg=\"fsmonitor--daemon doesnQt support --super-prefix\" &&\n>     +-\n>     +-\ttr '\\047' Q <$1 | grep -e \"$msg\"\n>     +-}\n>     ++# try to start the daemon in the submodule.\n>     + \n>     + test_expect_success \"stray submodule super-prefix warning\" '\n>     + \ttest_when_finished \"rm -rf super; \\\n>     +-\t\t\t    rm -rf sub;   \\\n>     +-\t\t\t    rm super-sub.trace\" &&\n>     ++\t\t\t    rm -rf sub\" &&\n>     + \n>     + \tcreate_super super &&\n>     + \tcreate_sub sub &&\n>     +@@ t/t7527-builtin-fsmonitor.sh: test_expect_success \"stray submodule super-prefix warning\" '\n>     + \n>     + \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n>     + \n>     +-\tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n>     +-\t\tgit -C super submodule absorbgitdirs &&\n>     +-\n>     +-\t! have_t2_error_event super-sub.trace\n>     ++\tcat >expect <<-\\EOF &&\n>     ++\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from '\\''dir_1/dir_2/sub/.git'\\'' to '\\''.git/modules/dir_1/dir_2/sub'\\''\n>     ++\tEOF\n>     ++\tgit -C super submodule absorbgitdirs >out 2>actual &&\n>     ++\ttest_cmp expect actual &&\n>     ++\ttest_must_be_empty out\n>     + '\n>     + \n>     + # On a case-insensitive file system, confirm that the daemon\n>  2:  87a780eb9bf =  3:  a7a1f9487dc submodule--helper: \"deinit\" has never used \"--super-prefix\"\n>  3:  4858e2ad0ed =  4:  935d8070834 submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n>  4:  5ffe4407e46 =  5:  933c752513d submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n>  5:  a46540b63c2 =  6:  67273f729e0 submodule--helper: convert \"status\" to its own \"--super-prefix\"\n>  6:  78ebf0e2abf =  7:  eaa73f5b1e4 submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"\n>  7:  00a9e789be7 =  8:  172b5865811 submodule tests: test \"git branch -t\" output and stderr\n>  8:  3ba894a6698 !  9:  9fdeab60773 read-tree: add \"--super-prefix\" option, eliminate global\n>     @@ git.c\n>        */\n>       #define NEED_WORK_TREE\t\t(1<<3)\n>      -#define SUPPORT_SUPER_PREFIX\t(1<<4)\n>     - #define DELAY_PAGER_CONFIG\t(1<<5)\n>     - #define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n>     +-#define DELAY_PAGER_CONFIG\t(1<<5)\n>     +-#define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n>     ++#define DELAY_PAGER_CONFIG\t(1<<4)\n>     ++#define NO_PARSEOPT\t\t(1<<5) /* parse-options is not used */\n>       \n>     + struct cmd_struct {\n>     + \tconst char *cmd;\n>      @@ git.c: const char git_usage_string[] =\n>       \t   \"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\\n\"\n>       \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\\n\"\n>     @@ t/t1001-read-tree-m-2way.sh: test_expect_success 'read-tree supports the super-p\n>       '\n>       \n>      \n>     + ## t/t5616-partial-clone.sh ##\n>     +@@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor objects' '\n>     + \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n>     + '\n>     + \n>     +-test_expect_failure 'lazy-fetch in submodule succeeds' '\n>     ++test_expect_success 'lazy-fetch in submodule succeeds' '\n>     + \t# setup\n>     + \ttest_config_global protocol.file.allow always &&\n>     + \n>     +\n>       ## unpack-trees.c ##\n>      @@ unpack-trees.c: static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {\n>       \t  ? ((o)->msgs[(type)])      \\\n>  -:  ----------- > 10:  100ba36dfb7 fetch: rename \"--submodule-prefix\" to \"--super-prefix\"\n> -- \n> 2.38.0.1471.ge4d8947e7aa\n"},{"id":"467288","messageId":"kl6lmt8tnmbt.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"221114.86y1sdlq2d.gmgdl@evledraar.gmail.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T23:33:10Z","receivedAt":"2022-11-14T23:33:16Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> As noted in the CL above I included this because I see you're keen to\n> include it, but I'm personally a bit \"meh\" on it. I.e. it's just\n> renaming an existing unrelated option, although being able to use\n> OPT__SUPER_PREFIX() makes it slightly nicer.\n>\n> As post-cleanups go I think removing the \"submodule_prefix\" from the\n> \"struct repository\" would make more sense, and maybe it's worth peeling\n> off the 10/10 to include in such a post-cleanup series? I.e. the below\n> on top of all of this works, and reduces allocations and cargo-culting\n> around the submodule API.\n\nAs a first impression I'm not particularly keen on this, since it makes\nperfect sense to me to have a repo->submodule_prefix, especially when\nrecursing into N-level deep submodules...\n\n>\n> -- >8 --\n> Subject: [PATCH] repo & submodule API: stop carrying \"repo->submodule_prefix\"\n>\n> As this change shows the \"submodule_prefix\" field to \"struct\n> repository\" added in 96dc883b3cd (repository: enable initialization of\n> submodules, 2017-06-22) was only used by \"ls-files\" and \"grep\". Let's\n> have those two carry forward the \"super_prefix\" instead.\n>\n> Having every user of \"struct repository\" needing to worry about this\n> created a mismatch in the API where e.g. \"grep\" would re-compute a\n> \"name_base_len\" which we knew before. Now we use a \"struct strbuf\" in\n> the \"struct grep_opt\" there instead, so we'll know the length\n> already. This simplifies \"grep_cache()\" and \"grep_tree()\".\n>\n> We're also deleting cargo-culted code that the previous API foisted\n> upon us. In 605f0ec1350 (submodule: use submodule repos for object\n> lookup, 2018-12-14) the \"Mark it as a submodule\" code was added to\n> \"open_submodule()\", but the resulting xstrdup()'d \"submodule_prefix\"\n> was never used by anything.\n\n(As an aside, I think open_submodule() should have been replaced by\nrepo_submodule_init().)\n\nIn which case, yes it isn't used by anything in that code path, but\nbeing meticulous about maintaining .super_prefix means that other\ncallers could use it if they wanted to, which might be crucial once we\nstart plumb \"struct repository\" deeper and deeper and...\n\n>\n> Still, removing this field might not be a good move, as the\n> \"super_prefix\" might be a common enough case in the future, e.g. when\n> eventually migrating the \"submodule--helper\" users[1] to run\n> in-process.\n>\n> As the \"grep\" example demonstrates I don't think that's the\n> case. There instead of xstrdup()-ing all the way down we're now\n> carrying a single \"super_prefix\" in the form of a \"struct strbuf\". As\n> we recurse we then append to it, and strbuf_setlen() it back when we\n> we recurse out of that submodule. This is similar to how e.g. the\n> \"read_tree_at()\" API works.\n\nThis technique might no longer be so appealing. We _could_ pass both\n\"struct repository\" and \"super_prefix\", but that seems odd given that\nthe super prefix is tied to the repository.\n\nBut that's just a first impression anyway. I don't mind taking another\nlook if this gets a standalone review.\n\n>\n> Doing it that way means that we have just one allocation, which in the\n> common case we might realloc() if we don't have enough room in the\n> \"struct strbuf\".\n>\n> 1. https://lore.kernel.org/git/cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com/\n> 2. https://github.com/avar/git/tree/avar/grep-post-drop-prefix-cleanup\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/grep.c     | 18 ++++++++----------\n>  builtin/ls-files.c | 40 +++++++++++++++++++++++++---------------\n>  grep.c             |  6 +++---\n>  grep.h             |  2 ++\n>  repository.c       |  7 -------\n>  repository.h       |  7 -------\n>  submodule.c        |  3 ---\n>  7 files changed, 38 insertions(+), 45 deletions(-)\n>\n> diff --git a/builtin/grep.c b/builtin/grep.c\n> index 5fa927d4e22..69826daba26 100644\n> --- a/builtin/grep.c\n> +++ b/builtin/grep.c\n> @@ -437,6 +437,7 @@ static int grep_submodule(struct grep_opt *opt,\n>  \tstruct repository *superproject = opt->repo;\n>  \tstruct grep_opt subopt;\n>  \tint hit = 0;\n> +\tsize_t oldlen = opt->super_prefix.len;\n>  \n>  \tif (!is_submodule_active(superproject, path))\n>  \t\treturn 0;\n> @@ -497,6 +498,7 @@ static int grep_submodule(struct grep_opt *opt,\n>  \tadd_submodule_odb_by_path(subrepo->objects->odb->path);\n>  \tobj_read_unlock();\n>  \n> +\tstrbuf_addf(&opt->super_prefix, \"%s/\", path);\n>  \tmemcpy(&subopt, opt, sizeof(subopt));\n>  \tsubopt.repo = subrepo;\n>  \n> @@ -527,6 +529,7 @@ static int grep_submodule(struct grep_opt *opt,\n>  \t} else {\n>  \t\thit = grep_cache(&subopt, pathspec, cached);\n>  \t}\n> +\tstrbuf_setlen(&opt->super_prefix, oldlen);\n>  \n>  \treturn hit;\n>  }\n> @@ -538,11 +541,8 @@ static int grep_cache(struct grep_opt *opt,\n>  \tint hit = 0;\n>  \tint nr;\n>  \tstruct strbuf name = STRBUF_INIT;\n> -\tint name_base_len = 0;\n> -\tif (repo->submodule_prefix) {\n> -\t\tname_base_len = strlen(repo->submodule_prefix);\n> -\t\tstrbuf_addstr(&name, repo->submodule_prefix);\n> -\t}\n> +\tsize_t name_base_len = opt->super_prefix.len;\n> +\tstrbuf_addbuf(&name, &opt->super_prefix);\n>  \n>  \tif (repo_read_index(repo) < 0)\n>  \t\tdie(_(\"index file corrupt\"));\n> @@ -618,11 +618,9 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n>  \tstruct name_entry entry;\n>  \tint old_baselen = base->len;\n>  \tstruct strbuf name = STRBUF_INIT;\n> -\tint name_base_len = 0;\n> -\tif (repo->submodule_prefix) {\n> -\t\tstrbuf_addstr(&name, repo->submodule_prefix);\n> -\t\tname_base_len = name.len;\n> -\t}\n> +\tsize_t name_base_len = opt->super_prefix.len;\n> +\n> +\tstrbuf_addbuf(&name, &opt->super_prefix);\n>  \n>  \twhile (tree_entry(tree, &entry)) {\n>  \t\tint te_len = tree_entry_len(&entry);\n> diff --git a/builtin/ls-files.c b/builtin/ls-files.c\n> index 4cf8a236483..c76a6be2fbe 100644\n> --- a/builtin/ls-files.c\n> +++ b/builtin/ls-files.c\n> @@ -216,10 +216,12 @@ static void show_killed_files(struct index_state *istate,\n>  \t}\n>  }\n>  \n> -static void show_files(struct repository *repo, struct dir_struct *dir);\n> +static void show_files(struct repository *repo, struct dir_struct *dir,\n> +\t\t       const char *super_prefix);\n>  \n>  static void show_submodule(struct repository *superproject,\n> -\t\t\t   struct dir_struct *dir, const char *path)\n> +\t\t\t   struct dir_struct *dir, const char *path,\n> +\t\t\t   const char *super_prefix)\n>  {\n>  \tstruct repository subrepo;\n>  \n> @@ -229,7 +231,7 @@ static void show_submodule(struct repository *superproject,\n>  \tif (repo_read_index(&subrepo) < 0)\n>  \t\tdie(\"index file corrupt\");\n>  \n> -\tshow_files(&subrepo, dir);\n> +\tshow_files(&subrepo, dir, super_prefix);\n>  \n>  \trepo_clear(&subrepo);\n>  }\n> @@ -303,14 +305,19 @@ static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,\n>  \n>  static void show_ce(struct repository *repo, struct dir_struct *dir,\n>  \t\t    const struct cache_entry *ce, const char *fullname,\n> -\t\t    const char *tag)\n> +\t\t    const char *tag, const char *super_prefix)\n>  {\n>  \tif (max_prefix_len > strlen(fullname))\n>  \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n>  \n>  \tif (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&\n>  \t    is_submodule_active(repo, ce->name)) {\n> -\t\tshow_submodule(repo, dir, ce->name);\n> +\t\tstruct strbuf sp = STRBUF_INIT;\n> +\n> +\t\tstrbuf_addf(&sp, \"%s%s/\", super_prefix ? super_prefix : \"\",\n> +\t\t\t    ce->name);\n> +\t\tshow_submodule(repo, dir, ce->name, sp.buf);\n> +\t\tstrbuf_release(&sp);\n>  \t} else if (match_pathspec(repo->index, &pathspec, fullname, strlen(fullname),\n>  \t\t\t\t  max_prefix_len, ps_matched,\n>  \t\t\t\t  S_ISDIR(ce->ce_mode) ||\n> @@ -374,16 +381,17 @@ static int ce_excluded(struct dir_struct *dir, struct index_state *istate,\n>  \treturn is_excluded(dir, istate, fullname, &dtype);\n>  }\n>  \n> -static void construct_fullname(struct strbuf *out, const struct repository *repo,\n> -\t\t\t       const struct cache_entry *ce)\n> +static void construct_fullname(struct strbuf *out, const struct cache_entry *ce,\n> +\t\t\t       const char *super_prefix)\n>  {\n>  \tstrbuf_reset(out);\n> -\tif (repo->submodule_prefix)\n> -\t\tstrbuf_addstr(out, repo->submodule_prefix);\n> +\tif (super_prefix)\n> +\t\tstrbuf_addstr(out, super_prefix);\n>  \tstrbuf_addstr(out, ce->name);\n>  }\n>  \n> -static void show_files(struct repository *repo, struct dir_struct *dir)\n> +static void show_files(struct repository *repo, struct dir_struct *dir,\n> +\t\t       const char *super_prefix)\n>  {\n>  \tint i;\n>  \tstruct strbuf fullname = STRBUF_INIT;\n> @@ -410,7 +418,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir)\n>  \t\tstruct stat st;\n>  \t\tint stat_err;\n>  \n> -\t\tconstruct_fullname(&fullname, repo, ce);\n> +\t\tconstruct_fullname(&fullname, ce, super_prefix);\n>  \n>  \t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n>  \t\t\t!ce_excluded(dir, repo->index, fullname.buf, ce))\n> @@ -422,7 +430,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir)\n>  \t\t\tshow_ce(repo, dir, ce, fullname.buf,\n>  \t\t\t\tce_stage(ce) ? tag_unmerged :\n>  \t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree :\n> -\t\t\t\t tag_cached));\n> +\t\t\t\t tag_cached), super_prefix);\n>  \t\t\tif (skipping_duplicates)\n>  \t\t\t\tgoto skip_to_next_name;\n>  \t\t}\n> @@ -435,13 +443,15 @@ static void show_files(struct repository *repo, struct dir_struct *dir)\n>  \t\tif (stat_err && (errno != ENOENT && errno != ENOTDIR))\n>  \t\t\terror_errno(\"cannot lstat '%s'\", fullname.buf);\n>  \t\tif (stat_err && show_deleted) {\n> -\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed);\n> +\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_removed,\n> +\t\t\t\tsuper_prefix);\n>  \t\t\tif (skipping_duplicates)\n>  \t\t\t\tgoto skip_to_next_name;\n>  \t\t}\n>  \t\tif (show_modified &&\n>  \t\t    (stat_err || ie_modified(repo->index, ce, &st, 0))) {\n> -\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified);\n> +\t\t\tshow_ce(repo, dir, ce, fullname.buf, tag_modified,\n> +\t\t\t\tsuper_prefix);\n>  \t\t\tif (skipping_duplicates)\n>  \t\t\t\tgoto skip_to_next_name;\n>  \t\t}\n> @@ -874,7 +884,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n>  \t\toverlay_tree_on_index(the_repository->index, with_tree, max_prefix);\n>  \t}\n>  \n> -\tshow_files(the_repository, &dir);\n> +\tshow_files(the_repository, &dir, NULL);\n>  \n>  \tif (show_resolve_undo)\n>  \t\tshow_ru_info(the_repository->index);\n> diff --git a/grep.c b/grep.c\n> index 06eed694936..10d52219229 100644\n> --- a/grep.c\n> +++ b/grep.c\n> @@ -791,9 +791,9 @@ void free_grep_patterns(struct grep_opt *opt)\n>  \t\tfree(p);\n>  \t}\n>  \n> -\tif (!opt->pattern_expression)\n> -\t\treturn;\n> -\tfree_pattern_expr(opt->pattern_expression);\n> +\tif (opt->pattern_expression)\n> +\t\tfree_pattern_expr(opt->pattern_expression);\n> +\tstrbuf_release(&opt->super_prefix);\n>  }\n>  \n>  static const char *end_of_line(const char *cp, unsigned long *left)\n> diff --git a/grep.h b/grep.h\n> index 6075f997e68..d353bfa21ce 100644\n> --- a/grep.h\n> +++ b/grep.h\n> @@ -133,6 +133,7 @@ struct grep_opt {\n>  \t * t7814-grep-recurse-submodules.sh for more information.\n>  \t */\n>  \tstruct repository *repo;\n> +\tstruct strbuf super_prefix;\n>  \n>  \tint linenum;\n>  \tint columnnum;\n> @@ -178,6 +179,7 @@ struct grep_opt {\n>  };\n>  \n>  #define GREP_OPT_INIT { \\\n> +\t.super_prefix = STRBUF_INIT, \\\n>  \t.relative = 1, \\\n>  \t.pathname = 1, \\\n>  \t.max_depth = -1, \\\n> diff --git a/repository.c b/repository.c\n> index 5d166b692c8..2f8581c517d 100644\n> --- a/repository.c\n> +++ b/repository.c\n> @@ -228,12 +228,6 @@ int repo_submodule_init(struct repository *subrepo,\n>  \t\t\tgoto out;\n>  \t\t}\n>  \t}\n> -\n> -\tsubrepo->submodule_prefix = xstrfmt(\"%s%s/\",\n> -\t\t\t\t\t    superproject->submodule_prefix ?\n> -\t\t\t\t\t    superproject->submodule_prefix :\n> -\t\t\t\t\t    \"\", path);\n> -\n>  out:\n>  \tstrbuf_release(&gitdir);\n>  \tstrbuf_release(&worktree);\n> @@ -261,7 +255,6 @@ void repo_clear(struct repository *repo)\n>  \tFREE_AND_NULL(repo->graft_file);\n>  \tFREE_AND_NULL(repo->index_file);\n>  \tFREE_AND_NULL(repo->worktree);\n> -\tFREE_AND_NULL(repo->submodule_prefix);\n>  \n>  \traw_object_store_clear(repo->objects);\n>  \tFREE_AND_NULL(repo->objects);\n> diff --git a/repository.h b/repository.h\n> index 6c461c5b9de..a08da26133c 100644\n> --- a/repository.h\n> +++ b/repository.h\n> @@ -120,13 +120,6 @@ struct repository {\n>  \t */\n>  \tchar *worktree;\n>  \n> -\t/*\n> -\t * Path from the root of the top-level superproject down to this\n> -\t * repository.  This is only non-NULL if the repository is initialized\n> -\t * as a submodule of another repository.\n> -\t */\n> -\tchar *submodule_prefix;\n> -\n>  \tstruct repo_settings settings;\n>  \n>  \t/* Subsystems */\n> diff --git a/submodule.c b/submodule.c\n> index 1e4eee3492b..1c5ef904a03 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -528,9 +528,6 @@ static struct repository *open_submodule(const char *path)\n>  \t\treturn NULL;\n>  \t}\n>  \n> -\t/* Mark it as a submodule */\n> -\tout->submodule_prefix = xstrdup(path);\n> -\n>  \tstrbuf_release(&sb);\n>  \treturn out;\n>  }\n> -- \n> 2.38.0.1471.ge4d8947e7aa\n"},{"id":"467289","messageId":"kl6lk03xnm1h.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"Re: [PATCH v2 00/10] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-14T23:39:22Z","receivedAt":"2022-11-14T23:39:26Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> It's also proposing to replace Glen's one-patch[6], which is working\n> around the problem shown in the test added in 1/10 here. Per\n> downthread of [7] I think Glen was aiming for getting a more narrow\n> fix in case we split off 9/10 here into some later fix.\n>\n> As we're fixing an edge case in something that's always been broken\n> (and thus wouldn't backport) I think it's better to just fix the\n> problem directly, rather than introducing new \"--super-prefix\" use,\n> just to take it away later.\n\nI still prefer that we take the one-patch to unbreak new releases,\nbecause partial clone + submodules is absolutely broken (e.g. it's\nalready causing quite a lot of headaches at $DAYJOB) and the patch is\nobviously harmless.\n\nAnd more importantly, it lets us take our time with this series and get\nit right without time pressure. It's not as pressing as, e.g. a\nregression fix, but it does render certain Git setups unusable.\n\nWith regards to urgency and when to choose \"small and harmless fixes vs\nbigger and better fixes\", I think Junio has generally made those calls\nin the past. @Taylor if you have an opinion, I'd love to hear it.\n\n> 6. https://lore.kernel.org/git/pull.1378.git.git.1668210935360.gitgitgadget@gmail.com/\n> 7. https://lore.kernel.org/git/221111.86fsepmbhe.gmgdl@evledraar.gmail.com/\n"},{"id":"467292","messageId":"221115.868rkdknmz.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6lk03xnm1h.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v2 00/10] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-15T01:27:31Z","receivedAt":"2022-11-15T01:33:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Nov 14 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> It's also proposing to replace Glen's one-patch[6], which is working\n>> around the problem shown in the test added in 1/10 here. Per\n>> downthread of [7] I think Glen was aiming for getting a more narrow\n>> fix in case we split off 9/10 here into some later fix.\n>>\n>> As we're fixing an edge case in something that's always been broken\n>> (and thus wouldn't backport) I think it's better to just fix the\n>> problem directly, rather than introducing new \"--super-prefix\" use,\n>> just to take it away later.\n>\n> I still prefer that we take the one-patch to unbreak new releases,\n> because partial clone + submodules is absolutely broken (e.g. it's\n> already causing quite a lot of headaches at $DAYJOB) and the patch is\n> obviously harmless.\n>\n> And more importantly, it lets us take our time with this series and get\n> it right without time pressure. It's not as pressing as, e.g. a\n> regression fix, but it does render certain Git setups unusable.\n>\n> With regards to urgency and when to choose \"small and harmless fixes vs\n> bigger and better fixes\", I think Junio has generally made those calls\n> in the past. @Taylor if you have an opinion, I'd love to hear it.\n\nI feel like I'm missing something here. What's the regression? The test\nyou're adding here didn't work at all until 0f5e8851737 (Merge branch\n'rc/fetch-refetch', 2022-04-04), as the command didn't exist yet. That\ncommit went out with v2.36.0.\n\nIf it never worked there's no regression, and we wouldn't be merging\ndown a fix for older point-releases.\n\nOr is there some case I've missed here which did work before, doesn't\nnow, but just isn't captured in this test? If so what case is that, and\nwhen did it break?\n"},{"id":"467293","messageId":"221115.864jv1kn4e.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6lmt8tnmbt.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [RFC PATCH 0/8] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-15T01:37:45Z","receivedAt":"2022-11-15T01:44:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Nov 14 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> As noted in the CL above I included this because I see you're keen to\n>> include it, but I'm personally a bit \"meh\" on it. I.e. it's just\n>> renaming an existing unrelated option, although being able to use\n>> OPT__SUPER_PREFIX() makes it slightly nicer.\n>>\n>> As post-cleanups go I think removing the \"submodule_prefix\" from the\n>> \"struct repository\" would make more sense, and maybe it's worth peeling\n>> off the 10/10 to include in such a post-cleanup series? I.e. the below\n>> on top of all of this works, and reduces allocations and cargo-culting\n>> around the submodule API.\n>\n> As a first impression I'm not particularly keen on this, since it makes\n> perfect sense to me to have a repo->submodule_prefix, especially when\n> recursing into N-level deep submodules...\n\nThis is mainly a quick experiment I drafted up, with that context...\n\n>> -- >8 --\n>> Subject: [PATCH] repo & submodule API: stop carrying \"repo->submodule_prefix\"\n>>\n>> As this change shows the \"submodule_prefix\" field to \"struct\n>> repository\" added in 96dc883b3cd (repository: enable initialization of\n>> submodules, 2017-06-22) was only used by \"ls-files\" and \"grep\". Let's\n>> have those two carry forward the \"super_prefix\" instead.\n>>\n>> Having every user of \"struct repository\" needing to worry about this\n>> created a mismatch in the API where e.g. \"grep\" would re-compute a\n>> \"name_base_len\" which we knew before. Now we use a \"struct strbuf\" in\n>> the \"struct grep_opt\" there instead, so we'll know the length\n>> already. This simplifies \"grep_cache()\" and \"grep_tree()\".\n>>\n>> We're also deleting cargo-culted code that the previous API foisted\n>> upon us. In 605f0ec1350 (submodule: use submodule repos for object\n>> lookup, 2018-12-14) the \"Mark it as a submodule\" code was added to\n>> \"open_submodule()\", but the resulting xstrdup()'d \"submodule_prefix\"\n>> was never used by anything.\n>\n> (As an aside, I think open_submodule() should have been replaced by\n> repo_submodule_init().)\n>\n> In which case, yes it isn't used by anything in that code path, but\n> being meticulous about maintaining .super_prefix means that other\n> callers could use it if they wanted to, which might be crucial once we\n> start plumb \"struct repository\" deeper and deeper and...\n\n...I just don't see the point of maintaining an API with this sort of\nreach for just two callers, when it's a bad fit for what those two\ncallers need.\n\n>>\n>> Still, removing this field might not be a good move, as the\n>> \"super_prefix\" might be a common enough case in the future, e.g. when\n>> eventually migrating the \"submodule--helper\" users[1] to run\n>> in-process.\n>>\n>> As the \"grep\" example demonstrates I don't think that's the\n>> case. There instead of xstrdup()-ing all the way down we're now\n>> carrying a single \"super_prefix\" in the form of a \"struct strbuf\". As\n>> we recurse we then append to it, and strbuf_setlen() it back when we\n>> we recurse out of that submodule. This is similar to how e.g. the\n>> \"read_tree_at()\" API works.\n>\n> This technique might no longer be so appealing. We _could_ pass both\n> \"struct repository\" and \"super_prefix\", but that seems odd given that\n> the super prefix is tied to the repository.\n\nFWIW I don't even think a \"super_prefix\" being tied to a repository is a\nuseful abstraction level in general.\n\nE.g. I've got some local hacky patches to make \"git ls-tree\" able to\nrecurse down submodules, and for that code you usually just want to\nprint the prefix to the current *dir*, and having to print the prefix to\nthe current module, then the current dir-within-module, then the file\njust makes things needlessly complex.\n\n> But that's just a first impression anyway. I don't mind taking another\n> look if this gets a standalone review.\n\n*nod*\n"},{"id":"467394","messageId":"kl6lsfiivcau.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"221115.868rkdknmz.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v2 00/10] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-16T21:07:05Z","receivedAt":"2022-11-16T21:08:12Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Mon, Nov 14 2022, Glen Choo wrote:\n>\n>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>\n>>> It's also proposing to replace Glen's one-patch[6], which is working\n>>> around the problem shown in the test added in 1/10 here. Per\n>>> downthread of [7] I think Glen was aiming for getting a more narrow\n>>> fix in case we split off 9/10 here into some later fix.\n>>>\n>>> As we're fixing an edge case in something that's always been broken\n>>> (and thus wouldn't backport) I think it's better to just fix the\n>>> problem directly, rather than introducing new \"--super-prefix\" use,\n>>> just to take it away later.\n>>\n>> I still prefer that we take the one-patch to unbreak new releases,\n>> because partial clone + submodules is absolutely broken (e.g. it's\n>> already causing quite a lot of headaches at $DAYJOB) and the patch is\n>> obviously harmless.\n>>\n>> And more importantly, it lets us take our time with this series and get\n>> it right without time pressure. It's not as pressing as, e.g. a\n>> regression fix, but it does render certain Git setups unusable.\n>>\n>> With regards to urgency and when to choose \"small and harmless fixes vs\n>> bigger and better fixes\", I think Junio has generally made those calls\n>> in the past. @Taylor if you have an opinion, I'd love to hear it.\n>\n> I feel like I'm missing something here. What's the regression? The test\n> you're adding here didn't work at all until 0f5e8851737 (Merge branch\n> 'rc/fetch-refetch', 2022-04-04), as the command didn't exist yet. That\n> commit went out with v2.36.0.\n>\n> If it never worked there's no regression, and we wouldn't be merging\n> down a fix for older point-releases.\n>\n> Or is there some case I've missed here which did work before, doesn't\n> now, but just isn't captured in this test? If so what case is that, and\n> when did it break?\n\nRight, this wasn't meant to be a regression fix at all. There's good\nreason to believe that this was always broken, so I never went digging\nto see if it ever worked.\n\nEven so, it doesn't change the fact that it's a use case that we've\nexpected to work, but doesn't due to some internal silliness, and that\nwe could fix it without invoking questions of the \"--super-prefix\"\ndesign and dragging out the process (which is admittedly what I should\nhave done in the first place). Since we have such an easy fix in front\nof us, I don't feel good about not fixing this before the next release.\n\nAt any rate, I'm wiling to accept that I'm being overly cautious,\nbecause it's quite likely that this series will make it into the next\nrelease. (We could technically we unbreak 'next', though I don't know\nwho distributes that other than internally @ Google.) I'm ok to drop my\npatch for now, but I'll revive it if it starts to look like this series\nwon't make it into the next release.\n"},{"id":"467454","messageId":"221117.86y1s9h2q5.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6lsfiivcau.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v2 00/10] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-17T18:07:04Z","receivedAt":"2022-11-17T18:10:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Nov 16 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> On Mon, Nov 14 2022, Glen Choo wrote:\n>>\n>>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>>\n>>>> It's also proposing to replace Glen's one-patch[6], which is working\n>>>> around the problem shown in the test added in 1/10 here. Per\n>>>> downthread of [7] I think Glen was aiming for getting a more narrow\n>>>> fix in case we split off 9/10 here into some later fix.\n>>>>\n>>>> As we're fixing an edge case in something that's always been broken\n>>>> (and thus wouldn't backport) I think it's better to just fix the\n>>>> problem directly, rather than introducing new \"--super-prefix\" use,\n>>>> just to take it away later.\n>>>\n>>> I still prefer that we take the one-patch to unbreak new releases,\n>>> because partial clone + submodules is absolutely broken (e.g. it's\n>>> already causing quite a lot of headaches at $DAYJOB) and the patch is\n>>> obviously harmless.\n>>>\n>>> And more importantly, it lets us take our time with this series and get\n>>> it right without time pressure. It's not as pressing as, e.g. a\n>>> regression fix, but it does render certain Git setups unusable.\n>>>\n>>> With regards to urgency and when to choose \"small and harmless fixes vs\n>>> bigger and better fixes\", I think Junio has generally made those calls\n>>> in the past. @Taylor if you have an opinion, I'd love to hear it.\n>>\n>> I feel like I'm missing something here. What's the regression? The test\n>> you're adding here didn't work at all until 0f5e8851737 (Merge branch\n>> 'rc/fetch-refetch', 2022-04-04), as the command didn't exist yet. That\n>> commit went out with v2.36.0.\n>>\n>> If it never worked there's no regression, and we wouldn't be merging\n>> down a fix for older point-releases.\n>>\n>> Or is there some case I've missed here which did work before, doesn't\n>> now, but just isn't captured in this test? If so what case is that, and\n>> when did it break?\n>\n> Right, this wasn't meant to be a regression fix at all. There's good\n> reason to believe that this was always broken, so I never went digging\n> to see if it ever worked.\n>\n> Even so, it doesn't change the fact that it's a use case that we've\n> expected to work, but doesn't due to some internal silliness, and that\n> we could fix it without invoking questions of the \"--super-prefix\"\n> design and dragging out the process (which is admittedly what I should\n> have done in the first place). Since we have such an easy fix in front\n> of us, I don't feel good about not fixing this before the next release.\n>\n> At any rate, I'm wiling to accept that I'm being overly cautious,\n> because it's quite likely that this series will make it into the next\n> release. (We could technically we unbreak 'next', though I don't know\n> who distributes that other than internally @ Google.) I'm ok to drop my\n> patch for now, but I'll revive it if it starts to look like this series\n> won't make it into the next release.\n\nUnderstood, I'm re-rolling this v2, will send it out soon.\n\nI'll keep that patch out for now, but if we're starting to run up\nagainst the next release how about we split it out? So it'll depend on\nhow fast we can review & test this, and if/when Taylor is OK with\nmerging it down.\n\nI really don't care if the fix comes first, but just thought I was\nmissing something and it didn't seem urgent, as it was in the \"never\nworked\" and not \"a regression\" category AFAICT. But if you'd still like\nit shout, and I'll just stack it at the start...\n\n"},{"id":"467455","messageId":"221117.86tu2xh2i1.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6la64tp6xc.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v2 02/10] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-17T18:10:02Z","receivedAt":"2022-11-17T18:15:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Nov 14 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> The \"--super-prefix\" facility was introduced in [1] has always been a\n>> transitory hack, which is why we've made it an error to supply it as\n>> an option to \"git\" to commands that don't know about it.\n>>\n>> That's been a good goal, as it has a global effect we haven't wanted\n>> calls to get_super_prefix() from built-ins we didn't expect.\n>>\n>> But it has meant that when we've had chains of different built-ins\n>> using it all of the processes in that \"chain\" have needed to support\n>> it, and worse processes that don't need it have needed to ask for\n>> \"SUPPORT_SUPER_PREFIX\" because their parent process needs it.\n>>\n>> That's how \"fsmonitor--daemon\" ended up with it, per [2] it's called\n>> from (among other things) \"submodule--helper absorbgitdirs\", but as we\n>> declared \"submodule--helper\" as \"SUPPORT_SUPER_PREFIX\" we needed to\n>> declare \"fsmonitor--daemon\" as accepting it too, even though it\n>> doesn't care about it.\n>>\n>> But in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\n>> invoke itself recursively, and we'd never have another \"in-between\"\n>> process in the chain. So we didn't need the bigger hammer of \"git\n>> --super-prefix\", and the \"setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)\"\n>> that it entails.\n>>\n>> Let's instead accept a hidden \"--super-prefix\" option to\n>> \"submodule--helper absorbgitdirs\" itself.\n>>\n>> Eventually (as with all other \"--super-prefix\" users) we'll want to\n>> clean this code up so that this all happens in-process. I.e. needing\n>> any variant of \"--super-prefix\" is itself a hack around our various\n>> global state, and implicit reliance on \"the_repository\". This stepping\n>> stone makes such an eventual change easier, as we'll need to deal with\n>> less global state at that point.\n>>\n>> The \"fsmonitor--daemon\" test adjusted here was added in [3]. The\n>> comment added in that commit has been out-of-date from the beginning,\n>> and the \"have_t2_error_event()\" was being overly specific in testing\n>> for a bug that we *don't* have. Let's instead test for the stdout and\n>> stderr that we *do have*.\n>\n> I didn't understand this bit initially, because I read this as\n> \"have_t2_error_event() isn't catching bugs\", which isn't true. But I see\n> what you mean after inspecting the test_cmp output:\n>\n>   @@ -1 +1,2 @@\n>   Migrating git directory of 'dir_1/dir_2/sub' from 'dir_1/dir_2/sub/.git' to '.git/modules/dir_1/dir_2/sub'\n>   +fatal: fsmonitor--daemon doesn't support --super-prefix\n>\n> IOW, it doesn't make sense to inspecting the tr2 output for stray\n> warnings when our stderr is so obviously broken. But at the end of the\n> series, I don't think we even need this test at all because if we don't\n> have a global \"--super-prefix\", there's literally no reason for\n> fsmonitor--daemon to worry about absorbgitdirs or \"supporting\" the super\n> prefix. That's why I removed it in [1].\n>\n> Wondering aloud, that stderr suggests that the \"git submodule absorbgitdirs\"\n> invocation failed. I wonder why the test didn't catch a bad exit code\n> (and resulting in us inspecting stderr unnecessarily). I think it's not\n> worth looking too closely at right now, but we could revisit this after\n> we get builtin/submodule.c.\n>\n> [1] https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com\n\nI'm prepping a re-roll where I'll keep some of this test, as testing\nfsmonitor+absorbgitdirs is worthhwile, but the commit message etc. is\nrephrased.\n\n>> diff --git a/git.c b/git.c\n>> index 10202a7f126..b1b7e1a837e 100644\n>> --- a/git.c\n>> +++ b/git.c\n>> @@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {\n>>  \t{ \"format-patch\", cmd_format_patch, RUN_SETUP },\n>>  \t{ \"fsck\", cmd_fsck, RUN_SETUP },\n>>  \t{ \"fsck-objects\", cmd_fsck, RUN_SETUP },\n>> -\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },\n>> +\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, RUN_SETUP },\n>>  \t{ \"gc\", cmd_gc, RUN_SETUP },\n>>  \t{ \"get-tar-commit-id\", cmd_get_tar_commit_id, NO_PARSEOPT },\n>>  \t{ \"grep\", cmd_grep, RUN_SETUP_GENTLY },\n>> diff --git a/parse-options.h b/parse-options.h\n>> index b6ef86e0d15..50d852f2991 100644\n>> --- a/parse-options.h\n>> +++ b/parse-options.h\n>> @@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);\n>>  \t{ OPTION_CALLBACK, 0, \"abbrev\", (var), N_(\"n\"),\t\\\n>>  \t  N_(\"use <n> digits to display object names\"),\t\\\n>>  \t  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }\n>> +#define OPT__SUPER_PREFIX(var) \\\n>> +\tOPT_STRING_F(0, \"super-prefix\", (var), N_(\"prefix\"), \\\n>> +\t\tN_(\"prefixed path to initial superproject\"), PARSE_OPT_HIDDEN)\n>> +\n>\n> Could we default to \"\" instead of NULL? (possibly via a callback). I\n> think there's never any good reason to have NULL instead of \"\", e.g.\n> since this is internal, we don't care to distinguish between\n> \"--super-prefix=''\" and not passing \"--super-prefix\" at all...\n\nI saw this comment on another patch, I think I'll keep it for now, but I\nupdated the reason: It's because the \"prefix\" is either NULL or a\nnon-zero length string, so we're doing the same here to be consistent\nwith it.\n\nI think that makes sense, but ultimately it's an arbitrary choice, but\nas they're sibling variables in the cases they're used doing the same\nseems worthwhile...\n\n>>  #define OPT__COLOR(var, h) \\\n>>  \tOPT_COLOR_FLAG(0, \"color\", (var), (h))\n>>  #define OPT_COLUMN(s, l, v, h) \\\n>> diff --git a/submodule.c b/submodule.c\n>> index c47358097fd..d9fd0af81b6 100644\n>> --- a/submodule.c\n>> +++ b/submodule.c\n>> @@ -2268,7 +2268,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)\n>>   * Embeds a single submodules git directory into the superprojects git dir,\n>>   * non recursively.\n>>   */\n>> -static void relocate_single_git_dir_into_superproject(const char *path)\n>> +static void relocate_single_git_dir_into_superproject(const char *path,\n>> +\t\t\t\t\t\t      const char *super_prefix)\n>>  {\n>>  \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n>>  \tstruct strbuf new_gitdir = STRBUF_INIT;\n>> @@ -2302,7 +2303,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n>>  \t       real_old_git_dir[off] == real_new_git_dir[off])\n>>  \t\toff++;\n>>  \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from '%s' to '%s'\\n\"),\n>> -\t\tget_super_prefix_or_empty(), path,\n>> +\t\t(super_prefix ? super_prefix : \"\"), path,\n>>  \t\treal_old_git_dir + off, real_new_git_dir + off);\n>\n>\n> Which would make sites like these a bit cleaner.\n>\n> Tangentially, 'default to \"\" if NULL' sounds like a common pattern. Is\n> there a good reason not to have a macro or inline function to do that?\n> e.g. we think the ternary expression is good enough?)\n\nSee above.\n\n>>  \n>>  \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n>> @@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n>>  \tstrbuf_release(&new_gitdir);\n>>  }\n>>  \n>> -static void absorb_git_dir_into_superproject_recurse(const char *path)\n>> +static void absorb_git_dir_into_superproject_recurse(const char *path,\n>> +\t\t\t\t\t\t     const char *super_prefix)\n>>  {\n>>  \n>>  \tstruct child_process cp = CHILD_PROCESS_INIT;\n>> @@ -2321,10 +2323,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n>>  \tcp.dir = path;\n>>  \tcp.git_cmd = 1;\n>>  \tcp.no_stdin = 1;\n>> -\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n>> -\t\t     get_super_prefix_or_empty(), path);\n>>  \tstrvec_pushl(&cp.args, \"submodule--helper\",\n>>  \t\t     \"absorbgitdirs\", NULL);\n>> +\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n>> +\t\t     super_prefix : \"\", path);\n>> +\n>>  \tprepare_submodule_repo_env(&cp.env);\n>>  \tif (run_command(&cp))\n>>  \t\tdie(_(\"could not recurse into submodule '%s'\"), path);\n>> @@ -2335,7 +2338,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n>>   * having its git directory within the working tree to the git dir nested\n>>   * in its superprojects git dir under modules/.\n>>   */\n>> -void absorb_git_dir_into_superproject(const char *path)\n>> +void absorb_git_dir_into_superproject_sp(const char *path,\n>> +\t\t\t\t\t const char *super_prefix)\n>>  {\n>>  \tint err_code;\n>>  \tconst char *sub_git_dir;\n>> @@ -2377,14 +2381,14 @@ void absorb_git_dir_into_superproject(const char *path)\n>>  \t\tchar *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);\n>>  \n>>  \t\tif (!starts_with(real_sub_git_dir, real_common_git_dir))\n>> -\t\t\trelocate_single_git_dir_into_superproject(path);\n>> +\t\t\trelocate_single_git_dir_into_superproject(path, super_prefix);\n>>  \n>>  \t\tfree(real_sub_git_dir);\n>>  \t\tfree(real_common_git_dir);\n>>  \t}\n>>  \tstrbuf_release(&gitdir);\n>>  \n>> -\tabsorb_git_dir_into_superproject_recurse(path);\n>> +\tabsorb_git_dir_into_superproject_recurse(path, super_prefix);\n>>  }\n>>  \n>>  int get_superproject_working_tree(struct strbuf *buf)\n>> diff --git a/submodule.h b/submodule.h\n>> index b52a4ff1e73..e5ee13fb06a 100644\n>> --- a/submodule.h\n>> +++ b/submodule.h\n>> @@ -164,7 +164,12 @@ void submodule_unset_core_worktree(const struct submodule *sub);\n>>   */\n>>  void prepare_submodule_repo_env(struct strvec *env);\n>>  \n>> -void absorb_git_dir_into_superproject(const char *path);\n>> +void absorb_git_dir_into_superproject_sp(const char *path,\n>> +\t\t\t\t\t const char *super_prefix);\n>> +static inline void absorb_git_dir_into_superproject(const char *path)\n>> +{\n>> +\tabsorb_git_dir_into_superproject_sp(path, NULL);\n>> +}\n>\n> Is there a reason you chose to go with _sp() instead of changing the\n> original function signature? I tested out that change, and it seems\n> rather small (absorb_git_dir_into_superproject() only has 4 call sites).\n\nI've just changed that, so no more *_sp()...\n\n> Crucially, changing the signature catches a \"git read-tree\" call site:\n>\n>   diff --git a/submodule.c b/submodule.c\n>   index d9fd0af81b..e79a04d3e3 100644\n>   --- a/submodule.c\n>   +++ b/submodule.c\n>   @@ -2139,7 +2139,9 @@ int submodule_move_head(const char *path,\n>           if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {\n>                   if (old_head) {\n>                           if (!submodule_uses_gitfile(path))\n>   -                               absorb_git_dir_into_superproject(path);\n>   +                               /* Pass super_prefix properly later. */\n>   +                               absorb_git_dir_into_superproject(path,\n>   +                                                                get_super_prefix());\n>                   } else {\n>                           struct strbuf gitdir = STRBUF_INIT;\n>                           submodule_name_to_gitdir(&gitdir, the_repository,\n>\n> which would otherwise be broken since we used to read the global super\n> prefix, but we don't do that in this patch. This has no test coverage\n> (bleh), but it shouldn't be too hard, something like:\n>\n>   git init super &&\n>   cd super &&\n>   # Create an unabsorbed submodule right in the worktree\n>   git init sub &&\n>   test_commit -C sub \"foo\" &&\n>   git add sub &&\n>   git commit -m \"Add submodule\" &&\n>   test_commit \"bar\" &&\n>   # This should invoke \"git read-tree\" and absorb the git dir.\n>   # Or maybe we should invoke \"git read-tree\" directly?\n>   git checkout --recurse-submodules HEAD^ 2>err &&\n>   # Search for the shortened message\n>   grep \"Migrating submodule sub from sub to .git/modules/....\" err\n\nAh! Yeah that is a good catch, and a great reason to do it this way.\n\nI tried to come up with a test case that actually tested this. I.e. I\nset a \"here = 1\" at that absorb_git_dir_into_superproject() in the diff\nabove, and then if BUG()'d out in that function, but the part where\nwe're about to recurse.\n\nI couldn't get it to trigger, but I didn't look at it very\nlong. I.e. doesn't this require not this sort of test, but something\nwhere it's being absorbed, *and* we'd walk and absorb it recursiveyl?\n\nAt least with checkout we then run into an error (can't remember the\nmessage, sorry, this was earlier), and I haven't found a way to trigger\nit.\n\nBut I'll poke it some more, but if you happen to have a test case for it\nthat would really help...\n"},{"id":"467456","messageId":"221117.86pmdlh2hh.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6l7czxp5dd.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v2 04/10] submodule--helper: convert \"foreach\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-17T18:14:54Z","receivedAt":"2022-11-17T18:15:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Nov 14 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> As with a preceding commit to convert \"absorbgitdirs\", we can convert\n>> \"submodule--helper foreach\" to use its own \"--super-prefix\", instead\n>> of relying on the global \"--super-prefix\" argument to \"git\"\n>> itself. See that earlier commit for the rationale and background.\n>>\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> ---\n>>  builtin/submodule--helper.c | 15 ++++++++++-----\n>>  1 file changed, 10 insertions(+), 5 deletions(-)\n>>\n>> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n>> index c4d5e029b37..989c75280af 100644\n>> --- a/builtin/submodule--helper.c\n>> +++ b/builtin/submodule--helper.c\n>> @@ -396,7 +398,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n>>  \tstruct foreach_cb info = FOREACH_CB_INIT;\n>>  \tstruct pathspec pathspec = { 0 };\n>>  \tstruct module_list list = MODULE_LIST_INIT;\n>> +\tconst char *super_prefix = NULL;\n>>  \tstruct option module_foreach_options[] = {\n>> +\t\tOPT__SUPER_PREFIX(&super_prefix),\n>>  \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n>>  \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n>>  \t\t\t N_(\"recurse into nested submodules\")),\n>> @@ -417,6 +421,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n>>  \tinfo.argc = argc;\n>>  \tinfo.argv = argv;\n>>  \tinfo.prefix = prefix;\n>> +\tinfo.super_prefix = super_prefix;\n>\n> (Also applies to subsequent patches) Why don't we assign the super\n> prefix directly to the struct's field? e.g.\n>\n> \t\tOPT__SUPER_PREFIX(&info.super_prefix),\n\nGood point! I've done that consistently in my WIP re-roll.\n"},{"id":"467566","messageId":"patch-v3-1.9-c930fc38356-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v3 1/9] read-tree + fetch tests: test failing \"--super-prefix\" interaction","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:20Z","receivedAt":"2022-11-19T12:41:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nEver since \"git fetch --refetch\" was introduced in 0f5e8851737 (Merge\nbranch 'rc/fetch-refetch', 2022-04-04) the test being added here would\nfail. This is because \"restore\" will \"read-tree .. --reset <hash>\",\nwhich will in turn invoke \"fetch\". The \"fetch\" will then die with:\n\n\tfatal: fetch doesn't support --super-prefix\n\nThis edge case and other \"--super-prefix\" bugs will be fixed in\nsubsequent commits, but let's first add a \"test_expect_failure\" test\nfor it. It passes until the very last command in the test.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 43 insertions(+)\n\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 037941b95d2..2846ec6629c 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '\n \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n '\n \n+test_expect_failure 'lazy-fetch in submodule succeeds' '\n+\t# setup\n+\ttest_config_global protocol.file.allow always &&\n+\n+\ttest_when_finished \"rm -rf src-sub\" &&\n+\tgit init src-sub &&\n+\tgit -C src-sub config uploadpack.allowfilter 1 &&\n+\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n+\n+\t# This blob must be missing in the subsequent commit.\n+\techo foo >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule one\" &&\n+\tSUB_ONE=$(git -C src-sub rev-parse HEAD) &&\n+\n+\techo bar >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule two\" &&\n+\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n+\n+\ttest_when_finished \"rm -rf src-super\" &&\n+\tgit init src-super &&\n+\tgit -C src-super config uploadpack.allowfilter 1 &&\n+\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n+\tgit -C src-super submodule add ../src-sub src-sub &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_ONE &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject one\" &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_TWO &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject two\" &&\n+\n+\t# the fetch\n+\ttest_when_finished \"rm -rf client\" &&\n+\tgit clone --filter=blob:none --also-filter-submodules \\\n+\t\t--recurse-submodules \"file://$(pwd)/src-super\" client &&\n+\n+\t# Trigger lazy-fetch from the superproject\n+\tgit -C client restore --recurse-submodules --source=HEAD^ :/\n+'\n+\n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n start_httpd\n \n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467567","messageId":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v2-00.10-00000000000-20221114T100803Z-avarab@gmail.com","subject":"[PATCH v3 0/9] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:19Z","receivedAt":"2022-11-19T12:41:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"= Summary\n\nWhat's \"--super-prefix\"? The \"git\" command takes an \"internal use\nonly\" \"--super-prefix\" option, which is used to inform processes\ninvoked in submodules what the path prefix to the invoking\nsuperproject is.\n\nThis is so so that e.g. \"git submodule absorbgitdirs\" can report\n\"sub-1/sub-2\", instead of \"sub-2\" when being invoked in the \"sub-1\"\nsubmodule.\n\nFor this the \"--super-prefix\" facility has been doing a\nsetenv(\"GIT_INTERNAL_SUPER_PREFIX\", \"sub-1/\") as soon as it got the\n\"--supre-prefix=sub-1/\". We'd then pass that along via the environment\nwhen invoking the sub-process.\n\nAs this series shows we don't need such a hands-off global facility to\ndo this, we can instead just pass the relevant context directly in\neach command. E.g. \"git submodule absorbgitdirs\" can pass the path to\nthe \"git submodule absorbgitdirs\" sub-process it's about to invoke.\n\n= Relation to other submissions\n\nThis is on top of \"ab/submodule-helper-prep-only\" and\n\"ab/submodule-no-abspath\", buth currently in \"next\".\n\n= Changes since v2:\n\n* Fixes for test_when_finished() in test setup, and got rid of\n  redundant test_config_global.\n\n* There's a new 2/9, which passes along get_super_prefix() as a\n  parameter. This allows us to gradually replace it, and drop the\n  *_sp() variants of functions that the previous version introduced,\n  and it adds \"super_prefix\" to the absorb_git_dir_into_superproject()\n  call in submodule_move_head(), which as Glen noticed I'd missed\n\n* Squashed the \"deinit\" change into that 2/9.\n\n* Explain why we keep the \"fsmonitor\" test bits that we do.\n\n* Dropped the new \"git branch\" output tests, turns out I was just\n  wrong, and was conflating it with the subsequent read-tree\n  invocation...\n\nSo, this should address all outstanding feedbakc, unless I've missed\nsomething.\n\nThe one loose end here is that I still have no idea if you can invoke\nget \"read-tree\" to invoke that submodule_move_head() in such a way as\nto have the \"super_prefix\" used, I've failed to come up with a test\ncase for that.\n\nBut for the purposes of this topic it doesn't really matter. In 8/10\nwe'll start passing the new \"--super-prefix\" that \"read-tree\" gets\ndown to that function. At worst we're handing it to it redundantly,\nbut that was the case before too.\n\nSo we can leave potentially turning that into a \"NULL\" for some other\ntime, for now providing the \"super_prefix\" is harmless, and guarantees\nthat we avoid any regression in that area from not providing it, in\ncase I've missed a way to have it matter in that case.\n\n= CI & fetch URL\n\nPassing at: https://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local-3\n\nGlen Choo (1):\n  read-tree + fetch tests: test failing \"--super-prefix\" interaction\n\nÆvar Arnfjörð Bjarmason (8):\n  submodule.c & submodule--helper: pass along \"super_prefix\" param\n  submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n  submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n  submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n  submodule--helper: convert \"status\" to its own \"--super-prefix\"\n  submodule--helper: convert \"{update,clone}\" to their own\n    \"--super-prefix\"\n  read-tree: add \"--super-prefix\" option, eliminate global\n  fetch: rename \"--submodule-prefix\" to \"--super-prefix\"\n\n Documentation/fetch-options.txt |  5 --\n Documentation/git.txt           |  8 +--\n builtin.h                       |  4 --\n builtin/checkout.c              |  2 +-\n builtin/fetch.c                 |  7 ++-\n builtin/read-tree.c             |  1 +\n builtin/rm.c                    |  2 +-\n builtin/submodule--helper.c     | 87 ++++++++++++++++++---------------\n cache.h                         |  2 -\n entry.c                         | 12 ++---\n entry.h                         |  6 ++-\n environment.c                   | 13 -----\n git.c                           | 41 +++-------------\n parse-options.h                 |  4 ++\n submodule.c                     | 73 +++++++++++++--------------\n submodule.h                     |  8 +--\n t/t1001-read-tree-m-2way.sh     |  2 +-\n t/t5616-partial-clone.sh        | 43 ++++++++++++++++\n t/t7527-builtin-fsmonitor.sh    | 33 +++----------\n unpack-trees.c                  | 23 +++++----\n unpack-trees.h                  |  1 +\n 21 files changed, 180 insertions(+), 197 deletions(-)\n\nRange-diff against v2:\n 1:  1114a4ff666 !  1:  c930fc38356 read-tree + fetch tests: test failing \"--super-prefix\" interaction\n    @@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor o\n     +\t# setup\n     +\ttest_config_global protocol.file.allow always &&\n     +\n    ++\ttest_when_finished \"rm -rf src-sub\" &&\n     +\tgit init src-sub &&\n     +\tgit -C src-sub config uploadpack.allowfilter 1 &&\n     +\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n    @@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor o\n     +\tgit -C src-sub commit -m \"submodule two\" &&\n     +\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n     +\n    ++\ttest_when_finished \"rm -rf src-super\" &&\n     +\tgit init src-super &&\n     +\tgit -C src-super config uploadpack.allowfilter 1 &&\n     +\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n    @@ t/t5616-partial-clone.sh: test_expect_success 'repack does not loosen promisor o\n     +\tgit -C src-super commit -m \"superproject two\" &&\n     +\n     +\t# the fetch\n    -+\ttest_when_finished \"rm -rf src-super src-sub client\" &&\n    -+\n    -+\ttest_config_global protocol.file.allow always &&\n    ++\ttest_when_finished \"rm -rf client\" &&\n     +\tgit clone --filter=blob:none --also-filter-submodules \\\n     +\t\t--recurse-submodules \"file://$(pwd)/src-super\" client &&\n     +\n 3:  a7a1f9487dc !  2:  2e4a2236898 submodule--helper: \"deinit\" has never used \"--super-prefix\"\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    submodule--helper: \"deinit\" has never used \"--super-prefix\"\n    +    submodule.c & submodule--helper: pass along \"super_prefix\" param\n     \n    -    The \"deinit_submodule()\" function has never been able to use the \"git\n    -    --super-prefix\". It will call \"absorb_git_dir_into_superproject()\",\n    -    but it will only do so from the top-level project.\n    +    Start passing the \"super_prefix\" along as a parameter to\n    +    get_submodule_displaypath() and absorb_git_dir_into_superproject(),\n    +    rather than get the value directly as a global.\n     \n    -    If \"absorbgitdirs\" recurses it will use the \"path\" passed to\n    -    \"absorb_git_dir_into_superproject()\" in \"deinit_submodule()\" as its\n    -    starting \"--super-prefix\".\n    +    This is in preparation for subsequent commits, where we'll gradually\n    +    phase out get_super_prefix() for an alternative way of getting the\n    +    \"super_prefix\".\n     \n    -    So, let's introduce a \"get_submodule_displaypath_sp()\" helper, and\n    -    make our existing \"get_submodule_displaypath()\" a wrapper for it. In a\n    -    subsequent commit the wrapper will be going away, as the rest of the\n    -    commands here will stop using the global \"get_super_prefix()\".\n    +    Most of the users of this get a get_super_prefix() value, either\n    +    directly or by indirection. The exceptions are:\n    +\n    +    - builtin/rm.c: Doesn't declare SUPPORT_SUPER_PREFIX, so we'd have\n    +      died if this was provided, so it's safe to passs \"NULL\".\n    +\n    +    - deinit_submodule(): The \"deinit_submodule()\" function has never been\n    +      able to use the \"git -super-prefix\". It will call\n    +      \"absorb_git_dir_into_superproject()\", but it will only do so from the\n    +      top-level project.\n    +\n    +      If \"absorbgitdirs\" recurses it will use the \"path\" passed to\n    +      \"absorb_git_dir_into_superproject()\" in \"deinit_submodule()\" as its\n    +      starting \"--super-prefix\". So we can safely remove the\n    +      get_super_prefix() call here, and pass NULL instead.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    + ## builtin/rm.c ##\n    +@@ builtin/rm.c: static void submodules_absorb_gitdir_if_needed(void)\n    + \t\t\tcontinue;\n    + \n    + \t\tif (!submodule_uses_gitfile(name))\n    +-\t\t\tabsorb_git_dir_into_superproject(name);\n    ++\t\t\tabsorb_git_dir_into_superproject(name, NULL);\n    + \t}\n    + }\n    + \n    +\n      ## builtin/submodule--helper.c ##\n     @@ builtin/submodule--helper.c: static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n      }\n      \n      /* the result should be freed by the caller. */\n     -static char *get_submodule_displaypath(const char *path, const char *prefix)\n    -+static char *get_submodule_displaypath_sp(const char *path, const char *prefix,\n    -+\t\t\t\t\t  const char *super_prefix)\n    ++static char *get_submodule_displaypath(const char *path, const char *prefix,\n    ++\t\t\t\t       const char *super_prefix)\n      {\n     -\tconst char *super_prefix = get_super_prefix();\n     -\n      \tif (prefix && super_prefix) {\n      \t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n      \t\t    prefix, super_prefix);\n    -@@ builtin/submodule--helper.c: static char *get_submodule_displaypath(const char *path, const char *prefix)\n    +@@ builtin/submodule--helper.c: static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n    + \tstruct child_process cp = CHILD_PROCESS_INIT;\n    + \tchar *displaypath;\n    + \n    +-\tdisplaypath = get_submodule_displaypath(path, info->prefix);\n    ++\tdisplaypath = get_submodule_displaypath(path, info->prefix,\n    ++\t\t\t\t\t\tget_super_prefix());\n    + \n    + \tsub = submodule_from_path(the_repository, null_oid(), path);\n    + \n    +@@ builtin/submodule--helper.c: static void init_submodule(const char *path, const char *prefix,\n    + \tconst char *upd;\n    + \tchar *url = NULL, *displaypath;\n    + \n    +-\tdisplaypath = get_submodule_displaypath(path, prefix);\n    ++\tdisplaypath = get_submodule_displaypath(path, prefix,\n    ++\t\t\t\t\t\tget_super_prefix());\n    + \n    + \tsub = submodule_from_path(the_repository, null_oid(), path);\n    + \n    +@@ builtin/submodule--helper.c: static void status_submodule(const char *path, const struct object_id *ce_oid,\n    + \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n    + \t\t      path);\n    + \n    +-\tdisplaypath = get_submodule_displaypath(path, prefix);\n    ++\tdisplaypath = get_submodule_displaypath(path, prefix,\n    ++\t\t\t\t\t\tget_super_prefix());\n    + \n    + \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n    + \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n    +@@ builtin/submodule--helper.c: static void generate_submodule_summary(struct summary_cb *info,\n    + \t\tdst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);\n      \t}\n    - }\n      \n    -+static char *get_submodule_displaypath(const char *path, const char *prefix)\n    -+{\n    -+\tconst char *super_prefix = get_super_prefix();\n    -+\n    -+\treturn get_submodule_displaypath_sp(path, prefix, super_prefix);\n    -+}\n    -+\n    - static char *compute_rev_name(const char *sub_path, const char* object_id)\n    - {\n    - \tstruct strbuf sb = STRBUF_INIT;\n    +-\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix);\n    ++\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix,\n    ++\t\t\t\t\t\tget_super_prefix());\n    + \n    + \tif (!missing_src && !missing_dst) {\n    + \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n    +@@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const char *prefix,\n    + \t\tsuper_config_url = xstrdup(\"\");\n    + \t}\n    + \n    +-\tdisplaypath = get_submodule_displaypath(path, prefix);\n    ++\tdisplaypath = get_submodule_displaypath(path, prefix,\n    ++\t\t\t\t\t\tget_super_prefix());\n    + \n    + \tif (!(flags & OPT_QUIET))\n    + \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n     @@ builtin/submodule--helper.c: static void deinit_submodule(const char *path, const char *prefix,\n      \tif (!sub || !sub->name)\n      \t\tgoto cleanup;\n      \n     -\tdisplaypath = get_submodule_displaypath(path, prefix);\n    -+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, NULL);\n    ++\tdisplaypath = get_submodule_displaypath(path, prefix, NULL);\n      \n      \t/* remove the submodule work tree (unless the user already did it) */\n      \tif (is_directory(path)) {\n    +@@ builtin/submodule--helper.c: static void deinit_submodule(const char *path, const char *prefix,\n    + \t\t\t\t\t  \".git file by using absorbgitdirs.\"),\n    + \t\t\t\t\tdisplaypath);\n    + \n    +-\t\t\tabsorb_git_dir_into_superproject(path);\n    ++\t\t\tabsorb_git_dir_into_superproject(path, NULL);\n    + \n    + \t\t}\n    + \n    +@@ builtin/submodule--helper.c: static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n    + \tenum submodule_update_type update_type;\n    + \tchar *key;\n    + \tconst struct update_data *ud = suc->update_data;\n    +-\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n    ++\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix,\n    ++\t\t\t\t\t\t      get_super_prefix());\n    + \tstruct strbuf sb = STRBUF_INIT;\n    + \tint needs_cloning = 0;\n    + \tint need_free_url = 0;\n    +@@ builtin/submodule--helper.c: static int update_submodules(struct update_data *update_data)\n    + \t\t\tgoto fail;\n    + \n    + \t\tupdate_data->displaypath = get_submodule_displaypath(\n    +-\t\t\tupdate_data->sm_path, update_data->prefix);\n    ++\t\t\tupdate_data->sm_path, update_data->prefix,\n    ++\t\t\tget_super_prefix());\n    + \t\tcode = update_submodule(update_data);\n    + \t\tFREE_AND_NULL(update_data->displaypath);\n    + fail:\n    +@@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n    + \tint i;\n    + \tstruct pathspec pathspec = { 0 };\n    + \tstruct module_list list = MODULE_LIST_INIT;\n    ++\tconst char *super_prefix;\n    + \tstruct option embed_gitdir_options[] = {\n    + \t\tOPT_END()\n    + \t};\n    +@@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n    + \tif (module_list_compute(argv, prefix, &pathspec, &list) < 0)\n    + \t\tgoto cleanup;\n    + \n    ++\tsuper_prefix = get_super_prefix();\n    + \tfor (i = 0; i < list.nr; i++)\n    +-\t\tabsorb_git_dir_into_superproject(list.entries[i]->name);\n    ++\t\tabsorb_git_dir_into_superproject(list.entries[i]->name,\n    ++\t\t\t\t\t\t super_prefix);\n    + \n    + \tret = 0;\n    + cleanup:\n    +\n    + ## submodule.c ##\n    +@@ submodule.c: int submodule_move_head(const char *path,\n    + \tif (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {\n    + \t\tif (old_head) {\n    + \t\t\tif (!submodule_uses_gitfile(path))\n    +-\t\t\t\tabsorb_git_dir_into_superproject(path);\n    ++\t\t\t\tabsorb_git_dir_into_superproject(path,\n    ++\t\t\t\t\t\t\t\t get_super_prefix());\n    + \t\t} else {\n    + \t\t\tstruct strbuf gitdir = STRBUF_INIT;\n    + \t\t\tsubmodule_name_to_gitdir(&gitdir, the_repository,\n    +@@ submodule.c: static void relocate_single_git_dir_into_superproject(const char *path)\n    + \tstrbuf_release(&new_gitdir);\n    + }\n    + \n    +-static void absorb_git_dir_into_superproject_recurse(const char *path)\n    ++static void absorb_git_dir_into_superproject_recurse(const char *path,\n    ++\t\t\t\t\t\t     const char *super_prefix)\n    + {\n    + \n    + \tstruct child_process cp = CHILD_PROCESS_INIT;\n    +@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path)\n    + \tcp.dir = path;\n    + \tcp.git_cmd = 1;\n    + \tcp.no_stdin = 1;\n    +-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n    +-\t\t     get_super_prefix_or_empty(), path);\n    ++\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n    ++\t\t     super_prefix : \"\", path);\n    + \tstrvec_pushl(&cp.args, \"submodule--helper\",\n    + \t\t     \"absorbgitdirs\", NULL);\n    + \tprepare_submodule_repo_env(&cp.env);\n    +@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path)\n    +  * having its git directory within the working tree to the git dir nested\n    +  * in its superprojects git dir under modules/.\n    +  */\n    +-void absorb_git_dir_into_superproject(const char *path)\n    ++void absorb_git_dir_into_superproject(const char *path,\n    ++\t\t\t\t      const char *super_prefix)\n    + {\n    + \tint err_code;\n    + \tconst char *sub_git_dir;\n    +@@ submodule.c: void absorb_git_dir_into_superproject(const char *path)\n    + \t}\n    + \tstrbuf_release(&gitdir);\n    + \n    +-\tabsorb_git_dir_into_superproject_recurse(path);\n    ++\tabsorb_git_dir_into_superproject_recurse(path, super_prefix);\n    + }\n    + \n    + int get_superproject_working_tree(struct strbuf *buf)\n    +\n    + ## submodule.h ##\n    +@@ submodule.h: void submodule_unset_core_worktree(const struct submodule *sub);\n    +  */\n    + void prepare_submodule_repo_env(struct strvec *env);\n    + \n    +-void absorb_git_dir_into_superproject(const char *path);\n    ++void absorb_git_dir_into_superproject(const char *path,\n    ++\t\t\t\t      const char *super_prefix);\n    + \n    + /*\n    +  * Return the absolute path of the working tree of the superproject, which this\n 2:  5a35f7b75b3 !  3:  6e10a47c60a submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n    @@ Commit message\n         stone makes such an eventual change easier, as we'll need to deal with\n         less global state at that point.\n     \n    -    The \"fsmonitor--daemon\" test adjusted here was added in [3]. The\n    -    comment added in that commit has been out-of-date from the beginning,\n    -    and the \"have_t2_error_event()\" was being overly specific in testing\n    -    for a bug that we *don't* have. Let's instead test for the stdout and\n    -    stderr that we *do have*.\n    +    The \"fsmonitor--daemon\" test adjusted here was added in [3]. To assert\n    +    that it didn't run into the \"--super-prefix\" message it was asserting\n    +    the output it didn't have. Let's instead assert the full output that\n    +    we *do* have, which we can do here as this is based on a change[4] to\n    +    make it predictable (until [4] it contained absolute paths).\n    +\n    +    We could also remove the test entirely (as [5] did), but even though\n    +    the initial reason for having it is gone we're still getting some\n    +    marginal benefit from testing the \"fsmonitor\" and \"submodule\n    +    absorbgitdirs\" interaction, so let's keep it.\n    +\n    +    The change here to have either a NULL or non-\"\" string as a\n    +    \"super_prefix\" instead of the previous arrangement of \"\" or non-\"\" is\n    +    somewhat arbitrary. We could also decide to never have to check for\n    +    NULL.\n    +\n    +    As we'll be changing the rest of the \"git --super-prefix\" users to the\n    +    same pattern, leaving them all consistent makes sense. Why not pick \"\"\n    +    over NULL? Because that's how the \"prefix\" works[6], and having\n    +    \"prefix\" and \"super_prefix\" work the same way will be less\n    +    confusing. That \"prefix\" picked NULL instead of \"\" is itself\n    +    arbitrary, but as it's easy to make this small bit of our overall API\n    +    consistent, let's go with that.\n     \n         1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n         2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n            2022-05-26)\n         3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n            2022-05-26)\n    +    4. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/\n    +    5. https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com/\n    +    6. 9725c8dda20 (built-ins: trust the \"prefix\" from run_builtin(),\n    +       2022-02-16)\n     \n         Signed-off-by: Glen Choo <chooglen@google.com>\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n    @@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **a\n      \tint i;\n      \tstruct pathspec pathspec = { 0 };\n      \tstruct module_list list = MODULE_LIST_INIT;\n    +-\tconst char *super_prefix;\n     +\tconst char *super_prefix = NULL;\n      \tstruct option embed_gitdir_options[] = {\n     +\t\tOPT__SUPER_PREFIX(&super_prefix),\n    @@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **a\n      \t};\n      \tconst char *const git_submodule_helper_usage[] = {\n     @@ builtin/submodule--helper.c: static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n    + \tif (module_list_compute(argv, prefix, &pathspec, &list) < 0)\n      \t\tgoto cleanup;\n      \n    +-\tsuper_prefix = get_super_prefix();\n      \tfor (i = 0; i < list.nr; i++)\n    --\t\tabsorb_git_dir_into_superproject(list.entries[i]->name);\n    -+\t\tabsorb_git_dir_into_superproject_sp(list.entries[i]->name,\n    -+\t\t\t\t\t\t    super_prefix);\n    - \n    - \tret = 0;\n    - cleanup:\n    + \t\tabsorb_git_dir_into_superproject(list.entries[i]->name,\n    + \t\t\t\t\t\t super_prefix);\n     @@ builtin/submodule--helper.c: int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n      \n      \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n    @@ submodule.c: static void relocate_single_git_dir_into_superproject(const char *p\n      \t\toff++;\n      \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from '%s' to '%s'\\n\"),\n     -\t\tget_super_prefix_or_empty(), path,\n    -+\t\t(super_prefix ? super_prefix : \"\"), path,\n    ++\t\tsuper_prefix ? super_prefix : \"\", path,\n      \t\treal_old_git_dir + off, real_new_git_dir + off);\n      \n      \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n    -@@ submodule.c: static void relocate_single_git_dir_into_superproject(const char *path)\n    - \tstrbuf_release(&new_gitdir);\n    - }\n    - \n    --static void absorb_git_dir_into_superproject_recurse(const char *path)\n    -+static void absorb_git_dir_into_superproject_recurse(const char *path,\n    -+\t\t\t\t\t\t     const char *super_prefix)\n    - {\n    - \n    - \tstruct child_process cp = CHILD_PROCESS_INIT;\n    -@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path)\n    +@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path,\n      \tcp.dir = path;\n      \tcp.git_cmd = 1;\n      \tcp.no_stdin = 1;\n    --\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n    --\t\t     get_super_prefix_or_empty(), path);\n    +-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n    +-\t\t     super_prefix : \"\", path);\n      \tstrvec_pushl(&cp.args, \"submodule--helper\",\n      \t\t     \"absorbgitdirs\", NULL);\n     +\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n    @@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *pa\n      \tprepare_submodule_repo_env(&cp.env);\n      \tif (run_command(&cp))\n      \t\tdie(_(\"could not recurse into submodule '%s'\"), path);\n    -@@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path)\n    -  * having its git directory within the working tree to the git dir nested\n    -  * in its superprojects git dir under modules/.\n    -  */\n    --void absorb_git_dir_into_superproject(const char *path)\n    -+void absorb_git_dir_into_superproject_sp(const char *path,\n    -+\t\t\t\t\t const char *super_prefix)\n    - {\n    - \tint err_code;\n    - \tconst char *sub_git_dir;\n    -@@ submodule.c: void absorb_git_dir_into_superproject(const char *path)\n    +@@ submodule.c: void absorb_git_dir_into_superproject(const char *path,\n      \t\tchar *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);\n      \n      \t\tif (!starts_with(real_sub_git_dir, real_common_git_dir))\n    @@ submodule.c: void absorb_git_dir_into_superproject(const char *path)\n      \n      \t\tfree(real_sub_git_dir);\n      \t\tfree(real_common_git_dir);\n    - \t}\n    - \tstrbuf_release(&gitdir);\n    - \n    --\tabsorb_git_dir_into_superproject_recurse(path);\n    -+\tabsorb_git_dir_into_superproject_recurse(path, super_prefix);\n    - }\n    - \n    - int get_superproject_working_tree(struct strbuf *buf)\n    -\n    - ## submodule.h ##\n    -@@ submodule.h: void submodule_unset_core_worktree(const struct submodule *sub);\n    -  */\n    - void prepare_submodule_repo_env(struct strvec *env);\n    - \n    --void absorb_git_dir_into_superproject(const char *path);\n    -+void absorb_git_dir_into_superproject_sp(const char *path,\n    -+\t\t\t\t\t const char *super_prefix);\n    -+static inline void absorb_git_dir_into_superproject(const char *path)\n    -+{\n    -+\tabsorb_git_dir_into_superproject_sp(path, NULL);\n    -+}\n    - \n    - /*\n    -  * Return the absolute path of the working tree of the superproject, which this\n     \n      ## t/t7527-builtin-fsmonitor.sh ##\n     @@ t/t7527-builtin-fsmonitor.sh: test_expect_success 'submodule always visited' '\n 4:  935d8070834 !  4:  da86eb3b867 submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n    @@ builtin/submodule--helper.c: struct foreach_cb {\n      \tint recursive;\n      };\n     @@ builtin/submodule--helper.c: static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n    - \tstruct child_process cp = CHILD_PROCESS_INIT;\n      \tchar *displaypath;\n      \n    --\tdisplaypath = get_submodule_displaypath(path, info->prefix);\n    -+\tdisplaypath = get_submodule_displaypath_sp(path, info->prefix,\n    -+\t\t\t\t\t\t   info->super_prefix);\n    + \tdisplaypath = get_submodule_displaypath(path, info->prefix,\n    +-\t\t\t\t\t\tget_super_prefix());\n    ++\t\t\t\t\t\tinfo->super_prefix);\n      \n      \tsub = submodule_from_path(the_repository, null_oid(), path);\n      \n    @@ builtin/submodule--helper.c: static void runcommand_in_submodule_cb(const struct\n      \t\tif (info->quiet)\n      \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n     @@ builtin/submodule--helper.c: static int module_foreach(int argc, const char **argv, const char *prefix)\n    - \tstruct foreach_cb info = FOREACH_CB_INIT;\n      \tstruct pathspec pathspec = { 0 };\n      \tstruct module_list list = MODULE_LIST_INIT;\n    -+\tconst char *super_prefix = NULL;\n      \tstruct option module_foreach_options[] = {\n    -+\t\tOPT__SUPER_PREFIX(&super_prefix),\n    ++\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n      \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n      \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n      \t\t\t N_(\"recurse into nested submodules\")),\n    -@@ builtin/submodule--helper.c: static int module_foreach(int argc, const char **argv, const char *prefix)\n    - \tinfo.argc = argc;\n    - \tinfo.argv = argv;\n    - \tinfo.prefix = prefix;\n    -+\tinfo.super_prefix = super_prefix;\n    - \n    - \tfor_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);\n    - \n     @@ builtin/submodule--helper.c: int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n      \tsubcmd = argv[0];\n      \n 5:  933c752513d !  5:  2eb583148a6 submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n    @@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const\n      \t\tsuper_config_url = xstrdup(\"\");\n      \t}\n      \n    --\tdisplaypath = get_submodule_displaypath(path, prefix);\n    -+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);\n    +-\tdisplaypath = get_submodule_displaypath(path, prefix,\n    +-\t\t\t\t\t\tget_super_prefix());\n    ++\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n      \n      \tif (!(flags & OPT_QUIET))\n      \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n    @@ builtin/submodule--helper.c: static void sync_submodule_cb(const struct cache_en\n      \n      static int module_sync(int argc, const char **argv, const char *prefix)\n     @@ builtin/submodule--helper.c: static int module_sync(int argc, const char **argv, const char *prefix)\n    - \tstruct module_list list = MODULE_LIST_INIT;\n      \tint quiet = 0;\n      \tint recursive = 0;\n    -+\tconst char *super_prefix = NULL;\n      \tstruct option module_sync_options[] = {\n    -+\t\tOPT__SUPER_PREFIX(&super_prefix),\n    ++\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n      \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n      \t\tOPT_BOOL(0, \"recursive\", &recursive,\n      \t\t\tN_(\"recurse into nested submodules\")),\n    -@@ builtin/submodule--helper.c: static int module_sync(int argc, const char **argv, const char *prefix)\n    - \t\tgoto cleanup;\n    - \n    - \tinfo.prefix = prefix;\n    -+\tinfo.super_prefix = super_prefix;\n    - \tif (quiet)\n    - \t\tinfo.flags |= OPT_QUIET;\n    - \tif (recursive)\n     @@ builtin/submodule--helper.c: static int module_set_url(int argc, const char **argv, const char *prefix)\n      \tconfig_name = xstrfmt(\"submodule.%s.url\", path);\n      \n 6:  67273f729e0 !  6:  8d8925c7e1f submodule--helper: convert \"status\" to its own \"--super-prefix\"\n    @@ builtin/submodule--helper.c: static void status_submodule(const char *path, cons\n      \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n      \t\t      path);\n      \n    --\tdisplaypath = get_submodule_displaypath(path, prefix);\n    -+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);\n    +-\tdisplaypath = get_submodule_displaypath(path, prefix,\n    +-\t\t\t\t\t\tget_super_prefix());\n    ++\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n      \n      \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n      \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n    @@ builtin/submodule--helper.c: static void status_submodule_cb(const struct cache_\n      \n      static int module_status(int argc, const char **argv, const char *prefix)\n     @@ builtin/submodule--helper.c: static int module_status(int argc, const char **argv, const char *prefix)\n    - \tstruct pathspec pathspec = { 0 };\n      \tstruct module_list list = MODULE_LIST_INIT;\n      \tint quiet = 0;\n    -+\tconst char *super_prefix = NULL;\n      \tstruct option module_status_options[] = {\n    -+\t\tOPT__SUPER_PREFIX(&super_prefix),\n    ++\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n      \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n      \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n      \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n    -@@ builtin/submodule--helper.c: static int module_status(int argc, const char **argv, const char *prefix)\n    - \t\tgoto cleanup;\n    - \n    - \tinfo.prefix = prefix;\n    -+\tinfo.super_prefix = super_prefix;\n    - \tif (quiet)\n    - \t\tinfo.flags |= OPT_QUIET;\n    - \n     @@ builtin/submodule--helper.c: int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n      \tsubcmd = argv[0];\n      \n 7:  eaa73f5b1e4 !  7:  754a7489aa5 submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"\n    @@ Commit message\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static char *get_submodule_displaypath_sp(const char *path, const char *prefix,\n    - \t}\n    - }\n    - \n    --static char *get_submodule_displaypath(const char *path, const char *prefix)\n    --{\n    --\tconst char *super_prefix = get_super_prefix();\n    --\n    --\treturn get_submodule_displaypath_sp(path, prefix, super_prefix);\n    --}\n    --\n    - static char *compute_rev_name(const char *sub_path, const char* object_id)\n    - {\n    - \tstruct strbuf sb = STRBUF_INIT;\n     @@ builtin/submodule--helper.c: static int starts_with_dot_dot_slash(const char *const path)\n      \n      struct init_cb {\n    @@ builtin/submodule--helper.c: static void init_submodule(const char *path, const\n      \tconst char *upd;\n      \tchar *url = NULL, *displaypath;\n      \n    --\tdisplaypath = get_submodule_displaypath(path, prefix);\n    -+\tdisplaypath = get_submodule_displaypath_sp(path, prefix, super_prefix);\n    +-\tdisplaypath = get_submodule_displaypath(path, prefix,\n    +-\t\t\t\t\t\tget_super_prefix());\n    ++\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n      \n      \tsub = submodule_from_path(the_repository, null_oid(), path);\n      \n    @@ builtin/submodule--helper.c: struct summary_cb {\n      \tunsigned int for_status: 1;\n      \tunsigned int files: 1;\n     @@ builtin/submodule--helper.c: static void generate_submodule_summary(struct summary_cb *info,\n    - \t\tdst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);\n      \t}\n      \n    --\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix);\n    -+\tdisplaypath = get_submodule_displaypath_sp(p->sm_path, info->prefix,\n    -+\t\t\t\t\t\t   info->super_prefix);\n    + \tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix,\n    +-\t\t\t\t\t\tget_super_prefix());\n    ++\t\t\t\t\t\tinfo->super_prefix);\n      \n      \tif (!missing_src && !missing_dst) {\n      \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n    @@ builtin/submodule--helper.c: static void submodule_update_clone_release(struct s\n      \tenum submodule_update_type update_default;\n      \tstruct object_id suboid;\n     @@ builtin/submodule--helper.c: static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n    - \tenum submodule_update_type update_type;\n      \tchar *key;\n      \tconst struct update_data *ud = suc->update_data;\n    --\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n    -+\tchar *displaypath = get_submodule_displaypath_sp(ce->name, ud->prefix,\n    -+\t\t\t\t\t\t\t ud->super_prefix);\n    + \tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix,\n    +-\t\t\t\t\t\t      get_super_prefix());\n    ++\t\t\t\t\t\t      ud->super_prefix);\n      \tstruct strbuf sb = STRBUF_INIT;\n      \tint needs_cloning = 0;\n      \tint need_free_url = 0;\n    @@ builtin/submodule--helper.c: static void update_data_to_args(const struct update\n      \tif (update_data->quiet)\n      \t\tstrvec_push(args, \"--quiet\");\n     @@ builtin/submodule--helper.c: static int update_submodules(struct update_data *update_data)\n    - \t\tif (code)\n    - \t\t\tgoto fail;\n      \n    --\t\tupdate_data->displaypath = get_submodule_displaypath(\n    --\t\t\tupdate_data->sm_path, update_data->prefix);\n    -+\t\tupdate_data->displaypath = get_submodule_displaypath_sp(\n    -+\t\t\tupdate_data->sm_path, update_data->prefix,\n    + \t\tupdate_data->displaypath = get_submodule_displaypath(\n    + \t\t\tupdate_data->sm_path, update_data->prefix,\n    +-\t\t\tget_super_prefix());\n     +\t\t\tupdate_data->super_prefix);\n      \t\tcode = update_submodule(update_data);\n      \t\tFREE_AND_NULL(update_data->displaypath);\n      fail:\n     @@ builtin/submodule--helper.c: static int module_update(int argc, const char **argv, const char *prefix)\n    - \tstruct list_objects_filter_options filter_options =\n      \t\tLIST_OBJECTS_FILTER_INIT;\n      \tint ret;\n    -+\tconst char *super_prefix = NULL;\n      \tstruct option module_update_options[] = {\n    -+\t\tOPT__SUPER_PREFIX(&super_prefix),\n    ++\t\tOPT__SUPER_PREFIX(&opt.super_prefix),\n      \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n      \t\tOPT_BOOL(0, \"init\", &opt.init,\n      \t\t\t N_(\"initialize uninitialized submodules before update\")),\n     @@ builtin/submodule--helper.c: static int module_update(int argc, const char **argv, const char *prefix)\n    - \n    - \topt.filter_options = &filter_options;\n    - \topt.prefix = prefix;\n    -+\topt.super_prefix = super_prefix;\n    - \n    - \tif (opt.update_default)\n    - \t\topt.update_strategy.type = opt.update_default;\n    -@@ builtin/submodule--helper.c: static int module_update(int argc, const char **argv, const char *prefix)\n      \t\t\tmodule_list_active(&list);\n      \n      \t\tinfo.prefix = opt.prefix;\n    -+\t\tinfo.super_prefix = super_prefix;\n    ++\t\tinfo.super_prefix = opt.super_prefix;\n      \t\tif (opt.quiet)\n      \t\t\tinfo.flags |= OPT_QUIET;\n      \n 8:  172b5865811 <  -:  ----------- submodule tests: test \"git branch -t\" output and stderr\n 9:  9fdeab60773 !  8:  f952fa3d01f read-tree: add \"--super-prefix\" option, eliminate global\n    @@ submodule.c: static void submodule_reset_index(const char *path)\n      {\n      \tint ret = 0;\n      \tstruct child_process cp = CHILD_PROCESS_INIT;\n    +@@ submodule.c: int submodule_move_head(const char *path,\n    + \t\tif (old_head) {\n    + \t\t\tif (!submodule_uses_gitfile(path))\n    + \t\t\t\tabsorb_git_dir_into_superproject(path,\n    +-\t\t\t\t\t\t\t\t get_super_prefix());\n    ++\t\t\t\t\t\t\t\t super_prefix);\n    + \t\t} else {\n    + \t\t\tstruct strbuf gitdir = STRBUF_INIT;\n    + \t\t\tsubmodule_name_to_gitdir(&gitdir, the_repository,\n     @@ submodule.c: int submodule_move_head(const char *path,\n      \t\t\tstrbuf_release(&gitdir);\n      \n10:  100ba36dfb7 =  9:  1aa4019527a fetch: rename \"--submodule-prefix\" to \"--super-prefix\"\n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467568","messageId":"patch-v3-3.9-6e10a47c60a-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v3 3/9] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:22Z","receivedAt":"2022-11-19T12:42:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" facility was introduced in [1] has always been a\ntransitory hack, which is why we've made it an error to supply it as\nan option to \"git\" to commands that don't know about it.\n\nThat's been a good goal, as it has a global effect we haven't wanted\ncalls to get_super_prefix() from built-ins we didn't expect.\n\nBut it has meant that when we've had chains of different built-ins\nusing it all of the processes in that \"chain\" have needed to support\nit, and worse processes that don't need it have needed to ask for\n\"SUPPORT_SUPER_PREFIX\" because their parent process needs it.\n\nThat's how \"fsmonitor--daemon\" ended up with it, per [2] it's called\nfrom (among other things) \"submodule--helper absorbgitdirs\", but as we\ndeclared \"submodule--helper\" as \"SUPPORT_SUPER_PREFIX\" we needed to\ndeclare \"fsmonitor--daemon\" as accepting it too, even though it\ndoesn't care about it.\n\nBut in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\ninvoke itself recursively, and we'd never have another \"in-between\"\nprocess in the chain. So we didn't need the bigger hammer of \"git\n--super-prefix\", and the \"setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)\"\nthat it entails.\n\nLet's instead accept a hidden \"--super-prefix\" option to\n\"submodule--helper absorbgitdirs\" itself.\n\nEventually (as with all other \"--super-prefix\" users) we'll want to\nclean this code up so that this all happens in-process. I.e. needing\nany variant of \"--super-prefix\" is itself a hack around our various\nglobal state, and implicit reliance on \"the_repository\". This stepping\nstone makes such an eventual change easier, as we'll need to deal with\nless global state at that point.\n\nThe \"fsmonitor--daemon\" test adjusted here was added in [3]. To assert\nthat it didn't run into the \"--super-prefix\" message it was asserting\nthe output it didn't have. Let's instead assert the full output that\nwe *do* have, which we can do here as this is based on a change[4] to\nmake it predictable (until [4] it contained absolute paths).\n\nWe could also remove the test entirely (as [5] did), but even though\nthe initial reason for having it is gone we're still getting some\nmarginal benefit from testing the \"fsmonitor\" and \"submodule\nabsorbgitdirs\" interaction, so let's keep it.\n\nThe change here to have either a NULL or non-\"\" string as a\n\"super_prefix\" instead of the previous arrangement of \"\" or non-\"\" is\nsomewhat arbitrary. We could also decide to never have to check for\nNULL.\n\nAs we'll be changing the rest of the \"git --super-prefix\" users to the\nsame pattern, leaving them all consistent makes sense. Why not pick \"\"\nover NULL? Because that's how the \"prefix\" works[6], and having\n\"prefix\" and \"super_prefix\" work the same way will be less\nconfusing. That \"prefix\" picked NULL instead of \"\" is itself\narbitrary, but as it's easy to make this small bit of our overall API\nconsistent, let's go with that.\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n   2022-05-26)\n3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n   2022-05-26)\n4. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/\n5. https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com/\n6. 9725c8dda20 (built-ins: trust the \"prefix\" from run_builtin(),\n   2022-02-16)\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c  |  7 +++----\n git.c                        |  2 +-\n parse-options.h              |  4 ++++\n submodule.c                  | 12 +++++++-----\n t/t7527-builtin-fsmonitor.sh | 33 ++++++++-------------------------\n 5 files changed, 23 insertions(+), 35 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex dc220d3348b..9f6ebc64140 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2834,8 +2834,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n-\tconst char *super_prefix;\n+\tconst char *super_prefix = NULL;\n \tstruct option embed_gitdir_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT_END()\n \t};\n \tconst char *const git_submodule_helper_usage[] = {\n@@ -2850,7 +2851,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tif (module_list_compute(argv, prefix, &pathspec, &list) < 0)\n \t\tgoto cleanup;\n \n-\tsuper_prefix = get_super_prefix();\n \tfor (i = 0; i < list.nr; i++)\n \t\tabsorb_git_dir_into_superproject(list.entries[i]->name,\n \t\t\t\t\t\t super_prefix);\n@@ -3391,8 +3391,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n \t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && strcmp(subcmd, \"absorbgitdirs\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\ndiff --git a/git.c b/git.c\nindex 10202a7f126..b1b7e1a837e 100644\n--- a/git.c\n+++ b/git.c\n@@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {\n \t{ \"format-patch\", cmd_format_patch, RUN_SETUP },\n \t{ \"fsck\", cmd_fsck, RUN_SETUP },\n \t{ \"fsck-objects\", cmd_fsck, RUN_SETUP },\n-\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },\n+\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, RUN_SETUP },\n \t{ \"gc\", cmd_gc, RUN_SETUP },\n \t{ \"get-tar-commit-id\", cmd_get_tar_commit_id, NO_PARSEOPT },\n \t{ \"grep\", cmd_grep, RUN_SETUP_GENTLY },\ndiff --git a/parse-options.h b/parse-options.h\nindex b6ef86e0d15..50d852f2991 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);\n \t{ OPTION_CALLBACK, 0, \"abbrev\", (var), N_(\"n\"),\t\\\n \t  N_(\"use <n> digits to display object names\"),\t\\\n \t  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }\n+#define OPT__SUPER_PREFIX(var) \\\n+\tOPT_STRING_F(0, \"super-prefix\", (var), N_(\"prefix\"), \\\n+\t\tN_(\"prefixed path to initial superproject\"), PARSE_OPT_HIDDEN)\n+\n #define OPT__COLOR(var, h) \\\n \tOPT_COLOR_FLAG(0, \"color\", (var), (h))\n #define OPT_COLUMN(s, l, v, h) \\\ndiff --git a/submodule.c b/submodule.c\nindex d339ce3b62c..3383c47c719 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2269,7 +2269,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)\n  * Embeds a single submodules git directory into the superprojects git dir,\n  * non recursively.\n  */\n-static void relocate_single_git_dir_into_superproject(const char *path)\n+static void relocate_single_git_dir_into_superproject(const char *path,\n+\t\t\t\t\t\t      const char *super_prefix)\n {\n \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n \tstruct strbuf new_gitdir = STRBUF_INIT;\n@@ -2303,7 +2304,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \t       real_old_git_dir[off] == real_new_git_dir[off])\n \t\toff++;\n \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from '%s' to '%s'\\n\"),\n-\t\tget_super_prefix_or_empty(), path,\n+\t\tsuper_prefix ? super_prefix : \"\", path,\n \t\treal_old_git_dir + off, real_new_git_dir + off);\n \n \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n@@ -2323,10 +2324,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path,\n \tcp.dir = path;\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n-\t\t     super_prefix : \"\", path);\n \tstrvec_pushl(&cp.args, \"submodule--helper\",\n \t\t     \"absorbgitdirs\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n+\t\t     super_prefix : \"\", path);\n+\n \tprepare_submodule_repo_env(&cp.env);\n \tif (run_command(&cp))\n \t\tdie(_(\"could not recurse into submodule '%s'\"), path);\n@@ -2380,7 +2382,7 @@ void absorb_git_dir_into_superproject(const char *path,\n \t\tchar *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);\n \n \t\tif (!starts_with(real_sub_git_dir, real_common_git_dir))\n-\t\t\trelocate_single_git_dir_into_superproject(path);\n+\t\t\trelocate_single_git_dir_into_superproject(path, super_prefix);\n \n \t\tfree(real_sub_git_dir);\n \t\tfree(real_common_git_dir);\ndiff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh\nindex 4abc74db2bb..31526937d95 100755\n--- a/t/t7527-builtin-fsmonitor.sh\n+++ b/t/t7527-builtin-fsmonitor.sh\n@@ -866,30 +866,11 @@ test_expect_success 'submodule always visited' '\n # the submodule, and someone does a `git submodule absorbgitdirs`\n # in the super, Git will recursively invoke `git submodule--helper`\n # to do the work and this may try to read the index.  This will\n-# try to start the daemon in the submodule *and* pass (either\n-# directly or via inheritance) the `--super-prefix` arg to the\n-# `git fsmonitor--daemon start` command inside the submodule.\n-# This causes a warning because fsmonitor--daemon does take that\n-# global arg (see the table in git.c)\n-#\n-# This causes a warning when trying to start the daemon that is\n-# somewhat confusing.  It does not seem to hurt anything because\n-# the fsmonitor code maps the query failure into a trivial response\n-# and does the work anyway.\n-#\n-# It would be nice to silence the warning, however.\n-\n-have_t2_error_event () {\n-\tlog=$1\n-\tmsg=\"fsmonitor--daemon doesnQt support --super-prefix\" &&\n-\n-\ttr '\\047' Q <$1 | grep -e \"$msg\"\n-}\n+# try to start the daemon in the submodule.\n \n test_expect_success \"stray submodule super-prefix warning\" '\n \ttest_when_finished \"rm -rf super; \\\n-\t\t\t    rm -rf sub;   \\\n-\t\t\t    rm super-sub.trace\" &&\n+\t\t\t    rm -rf sub\" &&\n \n \tcreate_super super &&\n \tcreate_sub sub &&\n@@ -904,10 +885,12 @@ test_expect_success \"stray submodule super-prefix warning\" '\n \n \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n \n-\tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n-\t\tgit -C super submodule absorbgitdirs &&\n-\n-\t! have_t2_error_event super-sub.trace\n+\tcat >expect <<-\\EOF &&\n+\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from '\\''dir_1/dir_2/sub/.git'\\'' to '\\''.git/modules/dir_1/dir_2/sub'\\''\n+\tEOF\n+\tgit -C super submodule absorbgitdirs >out 2>actual &&\n+\ttest_cmp expect actual &&\n+\ttest_must_be_empty out\n '\n \n # On a case-insensitive file system, confirm that the daemon\n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467569","messageId":"patch-v3-2.9-2e4a2236898-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v3 2/9] submodule.c & submodule--helper: pass along \"super_prefix\" param","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:21Z","receivedAt":"2022-11-19T12:42:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Start passing the \"super_prefix\" along as a parameter to\nget_submodule_displaypath() and absorb_git_dir_into_superproject(),\nrather than get the value directly as a global.\n\nThis is in preparation for subsequent commits, where we'll gradually\nphase out get_super_prefix() for an alternative way of getting the\n\"super_prefix\".\n\nMost of the users of this get a get_super_prefix() value, either\ndirectly or by indirection. The exceptions are:\n\n- builtin/rm.c: Doesn't declare SUPPORT_SUPER_PREFIX, so we'd have\n  died if this was provided, so it's safe to passs \"NULL\".\n\n- deinit_submodule(): The \"deinit_submodule()\" function has never been\n  able to use the \"git -super-prefix\". It will call\n  \"absorb_git_dir_into_superproject()\", but it will only do so from the\n  top-level project.\n\n  If \"absorbgitdirs\" recurses it will use the \"path\" passed to\n  \"absorb_git_dir_into_superproject()\" in \"deinit_submodule()\" as its\n  starting \"--super-prefix\". So we can safely remove the\n  get_super_prefix() call here, and pass NULL instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/rm.c                |  2 +-\n builtin/submodule--helper.c | 35 ++++++++++++++++++++++-------------\n submodule.c                 | 15 +++++++++------\n submodule.h                 |  3 ++-\n 4 files changed, 34 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex 05bfe20a469..24e13f6e899 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -86,7 +86,7 @@ static void submodules_absorb_gitdir_if_needed(void)\n \t\t\tcontinue;\n \n \t\tif (!submodule_uses_gitfile(name))\n-\t\t\tabsorb_git_dir_into_superproject(name);\n+\t\t\tabsorb_git_dir_into_superproject(name, NULL);\n \t}\n }\n \ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c75e9e86b06..dc220d3348b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n }\n \n /* the result should be freed by the caller. */\n-static char *get_submodule_displaypath(const char *path, const char *prefix)\n+static char *get_submodule_displaypath(const char *path, const char *prefix,\n+\t\t\t\t       const char *super_prefix)\n {\n-\tconst char *super_prefix = get_super_prefix();\n-\n \tif (prefix && super_prefix) {\n \t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n \t\t    prefix, super_prefix);\n@@ -294,7 +293,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath(path, info->prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -447,7 +447,8 @@ static void init_submodule(const char *path, const char *prefix,\n \tconst char *upd;\n \tchar *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -624,7 +625,8 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n \t\t      path);\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n@@ -948,7 +950,8 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t\tdst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tif (!missing_src && !missing_dst) {\n \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n@@ -1239,7 +1242,8 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tsuper_config_url = xstrdup(\"\");\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tif (!(flags & OPT_QUIET))\n \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n@@ -1365,7 +1369,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \tif (!sub || !sub->name)\n \t\tgoto cleanup;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix, NULL);\n \n \t/* remove the submodule work tree (unless the user already did it) */\n \tif (is_directory(path)) {\n@@ -1379,7 +1383,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \t\t\t\t\t  \".git file by using absorbgitdirs.\"),\n \t\t\t\t\tdisplaypath);\n \n-\t\t\tabsorb_git_dir_into_superproject(path);\n+\t\t\tabsorb_git_dir_into_superproject(path, NULL);\n \n \t\t}\n \n@@ -1958,7 +1962,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tenum submodule_update_type update_type;\n \tchar *key;\n \tconst struct update_data *ud = suc->update_data;\n-\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n+\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix,\n+\t\t\t\t\t\t      get_super_prefix());\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n \tint need_free_url = 0;\n@@ -2608,7 +2613,8 @@ static int update_submodules(struct update_data *update_data)\n \t\t\tgoto fail;\n \n \t\tupdate_data->displaypath = get_submodule_displaypath(\n-\t\t\tupdate_data->sm_path, update_data->prefix);\n+\t\t\tupdate_data->sm_path, update_data->prefix,\n+\t\t\tget_super_prefix());\n \t\tcode = update_submodule(update_data);\n \t\tFREE_AND_NULL(update_data->displaypath);\n fail:\n@@ -2828,6 +2834,7 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tconst char *super_prefix;\n \tstruct option embed_gitdir_options[] = {\n \t\tOPT_END()\n \t};\n@@ -2843,8 +2850,10 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tif (module_list_compute(argv, prefix, &pathspec, &list) < 0)\n \t\tgoto cleanup;\n \n+\tsuper_prefix = get_super_prefix();\n \tfor (i = 0; i < list.nr; i++)\n-\t\tabsorb_git_dir_into_superproject(list.entries[i]->name);\n+\t\tabsorb_git_dir_into_superproject(list.entries[i]->name,\n+\t\t\t\t\t\t super_prefix);\n \n \tret = 0;\n cleanup:\ndiff --git a/submodule.c b/submodule.c\nindex c47358097fd..d339ce3b62c 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2139,7 +2139,8 @@ int submodule_move_head(const char *path,\n \tif (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {\n \t\tif (old_head) {\n \t\t\tif (!submodule_uses_gitfile(path))\n-\t\t\t\tabsorb_git_dir_into_superproject(path);\n+\t\t\t\tabsorb_git_dir_into_superproject(path,\n+\t\t\t\t\t\t\t\t get_super_prefix());\n \t\t} else {\n \t\t\tstruct strbuf gitdir = STRBUF_INIT;\n \t\t\tsubmodule_name_to_gitdir(&gitdir, the_repository,\n@@ -2313,7 +2314,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \tstrbuf_release(&new_gitdir);\n }\n \n-static void absorb_git_dir_into_superproject_recurse(const char *path)\n+static void absorb_git_dir_into_superproject_recurse(const char *path,\n+\t\t\t\t\t\t     const char *super_prefix)\n {\n \n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2321,8 +2323,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n \tcp.dir = path;\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n+\t\t     super_prefix : \"\", path);\n \tstrvec_pushl(&cp.args, \"submodule--helper\",\n \t\t     \"absorbgitdirs\", NULL);\n \tprepare_submodule_repo_env(&cp.env);\n@@ -2335,7 +2337,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n  * having its git directory within the working tree to the git dir nested\n  * in its superprojects git dir under modules/.\n  */\n-void absorb_git_dir_into_superproject(const char *path)\n+void absorb_git_dir_into_superproject(const char *path,\n+\t\t\t\t      const char *super_prefix)\n {\n \tint err_code;\n \tconst char *sub_git_dir;\n@@ -2384,7 +2387,7 @@ void absorb_git_dir_into_superproject(const char *path)\n \t}\n \tstrbuf_release(&gitdir);\n \n-\tabsorb_git_dir_into_superproject_recurse(path);\n+\tabsorb_git_dir_into_superproject_recurse(path, super_prefix);\n }\n \n int get_superproject_working_tree(struct strbuf *buf)\ndiff --git a/submodule.h b/submodule.h\nindex b52a4ff1e73..f90ee547d08 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -164,7 +164,8 @@ void submodule_unset_core_worktree(const struct submodule *sub);\n  */\n void prepare_submodule_repo_env(struct strvec *env);\n \n-void absorb_git_dir_into_superproject(const char *path);\n+void absorb_git_dir_into_superproject(const char *path,\n+\t\t\t\t      const char *super_prefix);\n \n /*\n  * Return the absolute path of the working tree of the superproject, which this\n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467570","messageId":"patch-v3-4.9-da86eb3b867-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v3 4/9] submodule--helper: convert \"foreach\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:23Z","receivedAt":"2022-11-19T12:42:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper foreach\" to use its own \"--super-prefix\", instead\nof relying on the global \"--super-prefix\" argument to \"git\"\nitself. See that earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9f6ebc64140..7c6f367fa00 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -278,6 +278,7 @@ struct foreach_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint quiet;\n \tint recursive;\n };\n@@ -294,7 +295,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tchar *displaypath;\n \n \tdisplaypath = get_submodule_displaypath(path, info->prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\t\t\t\t\t\tinfo->super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -364,10 +365,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"foreach\", \"--recursive\",\n \t\t\t     NULL);\n+\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (info->quiet)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -391,6 +392,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n \tstruct option module_foreach_options[] = {\n+\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n \t\t\t N_(\"recurse into nested submodules\")),\n@@ -3390,8 +3392,8 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467571","messageId":"patch-v3-6.9-8d8925c7e1f-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v3 6/9] submodule--helper: convert \"status\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:25Z","receivedAt":"2022-11-19T12:42:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7ac51c3506d..8a186b61b9d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -573,6 +573,7 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \n struct status_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define STATUS_CB_INIT { 0 }\n@@ -611,7 +612,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,\n \n static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\t\t     unsigned int ce_flags, const char *prefix,\n-\t\t\t     unsigned int flags)\n+\t\t\t     const char *super_prefix, unsigned int flags)\n {\n \tchar *displaypath;\n \tstruct strvec diff_files_args = STRVEC_INIT;\n@@ -627,8 +628,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n \t\t      path);\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n \n \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n@@ -686,10 +686,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"status\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (flags & OPT_CACHED)\n \t\t\tstrvec_push(&cpr.args, \"--cached\");\n@@ -713,7 +713,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,\n \tstruct status_cb *info = cb_data;\n \n \tstatus_submodule(list_item->name, &list_item->oid, list_item->ce_flags,\n-\t\t\t info->prefix, info->flags);\n+\t\t\t info->prefix, info->super_prefix, info->flags);\n }\n \n static int module_status(int argc, const char **argv, const char *prefix)\n@@ -723,6 +723,7 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n \tstruct option module_status_options[] = {\n+\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n@@ -3395,7 +3396,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && get_super_prefix())\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467572","messageId":"patch-v3-5.9-2eb583148a6-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v3 5/9] submodule--helper: convert \"sync\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:24Z","receivedAt":"2022-11-19T12:42:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper sync\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 20 +++++++++++---------\n 1 file changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7c6f367fa00..7ac51c3506d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1208,12 +1208,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \n struct sync_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define SYNC_CB_INIT { 0 }\n \n static void sync_submodule(const char *path, const char *prefix,\n-\t\t\t   unsigned int flags)\n+\t\t\t   const char *super_prefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n@@ -1244,8 +1245,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tsuper_config_url = xstrdup(\"\");\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n \n \tif (!(flags & OPT_QUIET))\n \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n@@ -1282,10 +1282,11 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"sync\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n+\n \n \t\tif (flags & OPT_QUIET)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -1308,7 +1309,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct sync_cb *info = cb_data;\n \n-\tsync_submodule(list_item->name, info->prefix, info->flags);\n+\tsync_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_sync(int argc, const char **argv, const char *prefix)\n@@ -1319,6 +1321,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \tint quiet = 0;\n \tint recursive = 0;\n \tstruct option module_sync_options[] = {\n+\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n \t\tOPT_BOOL(0, \"recursive\", &recursive,\n \t\t\tN_(\"recurse into nested submodules\")),\n@@ -2887,7 +2890,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)\n \tconfig_name = xstrfmt(\"submodule.%s.url\", path);\n \n \tconfig_set_in_gitmodules_file_gently(config_name, newurl);\n-\tsync_submodule(path, prefix, quiet ? OPT_QUIET : 0);\n+\tsync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);\n \n \tfree(config_name);\n \n@@ -3392,8 +3395,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467573","messageId":"patch-v3-7.9-754a7489aa5-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v3 7/9] submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:26Z","receivedAt":"2022-11-19T12:42:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\".\n\nWe need to convert both of these away from the global \"--super-prefix\"\nat the same time, because \"update\" will call \"clone\", but \"clone\"\nitself didn't make use of the global \"--super-prefix\" for displaying\npaths. It was only on the list of sub-commands that accepted it\nbecause \"update\"'s use of it would set it in its environment.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 32 +++++++++++++-------------------\n git.c                       |  2 +-\n 2 files changed, 14 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 8a186b61b9d..b1945a06da1 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -437,11 +437,13 @@ static int starts_with_dot_dot_slash(const char *const path)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define INIT_CB_INIT { 0 }\n \n static void init_submodule(const char *path, const char *prefix,\n+\t\t\t   const char *super_prefix,\n \t\t\t   unsigned int flags)\n {\n \tconst struct submodule *sub;\n@@ -449,8 +451,7 @@ static void init_submodule(const char *path, const char *prefix,\n \tconst char *upd;\n \tchar *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -526,7 +527,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct init_cb *info = cb_data;\n \n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n@@ -792,6 +794,7 @@ struct summary_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int cached: 1;\n \tunsigned int for_status: 1;\n \tunsigned int files: 1;\n@@ -954,7 +957,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t}\n \n \tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\t\t\t\t\t\tinfo->super_prefix);\n \n \tif (!missing_src && !missing_dst) {\n \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n@@ -1893,6 +1896,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)\n \n struct update_data {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tchar *displaypath;\n \tenum submodule_update_type update_default;\n \tstruct object_id suboid;\n@@ -1969,7 +1973,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tchar *key;\n \tconst struct update_data *ud = suc->update_data;\n \tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix,\n-\t\t\t\t\t\t      get_super_prefix());\n+\t\t\t\t\t\t      ud->super_prefix);\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n \tint need_free_url = 0;\n@@ -2449,11 +2453,11 @@ static void update_data_to_args(const struct update_data *update_data,\n {\n \tenum submodule_update_type update_type = update_data->update_default;\n \n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tif (update_data->displaypath) {\n \t\tstrvec_push(args, \"--super-prefix\");\n \t\tstrvec_pushf(args, \"%s/\", update_data->displaypath);\n \t}\n-\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n \tif (update_data->quiet)\n \t\tstrvec_push(args, \"--quiet\");\n@@ -2620,7 +2624,7 @@ static int update_submodules(struct update_data *update_data)\n \n \t\tupdate_data->displaypath = get_submodule_displaypath(\n \t\t\tupdate_data->sm_path, update_data->prefix,\n-\t\t\tget_super_prefix());\n+\t\t\tupdate_data->super_prefix);\n \t\tcode = update_submodule(update_data);\n \t\tFREE_AND_NULL(update_data->displaypath);\n fail:\n@@ -2646,6 +2650,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\tLIST_OBJECTS_FILTER_INIT;\n \tint ret;\n \tstruct option module_update_options[] = {\n+\t\tOPT__SUPER_PREFIX(&opt.super_prefix),\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n \t\tOPT_BOOL(0, \"init\", &opt.init,\n \t\t\t N_(\"initialize uninitialized submodules before update\")),\n@@ -2742,6 +2747,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\t\tmodule_list_active(&list);\n \n \t\tinfo.prefix = opt.prefix;\n+\t\tinfo.super_prefix = opt.super_prefix;\n \t\tif (opt.quiet)\n \t\t\tinfo.flags |= OPT_QUIET;\n \n@@ -3368,8 +3374,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n {\n-\tconst char *cmd = argv[0];\n-\tconst char *subcmd;\n \tparse_opt_subcommand_fn *fn = NULL;\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule--helper <command>\"),\n@@ -3393,16 +3397,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\tsubcmd = argv[0];\n-\n-\tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    get_super_prefix())\n-\t\t/*\n-\t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n-\t\t * string identical to git.c's.\n-\t\t */\n-\t\tdie(_(\"%s doesn't support --super-prefix\"),\n-\t\t    xstrfmt(\"'%s %s'\", cmd, subcmd));\n \n \treturn fn(argc, argv, prefix);\n }\ndiff --git a/git.c b/git.c\nindex b1b7e1a837e..2bca22cfd9a 100644\n--- a/git.c\n+++ b/git.c\n@@ -610,7 +610,7 @@ static struct cmd_struct commands[] = {\n \t{ \"stash\", cmd_stash, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"stripspace\", cmd_stripspace },\n-\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP },\n \t{ \"switch\", cmd_switch, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"symbolic-ref\", cmd_symbolic_ref, RUN_SETUP },\n \t{ \"tag\", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },\n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467574","messageId":"patch-v3-9.9-1aa4019527a-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v3 9/9] fetch: rename \"--submodule-prefix\" to \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:28Z","receivedAt":"2022-11-19T12:42:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In preceding commits we've introduced a command-level \"--super-prefix\"\noption, which unlike the \"git --super-prefix\" it replaced doesn't rely\non setenv() or getenv(), it's just a normal command-line option that\nthe command passes down.\n\nSince we've done that, let's rename the \"--submodule-prefix\" option\nadded in 7dce19d374a (fetch/pull: Add the --recurse-submodules option,\n2010-11-12) to \"--super-prefix\" for consistency. This:\n\n * Allows us to use OPT__SUPER_PREFIX().\n * Leaves an unspecified \"--super-prefix\" with a \"NULL\" value, rather\n   than an empty string, as is the case with the other \"--super-prefix\"\n   users. We coerce the NULL to \"\" in submodule.c before using it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/fetch-options.txt |  5 -----\n builtin/fetch.c                 |  7 +++----\n submodule.c                     | 23 +++++++++++------------\n 3 files changed, 14 insertions(+), 21 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 622bd84768b..20cbd2c2910 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -241,11 +241,6 @@ endif::git-pull[]\n \tlinkgit:git-config[1].\n \n ifndef::git-pull[]\n---submodule-prefix=<path>::\n-\tPrepend <path> to paths printed in informative messages\n-\tsuch as \"Fetching submodule foo\".  This option is used\n-\tinternally when recursing over submodules.\n-\n --recurse-submodules-default=[yes|on-demand]::\n \tThis option is used internally to temporarily provide a\n \tnon-negative default value for the --recurse-submodules\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 7378cafeec9..353bcd36d24 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -74,7 +74,7 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;\n static struct strbuf default_rla = STRBUF_INIT;\n static struct transport *gtransport;\n static struct transport *gsecondary;\n-static const char *submodule_prefix = \"\";\n+static const char *super_prefix;\n static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;\n static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;\n@@ -195,8 +195,7 @@ static struct option builtin_fetch_options[] = {\n \tOPT_SET_INT_F(0, \"refetch\", &refetch,\n \t\t      N_(\"re-fetch without negotiating common commits\"),\n \t\t      1, PARSE_OPT_NONEG),\n-\t{ OPTION_STRING, 0, \"submodule-prefix\", &submodule_prefix, N_(\"dir\"),\n-\t\t   N_(\"prepend this to submodule path output\"), PARSE_OPT_HIDDEN },\n+\tOPT__SUPER_PREFIX(&super_prefix),\n \tOPT_CALLBACK_F(0, \"recurse-submodules-default\",\n \t\t   &recurse_submodules_default, N_(\"on-demand\"),\n \t\t   N_(\"default for recursive fetching of submodules \"\n@@ -2300,7 +2299,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t\tadd_options_to_argv(&options);\n \t\tresult = fetch_submodules(the_repository,\n \t\t\t\t\t  &options,\n-\t\t\t\t\t  submodule_prefix,\n+\t\t\t\t\t  super_prefix,\n \t\t\t\t\t  recurse_submodules,\n \t\t\t\t\t  recurse_submodules_default,\n \t\t\t\t\t  verbosity < 0,\ndiff --git a/submodule.c b/submodule.c\nindex f8497793790..3e0aaaa2af0 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1376,7 +1376,7 @@ struct submodule_parallel_fetch {\n \tint changed_count;\n \tstruct strvec args;\n \tstruct repository *r;\n-\tconst char *prefix;\n+\tconst char *super_prefix;\n \tint command_line_option;\n \tint default_option;\n \tint quiet;\n@@ -1567,7 +1567,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,\n \t\tif (task->repo) {\n \t\t\tif (!spf->quiet)\n \t\t\t\tstrbuf_addf(err, _(\"Fetching submodule %s%s\\n\"),\n-\t\t\t\t\t    spf->prefix, ce->name);\n+\t\t\t\t\t    spf->super_prefix, ce->name);\n \n \t\t\tspf->index_count++;\n \t\t\treturn task;\n@@ -1629,7 +1629,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,\n \t\tif (!spf->quiet)\n \t\t\tstrbuf_addf(err,\n \t\t\t\t    _(\"Fetching submodule %s%s at commit %s\\n\"),\n-\t\t\t\t    spf->prefix, task->sub->path,\n+\t\t\t\t    spf->super_prefix, task->sub->path,\n \t\t\t\t    find_unique_abbrev(cs_data->super_oid,\n \t\t\t\t\t\t       DEFAULT_ABBREV));\n \n@@ -1687,11 +1687,10 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n \t\t\tstrvec_pushv(&cp->args, task->git_args.v);\n \t\tstrvec_pushv(&cp->args, spf->args.v);\n \t\tstrvec_push(&cp->args, task->default_argv);\n-\t\tstrvec_push(&cp->args, \"--submodule-prefix\");\n+\t\tstrvec_push(&cp->args, \"--super-prefix\");\n \n-\t\tstrbuf_addf(&submodule_prefix, \"%s%s/\",\n-\t\t\t\t\t\tspf->prefix,\n-\t\t\t\t\t\ttask->sub->path);\n+\t\tstrbuf_addf(&submodule_prefix, \"%s%s/\", spf->super_prefix,\n+\t\t\t    task->sub->path);\n \t\tstrvec_push(&cp->args, submodule_prefix.buf);\n \t\t*task_cb = task;\n \n@@ -1707,7 +1706,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n \t\tspf->oid_fetch_tasks_nr--;\n \n \t\tstrbuf_addf(&submodule_prefix, \"%s%s/\",\n-\t\t\t    spf->prefix, task->sub->path);\n+\t\t\t    spf->super_prefix, task->sub->path);\n \n \t\tchild_process_init(cp);\n \t\tprepare_submodule_repo_env_in_gitdir(&cp->env);\n@@ -1717,7 +1716,7 @@ static int get_next_submodule(struct child_process *cp, struct strbuf *err,\n \t\tstrvec_init(&cp->args);\n \t\tstrvec_pushv(&cp->args, spf->args.v);\n \t\tstrvec_push(&cp->args, \"on-demand\");\n-\t\tstrvec_push(&cp->args, \"--submodule-prefix\");\n+\t\tstrvec_push(&cp->args, \"--super-prefix\");\n \t\tstrvec_push(&cp->args, submodule_prefix.buf);\n \n \t\t/* NEEDSWORK: have get_default_remote from submodule--helper */\n@@ -1813,7 +1812,7 @@ static int fetch_finish(int retvalue, struct strbuf *err,\n \n int fetch_submodules(struct repository *r,\n \t\t     const struct strvec *options,\n-\t\t     const char *prefix, int command_line_option,\n+\t\t     const char *super_prefix, int command_line_option,\n \t\t     int default_option,\n \t\t     int quiet, int max_parallel_jobs)\n {\n@@ -1835,7 +1834,7 @@ int fetch_submodules(struct repository *r,\n \tspf.command_line_option = command_line_option;\n \tspf.default_option = default_option;\n \tspf.quiet = quiet;\n-\tspf.prefix = prefix;\n+\tspf.super_prefix = super_prefix ? super_prefix : \"\";\n \n \tif (!r->worktree)\n \t\tgoto out;\n@@ -1847,7 +1846,7 @@ int fetch_submodules(struct repository *r,\n \tfor (i = 0; i < options->nr; i++)\n \t\tstrvec_push(&spf.args, options->v[i]);\n \tstrvec_push(&spf.args, \"--recurse-submodules-default\");\n-\t/* default value, \"--submodule-prefix\" and its value are added later */\n+\t/* default value, \"--super-prefix\" and its value are added later */\n \n \tcalculate_changed_submodule_paths(r, &spf.changed_submodule_names);\n \tstring_list_sort(&spf.changed_submodule_names);\n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467575","messageId":"patch-v3-8.9-f952fa3d01f-20221119T122853Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v3 8/9] read-tree: add \"--super-prefix\" option, eliminate global","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-11-19T12:41:27Z","receivedAt":"2022-11-19T12:42:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" option to \"git\" was initially added in [1] for\nuse with \"ls-files\"[2], and shortly thereafter \"submodule--helper\"[3]\nand \"grep\"[4]. It wasn't until [5] that \"read-tree\" made use of it.\n\nAt the time [5] made sense, but since then we've made \"ls-files\"\nrecurse in-process in [6], \"grep\" in [7], and finally\n\"submodule--helper\" in the preceding commits.\n\nLet's also remove it from \"read-tree\", which allows us to remove the\noption to \"git\" itself.\n\nWe can do this because the only remaining user of it is the submodule\nAPI, which will now invoke \"read-tree\" with its new \"--super-prefix\"\noption. It will only do so when the \"submodule_move_head()\" function\nis called.\n\nThat \"submodule_move_head()\" function was then only invoked by\n\"read-tree\" itself, but now rather than setting an environment\nvariable to pass \"--super-prefix\" between cmd_read_tree() we:\n\n- Set a new \"super_prefix\" in \"struct unpack_trees_options\". The\n  \"super_prefixed()\" function in \"unpack-trees.c\" added in [5] will now\n  use this, rather than get_super_prefix() looking up the environment\n  variable we set earlier in the same process.\n\n- Add the same field to the \"struct checkout\", which is only needed to\n  ferry the \"super_prefix\" in the \"struct unpack_trees_options\" all the\n  way down to the \"entry.c\" callers of \"submodule_move_head()\".\n\n  Those calls which used the super prefix all originated in\n  \"cmd_read_tree()\". The only other caller is the \"unlink_entry()\"\n  caller in \"builtin/checkout.c\", which now passes a \"NULL\".\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)\n3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)\n4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)\n5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)\n6. 188dce131fa (ls-files: use repository object, 2017-06-22)\n7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git.txt       |  8 +-------\n builtin.h                   |  4 ----\n builtin/checkout.c          |  2 +-\n builtin/read-tree.c         |  1 +\n cache.h                     |  2 --\n entry.c                     | 12 ++++++------\n entry.h                     |  6 +++++-\n environment.c               | 13 -------------\n git.c                       | 37 +++++--------------------------------\n submodule.c                 | 29 ++++++++++-------------------\n submodule.h                 |  5 ++---\n t/t1001-read-tree-m-2way.sh |  2 +-\n t/t5616-partial-clone.sh    |  2 +-\n unpack-trees.c              | 23 +++++++++++++----------\n unpack-trees.h              |  1 +\n 15 files changed, 47 insertions(+), 100 deletions(-)\n\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 1d33e083ab8..f9a7a4554cd 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -13,8 +13,7 @@ SYNOPSIS\n     [--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>]\n+    [--config-env=<name>=<envvar>] <command> [<args>]\n \n DESCRIPTION\n -----------\n@@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use\n \tdetails.  Equivalent to setting the `GIT_NAMESPACE` environment\n \tvariable.\n \n---super-prefix=<path>::\n-\tCurrently for internal use only.  Set a prefix which gives a path from\n-\tabove a repository down to its root.  One use is to give submodules\n-\tcontext about the superproject that invoked it.\n-\n --bare::\n \tTreat the repository as a bare repository.  If GIT_DIR\n \tenvironment is not set, it is set to the current working\ndiff --git a/builtin.h b/builtin.h\nindex 8901a34d6bf..8264b7e5241 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -51,10 +51,6 @@\n  *\ton bare repositories.\n  *\tThis only makes sense when `RUN_SETUP` is also set.\n  *\n- * `SUPPORT_SUPER_PREFIX`:\n- *\n- *\tThe built-in supports `--super-prefix`.\n- *\n  * `DELAY_PAGER_CONFIG`:\n  *\n  *\tIf RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2a132392fbe..dc008fb45e8 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -231,7 +231,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n \t\tpos++;\n \t}\n \tif (!overlay_mode) {\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, NULL);\n \t\treturn 0;\n \t}\n \tif (stage == 2)\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex f4cbe460b97..4b6f22e58c1 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)\n \tint prefix_set = 0;\n \tstruct lock_file lock_file = LOCK_INIT;\n \tconst struct option read_tree_options[] = {\n+\t\tOPT__SUPER_PREFIX(&opts.super_prefix),\n \t\tOPT_CALLBACK_F(0, \"index-output\", NULL, N_(\"file\"),\n \t\t  N_(\"write resulting index to <file>\"),\n \t\t  PARSE_OPT_NONEG, index_output_cb),\ndiff --git a/cache.h b/cache.h\nindex 26ed03bd6de..a4a0377b800 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -504,7 +504,6 @@ static inline enum object_type object_type(unsigned int mode)\n #define GIT_NAMESPACE_ENVIRONMENT \"GIT_NAMESPACE\"\n #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n #define GIT_PREFIX_ENVIRONMENT \"GIT_PREFIX\"\n-#define GIT_SUPER_PREFIX_ENVIRONMENT \"GIT_INTERNAL_SUPER_PREFIX\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n@@ -590,7 +589,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n int get_common_dir(struct strbuf *sb, const char *gitdir);\n const char *get_git_namespace(void);\n const char *strip_namespace(const char *namespaced_ref);\n-const char *get_super_prefix(void);\n const char *get_git_work_tree(void);\n \n /*\ndiff --git a/entry.c b/entry.c\nindex 616e4f073c1..971ab268714 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca\n \t\t\treturn error(\"cannot create submodule directory %s\", path);\n \t\tsub = submodule_from_ce(ce);\n \t\tif (sub)\n-\t\t\treturn submodule_move_head(ce->name,\n+\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\tNULL, oid_to_hex(&ce->oid),\n \t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\tbreak;\n@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t * no pathname to return.\n \t\t\t */\n \t\t\tBUG(\"Can't remove entry to a path\");\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, state->super_prefix);\n \t\treturn 0;\n \t}\n \n@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t\tif (!(st.st_mode & S_IFDIR))\n \t\t\t\t\tunlink_or_warn(ce->name);\n \n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\tNULL, oid_to_hex(&ce->oid), 0);\n \t\t\t} else\n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\t\"HEAD\", oid_to_hex(&ce->oid),\n \t\t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\t}\n@@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \treturn write_entry(ce, path.buf, ca, state, 0, nr_checkouts);\n }\n \n-void unlink_entry(const struct cache_entry *ce)\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)\n {\n \tconst struct submodule *sub = submodule_from_ce(ce);\n \tif (sub) {\n \t\t/* state.force is set at the caller. */\n-\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n+\t\tsubmodule_move_head(ce->name, super_prefix, \"HEAD\", NULL,\n \t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n \t}\n \tif (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)\ndiff --git a/entry.h b/entry.h\nindex 9be4659881e..2d4fbb88c8f 100644\n--- a/entry.h\n+++ b/entry.h\n@@ -8,6 +8,7 @@ struct checkout {\n \tstruct index_state *istate;\n \tconst char *base_dir;\n \tint base_dir_len;\n+\tconst char *super_prefix;\n \tstruct delayed_checkout *delayed_checkout;\n \tstruct checkout_metadata meta;\n \tunsigned force:1,\n@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);\n /*\n  * Unlink the last component and schedule the leading directories for\n  * removal, such that empty directories get removed.\n+ *\n+ * The \"super_prefix\" is either NULL, or the \"--super-prefix\" passed\n+ * down from \"read-tree\" et al.\n  */\n-void unlink_entry(const struct cache_entry *ce);\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);\n \n void *read_blob_entry(const struct cache_entry *ce, size_t *size);\n int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);\ndiff --git a/environment.c b/environment.c\nindex 18d042b467d..1ee3686fd8a 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -102,8 +102,6 @@ char *git_work_tree_cfg;\n \n static char *git_namespace;\n \n-static char *super_prefix;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {\n \tNO_REPLACE_OBJECTS_ENVIRONMENT,\n \tGIT_REPLACE_REF_BASE_ENVIRONMENT,\n \tGIT_PREFIX_ENVIRONMENT,\n-\tGIT_SUPER_PREFIX_ENVIRONMENT,\n \tGIT_SHALLOW_FILE_ENVIRONMENT,\n \tGIT_COMMON_DIR_ENVIRONMENT,\n \tNULL\n@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)\n \treturn NULL;\n }\n \n-const char *get_super_prefix(void)\n-{\n-\tstatic int initialized;\n-\tif (!initialized) {\n-\t\tsuper_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));\n-\t\tinitialized = 1;\n-\t}\n-\treturn super_prefix;\n-}\n-\n static int git_work_tree_initialized;\n \n /*\ndiff --git a/git.c b/git.c\nindex 2bca22cfd9a..00baaf23590 100644\n--- a/git.c\n+++ b/git.c\n@@ -14,9 +14,8 @@\n  * RUN_SETUP for reading from the configuration file.\n  */\n #define NEED_WORK_TREE\t\t(1<<3)\n-#define SUPPORT_SUPER_PREFIX\t(1<<4)\n-#define DELAY_PAGER_CONFIG\t(1<<5)\n-#define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n+#define DELAY_PAGER_CONFIG\t(1<<4)\n+#define NO_PARSEOPT\t\t(1<<5) /* parse-options is not used */\n \n struct cmd_struct {\n \tconst char *cmd;\n@@ -29,8 +28,7 @@ const char git_usage_string[] =\n \t   \"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\\n\"\n \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\\n\"\n \t   \"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\\n\"\n-\t   \"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\\n\"\n-\t   \"           <command> [<args>]\");\n+\t   \"           [--config-env=<name>=<envvar>] <command> [<args>]\");\n \n const char git_more_info_string[] =\n \tN_(\"'git help -a' and 'git help -g' list available subcommands and some\\n\"\n@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);\n \t\t\tif (envchanged)\n \t\t\t\t*envchanged = 1;\n-\t\t} else if (!strcmp(cmd, \"--super-prefix\")) {\n-\t\t\tif (*argc < 2) {\n-\t\t\t\tfprintf(stderr, _(\"no prefix given for --super-prefix\\n\" ));\n-\t\t\t\tusage(git_usage_string);\n-\t\t\t}\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n-\t\t\t(*argv)++;\n-\t\t\t(*argc)--;\n-\t\t} else if (skip_prefix(cmd, \"--super-prefix=\", &cmd)) {\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n \t\t} else if (!strcmp(cmd, \"--bare\")) {\n \t\t\tchar *cwd = xgetcwd();\n \t\t\tis_bare_repository_cfg = 1;\n@@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\ttrace_repo_setup(prefix);\n \tcommit_pager_choice();\n \n-\tif (!help && get_super_prefix()) {\n-\t\tif (!(p->option & SUPPORT_SUPER_PREFIX))\n-\t\t\tdie(_(\"%s doesn't support --super-prefix\"), p->cmd);\n-\t}\n-\n \tif (!help && p->option & NEED_WORK_TREE)\n \t\tsetup_work_tree();\n \n@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {\n \t{ \"check-ref-format\", cmd_check_ref_format, NO_PARSEOPT  },\n \t{ \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout--worker\", cmd_checkout__worker,\n-\t\tRUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },\n+\t\tRUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout-index\", cmd_checkout_index,\n \t\tRUN_SETUP | NEED_WORK_TREE},\n \t{ \"cherry\", cmd_cherry, RUN_SETUP },\n@@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n-\t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n \t{ \"rebase\", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n@@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tint status;\n \n-\tif (get_super_prefix())\n-\t\tdie(_(\"%s doesn't support --super-prefix\"), argv[0]);\n-\n \tif (use_pager == -1 && !is_builtin(argv[0]))\n \t\tuse_pager = check_pager_config(argv[0]);\n \tcommit_pager_choice();\n@@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)\n \t\t\t */\n \t\t\ttrace2_cmd_name(\"_run_git_alias_\");\n \n-\t\t\tif (get_super_prefix())\n-\t\t\t\tdie(\"%s doesn't support --super-prefix\", **argv);\n-\n \t\t\tcommit_pager_choice();\n \n \t\t\tstrvec_push(&cmd.args, \"git\");\ndiff --git a/submodule.c b/submodule.c\nindex 3383c47c719..f8497793790 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2048,14 +2048,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)\n \tstrbuf_release(&config_path);\n }\n \n-static const char *get_super_prefix_or_empty(void)\n-{\n-\tconst char *s = get_super_prefix();\n-\tif (!s)\n-\t\ts = \"\";\n-\treturn s;\n-}\n-\n static int submodule_has_dirty_index(const struct submodule *sub)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2074,7 +2066,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)\n \treturn finish_command(&cp);\n }\n \n-static void submodule_reset_index(const char *path)\n+static void submodule_reset_index(const char *path, const char *super_prefix)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tprepare_submodule_repo_env(&cp.env);\n@@ -2083,10 +2075,10 @@ static void submodule_reset_index(const char *path)\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \t/* TODO: determine if this might overwright untracked files */\n \tstrvec_pushl(&cp.args, \"read-tree\", \"-u\", \"--reset\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tstrvec_push(&cp.args, empty_tree_oid_hex());\n \n@@ -2099,10 +2091,9 @@ static void submodule_reset_index(const char *path)\n  * For edge cases (a submodule coming into existence or removing a submodule)\n  * pass NULL for old or new respectively.\n  */\n-int submodule_move_head(const char *path,\n-\t\t\t const char *old_head,\n-\t\t\t const char *new_head,\n-\t\t\t unsigned flags)\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n+\t\t\tunsigned flags)\n {\n \tint ret = 0;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2140,7 +2131,7 @@ int submodule_move_head(const char *path,\n \t\tif (old_head) {\n \t\t\tif (!submodule_uses_gitfile(path))\n \t\t\t\tabsorb_git_dir_into_superproject(path,\n-\t\t\t\t\t\t\t\t get_super_prefix());\n+\t\t\t\t\t\t\t\t super_prefix);\n \t\t} else {\n \t\t\tstruct strbuf gitdir = STRBUF_INIT;\n \t\t\tsubmodule_name_to_gitdir(&gitdir, the_repository,\n@@ -2149,7 +2140,7 @@ int submodule_move_head(const char *path,\n \t\t\tstrbuf_release(&gitdir);\n \n \t\t\t/* make sure the index is clean as well */\n-\t\t\tsubmodule_reset_index(path);\n+\t\t\tsubmodule_reset_index(path, NULL);\n \t\t}\n \n \t\tif (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {\n@@ -2167,9 +2158,9 @@ int submodule_move_head(const char *path,\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \tstrvec_pushl(&cp.args, \"read-tree\", \"--recurse-submodules\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tif (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)\n \t\tstrvec_push(&cp.args, \"-n\");\ndiff --git a/submodule.h b/submodule.h\nindex f90ee547d08..c55a25ca37d 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);\n \n #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)\n #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)\n-int submodule_move_head(const char *path,\n-\t\t\tconst char *old,\n-\t\t\tconst char *new_head,\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n \t\t\tunsigned flags);\n \n void submodule_unset_core_worktree(const struct submodule *sub);\ndiff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh\nindex 516a6112fdc..3fb1b0c162d 100755\n--- a/t/t1001-read-tree-m-2way.sh\n+++ b/t/t1001-read-tree-m-2way.sh\n@@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '\n \tcat <<-EOF >expect &&\n \t\terror: Updating '\\''fictional/a'\\'' would lose untracked files in it\n \tEOF\n-\ttest_must_fail git --super-prefix fictional/ read-tree -u -m \"$treeH\" \"$treeM\" 2>actual &&\n+\ttest_must_fail git read-tree --super-prefix fictional/ -u -m \"$treeH\" \"$treeM\" 2>actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 2846ec6629c..f519d2a87a7 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -644,7 +644,7 @@ test_expect_success 'repack does not loosen promisor objects' '\n \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n '\n \n-test_expect_failure 'lazy-fetch in submodule succeeds' '\n+test_expect_success 'lazy-fetch in submodule succeeds' '\n \t# setup\n \ttest_config_global protocol.file.allow always &&\n \ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex bae812156c4..61c02285454 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {\n \t  ? ((o)->msgs[(type)])      \\\n \t  : (unpack_plumbing_errors[(type)]) )\n \n-static const char *super_prefixed(const char *path)\n+static const char *super_prefixed(const char *path, const char *super_prefix)\n {\n \t/*\n \t * It is necessary and sufficient to have two static buffers\n@@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)\n \tstatic unsigned idx = ARRAY_SIZE(buf) - 1;\n \n \tif (super_prefix_len < 0) {\n-\t\tconst char *super_prefix = get_super_prefix();\n \t\tif (!super_prefix) {\n \t\t\tsuper_prefix_len = 0;\n \t\t} else {\n@@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,\n \t\treturn -1;\n \n \tif (!o->show_all_errors)\n-\t\treturn error(ERRORMSG(o, e), super_prefixed(path));\n+\t\treturn error(ERRORMSG(o, e), super_prefixed(path,\n+\t\t\t\t\t\t\t    o->super_prefix));\n \n \t/*\n \t * Otherwise, insert in a list for future display by\n@@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)\n \t\t\terror_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t     o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)\n \t\t\twarning_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t       o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,\n \tif (o->reset)\n \t\tflags |= SUBMODULE_MOVE_HEAD_FORCE;\n \n-\tif (submodule_move_head(ce->name, old_id, new_id, flags))\n+\tif (submodule_move_head(ce->name, NULL, old_id, new_id, flags))\n \t\treturn add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);\n \treturn 0;\n }\n@@ -415,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,\n \tint i, pc_workers, pc_threshold;\n \n \ttrace_performance_enter();\n+\tstate.super_prefix = o->super_prefix;\n \tstate.force = 1;\n \tstate.quiet = 1;\n \tstate.refresh_cache = 1;\n@@ -445,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,\n \n \t\tif (ce->ce_flags & CE_WT_REMOVE) {\n \t\t\tdisplay_progress(progress, ++cnt);\n-\t\t\tunlink_entry(ce);\n+\t\t\tunlink_entry(ce, o->super_prefix);\n \t\t}\n \t}\n \n@@ -2958,8 +2961,8 @@ int bind_merge(const struct cache_entry * const *src,\n \tif (a && old)\n \t\treturn o->quiet ? -1 :\n \t\t\terror(ERRORMSG(o, ERROR_BIND_OVERLAP),\n-\t\t\t      super_prefixed(a->name),\n-\t\t\t      super_prefixed(old->name));\n+\t\t\t      super_prefixed(a->name, o->super_prefix),\n+\t\t\t      super_prefixed(old->name, o->super_prefix));\n \tif (!a)\n \t\treturn keep_entry(old, o);\n \telse\n@@ -3020,7 +3023,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,\n \n \tif (worktree && untracked)\n \t\treturn error(_(\"worktree and untracked commit have duplicate entries: %s\"),\n-\t\t\t     super_prefixed(worktree->name));\n+\t\t\t     super_prefixed(worktree->name, o->super_prefix));\n \n \treturn merged_entry(worktree ? worktree : untracked, NULL, o);\n }\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex efb9edfbb27..9b81e284073 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -74,6 +74,7 @@ struct unpack_trees_options {\n \t\t     dry_run;\n \tenum unpack_trees_reset_type reset;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint cache_bottom;\n \tstruct pathspec *pathspec;\n \tmerge_fn_t fn;\n-- \n2.38.0.1509.g9445af83948\n\n"},{"id":"467714","messageId":"kl6lzgckdsow.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"221117.86y1s9h2q5.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v2 00/10] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-21T19:16:15Z","receivedAt":"2022-11-21T19:16:45Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Wed, Nov 16 2022, Glen Choo wrote:\n>\n>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>\n>>> On Mon, Nov 14 2022, Glen Choo wrote:\n>>>\n>>>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>>>\n>>>>> It's also proposing to replace Glen's one-patch[6], which is working\n>>>>> around the problem shown in the test added in 1/10 here. Per\n>>>>> downthread of [7] I think Glen was aiming for getting a more narrow\n>>>>> fix in case we split off 9/10 here into some later fix.\n>>>>>\n>>>>> As we're fixing an edge case in something that's always been broken\n>>>>> (and thus wouldn't backport) I think it's better to just fix the\n>>>>> problem directly, rather than introducing new \"--super-prefix\" use,\n>>>>> just to take it away later.\n>>>>\n>>>> I still prefer that we take the one-patch to unbreak new releases,\n>>>> because partial clone + submodules is absolutely broken (e.g. it's\n>>>> already causing quite a lot of headaches at $DAYJOB) and the patch is\n>>>> obviously harmless.\n>>>>\n>>>> And more importantly, it lets us take our time with this series and get\n>>>> it right without time pressure. It's not as pressing as, e.g. a\n>>>> regression fix, but it does render certain Git setups unusable.\n>>>>\n>>>> With regards to urgency and when to choose \"small and harmless fixes vs\n>>>> bigger and better fixes\", I think Junio has generally made those calls\n>>>> in the past. @Taylor if you have an opinion, I'd love to hear it.\n>>>\n>>> I feel like I'm missing something here. What's the regression? The test\n>>> you're adding here didn't work at all until 0f5e8851737 (Merge branch\n>>> 'rc/fetch-refetch', 2022-04-04), as the command didn't exist yet. That\n>>> commit went out with v2.36.0.\n>>>\n>>> If it never worked there's no regression, and we wouldn't be merging\n>>> down a fix for older point-releases.\n>>>\n>>> Or is there some case I've missed here which did work before, doesn't\n>>> now, but just isn't captured in this test? If so what case is that, and\n>>> when did it break?\n>>\n>> Right, this wasn't meant to be a regression fix at all. There's good\n>> reason to believe that this was always broken, so I never went digging\n>> to see if it ever worked.\n>>\n>> Even so, it doesn't change the fact that it's a use case that we've\n>> expected to work, but doesn't due to some internal silliness, and that\n>> we could fix it without invoking questions of the \"--super-prefix\"\n>> design and dragging out the process (which is admittedly what I should\n>> have done in the first place). Since we have such an easy fix in front\n>> of us, I don't feel good about not fixing this before the next release.\n>>\n>> At any rate, I'm wiling to accept that I'm being overly cautious,\n>> because it's quite likely that this series will make it into the next\n>> release. (We could technically we unbreak 'next', though I don't know\n>> who distributes that other than internally @ Google.) I'm ok to drop my\n>> patch for now, but I'll revive it if it starts to look like this series\n>> won't make it into the next release.\n>\n> Understood, I'm re-rolling this v2, will send it out soon.\n>\n> I'll keep that patch out for now, but if we're starting to run up\n> against the next release how about we split it out? So it'll depend on\n> how fast we can review & test this, and if/when Taylor is OK with\n> merging it down.\n>\n> I really don't care if the fix comes first, but just thought I was\n> missing something and it didn't seem urgent, as it was in the \"never\n> worked\" and not \"a regression\" category AFAICT. But if you'd still like\n> it shout, and I'll just stack it at the start...\n\nThat sounds good, thanks :) That's very helpful of you, and I appreciate\nyou making the way forward clear.\n"},{"id":"467807","messageId":"kl6lfseaepfu.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v3-3.9-6e10a47c60a-20221119T122853Z-avarab@gmail.com","subject":"Re: [PATCH v3 3/9] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-22T19:53:25Z","receivedAt":"2022-11-22T19:53:42Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> The \"fsmonitor--daemon\" test adjusted here was added in [3]. To assert\n> that it didn't run into the \"--super-prefix\" message it was asserting\n> the output it didn't have. Let's instead assert the full output that\n> we *do* have, which we can do here as this is based on a change[4] to\n> make it predictable (until [4] it contained absolute paths).\n>\n> We could also remove the test entirely (as [5] did), but even though\n> the initial reason for having it is gone we're still getting some\n> marginal benefit from testing the \"fsmonitor\" and \"submodule\n> absorbgitdirs\" interaction, so let's keep it.\n\nI'm a bit ambivalent on this, especially since we're testing \"submodule\nabsorbgitdirs\" output in \"fsmonitor\" tests, but as you say, there is\nsome benefit in testing the interaction. I think we'll have to change\nthe test though...\n\n> The change here to have either a NULL or non-\"\" string as a\n> \"super_prefix\" instead of the previous arrangement of \"\" or non-\"\" is\n> somewhat arbitrary. We could also decide to never have to check for\n> NULL.\n>\n> As we'll be changing the rest of the \"git --super-prefix\" users to the\n> same pattern, leaving them all consistent makes sense. Why not pick \"\"\n> over NULL? Because that's how the \"prefix\" works[6], and having\n> \"prefix\" and \"super_prefix\" work the same way will be less\n> confusing. That \"prefix\" picked NULL instead of \"\" is itself\n> arbitrary, but as it's easy to make this small bit of our overall API\n> consistent, let's go with that.\n\nOkay, I find consistency with \"prefix\" convincing, and I do hope that we\nuse \"\" someday :)\n\n> index 4abc74db2bb..31526937d95 100755\n> --- a/t/t7527-builtin-fsmonitor.sh\n> +++ b/t/t7527-builtin-fsmonitor.sh\n> @@ -866,30 +866,11 @@ test_expect_success 'submodule always visited' '\n>  # the submodule, and someone does a `git submodule absorbgitdirs`\n>  # in the super, Git will recursively invoke `git submodule--helper`\n>  # to do the work and this may try to read the index.  This will\n> -# try to start the daemon in the submodule *and* pass (either\n> -# directly or via inheritance) the `--super-prefix` arg to the\n> -# `git fsmonitor--daemon start` command inside the submodule.\n> -# This causes a warning because fsmonitor--daemon does take that\n> -# global arg (see the table in git.c)\n\nWe've removed mentions of the \"--super-prefix\", as we should, since\nfsmonitor doesn't need to care about \"--super-prefix\" any more...\n\n> @@ -904,10 +885,12 @@ test_expect_success \"stray submodule super-prefix warning\" '\n>  \n>  \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n>  \n> -\tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n> -\t\tgit -C super submodule absorbgitdirs &&\n> -\n> -\t! have_t2_error_event super-sub.trace\n> +\tcat >expect <<-\\EOF &&\n> +\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from '\\''dir_1/dir_2/sub/.git'\\'' to '\\''.git/modules/dir_1/dir_2/sub'\\''\n> +\tEOF\n> +\tgit -C super submodule absorbgitdirs >out 2>actual &&\n> +\ttest_cmp expect actual &&\n> +\ttest_must_be_empty out\n>  '\n\nSo let's adjust the test to match what we're testing. It's not the\n--super-prefix any more, it's the interaction between \"submodule\nabsorbgitdirs\" and \"fsmonitor--daemon\", so perhaps something like:\n\n  diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh\n  index 31526937d9..9f947341f5 100755\n  --- a/t/t7527-builtin-fsmonitor.sh\n  +++ b/t/t7527-builtin-fsmonitor.sh\n  @@ -868,7 +868,7 @@ test_expect_success 'submodule always visited' '\n  # to do the work and this may try to read the index.  This will\n  # try to start the daemon in the submodule.\n\n  -test_expect_success \"stray submodule super-prefix warning\" '\n  +test_expect_success \"submodule absorbgitdirs implicitly starts daemon\" '\n          test_when_finished \"rm -rf super; \\\n                              rm -rf sub\" &&\n\n  @@ -888,9 +888,14 @@ test_expect_success \"stray submodule super-prefix warning\" '\n          cat >expect <<-\\EOF &&\n          Migrating git directory of '\\''dir_1/dir_2/sub'\\'' from '\\''dir_1/dir_2/sub/.git'\\'' to '\\''.git/modules/dir_1/dir_2/sub'\\''\n          EOF\n  -       git -C super submodule absorbgitdirs >out 2>actual &&\n  +       GIT_TRACE2_EVENT=\"$PWD/.git/trace_absorbgitdirs\" \\\n  +               git -C super submodule absorbgitdirs >out 2>actual &&\n          test_cmp expect actual &&\n  -       test_must_be_empty out\n  +       test_must_be_empty out &&\n  +\n  +       # Confirm that the trace2 log contains a record of the\n  +       # daemon starting.\n  +       test_subcommand git fsmonitor--daemon start <.git/trace_absorbgitdirs\n  '\n\n  # On a case-insensitive file system, confirm that the daemon\n"},{"id":"467809","messageId":"kl6lcz9eep9k.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v3-8.9-f952fa3d01f-20221119T122853Z-avarab@gmail.com","subject":"Re: [PATCH v3 8/9] read-tree: add \"--super-prefix\" option, eliminate global","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-22T19:57:11Z","receivedAt":"2022-11-22T19:57:24Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> @@ -2149,7 +2140,7 @@ int submodule_move_head(const char *path,\n>  \t\t\tstrbuf_release(&gitdir);\n>  \n>  \t\t\t/* make sure the index is clean as well */\n> -\t\t\tsubmodule_reset_index(path);\n> +\t\t\tsubmodule_reset_index(path, NULL);\n>  \t\t}\n>  \n>  \t\tif (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {\n\nHere, and..\n\n> @@ -312,7 +314,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,\n>  \tif (o->reset)\n>  \t\tflags |= SUBMODULE_MOVE_HEAD_FORCE;\n>  \n> -\tif (submodule_move_head(ce->name, old_id, new_id, flags))\n> +\tif (submodule_move_head(ce->name, NULL, old_id, new_id, flags))\n>  \t\treturn add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);\n>  \treturn 0;\n>  }\n\nhere I think we should be passing a non-NULL value to super_prefix.\n\nPerhaps this was missed when going through the v2 feedback [1]?\n\n[1] https://lore.kernel.org/git/kl6lv8nhnpba.fsf@chooglen-macbookpro.roam.corp.google.com\n"},{"id":"467819","messageId":"kl6la64iei7k.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"Re: [PATCH v3 0/9] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-11-22T22:29:35Z","receivedAt":"2022-11-22T22:29:52Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Thanks! I think we're close to getting this merged :)\n\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> = Changes since v2:\n>\n> * Fixes for test_when_finished() in test setup, and got rid of\n>   redundant test_config_global.\n>\n> * There's a new 2/9, which passes along get_super_prefix() as a\n>   parameter. This allows us to gradually replace it, and drop the\n>   *_sp() variants of functions that the previous version introduced,\n>   and it adds \"super_prefix\" to the absorb_git_dir_into_superproject()\n>   call in submodule_move_head(), which as Glen noticed I'd missed\n>\n> * Squashed the \"deinit\" change into that 2/9.\n>\n> * Explain why we keep the \"fsmonitor\" test bits that we do.\n>\n> * Dropped the new \"git branch\" output tests, turns out I was just\n>   wrong, and was conflating it with the subsequent read-tree\n>   invocation...\n>\n> So, this should address all outstanding feedbakc, unless I've missed\n> something.\n\nAs noted in [1], I think we might have missed some sites where we should\npass super_prefix.\n\n[1] https://lore.kernel.org/git/kl6lcz9eep9k.fsf@chooglen-macbookpro.roam.corp.google.com,\n\n> The one loose end here is that I still have no idea if you can invoke\n> get \"read-tree\" to invoke that submodule_move_head() in such a way as\n> to have the \"super_prefix\" used, I've failed to come up with a test\n> case for that.\n>\n> But for the purposes of this topic it doesn't really matter. In 8/10\n> we'll start passing the new \"--super-prefix\" that \"read-tree\" gets\n> down to that function. At worst we're handing it to it redundantly,\n> but that was the case before too.\n>\n> So we can leave potentially turning that into a \"NULL\" for some other\n> time, for now providing the \"super_prefix\" is harmless, and guarantees\n> that we avoid any regression in that area from not providing it, in\n> case I've missed a way to have it matter in that case.\n\nYeah, I tried to do the same too, and it turned out to be harder than\nexpected. The \"absorbgitdir during read-tree\" code is definitely in use\n(e.g. by t1013), so it's certainly possible, but as you noted, I don't\nreally think it matters as long as we avoid a regression for the time\nbeing.\n\n"},{"id":"469089","messageId":"patch-v4-2.9-6424307a432-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v4 2/9] read-tree + fetch tests: test failing \"--super-prefix\" interaction","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:43Z","receivedAt":"2022-12-15T09:33:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nEver since \"git fetch --refetch\" was introduced in 0f5e8851737 (Merge\nbranch 'rc/fetch-refetch', 2022-04-04) the test being added here would\nfail. This is because \"restore\" will \"read-tree .. --reset <hash>\",\nwhich will in turn invoke \"fetch\". The \"fetch\" will then die with:\n\n\tfatal: fetch doesn't support --super-prefix\n\nThis edge case and other \"--super-prefix\" bugs will be fixed in\nsubsequent commits, but let's first add a \"test_expect_failure\" test\nfor it. It passes until the very last command in the test.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 43 insertions(+)\n\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 037941b95d2..2846ec6629c 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '\n \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n '\n \n+test_expect_failure 'lazy-fetch in submodule succeeds' '\n+\t# setup\n+\ttest_config_global protocol.file.allow always &&\n+\n+\ttest_when_finished \"rm -rf src-sub\" &&\n+\tgit init src-sub &&\n+\tgit -C src-sub config uploadpack.allowfilter 1 &&\n+\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n+\n+\t# This blob must be missing in the subsequent commit.\n+\techo foo >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule one\" &&\n+\tSUB_ONE=$(git -C src-sub rev-parse HEAD) &&\n+\n+\techo bar >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule two\" &&\n+\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n+\n+\ttest_when_finished \"rm -rf src-super\" &&\n+\tgit init src-super &&\n+\tgit -C src-super config uploadpack.allowfilter 1 &&\n+\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n+\tgit -C src-super submodule add ../src-sub src-sub &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_ONE &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject one\" &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_TWO &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject two\" &&\n+\n+\t# the fetch\n+\ttest_when_finished \"rm -rf client\" &&\n+\tgit clone --filter=blob:none --also-filter-submodules \\\n+\t\t--recurse-submodules \"file://$(pwd)/src-super\" client &&\n+\n+\t# Trigger lazy-fetch from the superproject\n+\tgit -C client restore --recurse-submodules --source=HEAD^ :/\n+'\n+\n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n start_httpd\n \n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469090","messageId":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com","subject":"[PATCH v4 0/9] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:41Z","receivedAt":"2022-12-15T09:33:20Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"For a general summary see the v3's CL at\nhttps://lore.kernel.org/git/cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com/\n\nChanges since v4:\n\n* This isn't on top of the now-ejected \"ab/submodule-no-abspath\" any\n  longer. Per\n  https://lore.kernel.org/git/kl6la647ow7e.fsf@chooglen-macbookpro.roam.corp.google.com/\n  we're not changing the output here anymore\n\n* Extract & amend the test that \"ab/submodule-no-abspath\" added to\n  test the existing behavior (using $(pwd) now).\n\n* There were a couple of cases where I missed passing the\n  \"super_prefix\", per earlier discussions we haven't found cases where\n  it's used in practice, but let's keep diligently passing it along.\n\n* I ejected the previous 10/10 to refactor \"git fetch\". I have more\n  patches on top of this to do some post-refactoring (e.g. saving\n  memory churn by getting rid of \"submodule_prefix\" from \"struct\n  repository\"), but none of that's essential for now, so let's drop\n  that patch.\n\nJunio: There's a conflict here in t/t7527* with\ned/fsmonitor-inotify. The conflict is easily solved. This side should\nbe kept, except for the new \"git -C ...\" command that was added to\ntest_when_finished(), which needs to be carried over. A --remerge-diff\noff the solved conflict:\n\n\tdiff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh\n\tremerge CONFLICT (content): Merge conflict in t/t7527-builtin-fsmonitor.sh\n\tindex 40c96c5f819..963c4df461e 100755\n\t--- a/t/t7527-builtin-fsmonitor.sh\n\t+++ b/t/t7527-builtin-fsmonitor.sh\n\t@@ -933,20 +933,8 @@ test_expect_success 'submodule always visited' '\n\t # to do the work and this may try to read the index.  This will\n\t # try to start the daemon in the submodule.\n\n\t-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 4824f33224f (read-tree: add \"--super-prefix\" option, eliminate global)\n\t test_expect_success \"submodule absorbgitdirs implicitly starts daemon\" '\n\t-\ttest_when_finished \"rm -rf super; \\\n\t-================================\n\t-have_t2_error_event () {\n\t-\tlog=$1\n\t-\tmsg=\"fsmonitor--daemon doesnQt support --super-prefix\" &&\n\t-\n\t-\ttr '\\047' Q <$1 | grep -e \"$msg\"\n\t-}\n\t-\n\t-test_expect_success \"stray submodule super-prefix warning\" '\n\t \ttest_when_finished \"git -C super/dir_1/dir_2/sub fsmonitor--daemon stop; \\\n\t \t\t\t    rm -rf super; \\\n\t->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> f4fb2e9797d (Merge branch 'so/diff-merges-more' into seen)\n\t \t\t\t    rm -rf sub;   \\\n\t \t\t\t    rm super-sub.trace\" &&\n\nBranch & passing CI at:\nhttps://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local-4\n\nGlen Choo (1):\n  read-tree + fetch tests: test failing \"--super-prefix\" interaction\n\nÆvar Arnfjörð Bjarmason (8):\n  submodule absorbgitdirs tests: add missing \"Migrating git...\" tests\n  submodule.c & submodule--helper: pass along \"super_prefix\" param\n  submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n  submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n  submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n  submodule--helper: convert \"status\" to its own \"--super-prefix\"\n  submodule--helper: convert \"{update,clone}\" to their own\n    \"--super-prefix\"\n  read-tree: add \"--super-prefix\" option, eliminate global\n\n Documentation/git.txt              |  8 +--\n builtin.h                          |  4 --\n builtin/checkout.c                 |  2 +-\n builtin/read-tree.c                |  1 +\n builtin/rm.c                       |  2 +-\n builtin/submodule--helper.c        | 87 ++++++++++++++++--------------\n cache.h                            |  2 -\n entry.c                            | 12 ++---\n entry.h                            |  6 ++-\n environment.c                      | 13 -----\n git.c                              | 41 +++-----------\n parse-options.h                    |  4 ++\n submodule.c                        | 50 ++++++++---------\n submodule.h                        |  8 +--\n t/t1001-read-tree-m-2way.sh        |  2 +-\n t/t5616-partial-clone.sh           | 43 +++++++++++++++\n t/t7412-submodule-absorbgitdirs.sh | 64 +++++++++++++++++++---\n t/t7527-builtin-fsmonitor.sh       | 36 +++++--------\n unpack-trees.c                     | 24 +++++----\n unpack-trees.h                     |  1 +\n 20 files changed, 230 insertions(+), 180 deletions(-)\n\nRange-diff against v3:\n 1:  5f463bbefb5 !  1:  f479003941b submodule--helper absorbgitdirs: no abspaths in \"Migrating git...\"\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    submodule--helper absorbgitdirs: no abspaths in \"Migrating git...\"\n    +    submodule absorbgitdirs tests: add missing \"Migrating git...\" tests\n     \n    -    Change the \"Migrating git directory\" messages to avoid emitting\n    -    absolute paths. We could use \"old_git_dir\" and \"new_gitdir.buf\" here\n    -    sometimes, but not in all the cases covered by these tests,\n    -    i.e. sometimes the latter will be an absolute path with a different\n    -    prefix.\n    +    Fix a blind spots in the tests surrounding \"submodule absorbgitdirs\"\n    +    and test what output we emit, and how emitted the message and behavior\n    +    interacts with a \"git worktree\" where the repository isn't at the base\n    +    of the working directory.\n     \n    -    So let's just strip off the common prefix of the two strings, which\n    -    handles the cases where we have nested submodules nicely. Note that\n    -    this case is different than the one in get_submodule_displaypath() in\n    -    \"builtin/submodule--helper.c\" handles, as we're dealing with the paths\n    -    to the two \".git\" here, not worktree paths.\n    -\n    -    Before this change we had no tests at all for this \"Migrating git\n    -    directory\" output.\n    +    The \"$(pwd)\" instead of \"$PWD\" here is needed due to Windows, where\n    +    the latter will be a path like \"/d/a/git/[...]\", whereas we need\n    +    \"D:/a/git/[...]\".\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    - ## submodule.c ##\n    -@@ submodule.c: static void relocate_single_git_dir_into_superproject(const char *path)\n    - \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n    - \tstruct strbuf new_gitdir = STRBUF_INIT;\n    - \tconst struct submodule *sub;\n    -+\tsize_t off = 0;\n    - \n    - \tif (submodule_uses_worktrees(path))\n    - \t\tdie(_(\"relocate_gitdir for submodule '%s' with \"\n    -@@ submodule.c: static void relocate_single_git_dir_into_superproject(const char *path)\n    - \t\tdie(_(\"could not create directory '%s'\"), new_gitdir.buf);\n    - \treal_new_git_dir = real_pathdup(new_gitdir.buf, 1);\n    - \n    --\tfprintf(stderr, _(\"Migrating git directory of '%s%s' from\\n'%s' to\\n'%s'\\n\"),\n    -+\twhile (real_old_git_dir[off] && real_new_git_dir[off] &&\n    -+\t       real_old_git_dir[off] == real_new_git_dir[off])\n    -+\t\toff++;\n    -+\tfprintf(stderr, _(\"Migrating git directory of '%s%s' from '%s' to '%s'\\n\"),\n    - \t\tget_super_prefix_or_empty(), path,\n    --\t\treal_old_git_dir, real_new_git_dir);\n    -+\t\treal_old_git_dir + off, real_new_git_dir + off);\n    - \n    - \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n    - \n    -\n      ## t/t7412-submodule-absorbgitdirs.sh ##\n    +@@ t/t7412-submodule-absorbgitdirs.sh: TEST_PASSES_SANITIZE_LEAK=true\n    + . ./test-lib.sh\n    + \n    + test_expect_success 'setup a real submodule' '\n    ++\tcwd=\"$(pwd)\" &&\n    + \tgit init sub1 &&\n    + \ttest_commit -C sub1 first &&\n    + \tgit submodule add ./sub1 &&\n     @@ t/t7412-submodule-absorbgitdirs.sh: test_expect_success 'setup a real submodule' '\n      '\n      \n    @@ t/t7412-submodule-absorbgitdirs.sh: test_expect_success 'setup a real submodule'\n      \tgit status >expect.1 &&\n      \tgit -C sub1 rev-parse HEAD >expect.2 &&\n     -\tgit submodule absorbgitdirs &&\n    -+\tcat >expect <<-\\EOF &&\n    -+\tMigrating git directory of '\\''sub1'\\'' from '\\''sub1/.git'\\'' to '\\''.git/modules/sub1'\\''\n    ++\tcat >expect <<-EOF &&\n    ++\tMigrating git directory of '\\''sub1'\\'' from\n    ++\t'\\''$cwd/sub1/.git'\\'' to\n    ++\t'\\''$cwd/.git/modules/sub1'\\''\n     +\tEOF\n     +\tgit submodule absorbgitdirs 2>actual &&\n     +\ttest_cmp expect actual &&\n    @@ t/t7412-submodule-absorbgitdirs.sh: test_expect_success 'setup nested submodule'\n      \tgit status >expect.1 &&\n      \tgit -C sub1/nested rev-parse HEAD >expect.2 &&\n     -\tgit submodule absorbgitdirs &&\n    -+\tcat >expect <<-\\EOF &&\n    -+\tMigrating git directory of '\\''sub1/nested'\\'' from '\\''sub1/nested/.git'\\'' to '\\''.git/modules/sub1/modules/nested'\\''\n    ++\tcat >expect <<-EOF &&\n    ++\tMigrating git directory of '\\''sub1/nested'\\'' from\n    ++\t'\\''$cwd/sub1/nested/.git'\\'' to\n    ++\t'\\''$cwd/.git/modules/sub1/modules/nested'\\''\n     +\tEOF\n     +\tgit submodule absorbgitdirs 2>actual &&\n     +\ttest_cmp expect actual &&\n    @@ t/t7412-submodule-absorbgitdirs.sh: test_expect_success 're-setup nested submodu\n      \tgit status >expect.1 &&\n      \tgit -C sub1/nested rev-parse HEAD >expect.2 &&\n     -\tgit submodule absorbgitdirs &&\n    -+\tcat >expect <<-\\EOF &&\n    -+\tMigrating git directory of '\\''sub1'\\'' from '\\''sub1/.git'\\'' to '\\''.git/modules/sub1'\\''\n    ++\tcat >expect <<-EOF &&\n    ++\tMigrating git directory of '\\''sub1'\\'' from\n    ++\t'\\''$cwd/sub1/.git'\\'' to\n    ++\t'\\''$cwd/.git/modules/sub1'\\''\n     +\tEOF\n     +\tgit submodule absorbgitdirs 2>actual &&\n     +\ttest_cmp expect actual &&\n      \ttest -f sub1/.git &&\n      \ttest -f sub1/nested/.git &&\n      \ttest -d .git/modules/sub1/modules/nested &&\n    +@@ t/t7412-submodule-absorbgitdirs.sh: test_expect_success 'absorb the git dir in a nested submodule' '\n    + \ttest_cmp expect.2 actual.2\n    + '\n    + \n    ++test_expect_success 'absorb the git dir outside of primary worktree' '\n    ++\ttest_when_finished \"rm -rf repo-bare.git\" &&\n    ++\tgit clone --bare . repo-bare.git &&\n    ++\ttest_when_finished \"rm -rf repo-wt\" &&\n    ++\tgit -C repo-bare.git worktree add ../repo-wt &&\n    ++\n    ++\ttest_when_finished \"rm -f .gitconfig\" &&\n    ++\ttest_config_global protocol.file.allow always &&\n    ++\tgit -C repo-wt submodule update --init &&\n    ++\tgit init repo-wt/sub2 &&\n    ++\ttest_commit -C repo-wt/sub2 A &&\n    ++\tgit -C repo-wt submodule add ./sub2 sub2 &&\n    ++\tcat >expect <<-EOF &&\n    ++\tMigrating git directory of '\\''sub2'\\'' from\n    ++\t'\\''$cwd/repo-wt/sub2/.git'\\'' to\n    ++\t'\\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\\''\n    ++\tEOF\n    ++\tDO_IT=1 git -C repo-wt submodule absorbgitdirs 2>actual &&\n    ++\ttest_cmp expect actual\n    ++'\n    ++\n    + test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n    + \tgit init sub2 &&\n    + \ttest_commit -C sub2 first &&\n     @@ t/t7412-submodule-absorbgitdirs.sh: test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n      test_expect_success 'absorbing the git dir fails for incomplete submodules' '\n      \tgit status >expect.1 &&\n 2:  c930fc38356 =  2:  6424307a432 read-tree + fetch tests: test failing \"--super-prefix\" interaction\n 3:  2e4a2236898 =  3:  b2e543bde03 submodule.c & submodule--helper: pass along \"super_prefix\" param\n 4:  6e10a47c60a !  4:  bde9038c4e3 submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n    @@ submodule.c: int validate_submodule_git_dir(char *git_dir, const char *submodule\n      \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n      \tstruct strbuf new_gitdir = STRBUF_INIT;\n     @@ submodule.c: static void relocate_single_git_dir_into_superproject(const char *path)\n    - \t       real_old_git_dir[off] == real_new_git_dir[off])\n    - \t\toff++;\n    - \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from '%s' to '%s'\\n\"),\n    + \treal_new_git_dir = real_pathdup(new_gitdir.buf, 1);\n    + \n    + \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from\\n'%s' to\\n'%s'\\n\"),\n     -\t\tget_super_prefix_or_empty(), path,\n     +\t\tsuper_prefix ? super_prefix : \"\", path,\n    - \t\treal_old_git_dir + off, real_new_git_dir + off);\n    + \t\treal_old_git_dir, real_new_git_dir);\n      \n      \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n     @@ submodule.c: static void absorb_git_dir_into_superproject_recurse(const char *path,\n    @@ t/t7527-builtin-fsmonitor.sh: test_expect_success 'submodule always visited' '\n     -}\n     +# try to start the daemon in the submodule.\n      \n    - test_expect_success \"stray submodule super-prefix warning\" '\n    +-test_expect_success \"stray submodule super-prefix warning\" '\n    ++test_expect_success \"submodule absorbgitdirs implicitly starts daemon\" '\n      \ttest_when_finished \"rm -rf super; \\\n    --\t\t\t    rm -rf sub;   \\\n    --\t\t\t    rm super-sub.trace\" &&\n    -+\t\t\t    rm -rf sub\" &&\n    - \n    - \tcreate_super super &&\n    - \tcreate_sub sub &&\n    + \t\t\t    rm -rf sub;   \\\n    + \t\t\t    rm super-sub.trace\" &&\n     @@ t/t7527-builtin-fsmonitor.sh: test_expect_success \"stray submodule super-prefix warning\" '\n      \n      \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n      \n    --\tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n    --\t\tgit -C super submodule absorbgitdirs &&\n    --\n    --\t! have_t2_error_event super-sub.trace\n    -+\tcat >expect <<-\\EOF &&\n    -+\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from '\\''dir_1/dir_2/sub/.git'\\'' to '\\''.git/modules/dir_1/dir_2/sub'\\''\n    ++\tcwd=\"$(cd super && pwd)\" &&\n    ++\tcat >expect <<-EOF &&\n    ++\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from\n    ++\t'\\''$cwd/dir_1/dir_2/sub/.git'\\'' to\n    ++\t'\\''$cwd/.git/modules/dir_1/dir_2/sub'\\''\n     +\tEOF\n    -+\tgit -C super submodule absorbgitdirs >out 2>actual &&\n    + \tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n    +-\t\tgit -C super submodule absorbgitdirs &&\n    ++\t\tgit -C super submodule absorbgitdirs >out 2>actual &&\n     +\ttest_cmp expect actual &&\n    -+\ttest_must_be_empty out\n    ++\ttest_must_be_empty out &&\n    + \n    +-\t! have_t2_error_event super-sub.trace\n    ++\t# Confirm that the trace2 log contains a record of the\n    ++\t# daemon starting.\n    ++\ttest_subcommand git fsmonitor--daemon start <super-sub.trace\n      '\n      \n      # On a case-insensitive file system, confirm that the daemon\n 5:  da86eb3b867 =  5:  4da58e7ea50 submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n 6:  2eb583148a6 =  6:  8dff576df7d submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n 7:  8d8925c7e1f =  7:  8800a433e29 submodule--helper: convert \"status\" to its own \"--super-prefix\"\n 8:  754a7489aa5 =  8:  54c1e29de1e submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"\n 9:  f952fa3d01f !  9:  4824f33224f read-tree: add \"--super-prefix\" option, eliminate global\n    @@ submodule.c: int submodule_move_head(const char *path,\n      \n      \t\t\t/* make sure the index is clean as well */\n     -\t\t\tsubmodule_reset_index(path);\n    -+\t\t\tsubmodule_reset_index(path, NULL);\n    ++\t\t\tsubmodule_reset_index(path, super_prefix);\n      \t\t}\n      \n      \t\tif (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {\n    @@ unpack-trees.c: static int check_submodule_move_head(const struct cache_entry *c\n      \t\tflags |= SUBMODULE_MOVE_HEAD_FORCE;\n      \n     -\tif (submodule_move_head(ce->name, old_id, new_id, flags))\n    -+\tif (submodule_move_head(ce->name, NULL, old_id, new_id, flags))\n    ++\tif (submodule_move_head(ce->name, o->super_prefix, old_id, new_id,\n    ++\t\t\t\tflags))\n      \t\treturn add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);\n      \treturn 0;\n      }\n    @@ unpack-trees.c: int stash_worktree_untracked_merge(const struct cache_entry * co\n     \n      ## unpack-trees.h ##\n     @@ unpack-trees.h: struct unpack_trees_options {\n    - \t\t     dry_run;\n    + \t\t     skip_cache_tree_update;\n      \tenum unpack_trees_reset_type reset;\n      \tconst char *prefix;\n     +\tconst char *super_prefix;\n10:  1aa4019527a <  -:  ----------- fetch: rename \"--submodule-prefix\" to \"--super-prefix\"\n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469091","messageId":"patch-v4-1.9-f479003941b-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v4 1/9] submodule absorbgitdirs tests: add missing \"Migrating git...\" tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:42Z","receivedAt":"2022-12-15T09:33:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a blind spots in the tests surrounding \"submodule absorbgitdirs\"\nand test what output we emit, and how emitted the message and behavior\ninteracts with a \"git worktree\" where the repository isn't at the base\nof the working directory.\n\nThe \"$(pwd)\" instead of \"$PWD\" here is needed due to Windows, where\nthe latter will be a path like \"/d/a/git/[...]\", whereas we need\n\"D:/a/git/[...]\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7412-submodule-absorbgitdirs.sh | 64 ++++++++++++++++++++++++++----\n 1 file changed, 57 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\nindex 2859695c6d2..d556342ea57 100755\n--- a/t/t7412-submodule-absorbgitdirs.sh\n+++ b/t/t7412-submodule-absorbgitdirs.sh\n@@ -10,6 +10,7 @@ TEST_PASSES_SANITIZE_LEAK=true\n . ./test-lib.sh\n \n test_expect_success 'setup a real submodule' '\n+\tcwd=\"$(pwd)\" &&\n \tgit init sub1 &&\n \ttest_commit -C sub1 first &&\n \tgit submodule add ./sub1 &&\n@@ -18,13 +19,21 @@ test_expect_success 'setup a real submodule' '\n '\n \n test_expect_success 'absorb the git dir' '\n+\t>expect &&\n+\t>actual &&\n \t>expect.1 &&\n \t>expect.2 &&\n \t>actual.1 &&\n \t>actual.2 &&\n \tgit status >expect.1 &&\n \tgit -C sub1 rev-parse HEAD >expect.2 &&\n-\tgit submodule absorbgitdirs &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''sub1'\\'' from\n+\t'\\''$cwd/sub1/.git'\\'' to\n+\t'\\''$cwd/.git/modules/sub1'\\''\n+\tEOF\n+\tgit submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual &&\n \tgit fsck &&\n \ttest -f sub1/.git &&\n \ttest -d .git/modules/sub1 &&\n@@ -37,7 +46,8 @@ test_expect_success 'absorb the git dir' '\n test_expect_success 'absorbing does not fail for deinitialized submodules' '\n \ttest_when_finished \"git submodule update --init\" &&\n \tgit submodule deinit --all &&\n-\tgit submodule absorbgitdirs &&\n+\tgit submodule absorbgitdirs 2>err &&\n+\ttest_must_be_empty err &&\n \ttest -d .git/modules/sub1 &&\n \ttest -d sub1 &&\n \t! test -e sub1/.git\n@@ -56,7 +66,13 @@ test_expect_success 'setup nested submodule' '\n test_expect_success 'absorb the git dir in a nested submodule' '\n \tgit status >expect.1 &&\n \tgit -C sub1/nested rev-parse HEAD >expect.2 &&\n-\tgit submodule absorbgitdirs &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''sub1/nested'\\'' from\n+\t'\\''$cwd/sub1/nested/.git'\\'' to\n+\t'\\''$cwd/.git/modules/sub1/modules/nested'\\''\n+\tEOF\n+\tgit submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual &&\n \ttest -f sub1/nested/.git &&\n \ttest -d .git/modules/sub1/modules/nested &&\n \tgit status >actual.1 &&\n@@ -87,7 +103,13 @@ test_expect_success 're-setup nested submodule' '\n test_expect_success 'absorb the git dir in a nested submodule' '\n \tgit status >expect.1 &&\n \tgit -C sub1/nested rev-parse HEAD >expect.2 &&\n-\tgit submodule absorbgitdirs &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''sub1'\\'' from\n+\t'\\''$cwd/sub1/.git'\\'' to\n+\t'\\''$cwd/.git/modules/sub1'\\''\n+\tEOF\n+\tgit submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual &&\n \ttest -f sub1/.git &&\n \ttest -f sub1/nested/.git &&\n \ttest -d .git/modules/sub1/modules/nested &&\n@@ -97,6 +119,27 @@ test_expect_success 'absorb the git dir in a nested submodule' '\n \ttest_cmp expect.2 actual.2\n '\n \n+test_expect_success 'absorb the git dir outside of primary worktree' '\n+\ttest_when_finished \"rm -rf repo-bare.git\" &&\n+\tgit clone --bare . repo-bare.git &&\n+\ttest_when_finished \"rm -rf repo-wt\" &&\n+\tgit -C repo-bare.git worktree add ../repo-wt &&\n+\n+\ttest_when_finished \"rm -f .gitconfig\" &&\n+\ttest_config_global protocol.file.allow always &&\n+\tgit -C repo-wt submodule update --init &&\n+\tgit init repo-wt/sub2 &&\n+\ttest_commit -C repo-wt/sub2 A &&\n+\tgit -C repo-wt submodule add ./sub2 sub2 &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''sub2'\\'' from\n+\t'\\''$cwd/repo-wt/sub2/.git'\\'' to\n+\t'\\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\\''\n+\tEOF\n+\tDO_IT=1 git -C repo-wt submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n \tgit init sub2 &&\n \ttest_commit -C sub2 first &&\n@@ -107,7 +150,11 @@ test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n test_expect_success 'absorbing the git dir fails for incomplete submodules' '\n \tgit status >expect.1 &&\n \tgit -C sub2 rev-parse HEAD >expect.2 &&\n-\ttest_must_fail git submodule absorbgitdirs &&\n+\tcat >expect <<-\\EOF &&\n+\tfatal: could not lookup name for submodule '\\''sub2'\\''\n+\tEOF\n+\ttest_must_fail git submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual &&\n \tgit -C sub2 fsck &&\n \ttest -d sub2/.git &&\n \tgit status >actual &&\n@@ -127,8 +174,11 @@ test_expect_success 'setup a submodule with multiple worktrees' '\n '\n \n test_expect_success 'absorbing fails for a submodule with multiple worktrees' '\n-\ttest_must_fail git submodule absorbgitdirs sub3 2>error &&\n-\ttest_i18ngrep \"not supported\" error\n+\tcat >expect <<-\\EOF &&\n+\tfatal: could not lookup name for submodule '\\''sub2'\\''\n+\tEOF\n+\ttest_must_fail git submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469092","messageId":"patch-v4-3.9-b2e543bde03-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v4 3/9] submodule.c & submodule--helper: pass along \"super_prefix\" param","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:44Z","receivedAt":"2022-12-15T09:33:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Start passing the \"super_prefix\" along as a parameter to\nget_submodule_displaypath() and absorb_git_dir_into_superproject(),\nrather than get the value directly as a global.\n\nThis is in preparation for subsequent commits, where we'll gradually\nphase out get_super_prefix() for an alternative way of getting the\n\"super_prefix\".\n\nMost of the users of this get a get_super_prefix() value, either\ndirectly or by indirection. The exceptions are:\n\n- builtin/rm.c: Doesn't declare SUPPORT_SUPER_PREFIX, so we'd have\n  died if this was provided, so it's safe to passs \"NULL\".\n\n- deinit_submodule(): The \"deinit_submodule()\" function has never been\n  able to use the \"git -super-prefix\". It will call\n  \"absorb_git_dir_into_superproject()\", but it will only do so from the\n  top-level project.\n\n  If \"absorbgitdirs\" recurses it will use the \"path\" passed to\n  \"absorb_git_dir_into_superproject()\" in \"deinit_submodule()\" as its\n  starting \"--super-prefix\". So we can safely remove the\n  get_super_prefix() call here, and pass NULL instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/rm.c                |  2 +-\n builtin/submodule--helper.c | 35 ++++++++++++++++++++++-------------\n submodule.c                 | 15 +++++++++------\n submodule.h                 |  3 ++-\n 4 files changed, 34 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex d4989d4d863..4a4aec0d00e 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -86,7 +86,7 @@ static void submodules_absorb_gitdir_if_needed(void)\n \t\t\tcontinue;\n \n \t\tif (!submodule_uses_gitfile(name))\n-\t\t\tabsorb_git_dir_into_superproject(name);\n+\t\t\tabsorb_git_dir_into_superproject(name, NULL);\n \t}\n }\n \ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 05f2c9bc985..da844cad5ce 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n }\n \n /* the result should be freed by the caller. */\n-static char *get_submodule_displaypath(const char *path, const char *prefix)\n+static char *get_submodule_displaypath(const char *path, const char *prefix,\n+\t\t\t\t       const char *super_prefix)\n {\n-\tconst char *super_prefix = get_super_prefix();\n-\n \tif (prefix && super_prefix) {\n \t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n \t\t    prefix, super_prefix);\n@@ -294,7 +293,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath(path, info->prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -447,7 +447,8 @@ static void init_submodule(const char *path, const char *prefix,\n \tconst char *upd;\n \tchar *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -624,7 +625,8 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n \t\t      path);\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n@@ -948,7 +950,8 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t\tdst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tif (!missing_src && !missing_dst) {\n \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n@@ -1239,7 +1242,8 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tsuper_config_url = xstrdup(\"\");\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tif (!(flags & OPT_QUIET))\n \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n@@ -1365,7 +1369,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \tif (!sub || !sub->name)\n \t\tgoto cleanup;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix, NULL);\n \n \t/* remove the submodule work tree (unless the user already did it) */\n \tif (is_directory(path)) {\n@@ -1379,7 +1383,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \t\t\t\t\t  \".git file by using absorbgitdirs.\"),\n \t\t\t\t\tdisplaypath);\n \n-\t\t\tabsorb_git_dir_into_superproject(path);\n+\t\t\tabsorb_git_dir_into_superproject(path, NULL);\n \n \t\t}\n \n@@ -1958,7 +1962,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tenum submodule_update_type update_type;\n \tchar *key;\n \tconst struct update_data *ud = suc->update_data;\n-\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n+\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix,\n+\t\t\t\t\t\t      get_super_prefix());\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n \tint need_free_url = 0;\n@@ -2608,7 +2613,8 @@ static int update_submodules(struct update_data *update_data)\n \t\t\tgoto fail;\n \n \t\tupdate_data->displaypath = get_submodule_displaypath(\n-\t\t\tupdate_data->sm_path, update_data->prefix);\n+\t\t\tupdate_data->sm_path, update_data->prefix,\n+\t\t\tget_super_prefix());\n \t\tcode = update_submodule(update_data);\n \t\tFREE_AND_NULL(update_data->displaypath);\n fail:\n@@ -2828,6 +2834,7 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tconst char *super_prefix;\n \tstruct option embed_gitdir_options[] = {\n \t\tOPT_END()\n \t};\n@@ -2843,8 +2850,10 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tif (module_list_compute(argv, prefix, &pathspec, &list) < 0)\n \t\tgoto cleanup;\n \n+\tsuper_prefix = get_super_prefix();\n \tfor (i = 0; i < list.nr; i++)\n-\t\tabsorb_git_dir_into_superproject(list.entries[i]->name);\n+\t\tabsorb_git_dir_into_superproject(list.entries[i]->name,\n+\t\t\t\t\t\t super_prefix);\n \n \tret = 0;\n cleanup:\ndiff --git a/submodule.c b/submodule.c\nindex 8ac2fca855d..bf19598b8c2 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2145,7 +2145,8 @@ int submodule_move_head(const char *path,\n \tif (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {\n \t\tif (old_head) {\n \t\t\tif (!submodule_uses_gitfile(path))\n-\t\t\t\tabsorb_git_dir_into_superproject(path);\n+\t\t\t\tabsorb_git_dir_into_superproject(path,\n+\t\t\t\t\t\t\t\t get_super_prefix());\n \t\t} else {\n \t\t\tstruct strbuf gitdir = STRBUF_INIT;\n \t\t\tsubmodule_name_to_gitdir(&gitdir, the_repository,\n@@ -2315,7 +2316,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \tstrbuf_release(&new_gitdir);\n }\n \n-static void absorb_git_dir_into_superproject_recurse(const char *path)\n+static void absorb_git_dir_into_superproject_recurse(const char *path,\n+\t\t\t\t\t\t     const char *super_prefix)\n {\n \n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2323,8 +2325,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n \tcp.dir = path;\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n+\t\t     super_prefix : \"\", path);\n \tstrvec_pushl(&cp.args, \"submodule--helper\",\n \t\t     \"absorbgitdirs\", NULL);\n \tprepare_submodule_repo_env(&cp.env);\n@@ -2337,7 +2339,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n  * having its git directory within the working tree to the git dir nested\n  * in its superprojects git dir under modules/.\n  */\n-void absorb_git_dir_into_superproject(const char *path)\n+void absorb_git_dir_into_superproject(const char *path,\n+\t\t\t\t      const char *super_prefix)\n {\n \tint err_code;\n \tconst char *sub_git_dir;\n@@ -2386,7 +2389,7 @@ void absorb_git_dir_into_superproject(const char *path)\n \t}\n \tstrbuf_release(&gitdir);\n \n-\tabsorb_git_dir_into_superproject_recurse(path);\n+\tabsorb_git_dir_into_superproject_recurse(path, super_prefix);\n }\n \n int get_superproject_working_tree(struct strbuf *buf)\ndiff --git a/submodule.h b/submodule.h\nindex b52a4ff1e73..f90ee547d08 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -164,7 +164,8 @@ void submodule_unset_core_worktree(const struct submodule *sub);\n  */\n void prepare_submodule_repo_env(struct strvec *env);\n \n-void absorb_git_dir_into_superproject(const char *path);\n+void absorb_git_dir_into_superproject(const char *path,\n+\t\t\t\t      const char *super_prefix);\n \n /*\n  * Return the absolute path of the working tree of the superproject, which this\n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469093","messageId":"patch-v4-5.9-4da58e7ea50-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v4 5/9] submodule--helper: convert \"foreach\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:46Z","receivedAt":"2022-12-15T09:33:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper foreach\" to use its own \"--super-prefix\", instead\nof relying on the global \"--super-prefix\" argument to \"git\"\nitself. See that earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b8b2bc776d1..2a6ced13f6d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -278,6 +278,7 @@ struct foreach_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint quiet;\n \tint recursive;\n };\n@@ -294,7 +295,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tchar *displaypath;\n \n \tdisplaypath = get_submodule_displaypath(path, info->prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\t\t\t\t\t\tinfo->super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -364,10 +365,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"foreach\", \"--recursive\",\n \t\t\t     NULL);\n+\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (info->quiet)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -391,6 +392,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n \tstruct option module_foreach_options[] = {\n+\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n \t\t\t N_(\"recurse into nested submodules\")),\n@@ -3390,8 +3392,8 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469094","messageId":"patch-v4-4.9-bde9038c4e3-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v4 4/9] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:45Z","receivedAt":"2022-12-15T09:33:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" facility was introduced in [1] has always been a\ntransitory hack, which is why we've made it an error to supply it as\nan option to \"git\" to commands that don't know about it.\n\nThat's been a good goal, as it has a global effect we haven't wanted\ncalls to get_super_prefix() from built-ins we didn't expect.\n\nBut it has meant that when we've had chains of different built-ins\nusing it all of the processes in that \"chain\" have needed to support\nit, and worse processes that don't need it have needed to ask for\n\"SUPPORT_SUPER_PREFIX\" because their parent process needs it.\n\nThat's how \"fsmonitor--daemon\" ended up with it, per [2] it's called\nfrom (among other things) \"submodule--helper absorbgitdirs\", but as we\ndeclared \"submodule--helper\" as \"SUPPORT_SUPER_PREFIX\" we needed to\ndeclare \"fsmonitor--daemon\" as accepting it too, even though it\ndoesn't care about it.\n\nBut in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\ninvoke itself recursively, and we'd never have another \"in-between\"\nprocess in the chain. So we didn't need the bigger hammer of \"git\n--super-prefix\", and the \"setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)\"\nthat it entails.\n\nLet's instead accept a hidden \"--super-prefix\" option to\n\"submodule--helper absorbgitdirs\" itself.\n\nEventually (as with all other \"--super-prefix\" users) we'll want to\nclean this code up so that this all happens in-process. I.e. needing\nany variant of \"--super-prefix\" is itself a hack around our various\nglobal state, and implicit reliance on \"the_repository\". This stepping\nstone makes such an eventual change easier, as we'll need to deal with\nless global state at that point.\n\nThe \"fsmonitor--daemon\" test adjusted here was added in [3]. To assert\nthat it didn't run into the \"--super-prefix\" message it was asserting\nthe output it didn't have. Let's instead assert the full output that\nwe *do* have, which we can do here as this is based on a change[4] to\nmake it predictable (until [4] it contained absolute paths).\n\nWe could also remove the test entirely (as [5] did), but even though\nthe initial reason for having it is gone we're still getting some\nmarginal benefit from testing the \"fsmonitor\" and \"submodule\nabsorbgitdirs\" interaction, so let's keep it.\n\nThe change here to have either a NULL or non-\"\" string as a\n\"super_prefix\" instead of the previous arrangement of \"\" or non-\"\" is\nsomewhat arbitrary. We could also decide to never have to check for\nNULL.\n\nAs we'll be changing the rest of the \"git --super-prefix\" users to the\nsame pattern, leaving them all consistent makes sense. Why not pick \"\"\nover NULL? Because that's how the \"prefix\" works[6], and having\n\"prefix\" and \"super_prefix\" work the same way will be less\nconfusing. That \"prefix\" picked NULL instead of \"\" is itself\narbitrary, but as it's easy to make this small bit of our overall API\nconsistent, let's go with that.\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n   2022-05-26)\n3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n   2022-05-26)\n4. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/\n5. https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com/\n6. 9725c8dda20 (built-ins: trust the \"prefix\" from run_builtin(),\n   2022-02-16)\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c  |  7 +++----\n git.c                        |  2 +-\n parse-options.h              |  4 ++++\n submodule.c                  | 12 +++++++-----\n t/t7527-builtin-fsmonitor.sh | 36 ++++++++++++++----------------------\n 5 files changed, 29 insertions(+), 32 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex da844cad5ce..b8b2bc776d1 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2834,8 +2834,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n-\tconst char *super_prefix;\n+\tconst char *super_prefix = NULL;\n \tstruct option embed_gitdir_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT_END()\n \t};\n \tconst char *const git_submodule_helper_usage[] = {\n@@ -2850,7 +2851,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tif (module_list_compute(argv, prefix, &pathspec, &list) < 0)\n \t\tgoto cleanup;\n \n-\tsuper_prefix = get_super_prefix();\n \tfor (i = 0; i < list.nr; i++)\n \t\tabsorb_git_dir_into_superproject(list.entries[i]->name,\n \t\t\t\t\t\t super_prefix);\n@@ -3391,8 +3391,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n \t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && strcmp(subcmd, \"absorbgitdirs\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\ndiff --git a/git.c b/git.c\nindex 277a8cce840..e473b4b7d72 100644\n--- a/git.c\n+++ b/git.c\n@@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {\n \t{ \"format-patch\", cmd_format_patch, RUN_SETUP },\n \t{ \"fsck\", cmd_fsck, RUN_SETUP },\n \t{ \"fsck-objects\", cmd_fsck, RUN_SETUP },\n-\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },\n+\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, RUN_SETUP },\n \t{ \"gc\", cmd_gc, RUN_SETUP },\n \t{ \"get-tar-commit-id\", cmd_get_tar_commit_id, NO_PARSEOPT },\n \t{ \"grep\", cmd_grep, RUN_SETUP_GENTLY },\ndiff --git a/parse-options.h b/parse-options.h\nindex b6ef86e0d15..50d852f2991 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);\n \t{ OPTION_CALLBACK, 0, \"abbrev\", (var), N_(\"n\"),\t\\\n \t  N_(\"use <n> digits to display object names\"),\t\\\n \t  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }\n+#define OPT__SUPER_PREFIX(var) \\\n+\tOPT_STRING_F(0, \"super-prefix\", (var), N_(\"prefix\"), \\\n+\t\tN_(\"prefixed path to initial superproject\"), PARSE_OPT_HIDDEN)\n+\n #define OPT__COLOR(var, h) \\\n \tOPT_COLOR_FLAG(0, \"color\", (var), (h))\n #define OPT_COLUMN(s, l, v, h) \\\ndiff --git a/submodule.c b/submodule.c\nindex bf19598b8c2..46a03473195 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2275,7 +2275,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)\n  * Embeds a single submodules git directory into the superprojects git dir,\n  * non recursively.\n  */\n-static void relocate_single_git_dir_into_superproject(const char *path)\n+static void relocate_single_git_dir_into_superproject(const char *path,\n+\t\t\t\t\t\t      const char *super_prefix)\n {\n \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n \tstruct strbuf new_gitdir = STRBUF_INIT;\n@@ -2305,7 +2306,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \treal_new_git_dir = real_pathdup(new_gitdir.buf, 1);\n \n \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from\\n'%s' to\\n'%s'\\n\"),\n-\t\tget_super_prefix_or_empty(), path,\n+\t\tsuper_prefix ? super_prefix : \"\", path,\n \t\treal_old_git_dir, real_new_git_dir);\n \n \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n@@ -2325,10 +2326,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path,\n \tcp.dir = path;\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n-\t\t     super_prefix : \"\", path);\n \tstrvec_pushl(&cp.args, \"submodule--helper\",\n \t\t     \"absorbgitdirs\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n+\t\t     super_prefix : \"\", path);\n+\n \tprepare_submodule_repo_env(&cp.env);\n \tif (run_command(&cp))\n \t\tdie(_(\"could not recurse into submodule '%s'\"), path);\n@@ -2382,7 +2384,7 @@ void absorb_git_dir_into_superproject(const char *path,\n \t\tchar *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);\n \n \t\tif (!starts_with(real_sub_git_dir, real_common_git_dir))\n-\t\t\trelocate_single_git_dir_into_superproject(path);\n+\t\t\trelocate_single_git_dir_into_superproject(path, super_prefix);\n \n \t\tfree(real_sub_git_dir);\n \t\tfree(real_common_git_dir);\ndiff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh\nindex 4abc74db2bb..76d0220daa0 100755\n--- a/t/t7527-builtin-fsmonitor.sh\n+++ b/t/t7527-builtin-fsmonitor.sh\n@@ -866,27 +866,9 @@ test_expect_success 'submodule always visited' '\n # the submodule, and someone does a `git submodule absorbgitdirs`\n # in the super, Git will recursively invoke `git submodule--helper`\n # to do the work and this may try to read the index.  This will\n-# try to start the daemon in the submodule *and* pass (either\n-# directly or via inheritance) the `--super-prefix` arg to the\n-# `git fsmonitor--daemon start` command inside the submodule.\n-# This causes a warning because fsmonitor--daemon does take that\n-# global arg (see the table in git.c)\n-#\n-# This causes a warning when trying to start the daemon that is\n-# somewhat confusing.  It does not seem to hurt anything because\n-# the fsmonitor code maps the query failure into a trivial response\n-# and does the work anyway.\n-#\n-# It would be nice to silence the warning, however.\n-\n-have_t2_error_event () {\n-\tlog=$1\n-\tmsg=\"fsmonitor--daemon doesnQt support --super-prefix\" &&\n-\n-\ttr '\\047' Q <$1 | grep -e \"$msg\"\n-}\n+# try to start the daemon in the submodule.\n \n-test_expect_success \"stray submodule super-prefix warning\" '\n+test_expect_success \"submodule absorbgitdirs implicitly starts daemon\" '\n \ttest_when_finished \"rm -rf super; \\\n \t\t\t    rm -rf sub;   \\\n \t\t\t    rm super-sub.trace\" &&\n@@ -904,10 +886,20 @@ test_expect_success \"stray submodule super-prefix warning\" '\n \n \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n \n+\tcwd=\"$(cd super && pwd)\" &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from\n+\t'\\''$cwd/dir_1/dir_2/sub/.git'\\'' to\n+\t'\\''$cwd/.git/modules/dir_1/dir_2/sub'\\''\n+\tEOF\n \tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n-\t\tgit -C super submodule absorbgitdirs &&\n+\t\tgit -C super submodule absorbgitdirs >out 2>actual &&\n+\ttest_cmp expect actual &&\n+\ttest_must_be_empty out &&\n \n-\t! have_t2_error_event super-sub.trace\n+\t# Confirm that the trace2 log contains a record of the\n+\t# daemon starting.\n+\ttest_subcommand git fsmonitor--daemon start <super-sub.trace\n '\n \n # On a case-insensitive file system, confirm that the daemon\n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469095","messageId":"patch-v4-6.9-8dff576df7d-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v4 6/9] submodule--helper: convert \"sync\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:47Z","receivedAt":"2022-12-15T09:33:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper sync\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 20 +++++++++++---------\n 1 file changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 2a6ced13f6d..7262ce72edf 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1208,12 +1208,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \n struct sync_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define SYNC_CB_INIT { 0 }\n \n static void sync_submodule(const char *path, const char *prefix,\n-\t\t\t   unsigned int flags)\n+\t\t\t   const char *super_prefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n@@ -1244,8 +1245,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tsuper_config_url = xstrdup(\"\");\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n \n \tif (!(flags & OPT_QUIET))\n \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n@@ -1282,10 +1282,11 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"sync\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n+\n \n \t\tif (flags & OPT_QUIET)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -1308,7 +1309,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct sync_cb *info = cb_data;\n \n-\tsync_submodule(list_item->name, info->prefix, info->flags);\n+\tsync_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_sync(int argc, const char **argv, const char *prefix)\n@@ -1319,6 +1321,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \tint quiet = 0;\n \tint recursive = 0;\n \tstruct option module_sync_options[] = {\n+\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n \t\tOPT_BOOL(0, \"recursive\", &recursive,\n \t\t\tN_(\"recurse into nested submodules\")),\n@@ -2887,7 +2890,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)\n \tconfig_name = xstrfmt(\"submodule.%s.url\", path);\n \n \tconfig_set_in_gitmodules_file_gently(config_name, newurl);\n-\tsync_submodule(path, prefix, quiet ? OPT_QUIET : 0);\n+\tsync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);\n \n \tfree(config_name);\n \n@@ -3392,8 +3395,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469096","messageId":"patch-v4-7.9-8800a433e29-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v4 7/9] submodule--helper: convert \"status\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:48Z","receivedAt":"2022-12-15T09:33:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7262ce72edf..448896f1b1d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -573,6 +573,7 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \n struct status_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define STATUS_CB_INIT { 0 }\n@@ -611,7 +612,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,\n \n static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\t\t     unsigned int ce_flags, const char *prefix,\n-\t\t\t     unsigned int flags)\n+\t\t\t     const char *super_prefix, unsigned int flags)\n {\n \tchar *displaypath;\n \tstruct strvec diff_files_args = STRVEC_INIT;\n@@ -627,8 +628,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n \t\t      path);\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n \n \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n@@ -686,10 +686,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"status\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (flags & OPT_CACHED)\n \t\t\tstrvec_push(&cpr.args, \"--cached\");\n@@ -713,7 +713,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,\n \tstruct status_cb *info = cb_data;\n \n \tstatus_submodule(list_item->name, &list_item->oid, list_item->ce_flags,\n-\t\t\t info->prefix, info->flags);\n+\t\t\t info->prefix, info->super_prefix, info->flags);\n }\n \n static int module_status(int argc, const char **argv, const char *prefix)\n@@ -723,6 +723,7 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n \tstruct option module_status_options[] = {\n+\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n@@ -3395,7 +3396,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && get_super_prefix())\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469097","messageId":"patch-v4-8.9-54c1e29de1e-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v4 8/9] submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:49Z","receivedAt":"2022-12-15T09:33:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\".\n\nWe need to convert both of these away from the global \"--super-prefix\"\nat the same time, because \"update\" will call \"clone\", but \"clone\"\nitself didn't make use of the global \"--super-prefix\" for displaying\npaths. It was only on the list of sub-commands that accepted it\nbecause \"update\"'s use of it would set it in its environment.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 32 +++++++++++++-------------------\n git.c                       |  2 +-\n 2 files changed, 14 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 448896f1b1d..a0aa4635a0c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -437,11 +437,13 @@ static int starts_with_dot_dot_slash(const char *const path)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define INIT_CB_INIT { 0 }\n \n static void init_submodule(const char *path, const char *prefix,\n+\t\t\t   const char *super_prefix,\n \t\t\t   unsigned int flags)\n {\n \tconst struct submodule *sub;\n@@ -449,8 +451,7 @@ static void init_submodule(const char *path, const char *prefix,\n \tconst char *upd;\n \tchar *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -526,7 +527,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct init_cb *info = cb_data;\n \n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n@@ -792,6 +794,7 @@ struct summary_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int cached: 1;\n \tunsigned int for_status: 1;\n \tunsigned int files: 1;\n@@ -954,7 +957,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t}\n \n \tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\t\t\t\t\t\tinfo->super_prefix);\n \n \tif (!missing_src && !missing_dst) {\n \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n@@ -1893,6 +1896,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)\n \n struct update_data {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tchar *displaypath;\n \tenum submodule_update_type update_default;\n \tstruct object_id suboid;\n@@ -1969,7 +1973,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tchar *key;\n \tconst struct update_data *ud = suc->update_data;\n \tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix,\n-\t\t\t\t\t\t      get_super_prefix());\n+\t\t\t\t\t\t      ud->super_prefix);\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n \tint need_free_url = 0;\n@@ -2449,11 +2453,11 @@ static void update_data_to_args(const struct update_data *update_data,\n {\n \tenum submodule_update_type update_type = update_data->update_default;\n \n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tif (update_data->displaypath) {\n \t\tstrvec_push(args, \"--super-prefix\");\n \t\tstrvec_pushf(args, \"%s/\", update_data->displaypath);\n \t}\n-\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n \tif (update_data->quiet)\n \t\tstrvec_push(args, \"--quiet\");\n@@ -2620,7 +2624,7 @@ static int update_submodules(struct update_data *update_data)\n \n \t\tupdate_data->displaypath = get_submodule_displaypath(\n \t\t\tupdate_data->sm_path, update_data->prefix,\n-\t\t\tget_super_prefix());\n+\t\t\tupdate_data->super_prefix);\n \t\tcode = update_submodule(update_data);\n \t\tFREE_AND_NULL(update_data->displaypath);\n fail:\n@@ -2646,6 +2650,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\tLIST_OBJECTS_FILTER_INIT;\n \tint ret;\n \tstruct option module_update_options[] = {\n+\t\tOPT__SUPER_PREFIX(&opt.super_prefix),\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n \t\tOPT_BOOL(0, \"init\", &opt.init,\n \t\t\t N_(\"initialize uninitialized submodules before update\")),\n@@ -2742,6 +2747,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\t\tmodule_list_active(&list);\n \n \t\tinfo.prefix = opt.prefix;\n+\t\tinfo.super_prefix = opt.super_prefix;\n \t\tif (opt.quiet)\n \t\t\tinfo.flags |= OPT_QUIET;\n \n@@ -3368,8 +3374,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n {\n-\tconst char *cmd = argv[0];\n-\tconst char *subcmd;\n \tparse_opt_subcommand_fn *fn = NULL;\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule--helper <command>\"),\n@@ -3393,16 +3397,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\tsubcmd = argv[0];\n-\n-\tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    get_super_prefix())\n-\t\t/*\n-\t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n-\t\t * string identical to git.c's.\n-\t\t */\n-\t\tdie(_(\"%s doesn't support --super-prefix\"),\n-\t\t    xstrfmt(\"'%s %s'\", cmd, subcmd));\n \n \treturn fn(argc, argv, prefix);\n }\ndiff --git a/git.c b/git.c\nindex e473b4b7d72..2c31ba27040 100644\n--- a/git.c\n+++ b/git.c\n@@ -610,7 +610,7 @@ static struct cmd_struct commands[] = {\n \t{ \"stash\", cmd_stash, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"stripspace\", cmd_stripspace },\n-\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP },\n \t{ \"switch\", cmd_switch, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"symbolic-ref\", cmd_symbolic_ref, RUN_SETUP },\n \t{ \"tag\", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },\n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469098","messageId":"patch-v4-9.9-4824f33224f-20221215T083502Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v4 9/9] read-tree: add \"--super-prefix\" option, eliminate global","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-15T09:32:50Z","receivedAt":"2022-12-15T09:33:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" option to \"git\" was initially added in [1] for\nuse with \"ls-files\"[2], and shortly thereafter \"submodule--helper\"[3]\nand \"grep\"[4]. It wasn't until [5] that \"read-tree\" made use of it.\n\nAt the time [5] made sense, but since then we've made \"ls-files\"\nrecurse in-process in [6], \"grep\" in [7], and finally\n\"submodule--helper\" in the preceding commits.\n\nLet's also remove it from \"read-tree\", which allows us to remove the\noption to \"git\" itself.\n\nWe can do this because the only remaining user of it is the submodule\nAPI, which will now invoke \"read-tree\" with its new \"--super-prefix\"\noption. It will only do so when the \"submodule_move_head()\" function\nis called.\n\nThat \"submodule_move_head()\" function was then only invoked by\n\"read-tree\" itself, but now rather than setting an environment\nvariable to pass \"--super-prefix\" between cmd_read_tree() we:\n\n- Set a new \"super_prefix\" in \"struct unpack_trees_options\". The\n  \"super_prefixed()\" function in \"unpack-trees.c\" added in [5] will now\n  use this, rather than get_super_prefix() looking up the environment\n  variable we set earlier in the same process.\n\n- Add the same field to the \"struct checkout\", which is only needed to\n  ferry the \"super_prefix\" in the \"struct unpack_trees_options\" all the\n  way down to the \"entry.c\" callers of \"submodule_move_head()\".\n\n  Those calls which used the super prefix all originated in\n  \"cmd_read_tree()\". The only other caller is the \"unlink_entry()\"\n  caller in \"builtin/checkout.c\", which now passes a \"NULL\".\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)\n3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)\n4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)\n5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)\n6. 188dce131fa (ls-files: use repository object, 2017-06-22)\n7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git.txt       |  8 +-------\n builtin.h                   |  4 ----\n builtin/checkout.c          |  2 +-\n builtin/read-tree.c         |  1 +\n cache.h                     |  2 --\n entry.c                     | 12 ++++++------\n entry.h                     |  6 +++++-\n environment.c               | 13 -------------\n git.c                       | 37 +++++--------------------------------\n submodule.c                 | 29 ++++++++++-------------------\n submodule.h                 |  5 ++---\n t/t1001-read-tree-m-2way.sh |  2 +-\n t/t5616-partial-clone.sh    |  2 +-\n unpack-trees.c              | 24 ++++++++++++++----------\n unpack-trees.h              |  1 +\n 15 files changed, 48 insertions(+), 100 deletions(-)\n\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 1d33e083ab8..f9a7a4554cd 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -13,8 +13,7 @@ SYNOPSIS\n     [--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>]\n+    [--config-env=<name>=<envvar>] <command> [<args>]\n \n DESCRIPTION\n -----------\n@@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use\n \tdetails.  Equivalent to setting the `GIT_NAMESPACE` environment\n \tvariable.\n \n---super-prefix=<path>::\n-\tCurrently for internal use only.  Set a prefix which gives a path from\n-\tabove a repository down to its root.  One use is to give submodules\n-\tcontext about the superproject that invoked it.\n-\n --bare::\n \tTreat the repository as a bare repository.  If GIT_DIR\n \tenvironment is not set, it is set to the current working\ndiff --git a/builtin.h b/builtin.h\nindex aa955466b4e..46cc7897898 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -51,10 +51,6 @@\n  *\ton bare repositories.\n  *\tThis only makes sense when `RUN_SETUP` is also set.\n  *\n- * `SUPPORT_SUPER_PREFIX`:\n- *\n- *\tThe built-in supports `--super-prefix`.\n- *\n  * `DELAY_PAGER_CONFIG`:\n  *\n  *\tIf RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex a0142c815fd..cd04f0bf572 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -232,7 +232,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n \t\tpos++;\n \t}\n \tif (!overlay_mode) {\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, NULL);\n \t\treturn 0;\n \t}\n \tif (stage == 2)\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex f702f9d47bb..3ce75417833 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)\n \tint prefix_set = 0;\n \tstruct lock_file lock_file = LOCK_INIT;\n \tconst struct option read_tree_options[] = {\n+\t\tOPT__SUPER_PREFIX(&opts.super_prefix),\n \t\tOPT_CALLBACK_F(0, \"index-output\", NULL, N_(\"file\"),\n \t\t  N_(\"write resulting index to <file>\"),\n \t\t  PARSE_OPT_NONEG, index_output_cb),\ndiff --git a/cache.h b/cache.h\nindex 07d40b0964b..7f7e2b5a38f 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -480,7 +480,6 @@ static inline enum object_type object_type(unsigned int mode)\n #define GIT_NAMESPACE_ENVIRONMENT \"GIT_NAMESPACE\"\n #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n #define GIT_PREFIX_ENVIRONMENT \"GIT_PREFIX\"\n-#define GIT_SUPER_PREFIX_ENVIRONMENT \"GIT_INTERNAL_SUPER_PREFIX\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n@@ -566,7 +565,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n int get_common_dir(struct strbuf *sb, const char *gitdir);\n const char *get_git_namespace(void);\n const char *strip_namespace(const char *namespaced_ref);\n-const char *get_super_prefix(void);\n const char *get_git_work_tree(void);\n \n /*\ndiff --git a/entry.c b/entry.c\nindex 616e4f073c1..971ab268714 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca\n \t\t\treturn error(\"cannot create submodule directory %s\", path);\n \t\tsub = submodule_from_ce(ce);\n \t\tif (sub)\n-\t\t\treturn submodule_move_head(ce->name,\n+\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\tNULL, oid_to_hex(&ce->oid),\n \t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\tbreak;\n@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t * no pathname to return.\n \t\t\t */\n \t\t\tBUG(\"Can't remove entry to a path\");\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, state->super_prefix);\n \t\treturn 0;\n \t}\n \n@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t\tif (!(st.st_mode & S_IFDIR))\n \t\t\t\t\tunlink_or_warn(ce->name);\n \n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\tNULL, oid_to_hex(&ce->oid), 0);\n \t\t\t} else\n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\t\"HEAD\", oid_to_hex(&ce->oid),\n \t\t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\t}\n@@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \treturn write_entry(ce, path.buf, ca, state, 0, nr_checkouts);\n }\n \n-void unlink_entry(const struct cache_entry *ce)\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)\n {\n \tconst struct submodule *sub = submodule_from_ce(ce);\n \tif (sub) {\n \t\t/* state.force is set at the caller. */\n-\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n+\t\tsubmodule_move_head(ce->name, super_prefix, \"HEAD\", NULL,\n \t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n \t}\n \tif (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)\ndiff --git a/entry.h b/entry.h\nindex 9be4659881e..2d4fbb88c8f 100644\n--- a/entry.h\n+++ b/entry.h\n@@ -8,6 +8,7 @@ struct checkout {\n \tstruct index_state *istate;\n \tconst char *base_dir;\n \tint base_dir_len;\n+\tconst char *super_prefix;\n \tstruct delayed_checkout *delayed_checkout;\n \tstruct checkout_metadata meta;\n \tunsigned force:1,\n@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);\n /*\n  * Unlink the last component and schedule the leading directories for\n  * removal, such that empty directories get removed.\n+ *\n+ * The \"super_prefix\" is either NULL, or the \"--super-prefix\" passed\n+ * down from \"read-tree\" et al.\n  */\n-void unlink_entry(const struct cache_entry *ce);\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);\n \n void *read_blob_entry(const struct cache_entry *ce, size_t *size);\n int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);\ndiff --git a/environment.c b/environment.c\nindex 18d042b467d..1ee3686fd8a 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -102,8 +102,6 @@ char *git_work_tree_cfg;\n \n static char *git_namespace;\n \n-static char *super_prefix;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {\n \tNO_REPLACE_OBJECTS_ENVIRONMENT,\n \tGIT_REPLACE_REF_BASE_ENVIRONMENT,\n \tGIT_PREFIX_ENVIRONMENT,\n-\tGIT_SUPER_PREFIX_ENVIRONMENT,\n \tGIT_SHALLOW_FILE_ENVIRONMENT,\n \tGIT_COMMON_DIR_ENVIRONMENT,\n \tNULL\n@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)\n \treturn NULL;\n }\n \n-const char *get_super_prefix(void)\n-{\n-\tstatic int initialized;\n-\tif (!initialized) {\n-\t\tsuper_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));\n-\t\tinitialized = 1;\n-\t}\n-\treturn super_prefix;\n-}\n-\n static int git_work_tree_initialized;\n \n /*\ndiff --git a/git.c b/git.c\nindex 2c31ba27040..32a5be68a17 100644\n--- a/git.c\n+++ b/git.c\n@@ -14,9 +14,8 @@\n  * RUN_SETUP for reading from the configuration file.\n  */\n #define NEED_WORK_TREE\t\t(1<<3)\n-#define SUPPORT_SUPER_PREFIX\t(1<<4)\n-#define DELAY_PAGER_CONFIG\t(1<<5)\n-#define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n+#define DELAY_PAGER_CONFIG\t(1<<4)\n+#define NO_PARSEOPT\t\t(1<<5) /* parse-options is not used */\n \n struct cmd_struct {\n \tconst char *cmd;\n@@ -29,8 +28,7 @@ const char git_usage_string[] =\n \t   \"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\\n\"\n \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\\n\"\n \t   \"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\\n\"\n-\t   \"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\\n\"\n-\t   \"           <command> [<args>]\");\n+\t   \"           [--config-env=<name>=<envvar>] <command> [<args>]\");\n \n const char git_more_info_string[] =\n \tN_(\"'git help -a' and 'git help -g' list available subcommands and some\\n\"\n@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);\n \t\t\tif (envchanged)\n \t\t\t\t*envchanged = 1;\n-\t\t} else if (!strcmp(cmd, \"--super-prefix\")) {\n-\t\t\tif (*argc < 2) {\n-\t\t\t\tfprintf(stderr, _(\"no prefix given for --super-prefix\\n\" ));\n-\t\t\t\tusage(git_usage_string);\n-\t\t\t}\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n-\t\t\t(*argv)++;\n-\t\t\t(*argc)--;\n-\t\t} else if (skip_prefix(cmd, \"--super-prefix=\", &cmd)) {\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n \t\t} else if (!strcmp(cmd, \"--bare\")) {\n \t\t\tchar *cwd = xgetcwd();\n \t\t\tis_bare_repository_cfg = 1;\n@@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\ttrace_repo_setup(prefix);\n \tcommit_pager_choice();\n \n-\tif (!help && get_super_prefix()) {\n-\t\tif (!(p->option & SUPPORT_SUPER_PREFIX))\n-\t\t\tdie(_(\"%s doesn't support --super-prefix\"), p->cmd);\n-\t}\n-\n \tif (!help && p->option & NEED_WORK_TREE)\n \t\tsetup_work_tree();\n \n@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {\n \t{ \"check-ref-format\", cmd_check_ref_format, NO_PARSEOPT  },\n \t{ \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout--worker\", cmd_checkout__worker,\n-\t\tRUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },\n+\t\tRUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout-index\", cmd_checkout_index,\n \t\tRUN_SETUP | NEED_WORK_TREE},\n \t{ \"cherry\", cmd_cherry, RUN_SETUP },\n@@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n-\t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n \t{ \"rebase\", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n@@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tint status;\n \n-\tif (get_super_prefix())\n-\t\tdie(_(\"%s doesn't support --super-prefix\"), argv[0]);\n-\n \tif (use_pager == -1 && !is_builtin(argv[0]))\n \t\tuse_pager = check_pager_config(argv[0]);\n \tcommit_pager_choice();\n@@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)\n \t\t\t */\n \t\t\ttrace2_cmd_name(\"_run_git_alias_\");\n \n-\t\t\tif (get_super_prefix())\n-\t\t\t\tdie(\"%s doesn't support --super-prefix\", **argv);\n-\n \t\t\tcommit_pager_choice();\n \n \t\t\tstrvec_push(&cmd.args, \"git\");\ndiff --git a/submodule.c b/submodule.c\nindex 46a03473195..d730b64b072 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2054,14 +2054,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)\n \tstrbuf_release(&config_path);\n }\n \n-static const char *get_super_prefix_or_empty(void)\n-{\n-\tconst char *s = get_super_prefix();\n-\tif (!s)\n-\t\ts = \"\";\n-\treturn s;\n-}\n-\n static int submodule_has_dirty_index(const struct submodule *sub)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2080,7 +2072,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)\n \treturn finish_command(&cp);\n }\n \n-static void submodule_reset_index(const char *path)\n+static void submodule_reset_index(const char *path, const char *super_prefix)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tprepare_submodule_repo_env(&cp.env);\n@@ -2089,10 +2081,10 @@ static void submodule_reset_index(const char *path)\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \t/* TODO: determine if this might overwright untracked files */\n \tstrvec_pushl(&cp.args, \"read-tree\", \"-u\", \"--reset\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tstrvec_push(&cp.args, empty_tree_oid_hex());\n \n@@ -2105,10 +2097,9 @@ static void submodule_reset_index(const char *path)\n  * For edge cases (a submodule coming into existence or removing a submodule)\n  * pass NULL for old or new respectively.\n  */\n-int submodule_move_head(const char *path,\n-\t\t\t const char *old_head,\n-\t\t\t const char *new_head,\n-\t\t\t unsigned flags)\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n+\t\t\tunsigned flags)\n {\n \tint ret = 0;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2146,7 +2137,7 @@ int submodule_move_head(const char *path,\n \t\tif (old_head) {\n \t\t\tif (!submodule_uses_gitfile(path))\n \t\t\t\tabsorb_git_dir_into_superproject(path,\n-\t\t\t\t\t\t\t\t get_super_prefix());\n+\t\t\t\t\t\t\t\t super_prefix);\n \t\t} else {\n \t\t\tstruct strbuf gitdir = STRBUF_INIT;\n \t\t\tsubmodule_name_to_gitdir(&gitdir, the_repository,\n@@ -2155,7 +2146,7 @@ int submodule_move_head(const char *path,\n \t\t\tstrbuf_release(&gitdir);\n \n \t\t\t/* make sure the index is clean as well */\n-\t\t\tsubmodule_reset_index(path);\n+\t\t\tsubmodule_reset_index(path, super_prefix);\n \t\t}\n \n \t\tif (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {\n@@ -2173,9 +2164,9 @@ int submodule_move_head(const char *path,\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \tstrvec_pushl(&cp.args, \"read-tree\", \"--recurse-submodules\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tif (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)\n \t\tstrvec_push(&cp.args, \"-n\");\ndiff --git a/submodule.h b/submodule.h\nindex f90ee547d08..c55a25ca37d 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);\n \n #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)\n #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)\n-int submodule_move_head(const char *path,\n-\t\t\tconst char *old,\n-\t\t\tconst char *new_head,\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n \t\t\tunsigned flags);\n \n void submodule_unset_core_worktree(const struct submodule *sub);\ndiff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh\nindex 516a6112fdc..3fb1b0c162d 100755\n--- a/t/t1001-read-tree-m-2way.sh\n+++ b/t/t1001-read-tree-m-2way.sh\n@@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '\n \tcat <<-EOF >expect &&\n \t\terror: Updating '\\''fictional/a'\\'' would lose untracked files in it\n \tEOF\n-\ttest_must_fail git --super-prefix fictional/ read-tree -u -m \"$treeH\" \"$treeM\" 2>actual &&\n+\ttest_must_fail git read-tree --super-prefix fictional/ -u -m \"$treeH\" \"$treeM\" 2>actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 2846ec6629c..f519d2a87a7 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -644,7 +644,7 @@ test_expect_success 'repack does not loosen promisor objects' '\n \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n '\n \n-test_expect_failure 'lazy-fetch in submodule succeeds' '\n+test_expect_success 'lazy-fetch in submodule succeeds' '\n \t# setup\n \ttest_config_global protocol.file.allow always &&\n \ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 8a762aa0772..2b8e5da4c21 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {\n \t  ? ((o)->msgs[(type)])      \\\n \t  : (unpack_plumbing_errors[(type)]) )\n \n-static const char *super_prefixed(const char *path)\n+static const char *super_prefixed(const char *path, const char *super_prefix)\n {\n \t/*\n \t * It is necessary and sufficient to have two static buffers\n@@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)\n \tstatic unsigned idx = ARRAY_SIZE(buf) - 1;\n \n \tif (super_prefix_len < 0) {\n-\t\tconst char *super_prefix = get_super_prefix();\n \t\tif (!super_prefix) {\n \t\t\tsuper_prefix_len = 0;\n \t\t} else {\n@@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,\n \t\treturn -1;\n \n \tif (!o->show_all_errors)\n-\t\treturn error(ERRORMSG(o, e), super_prefixed(path));\n+\t\treturn error(ERRORMSG(o, e), super_prefixed(path,\n+\t\t\t\t\t\t\t    o->super_prefix));\n \n \t/*\n \t * Otherwise, insert in a list for future display by\n@@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)\n \t\t\terror_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t     o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)\n \t\t\twarning_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t       o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -312,7 +314,8 @@ static int check_submodule_move_head(const struct cache_entry *ce,\n \tif (o->reset)\n \t\tflags |= SUBMODULE_MOVE_HEAD_FORCE;\n \n-\tif (submodule_move_head(ce->name, old_id, new_id, flags))\n+\tif (submodule_move_head(ce->name, o->super_prefix, old_id, new_id,\n+\t\t\t\tflags))\n \t\treturn add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);\n \treturn 0;\n }\n@@ -415,6 +418,7 @@ static int check_updates(struct unpack_trees_options *o,\n \tint i, pc_workers, pc_threshold;\n \n \ttrace_performance_enter();\n+\tstate.super_prefix = o->super_prefix;\n \tstate.force = 1;\n \tstate.quiet = 1;\n \tstate.refresh_cache = 1;\n@@ -445,7 +449,7 @@ static int check_updates(struct unpack_trees_options *o,\n \n \t\tif (ce->ce_flags & CE_WT_REMOVE) {\n \t\t\tdisplay_progress(progress, ++cnt);\n-\t\t\tunlink_entry(ce);\n+\t\t\tunlink_entry(ce, o->super_prefix);\n \t\t}\n \t}\n \n@@ -2959,8 +2963,8 @@ int bind_merge(const struct cache_entry * const *src,\n \tif (a && old)\n \t\treturn o->quiet ? -1 :\n \t\t\terror(ERRORMSG(o, ERROR_BIND_OVERLAP),\n-\t\t\t      super_prefixed(a->name),\n-\t\t\t      super_prefixed(old->name));\n+\t\t\t      super_prefixed(a->name, o->super_prefix),\n+\t\t\t      super_prefixed(old->name, o->super_prefix));\n \tif (!a)\n \t\treturn keep_entry(old, o);\n \telse\n@@ -3021,7 +3025,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,\n \n \tif (worktree && untracked)\n \t\treturn error(_(\"worktree and untracked commit have duplicate entries: %s\"),\n-\t\t\t     super_prefixed(worktree->name));\n+\t\t\t     super_prefixed(worktree->name, o->super_prefix));\n \n \treturn merged_entry(worktree ? worktree : untracked, NULL, o);\n }\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex 6ab0d74c84d..3a7b3e5f007 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -75,6 +75,7 @@ struct unpack_trees_options {\n \t\t     skip_cache_tree_update;\n \tenum unpack_trees_reset_type reset;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint cache_bottom;\n \tstruct pathspec *pathspec;\n \tmerge_fn_t fn;\n-- \n2.39.0.rc2.1048.g0e5493b8d5b\n\n"},{"id":"469140","messageId":"kl6l7cyse6bi.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v4-1.9-f479003941b-20221215T083502Z-avarab@gmail.com","subject":"Re: [PATCH v4 1/9] submodule absorbgitdirs tests: add missing \"Migrating git...\" tests","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-12-15T20:54:25Z","receivedAt":"2022-12-15T20:54:37Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"No comment on the structure of the tests themselves; those look good to\nme.\n\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\n> index 2859695c6d2..d556342ea57 100755\n> --- a/t/t7412-submodule-absorbgitdirs.sh\n> +++ b/t/t7412-submodule-absorbgitdirs.sh\n> @@ -10,6 +10,7 @@ TEST_PASSES_SANITIZE_LEAK=true\n>  . ./test-lib.sh\n>  \n>  test_expect_success 'setup a real submodule' '\n> +\tcwd=\"$(pwd)\" &&\n>  \tgit init sub1 &&\n>  \ttest_commit -C sub1 first &&\n>  \tgit submodule add ./sub1 &&\n\n[...]\n \n> @@ -18,13 +19,21 @@ test_expect_success 'setup a real submodule' '\n>  '\n>  \n>  test_expect_success 'absorb the git dir' '\n> +\t>expect &&\n> +\t>actual &&\n>  \t>expect.1 &&\n>  \t>expect.2 &&\n>  \t>actual.1 &&\n>  \t>actual.2 &&\n>  \tgit status >expect.1 &&\n>  \tgit -C sub1 rev-parse HEAD >expect.2 &&\n> -\tgit submodule absorbgitdirs &&\n> +\tcat >expect <<-EOF &&\n> +\tMigrating git directory of '\\''sub1'\\'' from\n> +\t'\\''$cwd/sub1/.git'\\'' to\n> +\t'\\''$cwd/.git/modules/sub1'\\''\n> +\tEOF\n> +\tgit submodule absorbgitdirs 2>actual &&\n> +\ttest_cmp expect actual &&\n>  \tgit fsck &&\n>  \ttest -f sub1/.git &&\n>  \ttest -d .git/modules/sub1 &&\n\nI thought that we typically avoid setting environment variables in the\ntest cases themselves, so when we set environment variables to be read\nin later tests, we typically set them outside of the test case (e.g.\nt/t5526-fetch-submodules.sh).\n\n> @@ -97,6 +119,27 @@ test_expect_success 'absorb the git dir in a nested submodule' '\n>  \ttest_cmp expect.2 actual.2\n>  '\n>  \n> +test_expect_success 'absorb the git dir outside of primary worktree' '\n> +\ttest_when_finished \"rm -rf repo-bare.git\" &&\n> +\tgit clone --bare . repo-bare.git &&\n> +\ttest_when_finished \"rm -rf repo-wt\" &&\n> +\tgit -C repo-bare.git worktree add ../repo-wt &&\n> +\n> +\ttest_when_finished \"rm -f .gitconfig\" &&\n> +\ttest_config_global protocol.file.allow always &&\n> +\tgit -C repo-wt submodule update --init &&\n> +\tgit init repo-wt/sub2 &&\n> +\ttest_commit -C repo-wt/sub2 A &&\n> +\tgit -C repo-wt submodule add ./sub2 sub2 &&\n> +\tcat >expect <<-EOF &&\n> +\tMigrating git directory of '\\''sub2'\\'' from\n> +\t'\\''$cwd/repo-wt/sub2/.git'\\'' to\n> +\t'\\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\\''\n> +\tEOF\n> +\tDO_IT=1 git -C repo-wt submodule absorbgitdirs 2>actual &&\n\nDO_IT is a leftover from dev?\n\n(I'm also curious as to what it does :)).\n"},{"id":"469141","messageId":"kl6l359ge5sh.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"patch-v4-4.9-bde9038c4e3-20221215T083502Z-avarab@gmail.com","subject":"Re: [PATCH v4 4/9] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-12-15T21:05:50Z","receivedAt":"2022-12-15T21:05:57Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n>                            Let's instead assert the full output that\n> we *do* have, which we can do here as this is based on a change[4] to\n> make it predictable (until [4] it contained absolute paths).\n> ...\n> 4. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/\n\nThis sentence is stale now, since the test uses absolute paths.\n\n> @@ -904,10 +886,20 @@ test_expect_success \"stray submodule super-prefix warning\" '\n>  \n>  \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n>  \n> +\tcwd=\"$(cd super && pwd)\" &&\n> +\tcat >expect <<-EOF &&\n> +\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from\n> +\t'\\''$cwd/dir_1/dir_2/sub/.git'\\'' to\n> +\t'\\''$cwd/.git/modules/dir_1/dir_2/sub'\\''\n> +\tEOF\n\nNamely, this test uses absolute paths.\n\n>  \tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n> -\t\tgit -C super submodule absorbgitdirs &&\n> +\t\tgit -C super submodule absorbgitdirs >out 2>actual &&\n> +\ttest_cmp expect actual &&\n> +\ttest_must_be_empty out &&\n>  \n> -\t! have_t2_error_event super-sub.trace\n> +\t# Confirm that the trace2 log contains a record of the\n> +\t# daemon starting.\n> +\ttest_subcommand git fsmonitor--daemon start <super-sub.trace\n>  '\n>  \n>  # On a case-insensitive file system, confirm that the daemon\n> -- \n> 2.39.0.rc2.1048.g0e5493b8d5b\n"},{"id":"469143","messageId":"kl6lzgbocqki.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"Re: [PATCH v4 0/9] Get rid of \"git --super-prefix\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-12-15T21:19:57Z","receivedAt":"2022-12-15T21:20:31Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Thanks! I only spotted typos this time, so I think this is ready to\nmerge once we fix those.\n\n(FYI I will be OOO for the next 3 weeks or so, so don't wait on a\nresponse from me :))\n\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Changes since v4:\n> * I ejected the previous 10/10 to refactor \"git fetch\". I have more\n>   patches on top of this to do some post-refactoring (e.g. saving\n>   memory churn by getting rid of \"submodule_prefix\" from \"struct\n>   repository\"), but none of that's essential for now, so let's drop\n>   that patch.\n\nOkay, dropping the \"git fetch\" refactor probably makes sense in light of\nbigger refactoring.\n\nThis might be premature (since the patches aren't out yet), but I'm a\nbit apprehensive about removing \"submodule_prefix\" from \"struct\nrepository\". You've noted that it isn't needed right now (which I'll\ngrant), but it feels taking away API features that we'll need soon™ to,\ne.g. run library functions against arbitrary repositories, some of which\nmay need additional submodule information. Feel free to CC me on those\npatches, perhaps my fears will be unfounded :)\n"},{"id":"469144","messageId":"xmqqcz8ks4do.fsf@gitster.g","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"Re: [PATCH v4 0/9] Get rid of \"git --super-prefix\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-15T22:12:35Z","receivedAt":"2022-12-15T22:12:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":""},{"id":"469145","messageId":"xmqqwn6sqphs.fsf@gitster.g","threadId":"58773","inReplyTo":"kl6lzgbocqki.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v4 0/9] Get rid of \"git --super-prefix\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-12-15T22:19:27Z","receivedAt":"2022-12-15T22:19:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Glen Choo <chooglen@google.com> writes:\n\n> Thanks! I only spotted typos this time, so I think this is ready to\n> merge once we fix those.\n>\n> (FYI I will be OOO for the next 3 weeks or so, so don't wait on a\n> response from me :))\n>\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> Changes since v4:\n>> * I ejected the previous 10/10 to refactor \"git fetch\". I have more\n>>   patches on top of this to do some post-refactoring (e.g. saving\n>>   memory churn by getting rid of \"submodule_prefix\" from \"struct\n>>   repository\"), but none of that's essential for now, so let's drop\n>>   that patch.\n>\n> Okay, dropping the \"git fetch\" refactor probably makes sense in light of\n> bigger refactoring.\n>\n> This might be premature (since the patches aren't out yet), but I'm a\n> bit apprehensive about removing \"submodule_prefix\" from \"struct\n> repository\". You've noted that it isn't needed right now (which I'll\n> grant), but it feels taking away API features that we'll need soon™ to,\n> e.g. run library functions against arbitrary repositories, some of which\n> may need additional submodule information. Feel free to CC me on those\n> patches, perhaps my fears will be unfounded :)\n\nThanks, both.  Will await for the hopefully final update.\n\n"},{"id":"469361","messageId":"221220.86a63ixt24.gmgdl@evledraar.gmail.com","threadId":"58773","inReplyTo":"kl6l7cyse6bi.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v4 1/9] submodule absorbgitdirs tests: add missing \"Migrating git...\" tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T10:32:46Z","receivedAt":"2022-12-20T10:34:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Dec 15 2022, Glen Choo wrote:\n\n> No comment on the structure of the tests themselves; those look good to\n> me.\n>\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\n>> index 2859695c6d2..d556342ea57 100755\n>> --- a/t/t7412-submodule-absorbgitdirs.sh\n>> +++ b/t/t7412-submodule-absorbgitdirs.sh\n>> @@ -10,6 +10,7 @@ TEST_PASSES_SANITIZE_LEAK=true\n>>  . ./test-lib.sh\n>>  \n>>  test_expect_success 'setup a real submodule' '\n>> +\tcwd=\"$(pwd)\" &&\n>>  \tgit init sub1 &&\n>>  \ttest_commit -C sub1 first &&\n>>  \tgit submodule add ./sub1 &&\n>\n> [...]\n>  \n>> @@ -18,13 +19,21 @@ test_expect_success 'setup a real submodule' '\n>>  '\n>>  \n>>  test_expect_success 'absorb the git dir' '\n>> +\t>expect &&\n>> +\t>actual &&\n>>  \t>expect.1 &&\n>>  \t>expect.2 &&\n>>  \t>actual.1 &&\n>>  \t>actual.2 &&\n>>  \tgit status >expect.1 &&\n>>  \tgit -C sub1 rev-parse HEAD >expect.2 &&\n>> -\tgit submodule absorbgitdirs &&\n>> +\tcat >expect <<-EOF &&\n>> +\tMigrating git directory of '\\''sub1'\\'' from\n>> +\t'\\''$cwd/sub1/.git'\\'' to\n>> +\t'\\''$cwd/.git/modules/sub1'\\''\n>> +\tEOF\n>> +\tgit submodule absorbgitdirs 2>actual &&\n>> +\ttest_cmp expect actual &&\n>>  \tgit fsck &&\n>>  \ttest -f sub1/.git &&\n>>  \ttest -d .git/modules/sub1 &&\n>\n> I thought that we typically avoid setting environment variables in the\n> test cases themselves, so when we set environment variables to be read\n> in later tests, we typically set them outside of the test case (e.g.\n> t/t5526-fetch-submodules.sh).\n\nWe could do it either way, but no, I think the preferred style is to do\nsuch setup/assignment in a test_expect_success, we don't run our tests\nas \"set -e\", so we'd miss any errors (however unlikely in this case)\nfrom the commands outside test bodies.\n\nSee e.g. t0002-gitfile.sh for the same pattern, i.e. setting the \"$REAL\"\nvariable in the setup \"test_expect_success\", then using it later.\n\n>> @@ -97,6 +119,27 @@ test_expect_success 'absorb the git dir in a nested submodule' '\n>>  \ttest_cmp expect.2 actual.2\n>>  '\n>>  \n>> +test_expect_success 'absorb the git dir outside of primary worktree' '\n>> +\ttest_when_finished \"rm -rf repo-bare.git\" &&\n>> +\tgit clone --bare . repo-bare.git &&\n>> +\ttest_when_finished \"rm -rf repo-wt\" &&\n>> +\tgit -C repo-bare.git worktree add ../repo-wt &&\n>> +\n>> +\ttest_when_finished \"rm -f .gitconfig\" &&\n>> +\ttest_config_global protocol.file.allow always &&\n>> +\tgit -C repo-wt submodule update --init &&\n>> +\tgit init repo-wt/sub2 &&\n>> +\ttest_commit -C repo-wt/sub2 A &&\n>> +\tgit -C repo-wt submodule add ./sub2 sub2 &&\n>> +\tcat >expect <<-EOF &&\n>> +\tMigrating git directory of '\\''sub2'\\'' from\n>> +\t'\\''$cwd/repo-wt/sub2/.git'\\'' to\n>> +\t'\\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\\''\n>> +\tEOF\n>> +\tDO_IT=1 git -C repo-wt submodule absorbgitdirs 2>actual &&\n>\n> DO_IT is a leftover from dev?\n>\n> (I'm also curious as to what it does :)).\n\nOops, will fix! It was just something for ad-hoc getenv()-debugging that\nescaped the lab.\n"},{"id":"469363","messageId":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v4-0.9-00000000000-20221215T083502Z-avarab@gmail.com","subject":"[PATCH v5 0/9] Get rid of \"git --super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:47Z","receivedAt":"2022-12-20T12:43:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"For a general summary see the v3's CL at\nhttps://lore.kernel.org/git/cover-v3-0.9-00000000000-20221119T122853Z-avarab@gmail.com/\n\n[Trivial] changes since v4:\n\n * Remove stray ad-hoc testing env variable from test.\n * s/passs/pass/ typo fix\n * Adjust commit message for the tests not checking relative paths anymore.\n\nBranch & passing CI at:\nhttps://github.com/avar/git/tree/avar/nuke-global-super-prefix-use-local-5\n\nGlen Choo (1):\n  read-tree + fetch tests: test failing \"--super-prefix\" interaction\n\nÆvar Arnfjörð Bjarmason (8):\n  submodule absorbgitdirs tests: add missing \"Migrating git...\" tests\n  submodule.c & submodule--helper: pass along \"super_prefix\" param\n  submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n  submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n  submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n  submodule--helper: convert \"status\" to its own \"--super-prefix\"\n  submodule--helper: convert \"{update,clone}\" to their own\n    \"--super-prefix\"\n  read-tree: add \"--super-prefix\" option, eliminate global\n\n Documentation/git.txt              |  8 +--\n builtin.h                          |  4 --\n builtin/checkout.c                 |  2 +-\n builtin/read-tree.c                |  1 +\n builtin/rm.c                       |  2 +-\n builtin/submodule--helper.c        | 87 ++++++++++++++++--------------\n cache.h                            |  2 -\n entry.c                            | 12 ++---\n entry.h                            |  6 ++-\n environment.c                      | 13 -----\n git.c                              | 41 +++-----------\n parse-options.h                    |  4 ++\n submodule.c                        | 50 ++++++++---------\n submodule.h                        |  8 +--\n t/t1001-read-tree-m-2way.sh        |  2 +-\n t/t5616-partial-clone.sh           | 43 +++++++++++++++\n t/t7412-submodule-absorbgitdirs.sh | 64 +++++++++++++++++++---\n t/t7527-builtin-fsmonitor.sh       | 36 +++++--------\n unpack-trees.c                     | 24 +++++----\n unpack-trees.h                     |  1 +\n 20 files changed, 230 insertions(+), 180 deletions(-)\n\nRange-diff against v4:\n 1:  f479003941b !  1:  f062cb2f265 submodule absorbgitdirs tests: add missing \"Migrating git...\" tests\n    @@ t/t7412-submodule-absorbgitdirs.sh: test_expect_success 'absorb the git dir in a\n     +\t'\\''$cwd/repo-wt/sub2/.git'\\'' to\n     +\t'\\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\\''\n     +\tEOF\n    -+\tDO_IT=1 git -C repo-wt submodule absorbgitdirs 2>actual &&\n    ++\tgit -C repo-wt submodule absorbgitdirs 2>actual &&\n     +\ttest_cmp expect actual\n     +'\n     +\n 2:  6424307a432 =  2:  5fa05492b62 read-tree + fetch tests: test failing \"--super-prefix\" interaction\n 3:  b2e543bde03 !  3:  3fb2a1b16cd submodule.c & submodule--helper: pass along \"super_prefix\" param\n    @@ Commit message\n         directly or by indirection. The exceptions are:\n     \n         - builtin/rm.c: Doesn't declare SUPPORT_SUPER_PREFIX, so we'd have\n    -      died if this was provided, so it's safe to passs \"NULL\".\n    +      died if this was provided, so it's safe to pass \"NULL\".\n     \n         - deinit_submodule(): The \"deinit_submodule()\" function has never been\n           able to use the \"git -super-prefix\". It will call\n           \"absorb_git_dir_into_superproject()\", but it will only do so from the\n           top-level project.\n     \n    -      If \"absorbgitdirs\" recurses it will use the \"path\" passed to\n    +      If \"absorbgitdirs\" recurses will use the \"path\" passed to\n           \"absorb_git_dir_into_superproject()\" in \"deinit_submodule()\" as its\n           starting \"--super-prefix\". So we can safely remove the\n           get_super_prefix() call here, and pass NULL instead.\n 4:  bde9038c4e3 !  4:  0b30497f187 submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"\n    @@ Commit message\n         The \"fsmonitor--daemon\" test adjusted here was added in [3]. To assert\n         that it didn't run into the \"--super-prefix\" message it was asserting\n         the output it didn't have. Let's instead assert the full output that\n    -    we *do* have, which we can do here as this is based on a change[4] to\n    -    make it predictable (until [4] it contained absolute paths).\n    +    we *do* have, using the same pattern as a preceding change to\n    +    \"t/t7412-submodule-absorbgitdirs.sh\" used.\n     \n    -    We could also remove the test entirely (as [5] did), but even though\n    +    We could also remove the test entirely (as [4] did), but even though\n         the initial reason for having it is gone we're still getting some\n         marginal benefit from testing the \"fsmonitor\" and \"submodule\n         absorbgitdirs\" interaction, so let's keep it.\n    @@ Commit message\n     \n         As we'll be changing the rest of the \"git --super-prefix\" users to the\n         same pattern, leaving them all consistent makes sense. Why not pick \"\"\n    -    over NULL? Because that's how the \"prefix\" works[6], and having\n    +    over NULL? Because that's how the \"prefix\" works[5], and having\n         \"prefix\" and \"super_prefix\" work the same way will be less\n         confusing. That \"prefix\" picked NULL instead of \"\" is itself\n         arbitrary, but as it's easy to make this small bit of our overall API\n    @@ Commit message\n            2022-05-26)\n         3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n            2022-05-26)\n    -    4. https://lore.kernel.org/git/patch-1.1-34b54fdd9bb-20221109T020347Z-avarab@gmail.com/\n    -    5. https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com/\n    -    6. 9725c8dda20 (built-ins: trust the \"prefix\" from run_builtin(),\n    +    4. https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com/\n    +    5. 9725c8dda20 (built-ins: trust the \"prefix\" from run_builtin(),\n            2022-02-16)\n     \n         Signed-off-by: Glen Choo <chooglen@google.com>\n 5:  4da58e7ea50 =  5:  13f1f0db07a submodule--helper: convert \"foreach\" to its own \"--super-prefix\"\n 6:  8dff576df7d =  6:  ace2920ccff submodule--helper: convert \"sync\" to its own \"--super-prefix\"\n 7:  8800a433e29 =  7:  1ccd1a57b64 submodule--helper: convert \"status\" to its own \"--super-prefix\"\n 8:  54c1e29de1e =  8:  72e774ebb06 submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"\n 9:  4824f33224f =  9:  48ba8d4938c read-tree: add \"--super-prefix\" option, eliminate global\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469364","messageId":"patch-v5-2.9-5fa05492b62-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","subject":"[PATCH v5 2/9] read-tree + fetch tests: test failing \"--super-prefix\" interaction","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:49Z","receivedAt":"2022-12-20T12:43:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nEver since \"git fetch --refetch\" was introduced in 0f5e8851737 (Merge\nbranch 'rc/fetch-refetch', 2022-04-04) the test being added here would\nfail. This is because \"restore\" will \"read-tree .. --reset <hash>\",\nwhich will in turn invoke \"fetch\". The \"fetch\" will then die with:\n\n\tfatal: fetch doesn't support --super-prefix\n\nThis edge case and other \"--super-prefix\" bugs will be fixed in\nsubsequent commits, but let's first add a \"test_expect_failure\" test\nfor it. It passes until the very last command in the test.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5616-partial-clone.sh | 43 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 43 insertions(+)\n\ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 037941b95d2..2846ec6629c 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '\n \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n '\n \n+test_expect_failure 'lazy-fetch in submodule succeeds' '\n+\t# setup\n+\ttest_config_global protocol.file.allow always &&\n+\n+\ttest_when_finished \"rm -rf src-sub\" &&\n+\tgit init src-sub &&\n+\tgit -C src-sub config uploadpack.allowfilter 1 &&\n+\tgit -C src-sub config uploadpack.allowanysha1inwant 1 &&\n+\n+\t# This blob must be missing in the subsequent commit.\n+\techo foo >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule one\" &&\n+\tSUB_ONE=$(git -C src-sub rev-parse HEAD) &&\n+\n+\techo bar >src-sub/file &&\n+\tgit -C src-sub add file &&\n+\tgit -C src-sub commit -m \"submodule two\" &&\n+\tSUB_TWO=$(git -C src-sub rev-parse HEAD) &&\n+\n+\ttest_when_finished \"rm -rf src-super\" &&\n+\tgit init src-super &&\n+\tgit -C src-super config uploadpack.allowfilter 1 &&\n+\tgit -C src-super config uploadpack.allowanysha1inwant 1 &&\n+\tgit -C src-super submodule add ../src-sub src-sub &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_ONE &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject one\" &&\n+\n+\tgit -C src-super/src-sub checkout $SUB_TWO &&\n+\tgit -C src-super add src-sub &&\n+\tgit -C src-super commit -m \"superproject two\" &&\n+\n+\t# the fetch\n+\ttest_when_finished \"rm -rf client\" &&\n+\tgit clone --filter=blob:none --also-filter-submodules \\\n+\t\t--recurse-submodules \"file://$(pwd)/src-super\" client &&\n+\n+\t# Trigger lazy-fetch from the superproject\n+\tgit -C client restore --recurse-submodules --source=HEAD^ :/\n+'\n+\n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n start_httpd\n \n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469365","messageId":"patch-v5-1.9-f062cb2f265-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","subject":"[PATCH v5 1/9] submodule absorbgitdirs tests: add missing \"Migrating git...\" tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:48Z","receivedAt":"2022-12-20T12:43:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a blind spots in the tests surrounding \"submodule absorbgitdirs\"\nand test what output we emit, and how emitted the message and behavior\ninteracts with a \"git worktree\" where the repository isn't at the base\nof the working directory.\n\nThe \"$(pwd)\" instead of \"$PWD\" here is needed due to Windows, where\nthe latter will be a path like \"/d/a/git/[...]\", whereas we need\n\"D:/a/git/[...]\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7412-submodule-absorbgitdirs.sh | 64 ++++++++++++++++++++++++++----\n 1 file changed, 57 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\nindex 2859695c6d2..f7783218576 100755\n--- a/t/t7412-submodule-absorbgitdirs.sh\n+++ b/t/t7412-submodule-absorbgitdirs.sh\n@@ -10,6 +10,7 @@ TEST_PASSES_SANITIZE_LEAK=true\n . ./test-lib.sh\n \n test_expect_success 'setup a real submodule' '\n+\tcwd=\"$(pwd)\" &&\n \tgit init sub1 &&\n \ttest_commit -C sub1 first &&\n \tgit submodule add ./sub1 &&\n@@ -18,13 +19,21 @@ test_expect_success 'setup a real submodule' '\n '\n \n test_expect_success 'absorb the git dir' '\n+\t>expect &&\n+\t>actual &&\n \t>expect.1 &&\n \t>expect.2 &&\n \t>actual.1 &&\n \t>actual.2 &&\n \tgit status >expect.1 &&\n \tgit -C sub1 rev-parse HEAD >expect.2 &&\n-\tgit submodule absorbgitdirs &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''sub1'\\'' from\n+\t'\\''$cwd/sub1/.git'\\'' to\n+\t'\\''$cwd/.git/modules/sub1'\\''\n+\tEOF\n+\tgit submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual &&\n \tgit fsck &&\n \ttest -f sub1/.git &&\n \ttest -d .git/modules/sub1 &&\n@@ -37,7 +46,8 @@ test_expect_success 'absorb the git dir' '\n test_expect_success 'absorbing does not fail for deinitialized submodules' '\n \ttest_when_finished \"git submodule update --init\" &&\n \tgit submodule deinit --all &&\n-\tgit submodule absorbgitdirs &&\n+\tgit submodule absorbgitdirs 2>err &&\n+\ttest_must_be_empty err &&\n \ttest -d .git/modules/sub1 &&\n \ttest -d sub1 &&\n \t! test -e sub1/.git\n@@ -56,7 +66,13 @@ test_expect_success 'setup nested submodule' '\n test_expect_success 'absorb the git dir in a nested submodule' '\n \tgit status >expect.1 &&\n \tgit -C sub1/nested rev-parse HEAD >expect.2 &&\n-\tgit submodule absorbgitdirs &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''sub1/nested'\\'' from\n+\t'\\''$cwd/sub1/nested/.git'\\'' to\n+\t'\\''$cwd/.git/modules/sub1/modules/nested'\\''\n+\tEOF\n+\tgit submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual &&\n \ttest -f sub1/nested/.git &&\n \ttest -d .git/modules/sub1/modules/nested &&\n \tgit status >actual.1 &&\n@@ -87,7 +103,13 @@ test_expect_success 're-setup nested submodule' '\n test_expect_success 'absorb the git dir in a nested submodule' '\n \tgit status >expect.1 &&\n \tgit -C sub1/nested rev-parse HEAD >expect.2 &&\n-\tgit submodule absorbgitdirs &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''sub1'\\'' from\n+\t'\\''$cwd/sub1/.git'\\'' to\n+\t'\\''$cwd/.git/modules/sub1'\\''\n+\tEOF\n+\tgit submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual &&\n \ttest -f sub1/.git &&\n \ttest -f sub1/nested/.git &&\n \ttest -d .git/modules/sub1/modules/nested &&\n@@ -97,6 +119,27 @@ test_expect_success 'absorb the git dir in a nested submodule' '\n \ttest_cmp expect.2 actual.2\n '\n \n+test_expect_success 'absorb the git dir outside of primary worktree' '\n+\ttest_when_finished \"rm -rf repo-bare.git\" &&\n+\tgit clone --bare . repo-bare.git &&\n+\ttest_when_finished \"rm -rf repo-wt\" &&\n+\tgit -C repo-bare.git worktree add ../repo-wt &&\n+\n+\ttest_when_finished \"rm -f .gitconfig\" &&\n+\ttest_config_global protocol.file.allow always &&\n+\tgit -C repo-wt submodule update --init &&\n+\tgit init repo-wt/sub2 &&\n+\ttest_commit -C repo-wt/sub2 A &&\n+\tgit -C repo-wt submodule add ./sub2 sub2 &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''sub2'\\'' from\n+\t'\\''$cwd/repo-wt/sub2/.git'\\'' to\n+\t'\\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\\''\n+\tEOF\n+\tgit -C repo-wt submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n \tgit init sub2 &&\n \ttest_commit -C sub2 first &&\n@@ -107,7 +150,11 @@ test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n test_expect_success 'absorbing the git dir fails for incomplete submodules' '\n \tgit status >expect.1 &&\n \tgit -C sub2 rev-parse HEAD >expect.2 &&\n-\ttest_must_fail git submodule absorbgitdirs &&\n+\tcat >expect <<-\\EOF &&\n+\tfatal: could not lookup name for submodule '\\''sub2'\\''\n+\tEOF\n+\ttest_must_fail git submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual &&\n \tgit -C sub2 fsck &&\n \ttest -d sub2/.git &&\n \tgit status >actual &&\n@@ -127,8 +174,11 @@ test_expect_success 'setup a submodule with multiple worktrees' '\n '\n \n test_expect_success 'absorbing fails for a submodule with multiple worktrees' '\n-\ttest_must_fail git submodule absorbgitdirs sub3 2>error &&\n-\ttest_i18ngrep \"not supported\" error\n+\tcat >expect <<-\\EOF &&\n+\tfatal: could not lookup name for submodule '\\''sub2'\\''\n+\tEOF\n+\ttest_must_fail git submodule absorbgitdirs 2>actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469366","messageId":"patch-v5-3.9-3fb2a1b16cd-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","subject":"[PATCH v5 3/9] submodule.c & submodule--helper: pass along \"super_prefix\" param","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:50Z","receivedAt":"2022-12-20T12:43:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Start passing the \"super_prefix\" along as a parameter to\nget_submodule_displaypath() and absorb_git_dir_into_superproject(),\nrather than get the value directly as a global.\n\nThis is in preparation for subsequent commits, where we'll gradually\nphase out get_super_prefix() for an alternative way of getting the\n\"super_prefix\".\n\nMost of the users of this get a get_super_prefix() value, either\ndirectly or by indirection. The exceptions are:\n\n- builtin/rm.c: Doesn't declare SUPPORT_SUPER_PREFIX, so we'd have\n  died if this was provided, so it's safe to pass \"NULL\".\n\n- deinit_submodule(): The \"deinit_submodule()\" function has never been\n  able to use the \"git -super-prefix\". It will call\n  \"absorb_git_dir_into_superproject()\", but it will only do so from the\n  top-level project.\n\n  If \"absorbgitdirs\" recurses will use the \"path\" passed to\n  \"absorb_git_dir_into_superproject()\" in \"deinit_submodule()\" as its\n  starting \"--super-prefix\". So we can safely remove the\n  get_super_prefix() call here, and pass NULL instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/rm.c                |  2 +-\n builtin/submodule--helper.c | 35 ++++++++++++++++++++++-------------\n submodule.c                 | 15 +++++++++------\n submodule.h                 |  3 ++-\n 4 files changed, 34 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex d4989d4d863..4a4aec0d00e 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -86,7 +86,7 @@ static void submodules_absorb_gitdir_if_needed(void)\n \t\t\tcontinue;\n \n \t\tif (!submodule_uses_gitfile(name))\n-\t\t\tabsorb_git_dir_into_superproject(name);\n+\t\t\tabsorb_git_dir_into_superproject(name, NULL);\n \t}\n }\n \ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 05f2c9bc985..da844cad5ce 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n }\n \n /* the result should be freed by the caller. */\n-static char *get_submodule_displaypath(const char *path, const char *prefix)\n+static char *get_submodule_displaypath(const char *path, const char *prefix,\n+\t\t\t\t       const char *super_prefix)\n {\n-\tconst char *super_prefix = get_super_prefix();\n-\n \tif (prefix && super_prefix) {\n \t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n \t\t    prefix, super_prefix);\n@@ -294,7 +293,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath(path, info->prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -447,7 +447,8 @@ static void init_submodule(const char *path, const char *prefix,\n \tconst char *upd;\n \tchar *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -624,7 +625,8 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n \t\t      path);\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n@@ -948,7 +950,8 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t\tdst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix);\n+\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tif (!missing_src && !missing_dst) {\n \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n@@ -1239,7 +1242,8 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tsuper_config_url = xstrdup(\"\");\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix,\n+\t\t\t\t\t\tget_super_prefix());\n \n \tif (!(flags & OPT_QUIET))\n \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n@@ -1365,7 +1369,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \tif (!sub || !sub->name)\n \t\tgoto cleanup;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(path, prefix, NULL);\n \n \t/* remove the submodule work tree (unless the user already did it) */\n \tif (is_directory(path)) {\n@@ -1379,7 +1383,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \t\t\t\t\t  \".git file by using absorbgitdirs.\"),\n \t\t\t\t\tdisplaypath);\n \n-\t\t\tabsorb_git_dir_into_superproject(path);\n+\t\t\tabsorb_git_dir_into_superproject(path, NULL);\n \n \t\t}\n \n@@ -1958,7 +1962,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tenum submodule_update_type update_type;\n \tchar *key;\n \tconst struct update_data *ud = suc->update_data;\n-\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n+\tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix,\n+\t\t\t\t\t\t      get_super_prefix());\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n \tint need_free_url = 0;\n@@ -2608,7 +2613,8 @@ static int update_submodules(struct update_data *update_data)\n \t\t\tgoto fail;\n \n \t\tupdate_data->displaypath = get_submodule_displaypath(\n-\t\t\tupdate_data->sm_path, update_data->prefix);\n+\t\t\tupdate_data->sm_path, update_data->prefix,\n+\t\t\tget_super_prefix());\n \t\tcode = update_submodule(update_data);\n \t\tFREE_AND_NULL(update_data->displaypath);\n fail:\n@@ -2828,6 +2834,7 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n+\tconst char *super_prefix;\n \tstruct option embed_gitdir_options[] = {\n \t\tOPT_END()\n \t};\n@@ -2843,8 +2850,10 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tif (module_list_compute(argv, prefix, &pathspec, &list) < 0)\n \t\tgoto cleanup;\n \n+\tsuper_prefix = get_super_prefix();\n \tfor (i = 0; i < list.nr; i++)\n-\t\tabsorb_git_dir_into_superproject(list.entries[i]->name);\n+\t\tabsorb_git_dir_into_superproject(list.entries[i]->name,\n+\t\t\t\t\t\t super_prefix);\n \n \tret = 0;\n cleanup:\ndiff --git a/submodule.c b/submodule.c\nindex 8ac2fca855d..bf19598b8c2 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2145,7 +2145,8 @@ int submodule_move_head(const char *path,\n \tif (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {\n \t\tif (old_head) {\n \t\t\tif (!submodule_uses_gitfile(path))\n-\t\t\t\tabsorb_git_dir_into_superproject(path);\n+\t\t\t\tabsorb_git_dir_into_superproject(path,\n+\t\t\t\t\t\t\t\t get_super_prefix());\n \t\t} else {\n \t\t\tstruct strbuf gitdir = STRBUF_INIT;\n \t\t\tsubmodule_name_to_gitdir(&gitdir, the_repository,\n@@ -2315,7 +2316,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \tstrbuf_release(&new_gitdir);\n }\n \n-static void absorb_git_dir_into_superproject_recurse(const char *path)\n+static void absorb_git_dir_into_superproject_recurse(const char *path,\n+\t\t\t\t\t\t     const char *super_prefix)\n {\n \n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2323,8 +2325,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n \tcp.dir = path;\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n+\t\t     super_prefix : \"\", path);\n \tstrvec_pushl(&cp.args, \"submodule--helper\",\n \t\t     \"absorbgitdirs\", NULL);\n \tprepare_submodule_repo_env(&cp.env);\n@@ -2337,7 +2339,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)\n  * having its git directory within the working tree to the git dir nested\n  * in its superprojects git dir under modules/.\n  */\n-void absorb_git_dir_into_superproject(const char *path)\n+void absorb_git_dir_into_superproject(const char *path,\n+\t\t\t\t      const char *super_prefix)\n {\n \tint err_code;\n \tconst char *sub_git_dir;\n@@ -2386,7 +2389,7 @@ void absorb_git_dir_into_superproject(const char *path)\n \t}\n \tstrbuf_release(&gitdir);\n \n-\tabsorb_git_dir_into_superproject_recurse(path);\n+\tabsorb_git_dir_into_superproject_recurse(path, super_prefix);\n }\n \n int get_superproject_working_tree(struct strbuf *buf)\ndiff --git a/submodule.h b/submodule.h\nindex b52a4ff1e73..f90ee547d08 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -164,7 +164,8 @@ void submodule_unset_core_worktree(const struct submodule *sub);\n  */\n void prepare_submodule_repo_env(struct strvec *env);\n \n-void absorb_git_dir_into_superproject(const char *path);\n+void absorb_git_dir_into_superproject(const char *path,\n+\t\t\t\t      const char *super_prefix);\n \n /*\n  * Return the absolute path of the working tree of the superproject, which this\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469367","messageId":"patch-v5-5.9-13f1f0db07a-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","subject":"[PATCH v5 5/9] submodule--helper: convert \"foreach\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:52Z","receivedAt":"2022-12-20T12:43:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper foreach\" to use its own \"--super-prefix\", instead\nof relying on the global \"--super-prefix\" argument to \"git\"\nitself. See that earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b8b2bc776d1..2a6ced13f6d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -278,6 +278,7 @@ struct foreach_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint quiet;\n \tint recursive;\n };\n@@ -294,7 +295,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tchar *displaypath;\n \n \tdisplaypath = get_submodule_displaypath(path, info->prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\t\t\t\t\t\tinfo->super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -364,10 +365,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"foreach\", \"--recursive\",\n \t\t\t     NULL);\n+\t\tstrvec_pushl(&cpr.args, \"--super-prefix\", NULL);\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (info->quiet)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -391,6 +392,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n \tstruct option module_foreach_options[] = {\n+\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n \t\t\t N_(\"recurse into nested submodules\")),\n@@ -3390,8 +3392,8 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469368","messageId":"patch-v5-4.9-0b30497f187-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","subject":"[PATCH v5 4/9] submodule--helper: don't use global --super-prefix in \"absorbgitdirs\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:51Z","receivedAt":"2022-12-20T12:43:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" facility was introduced in [1] has always been a\ntransitory hack, which is why we've made it an error to supply it as\nan option to \"git\" to commands that don't know about it.\n\nThat's been a good goal, as it has a global effect we haven't wanted\ncalls to get_super_prefix() from built-ins we didn't expect.\n\nBut it has meant that when we've had chains of different built-ins\nusing it all of the processes in that \"chain\" have needed to support\nit, and worse processes that don't need it have needed to ask for\n\"SUPPORT_SUPER_PREFIX\" because their parent process needs it.\n\nThat's how \"fsmonitor--daemon\" ended up with it, per [2] it's called\nfrom (among other things) \"submodule--helper absorbgitdirs\", but as we\ndeclared \"submodule--helper\" as \"SUPPORT_SUPER_PREFIX\" we needed to\ndeclare \"fsmonitor--daemon\" as accepting it too, even though it\ndoesn't care about it.\n\nBut in the case of \"absorbgitdirs\" it only needed \"--super-prefix\" to\ninvoke itself recursively, and we'd never have another \"in-between\"\nprocess in the chain. So we didn't need the bigger hammer of \"git\n--super-prefix\", and the \"setenv(GIT_SUPER_PREFIX_ENVIRONMENT, ...)\"\nthat it entails.\n\nLet's instead accept a hidden \"--super-prefix\" option to\n\"submodule--helper absorbgitdirs\" itself.\n\nEventually (as with all other \"--super-prefix\" users) we'll want to\nclean this code up so that this all happens in-process. I.e. needing\nany variant of \"--super-prefix\" is itself a hack around our various\nglobal state, and implicit reliance on \"the_repository\". This stepping\nstone makes such an eventual change easier, as we'll need to deal with\nless global state at that point.\n\nThe \"fsmonitor--daemon\" test adjusted here was added in [3]. To assert\nthat it didn't run into the \"--super-prefix\" message it was asserting\nthe output it didn't have. Let's instead assert the full output that\nwe *do* have, using the same pattern as a preceding change to\n\"t/t7412-submodule-absorbgitdirs.sh\" used.\n\nWe could also remove the test entirely (as [4] did), but even though\nthe initial reason for having it is gone we're still getting some\nmarginal benefit from testing the \"fsmonitor\" and \"submodule\nabsorbgitdirs\" interaction, so let's keep it.\n\nThe change here to have either a NULL or non-\"\" string as a\n\"super_prefix\" instead of the previous arrangement of \"\" or non-\"\" is\nsomewhat arbitrary. We could also decide to never have to check for\nNULL.\n\nAs we'll be changing the rest of the \"git --super-prefix\" users to the\nsame pattern, leaving them all consistent makes sense. Why not pick \"\"\nover NULL? Because that's how the \"prefix\" works[5], and having\n\"prefix\" and \"super_prefix\" work the same way will be less\nconfusing. That \"prefix\" picked NULL instead of \"\" is itself\narbitrary, but as it's easy to make this small bit of our overall API\nconsistent, let's go with that.\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n   2022-05-26)\n3. 53fcfbc84f6 (fsmonitor--daemon: allow --super-prefix argument,\n   2022-05-26)\n4. https://lore.kernel.org/git/20221109004708.97668-5-chooglen@google.com/\n5. 9725c8dda20 (built-ins: trust the \"prefix\" from run_builtin(),\n   2022-02-16)\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c  |  7 +++----\n git.c                        |  2 +-\n parse-options.h              |  4 ++++\n submodule.c                  | 12 +++++++-----\n t/t7527-builtin-fsmonitor.sh | 36 ++++++++++++++----------------------\n 5 files changed, 29 insertions(+), 32 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex da844cad5ce..b8b2bc776d1 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2834,8 +2834,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tint i;\n \tstruct pathspec pathspec = { 0 };\n \tstruct module_list list = MODULE_LIST_INIT;\n-\tconst char *super_prefix;\n+\tconst char *super_prefix = NULL;\n \tstruct option embed_gitdir_options[] = {\n+\t\tOPT__SUPER_PREFIX(&super_prefix),\n \t\tOPT_END()\n \t};\n \tconst char *const git_submodule_helper_usage[] = {\n@@ -2850,7 +2851,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tif (module_list_compute(argv, prefix, &pathspec, &list) < 0)\n \t\tgoto cleanup;\n \n-\tsuper_prefix = get_super_prefix();\n \tfor (i = 0; i < list.nr; i++)\n \t\tabsorb_git_dir_into_superproject(list.entries[i]->name,\n \t\t\t\t\t\t super_prefix);\n@@ -3391,8 +3391,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n \t    strcmp(subcmd, \"foreach\") && strcmp(subcmd, \"status\") &&\n-\t    strcmp(subcmd, \"sync\") && strcmp(subcmd, \"absorbgitdirs\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"sync\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\ndiff --git a/git.c b/git.c\nindex 277a8cce840..e473b4b7d72 100644\n--- a/git.c\n+++ b/git.c\n@@ -539,7 +539,7 @@ static struct cmd_struct commands[] = {\n \t{ \"format-patch\", cmd_format_patch, RUN_SETUP },\n \t{ \"fsck\", cmd_fsck, RUN_SETUP },\n \t{ \"fsck-objects\", cmd_fsck, RUN_SETUP },\n-\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },\n+\t{ \"fsmonitor--daemon\", cmd_fsmonitor__daemon, RUN_SETUP },\n \t{ \"gc\", cmd_gc, RUN_SETUP },\n \t{ \"get-tar-commit-id\", cmd_get_tar_commit_id, NO_PARSEOPT },\n \t{ \"grep\", cmd_grep, RUN_SETUP_GENTLY },\ndiff --git a/parse-options.h b/parse-options.h\nindex b6ef86e0d15..50d852f2991 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);\n \t{ OPTION_CALLBACK, 0, \"abbrev\", (var), N_(\"n\"),\t\\\n \t  N_(\"use <n> digits to display object names\"),\t\\\n \t  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }\n+#define OPT__SUPER_PREFIX(var) \\\n+\tOPT_STRING_F(0, \"super-prefix\", (var), N_(\"prefix\"), \\\n+\t\tN_(\"prefixed path to initial superproject\"), PARSE_OPT_HIDDEN)\n+\n #define OPT__COLOR(var, h) \\\n \tOPT_COLOR_FLAG(0, \"color\", (var), (h))\n #define OPT_COLUMN(s, l, v, h) \\\ndiff --git a/submodule.c b/submodule.c\nindex bf19598b8c2..46a03473195 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2275,7 +2275,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)\n  * Embeds a single submodules git directory into the superprojects git dir,\n  * non recursively.\n  */\n-static void relocate_single_git_dir_into_superproject(const char *path)\n+static void relocate_single_git_dir_into_superproject(const char *path,\n+\t\t\t\t\t\t      const char *super_prefix)\n {\n \tchar *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;\n \tstruct strbuf new_gitdir = STRBUF_INIT;\n@@ -2305,7 +2306,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \treal_new_git_dir = real_pathdup(new_gitdir.buf, 1);\n \n \tfprintf(stderr, _(\"Migrating git directory of '%s%s' from\\n'%s' to\\n'%s'\\n\"),\n-\t\tget_super_prefix_or_empty(), path,\n+\t\tsuper_prefix ? super_prefix : \"\", path,\n \t\treal_old_git_dir, real_new_git_dir);\n \n \trelocate_gitdir(path, real_old_git_dir, real_new_git_dir);\n@@ -2325,10 +2326,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path,\n \tcp.dir = path;\n \tcp.git_cmd = 1;\n \tcp.no_stdin = 1;\n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n-\t\t     super_prefix : \"\", path);\n \tstrvec_pushl(&cp.args, \"submodule--helper\",\n \t\t     \"absorbgitdirs\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\", super_prefix ?\n+\t\t     super_prefix : \"\", path);\n+\n \tprepare_submodule_repo_env(&cp.env);\n \tif (run_command(&cp))\n \t\tdie(_(\"could not recurse into submodule '%s'\"), path);\n@@ -2382,7 +2384,7 @@ void absorb_git_dir_into_superproject(const char *path,\n \t\tchar *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);\n \n \t\tif (!starts_with(real_sub_git_dir, real_common_git_dir))\n-\t\t\trelocate_single_git_dir_into_superproject(path);\n+\t\t\trelocate_single_git_dir_into_superproject(path, super_prefix);\n \n \t\tfree(real_sub_git_dir);\n \t\tfree(real_common_git_dir);\ndiff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh\nindex 4abc74db2bb..76d0220daa0 100755\n--- a/t/t7527-builtin-fsmonitor.sh\n+++ b/t/t7527-builtin-fsmonitor.sh\n@@ -866,27 +866,9 @@ test_expect_success 'submodule always visited' '\n # the submodule, and someone does a `git submodule absorbgitdirs`\n # in the super, Git will recursively invoke `git submodule--helper`\n # to do the work and this may try to read the index.  This will\n-# try to start the daemon in the submodule *and* pass (either\n-# directly or via inheritance) the `--super-prefix` arg to the\n-# `git fsmonitor--daemon start` command inside the submodule.\n-# This causes a warning because fsmonitor--daemon does take that\n-# global arg (see the table in git.c)\n-#\n-# This causes a warning when trying to start the daemon that is\n-# somewhat confusing.  It does not seem to hurt anything because\n-# the fsmonitor code maps the query failure into a trivial response\n-# and does the work anyway.\n-#\n-# It would be nice to silence the warning, however.\n-\n-have_t2_error_event () {\n-\tlog=$1\n-\tmsg=\"fsmonitor--daemon doesnQt support --super-prefix\" &&\n-\n-\ttr '\\047' Q <$1 | grep -e \"$msg\"\n-}\n+# try to start the daemon in the submodule.\n \n-test_expect_success \"stray submodule super-prefix warning\" '\n+test_expect_success \"submodule absorbgitdirs implicitly starts daemon\" '\n \ttest_when_finished \"rm -rf super; \\\n \t\t\t    rm -rf sub;   \\\n \t\t\t    rm super-sub.trace\" &&\n@@ -904,10 +886,20 @@ test_expect_success \"stray submodule super-prefix warning\" '\n \n \ttest_path_is_dir super/dir_1/dir_2/sub/.git &&\n \n+\tcwd=\"$(cd super && pwd)\" &&\n+\tcat >expect <<-EOF &&\n+\tMigrating git directory of '\\''dir_1/dir_2/sub'\\'' from\n+\t'\\''$cwd/dir_1/dir_2/sub/.git'\\'' to\n+\t'\\''$cwd/.git/modules/dir_1/dir_2/sub'\\''\n+\tEOF\n \tGIT_TRACE2_EVENT=\"$PWD/super-sub.trace\" \\\n-\t\tgit -C super submodule absorbgitdirs &&\n+\t\tgit -C super submodule absorbgitdirs >out 2>actual &&\n+\ttest_cmp expect actual &&\n+\ttest_must_be_empty out &&\n \n-\t! have_t2_error_event super-sub.trace\n+\t# Confirm that the trace2 log contains a record of the\n+\t# daemon starting.\n+\ttest_subcommand git fsmonitor--daemon start <super-sub.trace\n '\n \n # On a case-insensitive file system, confirm that the daemon\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469369","messageId":"patch-v5-6.9-ace2920ccff-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","subject":"[PATCH v5 6/9] submodule--helper: convert \"sync\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:53Z","receivedAt":"2022-12-20T12:43:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper sync\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 20 +++++++++++---------\n 1 file changed, 11 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 2a6ced13f6d..7262ce72edf 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1208,12 +1208,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \n struct sync_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define SYNC_CB_INIT { 0 }\n \n static void sync_submodule(const char *path, const char *prefix,\n-\t\t\t   unsigned int flags)\n+\t\t\t   const char *super_prefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n@@ -1244,8 +1245,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tsuper_config_url = xstrdup(\"\");\n \t}\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n \n \tif (!(flags & OPT_QUIET))\n \t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n@@ -1282,10 +1282,11 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"sync\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n+\n \n \t\tif (flags & OPT_QUIET)\n \t\t\tstrvec_push(&cpr.args, \"--quiet\");\n@@ -1308,7 +1309,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct sync_cb *info = cb_data;\n \n-\tsync_submodule(list_item->name, info->prefix, info->flags);\n+\tsync_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_sync(int argc, const char **argv, const char *prefix)\n@@ -1319,6 +1321,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \tint quiet = 0;\n \tint recursive = 0;\n \tstruct option module_sync_options[] = {\n+\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n \t\tOPT_BOOL(0, \"recursive\", &recursive,\n \t\t\tN_(\"recurse into nested submodules\")),\n@@ -2887,7 +2890,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)\n \tconfig_name = xstrfmt(\"submodule.%s.url\", path);\n \n \tconfig_set_in_gitmodules_file_gently(config_name, newurl);\n-\tsync_submodule(path, prefix, quiet ? OPT_QUIET : 0);\n+\tsync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);\n \n \tfree(config_name);\n \n@@ -3392,8 +3395,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && strcmp(subcmd, \"sync\") &&\n-\t    get_super_prefix())\n+\t    strcmp(subcmd, \"status\") && get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469370","messageId":"patch-v5-7.9-1ccd1a57b64-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","subject":"[PATCH v5 7/9] submodule--helper: convert \"status\" to its own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:54Z","receivedAt":"2022-12-20T12:43:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\" itself. See\nthat earlier commit for the rationale and background.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7262ce72edf..448896f1b1d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -573,6 +573,7 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \n struct status_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define STATUS_CB_INIT { 0 }\n@@ -611,7 +612,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,\n \n static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\t\t     unsigned int ce_flags, const char *prefix,\n-\t\t\t     unsigned int flags)\n+\t\t\t     const char *super_prefix, unsigned int flags)\n {\n \tchar *displaypath;\n \tstruct strvec diff_files_args = STRVEC_INIT;\n@@ -627,8 +628,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n \t\t      path);\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n \n \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n \t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n@@ -686,10 +686,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \t\tcpr.dir = path;\n \t\tprepare_submodule_repo_env(&cpr.env);\n \n-\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n-\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \t\tstrvec_pushl(&cpr.args, \"submodule--helper\", \"status\",\n \t\t\t     \"--recursive\", NULL);\n+\t\tstrvec_push(&cpr.args, \"--super-prefix\");\n+\t\tstrvec_pushf(&cpr.args, \"%s/\", displaypath);\n \n \t\tif (flags & OPT_CACHED)\n \t\t\tstrvec_push(&cpr.args, \"--cached\");\n@@ -713,7 +713,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,\n \tstruct status_cb *info = cb_data;\n \n \tstatus_submodule(list_item->name, &list_item->oid, list_item->ce_flags,\n-\t\t\t info->prefix, info->flags);\n+\t\t\t info->prefix, info->super_prefix, info->flags);\n }\n \n static int module_status(int argc, const char **argv, const char *prefix)\n@@ -723,6 +723,7 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n \tstruct option module_status_options[] = {\n+\t\tOPT__SUPER_PREFIX(&info.super_prefix),\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n@@ -3395,7 +3396,7 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \tsubcmd = argv[0];\n \n \tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    strcmp(subcmd, \"status\") && get_super_prefix())\n+\t    get_super_prefix())\n \t\t/*\n \t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n \t\t * string identical to git.c's.\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469371","messageId":"patch-v5-8.9-72e774ebb06-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","subject":"[PATCH v5 8/9] submodule--helper: convert \"{update,clone}\" to their own \"--super-prefix\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:55Z","receivedAt":"2022-12-20T12:43:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As with a preceding commit to convert \"absorbgitdirs\", we can convert\n\"submodule--helper status\" to use its own \"--super-prefix\", instead of\nrelying on the global \"--super-prefix\" argument to \"git\".\n\nWe need to convert both of these away from the global \"--super-prefix\"\nat the same time, because \"update\" will call \"clone\", but \"clone\"\nitself didn't make use of the global \"--super-prefix\" for displaying\npaths. It was only on the list of sub-commands that accepted it\nbecause \"update\"'s use of it would set it in its environment.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 32 +++++++++++++-------------------\n git.c                       |  2 +-\n 2 files changed, 14 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 448896f1b1d..a0aa4635a0c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -437,11 +437,13 @@ static int starts_with_dot_dot_slash(const char *const path)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int flags;\n };\n #define INIT_CB_INIT { 0 }\n \n static void init_submodule(const char *path, const char *prefix,\n+\t\t\t   const char *super_prefix,\n \t\t\t   unsigned int flags)\n {\n \tconst struct submodule *sub;\n@@ -449,8 +451,7 @@ static void init_submodule(const char *path, const char *prefix,\n \tconst char *upd;\n \tchar *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\tdisplaypath = get_submodule_displaypath(path, prefix, super_prefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -526,7 +527,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data\n {\n \tstruct init_cb *info = cb_data;\n \n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->super_prefix,\n+\t\t       info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n@@ -792,6 +794,7 @@ struct summary_cb {\n \tint argc;\n \tconst char **argv;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tunsigned int cached: 1;\n \tunsigned int for_status: 1;\n \tunsigned int files: 1;\n@@ -954,7 +957,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t}\n \n \tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix,\n-\t\t\t\t\t\tget_super_prefix());\n+\t\t\t\t\t\tinfo->super_prefix);\n \n \tif (!missing_src && !missing_dst) {\n \t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n@@ -1893,6 +1896,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)\n \n struct update_data {\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tchar *displaypath;\n \tenum submodule_update_type update_default;\n \tstruct object_id suboid;\n@@ -1969,7 +1973,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tchar *key;\n \tconst struct update_data *ud = suc->update_data;\n \tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix,\n-\t\t\t\t\t\t      get_super_prefix());\n+\t\t\t\t\t\t      ud->super_prefix);\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n \tint need_free_url = 0;\n@@ -2449,11 +2453,11 @@ static void update_data_to_args(const struct update_data *update_data,\n {\n \tenum submodule_update_type update_type = update_data->update_default;\n \n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tif (update_data->displaypath) {\n \t\tstrvec_push(args, \"--super-prefix\");\n \t\tstrvec_pushf(args, \"%s/\", update_data->displaypath);\n \t}\n-\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n \tif (update_data->quiet)\n \t\tstrvec_push(args, \"--quiet\");\n@@ -2620,7 +2624,7 @@ static int update_submodules(struct update_data *update_data)\n \n \t\tupdate_data->displaypath = get_submodule_displaypath(\n \t\t\tupdate_data->sm_path, update_data->prefix,\n-\t\t\tget_super_prefix());\n+\t\t\tupdate_data->super_prefix);\n \t\tcode = update_submodule(update_data);\n \t\tFREE_AND_NULL(update_data->displaypath);\n fail:\n@@ -2646,6 +2650,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\tLIST_OBJECTS_FILTER_INIT;\n \tint ret;\n \tstruct option module_update_options[] = {\n+\t\tOPT__SUPER_PREFIX(&opt.super_prefix),\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n \t\tOPT_BOOL(0, \"init\", &opt.init,\n \t\t\t N_(\"initialize uninitialized submodules before update\")),\n@@ -2742,6 +2747,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\t\tmodule_list_active(&list);\n \n \t\tinfo.prefix = opt.prefix;\n+\t\tinfo.super_prefix = opt.super_prefix;\n \t\tif (opt.quiet)\n \t\t\tinfo.flags |= OPT_QUIET;\n \n@@ -3368,8 +3374,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \n int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n {\n-\tconst char *cmd = argv[0];\n-\tconst char *subcmd;\n \tparse_opt_subcommand_fn *fn = NULL;\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule--helper <command>\"),\n@@ -3393,16 +3397,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\tsubcmd = argv[0];\n-\n-\tif (strcmp(subcmd, \"clone\") && strcmp(subcmd, \"update\") &&\n-\t    get_super_prefix())\n-\t\t/*\n-\t\t * xstrfmt() rather than \"%s %s\" to keep the translated\n-\t\t * string identical to git.c's.\n-\t\t */\n-\t\tdie(_(\"%s doesn't support --super-prefix\"),\n-\t\t    xstrfmt(\"'%s %s'\", cmd, subcmd));\n \n \treturn fn(argc, argv, prefix);\n }\ndiff --git a/git.c b/git.c\nindex e473b4b7d72..2c31ba27040 100644\n--- a/git.c\n+++ b/git.c\n@@ -610,7 +610,7 @@ static struct cmd_struct commands[] = {\n \t{ \"stash\", cmd_stash, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"stripspace\", cmd_stripspace },\n-\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },\n+\t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP },\n \t{ \"switch\", cmd_switch, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"symbolic-ref\", cmd_symbolic_ref, RUN_SETUP },\n \t{ \"tag\", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },\n-- \n2.39.0.1071.g97ce8966538\n\n"},{"id":"469372","messageId":"patch-v5-9.9-48ba8d4938c-20221220T104519Z-avarab@gmail.com","threadId":"58773","inReplyTo":"cover-v5-0.9-00000000000-20221220T104519Z-avarab@gmail.com","subject":"[PATCH v5 9/9] read-tree: add \"--super-prefix\" option, eliminate global","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-12-20T12:39:56Z","receivedAt":"2022-12-20T12:44:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"--super-prefix\" option to \"git\" was initially added in [1] for\nuse with \"ls-files\"[2], and shortly thereafter \"submodule--helper\"[3]\nand \"grep\"[4]. It wasn't until [5] that \"read-tree\" made use of it.\n\nAt the time [5] made sense, but since then we've made \"ls-files\"\nrecurse in-process in [6], \"grep\" in [7], and finally\n\"submodule--helper\" in the preceding commits.\n\nLet's also remove it from \"read-tree\", which allows us to remove the\noption to \"git\" itself.\n\nWe can do this because the only remaining user of it is the submodule\nAPI, which will now invoke \"read-tree\" with its new \"--super-prefix\"\noption. It will only do so when the \"submodule_move_head()\" function\nis called.\n\nThat \"submodule_move_head()\" function was then only invoked by\n\"read-tree\" itself, but now rather than setting an environment\nvariable to pass \"--super-prefix\" between cmd_read_tree() we:\n\n- Set a new \"super_prefix\" in \"struct unpack_trees_options\". The\n  \"super_prefixed()\" function in \"unpack-trees.c\" added in [5] will now\n  use this, rather than get_super_prefix() looking up the environment\n  variable we set earlier in the same process.\n\n- Add the same field to the \"struct checkout\", which is only needed to\n  ferry the \"super_prefix\" in the \"struct unpack_trees_options\" all the\n  way down to the \"entry.c\" callers of \"submodule_move_head()\".\n\n  Those calls which used the super prefix all originated in\n  \"cmd_read_tree()\". The only other caller is the \"unlink_entry()\"\n  caller in \"builtin/checkout.c\", which now passes a \"NULL\".\n\n1. 74866d75793 (git: make super-prefix option, 2016-10-07)\n2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)\n3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)\n4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)\n5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)\n6. 188dce131fa (ls-files: use repository object, 2017-06-22)\n7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git.txt       |  8 +-------\n builtin.h                   |  4 ----\n builtin/checkout.c          |  2 +-\n builtin/read-tree.c         |  1 +\n cache.h                     |  2 --\n entry.c                     | 12 ++++++------\n entry.h                     |  6 +++++-\n environment.c               | 13 -------------\n git.c                       | 37 +++++--------------------------------\n submodule.c                 | 29 ++++++++++-------------------\n submodule.h                 |  5 ++---\n t/t1001-read-tree-m-2way.sh |  2 +-\n t/t5616-partial-clone.sh    |  2 +-\n unpack-trees.c              | 24 ++++++++++++++----------\n unpack-trees.h              |  1 +\n 15 files changed, 48 insertions(+), 100 deletions(-)\n\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 1d33e083ab8..f9a7a4554cd 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -13,8 +13,7 @@ SYNOPSIS\n     [--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>]\n+    [--config-env=<name>=<envvar>] <command> [<args>]\n \n DESCRIPTION\n -----------\n@@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use\n \tdetails.  Equivalent to setting the `GIT_NAMESPACE` environment\n \tvariable.\n \n---super-prefix=<path>::\n-\tCurrently for internal use only.  Set a prefix which gives a path from\n-\tabove a repository down to its root.  One use is to give submodules\n-\tcontext about the superproject that invoked it.\n-\n --bare::\n \tTreat the repository as a bare repository.  If GIT_DIR\n \tenvironment is not set, it is set to the current working\ndiff --git a/builtin.h b/builtin.h\nindex aa955466b4e..46cc7897898 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -51,10 +51,6 @@\n  *\ton bare repositories.\n  *\tThis only makes sense when `RUN_SETUP` is also set.\n  *\n- * `SUPPORT_SUPER_PREFIX`:\n- *\n- *\tThe built-in supports `--super-prefix`.\n- *\n  * `DELAY_PAGER_CONFIG`:\n  *\n  *\tIf RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex a0142c815fd..cd04f0bf572 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -232,7 +232,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n \t\tpos++;\n \t}\n \tif (!overlay_mode) {\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, NULL);\n \t\treturn 0;\n \t}\n \tif (stage == 2)\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex f702f9d47bb..3ce75417833 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)\n \tint prefix_set = 0;\n \tstruct lock_file lock_file = LOCK_INIT;\n \tconst struct option read_tree_options[] = {\n+\t\tOPT__SUPER_PREFIX(&opts.super_prefix),\n \t\tOPT_CALLBACK_F(0, \"index-output\", NULL, N_(\"file\"),\n \t\t  N_(\"write resulting index to <file>\"),\n \t\t  PARSE_OPT_NONEG, index_output_cb),\ndiff --git a/cache.h b/cache.h\nindex 07d40b0964b..7f7e2b5a38f 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -480,7 +480,6 @@ static inline enum object_type object_type(unsigned int mode)\n #define GIT_NAMESPACE_ENVIRONMENT \"GIT_NAMESPACE\"\n #define GIT_WORK_TREE_ENVIRONMENT \"GIT_WORK_TREE\"\n #define GIT_PREFIX_ENVIRONMENT \"GIT_PREFIX\"\n-#define GIT_SUPER_PREFIX_ENVIRONMENT \"GIT_INTERNAL_SUPER_PREFIX\"\n #define DEFAULT_GIT_DIR_ENVIRONMENT \".git\"\n #define DB_ENVIRONMENT \"GIT_OBJECT_DIRECTORY\"\n #define INDEX_ENVIRONMENT \"GIT_INDEX_FILE\"\n@@ -566,7 +565,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);\n int get_common_dir(struct strbuf *sb, const char *gitdir);\n const char *get_git_namespace(void);\n const char *strip_namespace(const char *namespaced_ref);\n-const char *get_super_prefix(void);\n const char *get_git_work_tree(void);\n \n /*\ndiff --git a/entry.c b/entry.c\nindex 616e4f073c1..971ab268714 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca\n \t\t\treturn error(\"cannot create submodule directory %s\", path);\n \t\tsub = submodule_from_ce(ce);\n \t\tif (sub)\n-\t\t\treturn submodule_move_head(ce->name,\n+\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\tNULL, oid_to_hex(&ce->oid),\n \t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\tbreak;\n@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t * no pathname to return.\n \t\t\t */\n \t\t\tBUG(\"Can't remove entry to a path\");\n-\t\tunlink_entry(ce);\n+\t\tunlink_entry(ce, state->super_prefix);\n \t\treturn 0;\n \t}\n \n@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \t\t\t\tif (!(st.st_mode & S_IFDIR))\n \t\t\t\t\tunlink_or_warn(ce->name);\n \n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\tNULL, oid_to_hex(&ce->oid), 0);\n \t\t\t} else\n-\t\t\t\treturn submodule_move_head(ce->name,\n+\t\t\t\treturn submodule_move_head(ce->name, state->super_prefix,\n \t\t\t\t\t\"HEAD\", oid_to_hex(&ce->oid),\n \t\t\t\t\tstate->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);\n \t\t}\n@@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,\n \treturn write_entry(ce, path.buf, ca, state, 0, nr_checkouts);\n }\n \n-void unlink_entry(const struct cache_entry *ce)\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)\n {\n \tconst struct submodule *sub = submodule_from_ce(ce);\n \tif (sub) {\n \t\t/* state.force is set at the caller. */\n-\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n+\t\tsubmodule_move_head(ce->name, super_prefix, \"HEAD\", NULL,\n \t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n \t}\n \tif (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)\ndiff --git a/entry.h b/entry.h\nindex 9be4659881e..2d4fbb88c8f 100644\n--- a/entry.h\n+++ b/entry.h\n@@ -8,6 +8,7 @@ struct checkout {\n \tstruct index_state *istate;\n \tconst char *base_dir;\n \tint base_dir_len;\n+\tconst char *super_prefix;\n \tstruct delayed_checkout *delayed_checkout;\n \tstruct checkout_metadata meta;\n \tunsigned force:1,\n@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);\n /*\n  * Unlink the last component and schedule the leading directories for\n  * removal, such that empty directories get removed.\n+ *\n+ * The \"super_prefix\" is either NULL, or the \"--super-prefix\" passed\n+ * down from \"read-tree\" et al.\n  */\n-void unlink_entry(const struct cache_entry *ce);\n+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);\n \n void *read_blob_entry(const struct cache_entry *ce, size_t *size);\n int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);\ndiff --git a/environment.c b/environment.c\nindex 18d042b467d..1ee3686fd8a 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -102,8 +102,6 @@ char *git_work_tree_cfg;\n \n static char *git_namespace;\n \n-static char *super_prefix;\n-\n /*\n  * Repository-local GIT_* environment variables; see cache.h for details.\n  */\n@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {\n \tNO_REPLACE_OBJECTS_ENVIRONMENT,\n \tGIT_REPLACE_REF_BASE_ENVIRONMENT,\n \tGIT_PREFIX_ENVIRONMENT,\n-\tGIT_SUPER_PREFIX_ENVIRONMENT,\n \tGIT_SHALLOW_FILE_ENVIRONMENT,\n \tGIT_COMMON_DIR_ENVIRONMENT,\n \tNULL\n@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)\n \treturn NULL;\n }\n \n-const char *get_super_prefix(void)\n-{\n-\tstatic int initialized;\n-\tif (!initialized) {\n-\t\tsuper_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));\n-\t\tinitialized = 1;\n-\t}\n-\treturn super_prefix;\n-}\n-\n static int git_work_tree_initialized;\n \n /*\ndiff --git a/git.c b/git.c\nindex 2c31ba27040..32a5be68a17 100644\n--- a/git.c\n+++ b/git.c\n@@ -14,9 +14,8 @@\n  * RUN_SETUP for reading from the configuration file.\n  */\n #define NEED_WORK_TREE\t\t(1<<3)\n-#define SUPPORT_SUPER_PREFIX\t(1<<4)\n-#define DELAY_PAGER_CONFIG\t(1<<5)\n-#define NO_PARSEOPT\t\t(1<<6) /* parse-options is not used */\n+#define DELAY_PAGER_CONFIG\t(1<<4)\n+#define NO_PARSEOPT\t\t(1<<5) /* parse-options is not used */\n \n struct cmd_struct {\n \tconst char *cmd;\n@@ -29,8 +28,7 @@ const char git_usage_string[] =\n \t   \"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\\n\"\n \t   \"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\\n\"\n \t   \"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\\n\"\n-\t   \"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\\n\"\n-\t   \"           <command> [<args>]\");\n+\t   \"           [--config-env=<name>=<envvar>] <command> [<args>]\");\n \n const char git_more_info_string[] =\n \tN_(\"'git help -a' and 'git help -g' list available subcommands and some\\n\"\n@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);\n \t\t\tif (envchanged)\n \t\t\t\t*envchanged = 1;\n-\t\t} else if (!strcmp(cmd, \"--super-prefix\")) {\n-\t\t\tif (*argc < 2) {\n-\t\t\t\tfprintf(stderr, _(\"no prefix given for --super-prefix\\n\" ));\n-\t\t\t\tusage(git_usage_string);\n-\t\t\t}\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n-\t\t\t(*argv)++;\n-\t\t\t(*argc)--;\n-\t\t} else if (skip_prefix(cmd, \"--super-prefix=\", &cmd)) {\n-\t\t\tsetenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);\n-\t\t\tif (envchanged)\n-\t\t\t\t*envchanged = 1;\n \t\t} else if (!strcmp(cmd, \"--bare\")) {\n \t\t\tchar *cwd = xgetcwd();\n \t\t\tis_bare_repository_cfg = 1;\n@@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\ttrace_repo_setup(prefix);\n \tcommit_pager_choice();\n \n-\tif (!help && get_super_prefix()) {\n-\t\tif (!(p->option & SUPPORT_SUPER_PREFIX))\n-\t\t\tdie(_(\"%s doesn't support --super-prefix\"), p->cmd);\n-\t}\n-\n \tif (!help && p->option & NEED_WORK_TREE)\n \t\tsetup_work_tree();\n \n@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {\n \t{ \"check-ref-format\", cmd_check_ref_format, NO_PARSEOPT  },\n \t{ \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout--worker\", cmd_checkout__worker,\n-\t\tRUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },\n+\t\tRUN_SETUP | NEED_WORK_TREE },\n \t{ \"checkout-index\", cmd_checkout_index,\n \t\tRUN_SETUP | NEED_WORK_TREE},\n \t{ \"cherry\", cmd_cherry, RUN_SETUP },\n@@ -583,7 +562,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n-\t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n \t{ \"rebase\", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n@@ -727,9 +706,6 @@ static void execv_dashed_external(const char **argv)\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tint status;\n \n-\tif (get_super_prefix())\n-\t\tdie(_(\"%s doesn't support --super-prefix\"), argv[0]);\n-\n \tif (use_pager == -1 && !is_builtin(argv[0]))\n \t\tuse_pager = check_pager_config(argv[0]);\n \tcommit_pager_choice();\n@@ -799,9 +775,6 @@ static int run_argv(int *argcp, const char ***argv)\n \t\t\t */\n \t\t\ttrace2_cmd_name(\"_run_git_alias_\");\n \n-\t\t\tif (get_super_prefix())\n-\t\t\t\tdie(\"%s doesn't support --super-prefix\", **argv);\n-\n \t\t\tcommit_pager_choice();\n \n \t\t\tstrvec_push(&cmd.args, \"git\");\ndiff --git a/submodule.c b/submodule.c\nindex 46a03473195..d730b64b072 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -2054,14 +2054,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)\n \tstrbuf_release(&config_path);\n }\n \n-static const char *get_super_prefix_or_empty(void)\n-{\n-\tconst char *s = get_super_prefix();\n-\tif (!s)\n-\t\ts = \"\";\n-\treturn s;\n-}\n-\n static int submodule_has_dirty_index(const struct submodule *sub)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2080,7 +2072,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)\n \treturn finish_command(&cp);\n }\n \n-static void submodule_reset_index(const char *path)\n+static void submodule_reset_index(const char *path, const char *super_prefix)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tprepare_submodule_repo_env(&cp.env);\n@@ -2089,10 +2081,10 @@ static void submodule_reset_index(const char *path)\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \t/* TODO: determine if this might overwright untracked files */\n \tstrvec_pushl(&cp.args, \"read-tree\", \"-u\", \"--reset\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tstrvec_push(&cp.args, empty_tree_oid_hex());\n \n@@ -2105,10 +2097,9 @@ static void submodule_reset_index(const char *path)\n  * For edge cases (a submodule coming into existence or removing a submodule)\n  * pass NULL for old or new respectively.\n  */\n-int submodule_move_head(const char *path,\n-\t\t\t const char *old_head,\n-\t\t\t const char *new_head,\n-\t\t\t unsigned flags)\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n+\t\t\tunsigned flags)\n {\n \tint ret = 0;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2146,7 +2137,7 @@ int submodule_move_head(const char *path,\n \t\tif (old_head) {\n \t\t\tif (!submodule_uses_gitfile(path))\n \t\t\t\tabsorb_git_dir_into_superproject(path,\n-\t\t\t\t\t\t\t\t get_super_prefix());\n+\t\t\t\t\t\t\t\t super_prefix);\n \t\t} else {\n \t\t\tstruct strbuf gitdir = STRBUF_INIT;\n \t\t\tsubmodule_name_to_gitdir(&gitdir, the_repository,\n@@ -2155,7 +2146,7 @@ int submodule_move_head(const char *path,\n \t\t\tstrbuf_release(&gitdir);\n \n \t\t\t/* make sure the index is clean as well */\n-\t\t\tsubmodule_reset_index(path);\n+\t\t\tsubmodule_reset_index(path, super_prefix);\n \t\t}\n \n \t\tif (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {\n@@ -2173,9 +2164,9 @@ int submodule_move_head(const char *path,\n \tcp.no_stdin = 1;\n \tcp.dir = path;\n \n-\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n-\t\t     get_super_prefix_or_empty(), path);\n \tstrvec_pushl(&cp.args, \"read-tree\", \"--recurse-submodules\", NULL);\n+\tstrvec_pushf(&cp.args, \"--super-prefix=%s%s/\",\n+\t\t     (super_prefix ? super_prefix : \"\"), path);\n \n \tif (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)\n \t\tstrvec_push(&cp.args, \"-n\");\ndiff --git a/submodule.h b/submodule.h\nindex f90ee547d08..c55a25ca37d 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);\n \n #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)\n #define SUBMODULE_MOVE_HEAD_FORCE   (1<<1)\n-int submodule_move_head(const char *path,\n-\t\t\tconst char *old,\n-\t\t\tconst char *new_head,\n+int submodule_move_head(const char *path, const char *super_prefix,\n+\t\t\tconst char *old_head, const char *new_head,\n \t\t\tunsigned flags);\n \n void submodule_unset_core_worktree(const struct submodule *sub);\ndiff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh\nindex 516a6112fdc..3fb1b0c162d 100755\n--- a/t/t1001-read-tree-m-2way.sh\n+++ b/t/t1001-read-tree-m-2way.sh\n@@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '\n \tcat <<-EOF >expect &&\n \t\terror: Updating '\\''fictional/a'\\'' would lose untracked files in it\n \tEOF\n-\ttest_must_fail git --super-prefix fictional/ read-tree -u -m \"$treeH\" \"$treeM\" 2>actual &&\n+\ttest_must_fail git read-tree --super-prefix fictional/ -u -m \"$treeH\" \"$treeM\" 2>actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh\nindex 2846ec6629c..f519d2a87a7 100755\n--- a/t/t5616-partial-clone.sh\n+++ b/t/t5616-partial-clone.sh\n@@ -644,7 +644,7 @@ test_expect_success 'repack does not loosen promisor objects' '\n \tgrep \"loosen_unused_packed_objects/loosened:0\" trace\n '\n \n-test_expect_failure 'lazy-fetch in submodule succeeds' '\n+test_expect_success 'lazy-fetch in submodule succeeds' '\n \t# setup\n \ttest_config_global protocol.file.allow always &&\n \ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 8a762aa0772..2b8e5da4c21 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -71,7 +71,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {\n \t  ? ((o)->msgs[(type)])      \\\n \t  : (unpack_plumbing_errors[(type)]) )\n \n-static const char *super_prefixed(const char *path)\n+static const char *super_prefixed(const char *path, const char *super_prefix)\n {\n \t/*\n \t * It is necessary and sufficient to have two static buffers\n@@ -83,7 +83,6 @@ static const char *super_prefixed(const char *path)\n \tstatic unsigned idx = ARRAY_SIZE(buf) - 1;\n \n \tif (super_prefix_len < 0) {\n-\t\tconst char *super_prefix = get_super_prefix();\n \t\tif (!super_prefix) {\n \t\t\tsuper_prefix_len = 0;\n \t\t} else {\n@@ -236,7 +235,8 @@ static int add_rejected_path(struct unpack_trees_options *o,\n \t\treturn -1;\n \n \tif (!o->show_all_errors)\n-\t\treturn error(ERRORMSG(o, e), super_prefixed(path));\n+\t\treturn error(ERRORMSG(o, e), super_prefixed(path,\n+\t\t\t\t\t\t\t    o->super_prefix));\n \n \t/*\n \t * Otherwise, insert in a list for future display by\n@@ -263,7 +263,8 @@ static void display_error_msgs(struct unpack_trees_options *o)\n \t\t\terror_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\terror(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t     o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -290,7 +291,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)\n \t\t\twarning_displayed = 1;\n \t\t\tfor (i = 0; i < rejects->nr; i++)\n \t\t\t\tstrbuf_addf(&path, \"\\t%s\\n\", rejects->items[i].string);\n-\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf));\n+\t\t\twarning(ERRORMSG(o, e), super_prefixed(path.buf,\n+\t\t\t\t\t\t\t       o->super_prefix));\n \t\t\tstrbuf_release(&path);\n \t\t}\n \t\tstring_list_clear(rejects, 0);\n@@ -312,7 +314,8 @@ static int check_submodule_move_head(const struct cache_entry *ce,\n \tif (o->reset)\n \t\tflags |= SUBMODULE_MOVE_HEAD_FORCE;\n \n-\tif (submodule_move_head(ce->name, old_id, new_id, flags))\n+\tif (submodule_move_head(ce->name, o->super_prefix, old_id, new_id,\n+\t\t\t\tflags))\n \t\treturn add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);\n \treturn 0;\n }\n@@ -415,6 +418,7 @@ static int check_updates(struct unpack_trees_options *o,\n \tint i, pc_workers, pc_threshold;\n \n \ttrace_performance_enter();\n+\tstate.super_prefix = o->super_prefix;\n \tstate.force = 1;\n \tstate.quiet = 1;\n \tstate.refresh_cache = 1;\n@@ -445,7 +449,7 @@ static int check_updates(struct unpack_trees_options *o,\n \n \t\tif (ce->ce_flags & CE_WT_REMOVE) {\n \t\t\tdisplay_progress(progress, ++cnt);\n-\t\t\tunlink_entry(ce);\n+\t\t\tunlink_entry(ce, o->super_prefix);\n \t\t}\n \t}\n \n@@ -2959,8 +2963,8 @@ int bind_merge(const struct cache_entry * const *src,\n \tif (a && old)\n \t\treturn o->quiet ? -1 :\n \t\t\terror(ERRORMSG(o, ERROR_BIND_OVERLAP),\n-\t\t\t      super_prefixed(a->name),\n-\t\t\t      super_prefixed(old->name));\n+\t\t\t      super_prefixed(a->name, o->super_prefix),\n+\t\t\t      super_prefixed(old->name, o->super_prefix));\n \tif (!a)\n \t\treturn keep_entry(old, o);\n \telse\n@@ -3021,7 +3025,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,\n \n \tif (worktree && untracked)\n \t\treturn error(_(\"worktree and untracked commit have duplicate entries: %s\"),\n-\t\t\t     super_prefixed(worktree->name));\n+\t\t\t     super_prefixed(worktree->name, o->super_prefix));\n \n \treturn merged_entry(worktree ? worktree : untracked, NULL, o);\n }\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex 6ab0d74c84d..3a7b3e5f007 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -75,6 +75,7 @@ struct unpack_trees_options {\n \t\t     skip_cache_tree_update;\n \tenum unpack_trees_reset_type reset;\n \tconst char *prefix;\n+\tconst char *super_prefix;\n \tint cache_bottom;\n \tstruct pathspec *pathspec;\n \tmerge_fn_t fn;\n-- \n2.39.0.1071.g97ce8966538\n\n"}]}