{"thread":{"id":"56453","subject":"[PATCH 00/13] submodule: convert the rest of 'update' to C","startedAt":"2021-09-07T12:00:02Z","lastAt":"2022-02-17T16:14:26Z","messageCount":142,"participants":["Atharva Raykar","Ævar Arnfjörð Bjarmason","Junio C Hamano","Jonathan Tan","Emily Shaffer","Glen Choo"],"isPatch":true,"patchVersion":1,"patchTotal":13},"messages":[{"id":"434849","messageId":"20210907115932.36068-1-raykar.ath@gmail.com","threadId":"56453","inReplyTo":null,"subject":"[PATCH 00/13] submodule: convert the rest of 'update' to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:19Z","receivedAt":"2021-09-07T12:00:02Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"NOTE: This series uses ar/submodule-run-update-procedure [1]\n\nThis series builds upon the previous conversion work on 'submodule update' and\nmoves out all of that shell logic in 'git-submodule.sh' into\n'builtin/submodule--helper.c'. Even though this patch series looks long, a lot\nof it is preparatory patches and cleanup of unused functions that result from\nthis conversion. The real action happens at [6/8].\n\nAs with the other series, the goal is to be a faithful conversion, with no\nchange in behaviour.\n\nThis would be the last command whose logic would be moved into C, other than\n'submodule add', whose patches have been sent already.\n\nAfter this works out, we can invert the shell-C relationship and make\n'submodule' a proper C builtin.\n\nFetch-it-Via:\ngit fetch https://github.com/tfidfwastaken/git submodule-update-list-1\n\n[1] https://lore.kernel.org/git/20210824140609.1496-1-raykar.ath@gmail.com/\n\nAtharva Raykar (13):\n  submodule--helper: split up ensure_core_worktree()\n  submodule--helper: get remote names from any repository\n  submodule--helper: introduce get_default_remote_submodule()\n  submodule--helper: rename helpers for update-clone\n  submodule--helper: refactor get_submodule_displaypath()\n  submodule: move core cmd_update() logic to C\n  submodule: remove fetch_in_submodule shell function\n  submodule--helper: remove update-clone subcommand\n  submodule--helper: remove update-module-mode subcommand\n  submodule--helper: remove shell interface to ensure_core_worktree()\n  submodule--helper: remove print-default-remote subcommand\n  submodule--helper: remove relative-path subcommand\n  submodule--helper: remove run-update-procedure subcommand\n\n builtin/submodule--helper.c | 764 +++++++++++++++++++++---------------\n git-submodule.sh            | 145 +------\n 2 files changed, 455 insertions(+), 454 deletions(-)\n\n-- \n2.32.0\n\n"},{"id":"434850","messageId":"20210907115932.36068-2-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 01/13] submodule--helper: split up ensure_core_worktree()","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:20Z","receivedAt":"2021-09-07T12:00:02Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"Let's split up `ensure_core_worktree()` so that we can call it from C\ncode without needing to deal with command line arguments.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 80619361fc..97512ccf0b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2794,18 +2794,12 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+static void do_ensure_core_worktree(const char *path)\n {\n \tconst struct submodule *sub;\n-\tconst char *path;\n \tconst char *cw;\n \tstruct repository subrepo;\n \n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \tif (!sub)\n \t\tBUG(\"We could get the submodule handle before?\");\n@@ -2829,6 +2823,17 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n+}\n+\n+static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *path;\n+\n+\tif (argc != 2)\n+\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n+\n+\tpath = argv[1];\n+\tdo_ensure_core_worktree(path);\n \n \treturn 0;\n }\n-- \n2.32.0\n\n"},{"id":"434851","messageId":"20210907115932.36068-3-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 02/13] submodule--helper: get remote names from any repository","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:21Z","receivedAt":"2021-09-07T12:00:02Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"`get_default_remote()` retrieves the name of a remote by resolving the\nrefs from of the current repository's ref store.\n\nThus in order to use it for retrieving the remote name of a submodule,\nwe have to start a new subprocess which runs from the submodule\ndirectory.\n\nLet's instead introduce a function called `repo_get_default_remote()`\nwhich takes any repository object and retrieves the remote accordingly.\n\n`get_default_remote()` is then defined as a call to\n`repo_get_default_remote()` with 'the_repository' passed to it.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 11 ++++++++---\n 1 file changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 97512ccf0b..1a65de4fa4 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -29,11 +29,10 @@\n typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n \t\t\t\t  void *cb_data);\n \n-static char *get_default_remote(void)\n+static char *repo_get_default_remote(struct repository *repo, const char *refname)\n {\n \tchar *dest = NULL, *ret;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n \n \tif (!refname)\n \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n@@ -46,7 +45,7 @@ static char *get_default_remote(void)\n \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n \n \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n-\tif (git_config_get_string(sb.buf, &dest))\n+\tif (repo_config_get_string(repo, sb.buf, &dest))\n \t\tret = xstrdup(\"origin\");\n \telse\n \t\tret = dest;\n@@ -55,6 +54,12 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static char *get_default_remote(void)\n+{\n+\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n+\treturn repo_get_default_remote(the_repository, refname);\n+}\n+\n static int print_default_remote(int argc, const char **argv, const char *prefix)\n {\n \tchar *remote;\n-- \n2.32.0\n\n"},{"id":"434852","messageId":"20210907115932.36068-4-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 03/13] submodule--helper: introduce get_default_remote_submodule()","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:22Z","receivedAt":"2021-09-07T12:00:05Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"Before 8ef1d2b549 (submodule--helper: get remote names from any\nrepository, 2021-07-20), it was not possible to directly retrieve a\nsubmodule's remote name within the same process, because\n`get_default_remote()` used only knew about the current repository.\n\nNow that we have `repo_get_default_remote()`, we no longer have to start\na subprocess that called `submodule--helper get-default-remote` from\nwithin the submodule directory.\n\nLet's make a function called `get_default_remote_submodule()` which\ntakes a submodule path, and returns the default remote for that\nsubmodule, all within the same process.\n\nWe can now use this function to save an unnecessary subprocess spawn in\n`sync_submodule()`, and also in the next patch, which will require this\nfunctionality.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 23 +++++++++++++++--------\n 1 file changed, 15 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 1a65de4fa4..f6c4fc349b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -54,6 +54,19 @@ static char *repo_get_default_remote(struct repository *repo, const char *refnam\n \treturn ret;\n }\n \n+static char *get_default_remote_submodule(const char *module_path)\n+{\n+\tconst char *refname;\n+\tconst struct submodule *sub;\n+\tstruct repository subrepo;\n+\n+\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n+\t\t\t\t\t  \"HEAD\", 0, NULL, NULL);\n+\tsub = submodule_from_path(the_repository, null_oid(), module_path);\n+\trepo_submodule_init(&subrepo, the_repository, sub);\n+\treturn repo_get_default_remote(&subrepo, refname);\n+}\n+\n static char *get_default_remote(void)\n {\n \tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n@@ -1374,7 +1387,6 @@ static void sync_submodule(const char *path, const char *prefix,\n \tchar *remote_key = NULL;\n \tchar *sub_origin_url, *super_config_url, *displaypath;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *sub_config_path = NULL;\n \n \tif (!is_submodule_active(the_repository, path))\n@@ -1423,14 +1435,9 @@ static void sync_submodule(const char *path, const char *prefix,\n \tif (!is_submodule_populated_gently(path, NULL))\n \t\tgoto cleanup;\n \n-\tprepare_submodule_repo_env(&cp.env_array);\n-\tcp.git_cmd = 1;\n-\tcp.dir = path;\n-\tstrvec_pushl(&cp.args, \"submodule--helper\",\n-\t\t     \"print-default-remote\", NULL);\n-\n \tstrbuf_reset(&sb);\n-\tif (capture_command(&cp, &sb, 0))\n+\tstrbuf_addstr(&sb, get_default_remote_submodule(path));\n+\tif (!sb.buf)\n \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n \t\t      path);\n \n-- \n2.32.0\n\n"},{"id":"434853","messageId":"20210907115932.36068-5-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 04/13] submodule--helper: rename helpers for update-clone","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:23Z","receivedAt":"2021-09-07T12:00:09Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"The `update-clone` subcommand helpers that perform the parallel clone\nand printing to stdout for shell script consumption, are renamed.\n\nThis lets us use the names `update_submodules()` and\n`update_submodule()` for the helpers in the next patch, when we create\nan `update` subcommand that does a full conversion.\n\nWe will get rid of these helpers in a cleanup patch at the end of this\nseries, when the `update-clone` command is no longer useful to us.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex f6c4fc349b..b0336b0377 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2499,7 +2499,7 @@ static int do_run_update_procedure(struct update_data *ud)\n \treturn run_update_command(ud, subforce);\n }\n \n-static void update_submodule(struct update_clone_data *ucd)\n+static void update_clone_submodule(struct update_clone_data *ucd)\n {\n \tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n \t\toid_to_hex(&ucd->oid),\n@@ -2507,7 +2507,7 @@ static void update_submodule(struct update_clone_data *ucd)\n \t\tucd->sub->path);\n }\n \n-static int update_submodules(struct submodule_update_clone *suc)\n+static int update_clone_submodules(struct submodule_update_clone *suc)\n {\n \tint i;\n \n@@ -2528,7 +2528,7 @@ static int update_submodules(struct submodule_update_clone *suc)\n \t\treturn 1;\n \n \tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_submodule(&suc->update_clone[i]);\n+\t\tupdate_clone_submodule(&suc->update_clone[i]);\n \n \treturn 0;\n }\n@@ -2593,7 +2593,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \tif (pathspec.nr)\n \t\tsuc.warn_if_uninitialized = 1;\n \n-\treturn update_submodules(&suc);\n+\treturn update_clone_submodules(&suc);\n }\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-- \n2.32.0\n\n"},{"id":"434854","messageId":"20210907115932.36068-6-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 05/13] submodule--helper: refactor get_submodule_displaypath()","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:24Z","receivedAt":"2021-09-07T12:00:21Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"We create a function called `do_get_submodule_displaypath()` that\ngenerates the display path required by several submodule functions, and\ntakes a custom superprefix parameter, instead of reading it from the\nenvironment.\n\nWe then redefine the existing `get_submodule_displaypath()` function\nas a call to this new function, where the superprefix is obtained from\nthe environment.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b0336b0377..10de01a1f7 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -269,11 +269,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\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 *do_get_submodule_displaypath(const char *path, const char *prefix, 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@@ -289,6 +286,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \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+\treturn do_get_submodule_displaypath(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-- \n2.32.0\n\n"},{"id":"434855","messageId":"20210907115932.36068-7-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 06/13] submodule: move core cmd_update() logic to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:25Z","receivedAt":"2021-09-07T12:00:23Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"This patch completes the conversion past the flag parsing of\n`submodule update` by introducing a helper subcommand called\n`submodule--helper update`. The behaviour of `submodule update` should\nremain the same after this patch.\n\nWe add more fields to the `struct update_data` that are required by\n`struct submodule_update_clone` to be able to perform a clone, when that\nis needed to be done.\n\nRecursing on a submodule is done by calling a subprocess that launches\n`submodule--helper update`, with a modified `--recursive-prefix` and\n`--prefix` parameter.\n\nWe also introduce `update_submodules()` and `update_submodule()` which\nare quite similar to `update_clone_submodules()` and\n`update_clone_submodule()`, and will supersede them.\n\nWhen the `--init` flag is passed to the subcommand, we do not spawn a\nnew subprocess and call `submodule--helper init` on the submodule paths,\nbecause the Git machinery is not able to pick up the configuration\nchanges introduced by that init call[1]. So we instead run the\n`init_submodule_cb()` callback over each submodule directly.\n\nThis introduces another problem, because there is no mechanism to pass\nthe superproject path prefix (ie, `--super-prefix`) without starting a\nnew git process. This field is required for obtaining the display path\nfor that is used by the command's output messages. So let's add a field\ninto the `init_cb` struct that lets us pass this information to\n`init_submodule()`, which will now also take an explicit 'superprefix'\nargument.\n\n[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 502 ++++++++++++++++++++++++++++++------\n git-submodule.sh            | 131 +---------\n 2 files changed, 430 insertions(+), 203 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 10de01a1f7..2cccb9a9ab 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -634,18 +634,22 @@ static char *compute_submodule_clone_url(const char *rel_url)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *superprefix;\n \tunsigned int flags;\n };\n-#define INIT_CB_INIT { NULL, 0 }\n+#define INIT_CB_INIT { NULL, NULL, 0 }\n \n static void init_submodule(const char *path, const char *prefix,\n-\t\t\t   unsigned int flags)\n+\t\t\t   const char *superprefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\t/* try superprefix from the environment, if it is not passed explicitly */\n+\tif (!superprefix)\n+\t\tsuperprefix = get_super_prefix();\n+\tdisplaypath = do_get_submodule_displaypath(path, prefix, superprefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -719,7 +723,7 @@ static void init_submodule(const char *path, const char *prefix,\n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct init_cb *info = cb_data;\n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n@@ -2039,7 +2043,6 @@ struct submodule_update_clone {\n \tconst char *prefix;\n \tint single_branch;\n \n-\t/* to be consumed by git-submodule.sh */\n \tstruct update_clone_data *update_clone;\n \tint update_clone_nr; int update_clone_alloc;\n \n@@ -2062,19 +2065,63 @@ struct submodule_update_clone {\n }\n \n struct update_data {\n+\tconst char *prefix;\n \tconst char *recursive_prefix;\n \tconst char *sm_path;\n \tconst char *displaypath;\n \tstruct object_id oid;\n \tstruct object_id suboid;\n-\tstruct submodule_update_strategy update_strategy;\n+\tint max_jobs;\n \tint depth;\n+\tint recommend_shallow;\n+\tint single_branch;\n+\tunsigned int init: 1;\n \tunsigned int force: 1;\n \tunsigned int quiet: 1;\n \tunsigned int nofetch: 1;\n-\tunsigned int just_cloned: 1;\n+\tunsigned int remote: 1;\n+\tunsigned int recursive: 1;\n+\tunsigned int progress: 1;\n+\tunsigned int dissociate: 1;\n+\tunsigned int require_init: 1;\n+\tunsigned warn_if_uninitialized : 1;\n+\tunsigned int just_cloned : 1;\n+\tstruct submodule_update_strategy update_strategy;\n+\tstruct string_list references;\n+\tstruct module_list list;\n };\n-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }\n+#define UPDATE_DATA_INIT { \\\n+\t.list = MODULE_LIST_INIT, \\\n+\t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+\t.recommend_shallow = -1, \\\n+\t.references = STRING_LIST_INIT_DUP, \\\n+\t.single_branch = -1, \\\n+\t.max_jobs = 1, \\\n+}\n+\n+static void update_clone_from_update_data(struct submodule_update_clone *suc,\n+\t\t\t\t\t  struct update_data *update_data)\n+{\n+\tsuc->prefix = update_data->prefix;\n+\tsuc->recursive_prefix = update_data->recursive_prefix;\n+\tsuc->max_jobs = update_data->max_jobs;\n+\tsuc->progress = update_data->progress;\n+\tsuc->quiet = update_data->quiet;\n+\tsuc->dissociate = update_data->dissociate;\n+\tsuc->require_init = update_data->require_init;\n+\tsuc->single_branch = update_data->single_branch;\n+\tsuc->warn_if_uninitialized = update_data->warn_if_uninitialized;\n+\tsuc->list = update_data->list;\n+\tsuc->update = update_data->update_strategy;\n+\tsuc->recommend_shallow = update_data->recommend_shallow;\n+\tif (update_data->depth)\n+\t\tsuc->depth = xstrfmt(\"--depth=%d\", update_data->depth);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstring_list_append(&suc->references, item->string);\n+\t}\n+}\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n \t\tstruct strbuf *out, const char *displaypath)\n@@ -2369,111 +2416,113 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \treturn run_command(&cp);\n }\n \n-static int run_update_command(struct update_data *ud, int subforce)\n+static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)\n {\n-\tstruct strvec args = STRVEC_INIT;\n-\tstruct strvec child_env = STRVEC_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n+\tstruct strbuf out = STRBUF_INIT;\n \tint must_die_on_failure = 0;\n-\tint git_cmd;\n+\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n \n-\tswitch (ud->update_strategy.type) {\n+\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n+\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n+\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n+\telse\n+\t\tstrategy = ud->update_strategy;\n+\n+\tcp.dir = xstrdup(ud->sm_path);\n+\tswitch (strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_pushl(&args, \"checkout\", \"-q\", NULL);\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n \t\tif (subforce)\n-\t\t\tstrvec_push(&args, \"-f\");\n+\t\t\tstrvec_push(&cp.args, \"-f\");\n \t\tbreak;\n \tcase SM_UPDATE_REBASE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"rebase\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_MERGE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"merge\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n-\t\tgit_cmd = 0;\n-\t\tstrvec_push(&args, ud->update_strategy.command);\n+\t\tcp.git_cmd = 0;\n+\t\tcp.use_shell = 1;\n+\t\tstrvec_push(&cp.args, strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t    submodule_strategy_to_string(&strategy));\n \t}\n-\tstrvec_push(&args, oid);\n+\tstrvec_push(&cp.args, oid);\n \n-\tprepare_submodule_repo_env(&child_env);\n-\tif (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,\n-\t\t\t\t     ud->sm_path, child_env.v)) {\n-\t\tswitch (ud->update_strategy.type) {\n-\t\tcase SM_UPDATE_CHECKOUT:\n-\t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tcase SM_UPDATE_REBASE:\n-\t\t\tprintf(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tcase SM_UPDATE_MERGE:\n-\t\t\tprintf(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tcase SM_UPDATE_COMMAND:\n-\t\t\tprintf(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n-\t\t\t       ud->update_strategy.command, oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tif (capture_command(&cp, &out, 0)) {\n+\t\tif (must_die_on_failure) {\n+\t\t\tswitch (strategy.type) {\n+\t\t\tcase SM_UPDATE_CHECKOUT:\n+\t\t\t\tdie(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_REBASE:\n+\t\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_MERGE:\n+\t\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_COMMAND:\n+\t\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\t\t    strategy.command, oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tBUG(\"unexpected update strategy type: %s\",\n+\t\t\t\t    submodule_strategy_to_string(&strategy));\n+\t\t\t}\n \t\t}\n-\t\t/*\n-\t\t * NEEDSWORK: We are currently printing to stdout with error\n-\t\t * return so that the shell caller handles the error output\n-\t\t * properly. Once we start handling the error messages within\n-\t\t * C, we should use die() instead.\n-\t\t */\n-\t\tif (must_die_on_failure)\n-\t\t\treturn 2;\n-\t\t/*\n-\t\t * This signifies to the caller in shell that the command\n-\t\t * failed without dying\n-\t\t */\n+\n+\t\t/* the command failed, but update must continue */\n+\t\tstring_list_append(err, out.buf);\n \t\treturn 1;\n \t}\n \n-\tswitch (ud->update_strategy.type) {\n-\tcase SM_UPDATE_CHECKOUT:\n-\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_REBASE:\n-\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_MERGE:\n-\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_COMMAND:\n-\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n-\t\t       ud->displaypath, ud->update_strategy.command, oid);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\tif (!ud->quiet) {\n+\t\tswitch (strategy.type) {\n+\t\tcase SM_UPDATE_CHECKOUT:\n+\t\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n+\t\t\tbreak;\n+\t\tcase SM_UPDATE_REBASE:\n+\t\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n+\t\t\tbreak;\n+\t\tcase SM_UPDATE_MERGE:\n+\t\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n+\t\t\tbreak;\n+\t\tcase SM_UPDATE_COMMAND:\n+\t\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n+\t\t\t       ud->displaypath, strategy.command, oid);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"unexpected update strategy type: %s\",\n+\t\t\t    submodule_strategy_to_string(&strategy));\n+\t\t}\n \t}\n \n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud)\n+static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2500,7 +2549,7 @@ static int do_run_update_procedure(struct update_data *ud)\n \t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n \t}\n \n-\treturn run_update_command(ud, subforce);\n+\treturn run_update_command(ud, subforce, err);\n }\n \n static void update_clone_submodule(struct update_clone_data *ucd)\n@@ -2605,6 +2654,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n \tchar *prefixed_path, *update = NULL;\n \tstruct update_data update_data = UPDATE_DATA_INIT;\n+\tstruct string_list err = STRING_LIST_INIT_DUP;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n@@ -2662,7 +2712,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tfree(prefixed_path);\n \n \tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data);\n+\t\treturn do_run_update_procedure(&update_data, &err);\n \n \treturn 3;\n }\n@@ -3038,6 +3088,288 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \treturn !!ret;\n }\n \n+static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n+{\n+\tconst char *update = submodule_strategy_to_string(&update_data->update_strategy);\n+\n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n+\tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n+\tif (update_data->prefix)\n+\t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n+\tif (update_data->recursive_prefix)\n+\t\tstrvec_pushl(args, \"--recursive-prefix\",\n+\t\t\t     update_data->recursive_prefix, NULL);\n+\tif (update_data->quiet)\n+\t\tstrvec_push(args, \"--quiet\");\n+\tif (update_data->force)\n+\t\tstrvec_push(args, \"--force\");\n+\tif (update_data->init)\n+\t\tstrvec_push(args, \"--init\");\n+\tif (update_data->remote)\n+\t\tstrvec_push(args, \"--remote\");\n+\tif (update_data->nofetch)\n+\t\tstrvec_push(args, \"--no-fetch\");\n+\tif (update_data->dissociate)\n+\t\tstrvec_push(args, \"--dissociate\");\n+\tif (update_data->progress)\n+\t\tstrvec_push(args, \"--progress\");\n+\tif (update_data->require_init)\n+\t\tstrvec_push(args, \"--require-init\");\n+\tif (update_data->depth)\n+\t\tstrvec_pushf(args, \"--depth=%d\", update_data->depth);\n+\tif (update)\n+\t\tstrvec_pushl(args, \"--update\", update, NULL);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n+\t}\n+\tif (update_data->recommend_shallow == 0)\n+\t\tstrvec_push(args, \"--no-recommend-shallow\");\n+\telse if (update_data->recommend_shallow == 1)\n+\t\tstrvec_push(args, \"--recommend-shallow\");\n+\tif (update_data->single_branch >= 0)\n+\t\tstrvec_push(args, \"--single-branch\");\n+}\n+\n+static int update_submodule(struct update_data *update_data)\n+{\n+\tchar *prefixed_path;\n+\tstruct string_list err = STRING_LIST_INIT_DUP;\n+\n+\tdo_ensure_core_worktree(update_data->sm_path);\n+\n+\tif (update_data->recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n+\t\t\t\t\tupdate_data->sm_path);\n+\telse\n+\t\tprefixed_path = xstrdup(update_data->sm_path);\n+\n+\tupdate_data->displaypath = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t     update_data->prefix);\n+\tfree(prefixed_path);\n+\n+\tif (update_data->just_cloned) {\n+\t\toidcpy(&update_data->suboid, null_oid());\n+\t} else {\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n+\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t}\n+\n+\tif (update_data->remote) {\n+\t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n+\t\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n+\t\tchar *remote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n+\n+\t\tif (!update_data->nofetch) {\n+\t\t\tif(fetch_in_submodule(update_data->sm_path, update_data->depth,\n+\t\t\t\t\t      0, NULL))\n+\t\t\t\tdie(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\t\t    update_data->sm_path);\n+\t\t}\n+\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))\n+\t\t\tdie(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t    remote_ref, update_data->sm_path);\n+\n+\t\tfree(remote_ref);\n+\t}\n+\n+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n+\t\tif (do_run_update_procedure(update_data, &err))\n+\t\t\treturn 1;\n+\n+\tif (update_data->recursive) {\n+\t\tint res;\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct update_data next = *update_data;\n+\t\tchar *die_msg = xstrfmt(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t\t\tupdate_data->displaypath);\n+\n+\t\tif (update_data->recursive_prefix)\n+\t\t\tprefixed_path = xstrfmt(\"%s%s/\", update_data->recursive_prefix,\n+\t\t\t\t\t\tupdate_data->sm_path);\n+\t\telse\n+\t\t\tprefixed_path = xstrfmt(\"%s/\", update_data->sm_path);\n+\n+\t\tnext.recursive_prefix = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t\t  update_data->prefix);\n+\t\tnext.prefix = NULL;\n+\t\toidcpy(&next.oid, null_oid());\n+\t\toidcpy(&next.suboid, null_oid());\n+\n+\t\tcp.dir = update_data->sm_path;\n+\t\tcp.git_cmd = 1;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tupdate_data_to_args(&next, &cp.args);\n+\n+\t\t/* die() if child process die()'d */\n+\t\tif ((res = run_command(&cp)) == 128)\n+\t\t\tdie(\"%s\", die_msg);\n+\t\tif (res)\n+\t\t\tstring_list_append(&err, die_msg);\n+\n+\t\tfree(die_msg);\n+\t}\n+\n+\tif (err.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &err)\n+\t\t\tfputs(item->string, stderr);\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int update_submodules(struct update_data *update_data)\n+{\n+\tint i, res = 0;\n+\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\n+\tupdate_clone_from_update_data(&suc, update_data);\n+\trun_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,\n+\t\t\t\t   update_clone_start_failure,\n+\t\t\t\t   update_clone_task_finished, &suc, \"submodule\",\n+\t\t\t\t   \"parallel/update\");\n+\n+\t/*\n+\t * We saved the output and put it out all at once now.\n+\t * That means:\n+\t * - the listener does not have to interleave their (checkout)\n+\t *   work with our fetching.  The writes involved in a\n+\t *   checkout involve more straightforward sequential I/O.\n+\t * - the listener can avoid doing any work if fetching failed.\n+\t */\n+\tif (suc.quickstop)\n+\t\treturn 1;\n+\n+\tfor (i = 0; i < suc.update_clone_nr; i++) {\n+\t\tstruct update_clone_data ucd = suc.update_clone[i];\n+\n+\t\toidcpy(&update_data->oid, &ucd.oid);\n+\t\tupdate_data->just_cloned = ucd.just_cloned;\n+\t\tupdate_data->sm_path = ucd.sub->path;\n+\n+\t\tif (update_submodule(update_data))\n+\t\t\tres = 1;\n+\t}\n+\n+\treturn res;\n+}\n+\n+static int module_update(int argc, const char **argv, const char *prefix)\n+{\n+\tint init = 0, force = 0, quiet = 0, nofetch = 0;\n+\tint remote = 0, recursive = 0, dissociate = 0;\n+\tint progress = 0, require_init = 0;\n+\tconst char *update = NULL;\n+\tstruct pathspec pathspec;\n+\tstruct update_data update_data = UPDATE_DATA_INIT;\n+\n+\tstruct option module_update_clone_options[] = {\n+\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n+\t\tOPT_BOOL(0, \"init\", &init,\n+\t\t\t N_(\"initialize uninitialized submodules before update\")),\n+\t\tOPT_BOOL(0, \"remote\", &remote,\n+\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive,\n+\t\t\t N_(\"traverse submodules recursively\")),\n+\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n+\t\t\t N_(\"don't fetch new objects from the remote site\")),\n+\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree\")),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree, across nested \"\n+\t\t\t      \"submodule boundaries\")),\n+\t\tOPT_STRING(0, \"update\", &update,\n+\t\t\t   N_(\"string\"),\n+\t\t\t   N_(\"rebase, merge, checkout or none\")),\n+\t\tOPT_STRING_LIST(0, \"reference\", &update_data.references, N_(\"repo\"),\n+\t\t\t\tN_(\"reference repository\")),\n+\t\tOPT_BOOL(0, \"dissociate\", &dissociate,\n+\t\t\t N_(\"use --reference only while cloning\")),\n+\t\tOPT_INTEGER(0, \"depth\", &update_data.depth,\n+\t\t\t    N_(\"create a shallow clone truncated to the \"\n+\t\t\t       \"specified number of revisions\")),\n+\t\tOPT_INTEGER('j', \"jobs\", &update_data.max_jobs,\n+\t\t\t    N_(\"parallel jobs\")),\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &update_data.recommend_shallow,\n+\t\t\t N_(\"whether the initial clone should follow the shallow recommendation\")),\n+\t\tOPT__QUIET(&quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &progress,\n+\t\t\t N_(\"force cloning progress\")),\n+\t\tOPT_BOOL(0, \"require-init\", &require_init,\n+\t\t\t N_(\"disallow cloning into non-empty directory\")),\n+\t\tOPT_BOOL(0, \"single-branch\", &update_data.single_branch,\n+\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n+\t\tNULL\n+\t};\n+\n+\tupdate_clone_config_from_gitmodules(&update_data.max_jobs);\n+\tgit_config(git_update_clone_config, &update_data.max_jobs);\n+\n+\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\tupdate_data.prefix = prefix;\n+\n+\tupdate_data.force = !!force;\n+\tupdate_data.quiet = !!quiet;\n+\tupdate_data.nofetch = !!nofetch;\n+\tupdate_data.init = !!init;\n+\tupdate_data.require_init = !!require_init;\n+\tupdate_data.remote = !!remote;\n+\tupdate_data.recursive = !!recursive;\n+\tupdate_data.progress = !!progress;\n+\tupdate_data.dissociate = !!dissociate;\n+\toidcpy(&update_data.oid, null_oid());\n+\toidcpy(&update_data.suboid, null_oid());\n+\n+\tif (update)\n+\t\tif (parse_submodule_update_strategy(update,\n+\t\t\t\t\t\t    &update_data.update_strategy) < 0)\n+\t\t\tdie(_(\"bad value for update parameter\"));\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &update_data.list) < 0)\n+\t\treturn 1;\n+\n+\tif (pathspec.nr)\n+\t\tupdate_data.warn_if_uninitialized = 1;\n+\n+\tif (update_data.init) {\n+\t\tstruct module_list list = MODULE_LIST_INIT;\n+\t\tstruct init_cb info = INIT_CB_INIT;\n+\n+\t\tif (module_list_compute(argc, argv, update_data.prefix,\n+\t\t\t\t\t&pathspec, &list) < 0)\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * If there are no path args and submodule.active is set then,\n+\t\t * by default, only initialize 'active' modules.\n+\t\t */\n+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n+\t\t\tmodule_list_active(&list);\n+\n+\t\tinfo.prefix = update_data.prefix;\n+\t\tinfo.superprefix = update_data.recursive_prefix;\n+\t\tif (update_data.quiet)\n+\t\t\tinfo.flags |= OPT_QUIET;\n+\n+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n+\t}\n+\n+\treturn update_submodules(&update_data);\n+}\n+\n struct add_data {\n \tconst char *prefix;\n \tconst char *branch;\n@@ -3213,6 +3545,7 @@ static int add_clone(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+\n #define SUPPORT_SUPER_PREFIX (1<<0)\n \n struct cmd_struct {\n@@ -3226,6 +3559,7 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"add-clone\", add_clone, 0},\n+\t{\"update\", module_update, 0},\n \t{\"update-module-mode\", module_update_module_mode, 0},\n \t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex f703cddce8..4e21d9715c 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -484,133 +484,26 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\tif test -n \"$init\"\n-\tthen\n-\t\tcmd_init \"--\" \"$@\" || return\n-\tfi\n-\n-\t{\n-\tgit submodule--helper update-clone ${GIT_QUIET:+--quiet} \\\n-\t\t${progress:+\"--progress\"} \\\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n+\t\t${GIT_QUIET:+--quiet} \\\n+\t\t${force:+--force} \\\n+\t\t${progress:+--progress} \\\n+\t\t${dissociate:+--dissociate} \\\n+\t\t${remote:+--remote} \\\n+\t\t${recursive:+--recursive} \\\n+\t\t${init:+--init} \\\n+\t\t${require_init:+--require-init} \\\n+\t\t${nofetch:+--no-fetch} \\\n \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t${update:+--update \"$update\"} \\\n \t\t${reference:+\"$reference\"} \\\n-\t\t${dissociate:+\"--dissociate\"} \\\n-\t\t${depth:+--depth \"$depth\"} \\\n-\t\t${require_init:+--require-init} \\\n+\t\t${depth:+\"$depth\"} \\\n \t\t$single_branch \\\n \t\t$recommend_shallow \\\n \t\t$jobs \\\n \t\t-- \\\n-\t\t\"$@\" || echo \"#unmatched\" $?\n-\t} | {\n-\terr=\n-\twhile read -r quickabort sha1 just_cloned sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n-\n-\t\tgit submodule--helper ensure-core-worktree \"$sm_path\" || exit 1\n-\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\n-\t\tif test $just_cloned -eq 1\n-\t\tthen\n-\t\t\tsubsha1=\n-\t\telse\n-\t\t\tjust_cloned=\n-\t\t\tsubsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify HEAD) ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current revision in submodule path '\\$displaypath'\")\"\n-\t\tfi\n-\n-\t\tif test -n \"$remote\"\n-\t\tthen\n-\t\t\tbranch=$(git submodule--helper remote-branch \"$sm_path\")\n-\t\t\tif test -z \"$nofetch\"\n-\t\t\tthen\n-\t\t\t\t# Fetch remote before determining tracking $sha1\n-\t\t\t\tfetch_in_submodule \"$sm_path\" $depth ||\n-\t\t\t\tdie \"fatal: $(eval_gettext \"Unable to fetch in submodule path '\\$sm_path'\")\"\n-\t\t\tfi\n-\t\t\tremote_name=$(sanitize_submodule_env; cd \"$sm_path\" && git submodule--helper print-default-remote)\n-\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify \"${remote_name}/${branch}\") ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\n-\t\tout=$(git submodule--helper run-update-procedure \\\n-\t\t\t  ${wt_prefix:+--prefix \"$wt_prefix\"} \\\n-\t\t\t  ${GIT_QUIET:+--quiet} \\\n-\t\t\t  ${force:+--force} \\\n-\t\t\t  ${just_cloned:+--just-cloned} \\\n-\t\t\t  ${nofetch:+--no-fetch} \\\n-\t\t\t  ${depth:+\"$depth\"} \\\n-\t\t\t  ${update:+--update \"$update\"} \\\n-\t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n-\t\t\t  ${sha1:+--oid \"$sha1\"} \\\n-\t\t\t  ${subsha1:+--suboid \"$subsha1\"} \\\n-\t\t\t  \"--\" \\\n-\t\t\t  \"$sm_path\")\n-\n-\t\t# exit codes for run-update-procedure:\n-\t\t# 0: update was successful, say command output\n-\t\t# 1: update procedure failed, but should not die\n-\t\t# 2 or 128: subcommand died during execution\n-\t\t# 3: no update procedure was run\n-\t\tres=\"$?\"\n-\t\tcase $res in\n-\t\t0)\n-\t\t\tsay \"$out\"\n-\t\t\t;;\n-\t\t1)\n-\t\t\terr=\"${err};fatal: $out\"\n-\t\t\tcontinue\n-\t\t\t;;\n-\t\t2|128)\n-\t\t\tdie_with_status $res \"fatal: $out\"\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=$(git submodule--helper relative-path \"$prefix$sm_path/\" \"$wt_prefix\")\n-\t\t\t\twt_prefix=\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_update\n-\t\t\t)\n-\t\t\tres=$?\n-\t\t\tif test $res -gt 0\n-\t\t\tthen\n-\t\t\t\tdie_msg=\"fatal: $(eval_gettext \"Failed to recurse into submodule path '\\$displaypath'\")\"\n-\t\t\t\tif test $res -ne 2\n-\t\t\t\tthen\n-\t\t\t\t\terr=\"${err};$die_msg\"\n-\t\t\t\t\tcontinue\n-\t\t\t\telse\n-\t\t\t\t\tdie_with_status $res \"$die_msg\"\n-\t\t\t\tfi\n-\t\t\tfi\n-\t\tfi\n-\tdone\n-\n-\tif test -n \"$err\"\n-\tthen\n-\t\tOIFS=$IFS\n-\t\tIFS=';'\n-\t\tfor e in $err\n-\t\tdo\n-\t\t\tif test -n \"$e\"\n-\t\t\tthen\n-\t\t\t\techo >&2 \"$e\"\n-\t\t\tfi\n-\t\tdone\n-\t\tIFS=$OIFS\n-\t\texit 1\n-\tfi\n-\t}\n+\t\t\"$@\"\n }\n \n #\n-- \n2.32.0\n\n"},{"id":"434856","messageId":"20210907115932.36068-8-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 07/13] submodule: remove fetch_in_submodule shell function","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:26Z","receivedAt":"2021-09-07T12:00:27Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"This function has no more use in 'git-submodule.sh' after\nbd82d7d467 (submodule: move core cmd_update() logic to C, 2021-07-20),\nwhere we moved all of its uses to C, which has its own version for the\nsame.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n git-submodule.sh | 14 --------------\n 1 file changed, 14 deletions(-)\n\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 4e21d9715c..5197de4551 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -369,20 +369,6 @@ cmd_deinit()\n \tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- \"$@\"\n }\n \n-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]\n-# Because arguments are positional, use an empty string to omit <depth>\n-# but include <sha1>.\n-fetch_in_submodule () (\n-\tsanitize_submodule_env &&\n-\tcd \"$1\" &&\n-\tif test $# -eq 3\n-\tthen\n-\t\techo \"$3\" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+\"$2\"}\n-\telse\n-\t\tgit fetch ${GIT_QUIET:+--quiet} ${2:+\"$2\"}\n-\tfi\n-)\n-\n #\n # Update each submodule path to correct revision, using clone and checkout as needed\n #\n-- \n2.32.0\n\n"},{"id":"434857","messageId":"20210907115932.36068-9-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 08/13] submodule--helper: remove update-clone subcommand","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:27Z","receivedAt":"2021-09-07T12:00:33Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"We no longer need this subcommand as the shell version calls the\n'update' subcommand instead, which does all the cloning within C itself.\n\nWe also no longer need the 'update_clone_submodules()' and\n'update_clone_submodule()' functions, so we remove those as well.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 98 -------------------------------------\n 1 file changed, 98 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 2cccb9a9ab..a628660d6b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2552,103 +2552,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e\n \treturn run_update_command(ud, subforce, err);\n }\n \n-static void update_clone_submodule(struct update_clone_data *ucd)\n-{\n-\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n-\t\toid_to_hex(&ucd->oid),\n-\t\tucd->just_cloned,\n-\t\tucd->sub->path);\n-}\n-\n-static int update_clone_submodules(struct submodule_update_clone *suc)\n-{\n-\tint i;\n-\n-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n-\t\t\t\t   update_clone_start_failure,\n-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n-\t\t\t\t   \"parallel/update\");\n-\n-\t/*\n-\t * We saved the output and put it out all at once now.\n-\t * That means:\n-\t * - the listener does not have to interleave their (checkout)\n-\t *   work with our fetching.  The writes involved in a\n-\t *   checkout involve more straightforward sequential I/O.\n-\t * - the listener can avoid doing any work if fetching failed.\n-\t */\n-\tif (suc->quickstop)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_clone_submodule(&suc->update_clone[i]);\n-\n-\treturn 0;\n-}\n-\n-static int update_clone(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *update = NULL;\n-\tstruct pathspec pathspec;\n-\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n-\n-\tstruct option module_update_clone_options[] = {\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &suc.recursive_prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &suc.references, N_(\"repo\"),\n-\t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &suc.dissociate,\n-\t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &suc.depth, \"<depth>\",\n-\t\t\t   N_(\"create a shallow clone truncated to the \"\n-\t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &suc.max_jobs,\n-\t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &suc.recommend_shallow,\n-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&suc.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &suc.progress,\n-\t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &suc.require_init,\n-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &suc.single_branch,\n-\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\tsuc.prefix = prefix;\n-\n-\tupdate_clone_config_from_gitmodules(&suc.max_jobs);\n-\tgit_config(git_update_clone_config, &suc.max_jobs);\n-\n-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &suc.update) < 0)\n-\t\t\tdie(_(\"bad value for update parameter\"));\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)\n-\t\treturn 1;\n-\n-\tif (pathspec.nr)\n-\t\tsuc.warn_if_uninitialized = 1;\n-\n-\treturn update_clone_submodules(&suc);\n-}\n-\n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n@@ -3561,7 +3464,6 @@ static struct cmd_struct commands[] = {\n \t{\"add-clone\", add_clone, 0},\n \t{\"update\", module_update, 0},\n \t{\"update-module-mode\", module_update_module_mode, 0},\n-\t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n \t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n \t{\"relative-path\", resolve_relative_path, 0},\n-- \n2.32.0\n\n"},{"id":"434858","messageId":"20210907115932.36068-10-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 09/13] submodule--helper: remove update-module-mode subcommand","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:28Z","receivedAt":"2021-09-07T12:00:38Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"This subcommand was once useful for 'submodule update', but now that we\nhave converted the shell code to C, it is no longer used.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 24 ------------------------\n 1 file changed, 24 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a628660d6b..e3e85600c3 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1993,29 +1993,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n \tfree(key);\n }\n \n-static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path, *update = NULL;\n-\tint just_cloned;\n-\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n-\n-\tif (argc < 3 || argc > 4)\n-\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n-\n-\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n-\tpath = argv[2];\n-\n-\tif (argc == 4)\n-\t\tupdate = argv[3];\n-\n-\tdetermine_submodule_update_strategy(the_repository,\n-\t\t\t\t\t    just_cloned, path, update,\n-\t\t\t\t\t    &update_strategy);\n-\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n-\n-\treturn 0;\n-}\n-\n struct update_clone_data {\n \tconst struct submodule *sub;\n \tstruct object_id oid;\n@@ -3463,7 +3440,6 @@ static struct cmd_struct commands[] = {\n \t{\"clone\", module_clone, 0},\n \t{\"add-clone\", add_clone, 0},\n \t{\"update\", module_update, 0},\n-\t{\"update-module-mode\", module_update_module_mode, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n \t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n \t{\"relative-path\", resolve_relative_path, 0},\n-- \n2.32.0\n\n"},{"id":"434859","messageId":"20210907115932.36068-11-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 10/13] submodule--helper: remove shell interface to ensure_core_worktree()","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:29Z","receivedAt":"2021-09-07T12:00:40Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"The 'ensure-core-worktree' subcommand is no longer needed since the\nconversion of the update code from shell to C.\n\nLet's remove the subcommand, and while we are at it, let's rename\n'do_ensure_core_worktree()' to 'ensure_core_worktree()' to signal that\nit is no longer a utility function meant to be called by another\nfunction.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 18 ++----------------\n 1 file changed, 2 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e3e85600c3..597e303889 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2740,7 +2740,7 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void do_ensure_core_worktree(const char *path)\n+static void ensure_core_worktree(const char *path)\n {\n \tconst struct submodule *sub;\n \tconst char *cw;\n@@ -2771,19 +2771,6 @@ static void do_ensure_core_worktree(const char *path)\n \t}\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path;\n-\n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\tdo_ensure_core_worktree(path);\n-\n-\treturn 0;\n-}\n-\n static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n@@ -3017,7 +3004,7 @@ static int update_submodule(struct update_data *update_data)\n \tchar *prefixed_path;\n \tstruct string_list err = STRING_LIST_INIT_DUP;\n \n-\tdo_ensure_core_worktree(update_data->sm_path);\n+\tensure_core_worktree(update_data->sm_path);\n \n \tif (update_data->recursive_prefix)\n \t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n@@ -3441,7 +3428,6 @@ static struct cmd_struct commands[] = {\n \t{\"add-clone\", add_clone, 0},\n \t{\"update\", module_update, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n-- \n2.32.0\n\n"},{"id":"434860","messageId":"20210907115932.36068-12-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 11/13] submodule--helper: remove print-default-remote subcommand","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:30Z","receivedAt":"2021-09-07T12:00:45Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"This subcommand was once useful for submodule functionality, but after\nthe various conversions of shell code to C, it is no longer used.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 16 ----------------\n 1 file changed, 16 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 597e303889..9470ff3de0 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -73,21 +73,6 @@ static char *get_default_remote(void)\n \treturn repo_get_default_remote(the_repository, refname);\n }\n \n-static int print_default_remote(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remote;\n-\n-\tif (argc != 1)\n-\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n-\n-\tremote = get_default_remote();\n-\tif (remote)\n-\t\tprintf(\"%s\\n\", remote);\n-\n-\tfree(remote);\n-\treturn 0;\n-}\n-\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -3434,7 +3419,6 @@ static struct cmd_struct commands[] = {\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n-\t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, 0},\n \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n-- \n2.32.0\n\n"},{"id":"434861","messageId":"20210907115932.36068-13-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 12/13] submodule--helper: remove relative-path subcommand","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:31Z","receivedAt":"2021-09-07T12:00:46Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"This subcommand was once used extensively for submodule functionality\nwhen it was written in shell, but now that we have converted the shell\ncode to C, it is no longer used.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 12 ------------\n 1 file changed, 12 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9470ff3de0..7622d6bd24 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2582,17 +2582,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \treturn 3;\n }\n \n-static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 3)\n-\t\tdie(\"submodule--helper relative-path takes exactly 2 arguments, got %d\", argc);\n-\n-\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n-\tstrbuf_release(&sb);\n-\treturn 0;\n-}\n-\n static const char *remote_submodule_branch(const char *path)\n {\n \tconst struct submodule *sub;\n@@ -3413,7 +3402,6 @@ static struct cmd_struct commands[] = {\n \t{\"add-clone\", add_clone, 0},\n \t{\"update\", module_update, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n-- \n2.32.0\n\n"},{"id":"434862","messageId":"20210907115932.36068-14-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH 13/13] submodule--helper: remove run-update-procedure subcommand","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T11:59:32Z","receivedAt":"2021-09-07T12:00:47Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"The subcommand 'submodule--helper run-update-procedure' is no longer\nneeded after the conversion of the bulk of 'update' to C.\n\nWhile we are at it, let's rename 'do_run_update_procedure()' to\n'run_update_procedure()' to reflect the fact that it is no longer a\nutility function meant to be wrapped in another function.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 73 +------------------------------------\n 1 file changed, 2 insertions(+), 71 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7622d6bd24..6565e2cd78 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2484,7 +2484,7 @@ static int run_update_command(struct update_data *ud, int subforce, struct strin\n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n+static int run_update_procedure(struct update_data *ud, struct string_list *err)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2514,74 +2514,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e\n \treturn run_update_command(ud, subforce, err);\n }\n \n-static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-{\n-\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n-\tchar *prefixed_path, *update = NULL;\n-\tstruct update_data update_data = UPDATE_DATA_INIT;\n-\tstruct string_list err = STRING_LIST_INIT_DUP;\n-\n-\tstruct option options[] = {\n-\t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n-\t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n-\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n-\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n-\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const usage[] = {\n-\t\tN_(\"git submodule--helper run-update-procedure [<options>] <path>\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\n-\tif (argc != 1)\n-\t\tusage_with_options(usage, options);\n-\n-\tupdate_data.force = !!force;\n-\tupdate_data.quiet = !!quiet;\n-\tupdate_data.nofetch = !!nofetch;\n-\tupdate_data.just_cloned = !!just_cloned;\n-\tupdate_data.sm_path = argv[0];\n-\n-\tif (update_data.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n-\telse\n-\t\tprefixed_path = xstrdup(update_data.sm_path);\n-\n-\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n-\n-\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n-\t\t\t\t\t    update_data.sm_path, update,\n-\t\t\t\t\t    &update_data.update_strategy);\n-\n-\tfree(prefixed_path);\n-\n-\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data, &err);\n-\n-\treturn 3;\n-}\n-\n static const char *remote_submodule_branch(const char *path)\n {\n \tconst struct submodule *sub;\n@@ -3018,7 +2950,7 @@ static int update_submodule(struct update_data *update_data)\n \t}\n \n \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n-\t\tif (do_run_update_procedure(update_data, &err))\n+\t\tif (run_update_procedure(update_data, &err))\n \t\t\treturn 1;\n \n \tif (update_data->recursive) {\n@@ -3401,7 +3333,6 @@ static struct cmd_struct commands[] = {\n \t{\"clone\", module_clone, 0},\n \t{\"add-clone\", add_clone, 0},\n \t{\"update\", module_update, 0},\n-\t{\"run-update-procedure\", run_update_procedure, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n-- \n2.32.0\n\n"},{"id":"434865","messageId":"875yvcmum2.fsf@evledraar.gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"Re: [PATCH 00/13] submodule: convert the rest of 'update' to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-09-07T12:34:51Z","receivedAt":"2021-09-07T12:35:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Sep 07 2021, Atharva Raykar wrote:\n\n> NOTE: This series uses ar/submodule-run-update-procedure [1]\n>\n> This series builds upon the previous conversion work on 'submodule update' and\n> moves out all of that shell logic in 'git-submodule.sh' into\n> 'builtin/submodule--helper.c'. Even though this patch series looks long, a lot\n> of it is preparatory patches and cleanup of unused functions that result from\n> this conversion. The real action happens at [6/8].\n\nIt looks like the 6/x part of that still applies, but not the \"/8\",\ni.e. this is now a 13-part series. Is this summary otherwise still\ncurrent with what's being submitted here?\n"},{"id":"434866","messageId":"871r60muge.fsf@evledraar.gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-3-raykar.ath@gmail.com","subject":"Re: [PATCH 02/13] submodule--helper: get remote names from any repository","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-09-07T12:37:51Z","receivedAt":"2021-09-07T12:38:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Sep 07 2021, Atharva Raykar wrote:\n\n> `get_default_remote()` retrieves the name of a remote by resolving the\n> refs from of the current repository's ref store.\n>\n> Thus in order to use it for retrieving the remote name of a submodule,\n> we have to start a new subprocess which runs from the submodule\n> directory.\n>\n> Let's instead introduce a function called `repo_get_default_remote()`\n> which takes any repository object and retrieves the remote accordingly.\n>\n> `get_default_remote()` is then defined as a call to\n> `repo_get_default_remote()` with 'the_repository' passed to it.\n\nI'd find this easier to follow if this were just squashed into the next\ncommit. Both are rather small, but following the context of first adding\na function, then using it, instead of just adding it, changing the old\nusers etc. is harder than just having it in one commit.\n"},{"id":"434868","messageId":"87wnnslfnz.fsf@evledraar.gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-7-raykar.ath@gmail.com","subject":"Re: [PATCH 06/13] submodule: move core cmd_update() logic to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-09-07T12:40:22Z","receivedAt":"2021-09-07T12:43:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Sep 07 2021, Atharva Raykar wrote:\n\n>  struct init_cb {\n>  \tconst char *prefix;\n> +\tconst char *superprefix;\n>  \tunsigned int flags;\n>  };\n> -#define INIT_CB_INIT { NULL, 0 }\n> +#define INIT_CB_INIT { NULL, NULL, 0 }\n\nSince you're doing some cleanup while you're at it, just changing this\nin some earlier step to:\n\n    define INIT_CB_INIT { 0 }\n\nIs better, i.e. the NULL-ing out is implicit here. I have an unsubmitted\nseries that does that across the codebase.\n\n> +\t.references = STRING_LIST_INIT_DUP, \\\n\nWe do inits here, and append, but it seems nothing clears this string_list.\n"},{"id":"434869","messageId":"87sfyglfl9.fsf@evledraar.gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-8-raykar.ath@gmail.com","subject":"Re: [PATCH 07/13] submodule: remove fetch_in_submodule shell function","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-09-07T12:44:27Z","receivedAt":"2021-09-07T12:45:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Sep 07 2021, Atharva Raykar wrote:\n\n> This function has no more use in 'git-submodule.sh' after\n> bd82d7d467 (submodule: move core cmd_update() logic to C, 2021-07-20),\n> where we moved all of its uses to C, which has its own version for the\n> same.\n\nThis commit ID appears to be a reference to your own 06/13, so the OID\nwon't work once this is merged to git.git.\n\nPerhaps just squash this into 06/13 instead?\n"},{"id":"434870","messageId":"87o894lfim.fsf@evledraar.gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-9-raykar.ath@gmail.com","subject":"Re: [PATCH 08/13] submodule--helper: remove update-clone subcommand","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-09-07T12:46:10Z","receivedAt":"2021-09-07T12:46:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Sep 07 2021, Atharva Raykar wrote:\n\n> We no longer need this subcommand as the shell version calls the\n> 'update' subcommand instead, which does all the cloning within C itself.\n>\n> We also no longer need the 'update_clone_submodules()' and\n> 'update_clone_submodule()' functions, so we remove those as well.\n\nSo in 04/13 update_clone_submodules() was renamed, but now we're getting\nrid of it. Maybe there's not an easy way to avoid this churn, but if there is...\n"},{"id":"434872","messageId":"87k0jslf3p.fsf@evledraar.gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-10-raykar.ath@gmail.com","subject":"Re: [PATCH 09/13] submodule--helper: remove update-module-mode subcommand","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-09-07T12:49:49Z","receivedAt":"2021-09-07T12:55:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Sep 07 2021, Atharva Raykar wrote:\n\n> This subcommand was once useful for 'submodule update', but now that we\n> have converted the shell code to C, it is no longer used.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 24 ------------------------\n>  1 file changed, 24 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index a628660d6b..e3e85600c3 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -1993,29 +1993,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n>  \tfree(key);\n>  }\n>  \n> -static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n> -{\n> -\tconst char *path, *update = NULL;\n> -\tint just_cloned;\n> -\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n> -\n> -\tif (argc < 3 || argc > 4)\n> -\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n> -\n> -\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n> -\tpath = argv[2];\n> -\n> -\tif (argc == 4)\n> -\t\tupdate = argv[3];\n> -\n> -\tdetermine_submodule_update_strategy(the_repository,\n> -\t\t\t\t\t    just_cloned, path, update,\n> -\t\t\t\t\t    &update_strategy);\n> -\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n> -\n> -\treturn 0;\n> -}\n> -\n>  struct update_clone_data {\n>  \tconst struct submodule *sub;\n>  \tstruct object_id oid;\n> @@ -3463,7 +3440,6 @@ static struct cmd_struct commands[] = {\n>  \t{\"clone\", module_clone, 0},\n>  \t{\"add-clone\", add_clone, 0},\n>  \t{\"update\", module_update, 0},\n> -\t{\"update-module-mode\", module_update_module_mode, 0},\n>  \t{\"run-update-procedure\", run_update_procedure, 0},\n>  \t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n>  \t{\"relative-path\", resolve_relative_path, 0},\n\nSo in https://lore.kernel.org/git/87sfyglfl9.fsf@evledraar.gmail.com I\nsuggested squashing the shell removal, but I see now that here later in\n09-13/13.\n\nSo yeah, having 08/13 stand-alone is easier to read then, but I think\nthen squashing all of 09-13 together is better. I.e. there's no reason\nto remove these one at a time, let's just remove them all at once.\n\nThat also makes it clear that it's a remove-only change aside from your\n\"refactor while at it\" of renaming this function:\n\n    -static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n    +static int run_update_procedure(struct update_data *ud, struct string_list *err)\n\nWe could either skip that, or split that later refactoring into another\ncommit.\n\nThanks for working on this, I'm exciting to see more of git-submodule.sh\ngo away. Hopefully these comments I left are useful / will aid future\nreviewer readability of this series.\n"},{"id":"434873","messageId":"m2fsuglf2z.fsf@gmail.com","threadId":"56453","inReplyTo":"875yvcmum2.fsf@evledraar.gmail.com","subject":"Re: [PATCH 00/13] submodule: convert the rest of 'update' to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T12:53:20Z","receivedAt":"2021-09-07T12:56:21Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Tue, Sep 07 2021, Atharva Raykar wrote:\n>\n>> NOTE: This series uses ar/submodule-run-update-procedure [1]\n>>\n>> This series builds upon the previous conversion work on 'submodule update' and\n>> moves out all of that shell logic in 'git-submodule.sh' into\n>> 'builtin/submodule--helper.c'. Even though this patch series looks long, a lot\n>> of it is preparatory patches and cleanup of unused functions that result from\n>> this conversion. The real action happens at [6/8].\n>\n> It looks like the 6/x part of that still applies, but not the \"/8\",\n> i.e. this is now a 13-part series. Is this summary otherwise still\n> current with what's being submitted here?\n\nSorry, I meant [6/13], this is meant to be 13 parts only. Other than\nthat typo, the summary is up-to-date with what the series contains (I\nwrote all of it today).\n"},{"id":"434883","messageId":"m2czpklcnh.fsf@gmail.com","threadId":"56453","inReplyTo":"871r60muge.fsf@evledraar.gmail.com","subject":"Re: [PATCH 02/13] submodule--helper: get remote names from any repository","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T13:33:48Z","receivedAt":"2021-09-07T13:48:47Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Tue, Sep 07 2021, Atharva Raykar wrote:\n>\n>> `get_default_remote()` retrieves the name of a remote by resolving the\n>> refs from of the current repository's ref store.\n>>\n>> Thus in order to use it for retrieving the remote name of a submodule,\n>> we have to start a new subprocess which runs from the submodule\n>> directory.\n>>\n>> Let's instead introduce a function called `repo_get_default_remote()`\n>> which takes any repository object and retrieves the remote accordingly.\n>>\n>> `get_default_remote()` is then defined as a call to\n>> `repo_get_default_remote()` with 'the_repository' passed to it.\n>\n> I'd find this easier to follow if this were just squashed into the next\n> commit. Both are rather small, but following the context of first adding\n> a function, then using it, instead of just adding it, changing the old\n> users etc. is harder than just having it in one commit.\n\nI am in two minds about this. I initially had both these changes in one\ncommit, but Christian suggested I split the changes into a part that\nrefactors existing code (this commit), and one that introduces a new\nhelper (the next commit).\n\nI guess I will squash it for now and see how it is received. Maybe\nbringing down the \"/13\" might help get more reviews ;-)\n"},{"id":"434884","messageId":"m2a6kolcfu.fsf@gmail.com","threadId":"56453","inReplyTo":"87k0jslf3p.fsf@evledraar.gmail.com","subject":"Re: [PATCH 09/13] submodule--helper: remove update-module-mode subcommand","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-07T13:50:18Z","receivedAt":"2021-09-07T13:53:26Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Tue, Sep 07 2021, Atharva Raykar wrote:\n>\n>> This subcommand was once useful for 'submodule update', but now that we\n>> have converted the shell code to C, it is no longer used.\n>>\n>> Mentored-by: Christian Couder <christian.couder@gmail.com>\n>> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n>> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n>> ---\n>>  builtin/submodule--helper.c | 24 ------------------------\n>>  1 file changed, 24 deletions(-)\n>>\n>> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n>> index a628660d6b..e3e85600c3 100644\n>> --- a/builtin/submodule--helper.c\n>> +++ b/builtin/submodule--helper.c\n>> @@ -1993,29 +1993,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n>>  \tfree(key);\n>>  }\n>>\n>> -static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n>> -{\n>> -\tconst char *path, *update = NULL;\n>> -\tint just_cloned;\n>> -\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n>> -\n>> -\tif (argc < 3 || argc > 4)\n>> -\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n>> -\n>> -\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n>> -\tpath = argv[2];\n>> -\n>> -\tif (argc == 4)\n>> -\t\tupdate = argv[3];\n>> -\n>> -\tdetermine_submodule_update_strategy(the_repository,\n>> -\t\t\t\t\t    just_cloned, path, update,\n>> -\t\t\t\t\t    &update_strategy);\n>> -\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n>> -\n>> -\treturn 0;\n>> -}\n>> -\n>>  struct update_clone_data {\n>>  \tconst struct submodule *sub;\n>>  \tstruct object_id oid;\n>> @@ -3463,7 +3440,6 @@ static struct cmd_struct commands[] = {\n>>  \t{\"clone\", module_clone, 0},\n>>  \t{\"add-clone\", add_clone, 0},\n>>  \t{\"update\", module_update, 0},\n>> -\t{\"update-module-mode\", module_update_module_mode, 0},\n>>  \t{\"run-update-procedure\", run_update_procedure, 0},\n>>  \t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n>>  \t{\"relative-path\", resolve_relative_path, 0},\n>\n> So in https://lore.kernel.org/git/87sfyglfl9.fsf@evledraar.gmail.com I\n> suggested squashing the shell removal, but I see now that here later in\n> 09-13/13.\n>\n> So yeah, having 08/13 stand-alone is easier to read then, but I think\n> then squashing all of 09-13 together is better. I.e. there's no reason\n> to remove these one at a time, let's just remove them all at once.\n\nOkay, I shall do this.\n\n> That also makes it clear that it's a remove-only change aside from your\n> \"refactor while at it\" of renaming this function:\n>\n>     -static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n>     +static int run_update_procedure(struct update_data *ud, struct string_list *err)\n>\n> We could either skip that, or split that later refactoring into another\n> commit.\n>\n> Thanks for working on this, I'm exciting to see more of git-submodule.sh\n> go away. Hopefully these comments I left are useful / will aid future\n> reviewer readability of this series.\n\nThanks for your suggestions. I've gone through all of them, and I'll\nreroll soon.\n"},{"id":"436097","messageId":"20210916103241.62376-1-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"[PATCH v2 0/8] submodule: convert the rest of 'update' to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-16T10:32:33Z","receivedAt":"2021-09-16T10:33:06Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"NOTE: This series uses ar/submodule-run-update-procedure, which is now part of\n'next'. [1]\n\nSince v1:\n  I have incorporated Ævar's suggestions, and attempted to make this easier to\n  review.\n\nThis series builds upon the previous conversion work on 'submodule update' and\nmoves out all of that shell logic in 'git-submodule.sh' into\n'builtin/submodule--helper.c'. Even though this patch series looks a bit long, a\nlot of it is preparatory patches and cleanup of unused functions that result\nfrom this conversion. The real action happens at [5/8].\n\nAs with the other series, the goal is to be a faithful conversion, with no\nchange in behaviour.\n\nThis would be the last command whose logic would be moved into C, other than\n'submodule add', whose patches have been sent already.\n\nAfter this works out, we can invert the shell-C relationship and make\n'submodule' a proper C builtin.\n\nFetch-it-Via:\ngit fetch https://github.com/tfidfwastaken/git submodule-update-list-2\n\n[1] https://lore.kernel.org/git/20210824140609.1496-1-raykar.ath@gmail.com/\n\nAtharva Raykar (8):\n  submodule--helper: split up ensure_core_worktree()\n  submodule--helper: get remote names from any repository\n  submodule--helper: rename helpers for update-clone\n  submodule--helper: refactor get_submodule_displaypath()\n  submodule: move core cmd_update() logic to C\n  submodule--helper: remove update-clone subcommand\n  submodule--helper: remove unused helpers\n  submodule--helper: rename helper functions\n\n builtin/submodule--helper.c | 767 +++++++++++++++++++++---------------\n git-submodule.sh            | 145 +------\n 2 files changed, 458 insertions(+), 454 deletions(-)\n\nRange-diff against v1:\n 1:  2cfdc0e10a <  -:  ---------- submodule--helper: get remote names from any repository\n -:  ---------- >  1:  f83a5b7f34 submodule--helper: split up ensure_core_worktree()\n 2:  be83ba7fdb !  2:  7f4e24ce25 submodule--helper: introduce get_default_remote_submodule()\n    @@ Metadata\n     Author: Atharva Raykar <raykar.ath@gmail.com>\n     \n      ## Commit message ##\n    -    submodule--helper: introduce get_default_remote_submodule()\n    +    submodule--helper: get remote names from any repository\n     \n    -    Before 8ef1d2b549 (submodule--helper: get remote names from any\n    -    repository, 2021-07-20), it was not possible to directly retrieve a\n    -    submodule's remote name within the same process, because\n    -    `get_default_remote()` used only knew about the current repository.\n    +    `get_default_remote()` retrieves the name of a remote by resolving the\n    +    refs from of the current repository's ref store.\n    +\n    +    Thus in order to use it for retrieving the remote name of a submodule,\n    +    we have to start a new subprocess which runs from the submodule\n    +    directory.\n    +\n    +    Let's instead introduce a function called `repo_get_default_remote()`\n    +    which takes any repository object and retrieves the remote accordingly.\n    +\n    +    `get_default_remote()` is then defined as a call to\n    +    `repo_get_default_remote()` with 'the_repository' passed to it.\n     \n         Now that we have `repo_get_default_remote()`, we no longer have to start\n         a subprocess that called `submodule--helper get-default-remote` from\n         within the submodule directory.\n     \n    -    Let's make a function called `get_default_remote_submodule()` which\n    +    So let's make a function called `get_default_remote_submodule()` which\n         takes a submodule path, and returns the default remote for that\n         submodule, all within the same process.\n     \n    @@ Commit message\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static char *repo_get_default_remote(struct repository *repo, const char *refnam\n    +@@\n    + typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n    + \t\t\t\t  void *cb_data);\n    + \n    +-static char *get_default_remote(void)\n    ++static char *repo_get_default_remote(struct repository *repo, const char *refname)\n    + {\n    + \tchar *dest = NULL, *ret;\n    + \tstruct strbuf sb = STRBUF_INIT;\n    +-\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n    + \n    + \tif (!refname)\n    + \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n    +@@ builtin/submodule--helper.c: static char *get_default_remote(void)\n    + \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n    + \n    + \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n    +-\tif (git_config_get_string(sb.buf, &dest))\n    ++\tif (repo_config_get_string(repo, sb.buf, &dest))\n    + \t\tret = xstrdup(\"origin\");\n    + \telse\n    + \t\tret = dest;\n    +@@ builtin/submodule--helper.c: static char *get_default_remote(void)\n      \treturn ret;\n      }\n      \n    @@ builtin/submodule--helper.c: static char *repo_get_default_remote(struct reposit\n     +\treturn repo_get_default_remote(&subrepo, refname);\n     +}\n     +\n    - static char *get_default_remote(void)\n    ++static char *get_default_remote(void)\n    ++{\n    ++\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n    ++\treturn repo_get_default_remote(the_repository, refname);\n    ++}\n    ++\n    + static int print_default_remote(int argc, const char **argv, const char *prefix)\n      {\n    - \tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n    + \tchar *remote;\n     @@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const char *prefix,\n      \tchar *remote_key = NULL;\n      \tchar *sub_origin_url, *super_config_url, *displaypath;\n 3:  8981b2c4c5 =  3:  390596ee7c submodule--helper: rename helpers for update-clone\n 4:  420d792f99 =  4:  2a2ddcac91 submodule--helper: refactor get_submodule_displaypath()\n 5:  6c4696b70a !  5:  832020a290 submodule: move core cmd_update() logic to C\n    @@ Commit message\n         `init_submodule()`, which will now also take an explicit 'superprefix'\n         argument.\n     \n    +    While we are at it, we also remove the fetch_in_submodule() shell\n    +    function since it is no longer used anywhere.\n    +\n         [1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n     \n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n    @@ builtin/submodule--helper.c: static char *compute_submodule_clone_url(const char\n      \tunsigned int flags;\n      };\n     -#define INIT_CB_INIT { NULL, 0 }\n    -+#define INIT_CB_INIT { NULL, NULL, 0 }\n    ++#define INIT_CB_INIT { 0 }\n      \n      static void init_submodule(const char *path, const char *prefix,\n     -\t\t\t   unsigned int flags)\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t *   checkout involve more straightforward sequential I/O.\n     +\t * - the listener can avoid doing any work if fetching failed.\n     +\t */\n    -+\tif (suc.quickstop)\n    ++\tif (suc.quickstop) {\n    ++\t\tstring_list_clear(&update_data->references, 0);\n     +\t\treturn 1;\n    ++\t}\n     +\n     +\tfor (i = 0; i < suc.update_clone_nr; i++) {\n     +\t\tstruct update_clone_data ucd = suc.update_clone[i];\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\t\tres = 1;\n     +\t}\n     +\n    ++\tstring_list_clear(&update_data->references, 0);\n     +\treturn res;\n     +}\n     +\n    @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {\n      \t{\"run-update-procedure\", run_update_procedure, 0},\n     \n      ## git-submodule.sh ##\n    +@@ git-submodule.sh: cmd_deinit()\n    + \tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- \"$@\"\n    + }\n    + \n    +-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]\n    +-# Because arguments are positional, use an empty string to omit <depth>\n    +-# but include <sha1>.\n    +-fetch_in_submodule () (\n    +-\tsanitize_submodule_env &&\n    +-\tcd \"$1\" &&\n    +-\tif test $# -eq 3\n    +-\tthen\n    +-\t\techo \"$3\" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+\"$2\"}\n    +-\telse\n    +-\t\tgit fetch ${GIT_QUIET:+--quiet} ${2:+\"$2\"}\n    +-\tfi\n    +-)\n    +-\n    + #\n    + # Update each submodule path to correct revision, using clone and checkout as needed\n    + #\n     @@ git-submodule.sh: cmd_update()\n      \t\tshift\n      \tdone\n 6:  524ae77c3f <  -:  ---------- submodule: remove fetch_in_submodule shell function\n 7:  ea56f7319a =  6:  fb3fa8174a submodule--helper: remove update-clone subcommand\n 8:  10a62172a2 <  -:  ---------- submodule--helper: remove update-module-mode subcommand\n 9:  dbbe5d3f53 <  -:  ---------- submodule--helper: remove shell interface to ensure_core_worktree()\n10:  a015af3a16 <  -:  ---------- submodule--helper: remove print-default-remote subcommand\n11:  f5a7ba1405 <  -:  ---------- submodule--helper: remove relative-path subcommand\n12:  9f54eb5972 !  7:  364f72f870 submodule--helper: remove run-update-procedure subcommand\n    @@ Metadata\n     Author: Atharva Raykar <raykar.ath@gmail.com>\n     \n      ## Commit message ##\n    -    submodule--helper: remove run-update-procedure subcommand\n    +    submodule--helper: remove unused helpers\n     \n    -    The subcommand 'submodule--helper run-update-procedure' is no longer\n    -    needed after the conversion of the bulk of 'update' to C.\n    -\n    -    While we are at it, let's rename 'do_run_update_procedure()' to\n    -    'run_update_procedure()' to reflect the fact that it is no longer a\n    -    utility function meant to be wrapped in another function.\n    +    These helpers were useful back when 'submodule update' had most of its\n    +    logic in shell. Now that they will never be invoked, let us remove them.\n     \n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n         Mentored-by: Shourya Shukla <periperidip@gmail.com>\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce, struct strin\n    - \treturn 0;\n    +@@ builtin/submodule--helper.c: static char *get_default_remote(void)\n    + \treturn repo_get_default_remote(the_repository, refname);\n      }\n      \n    --static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n    -+static int run_update_procedure(struct update_data *ud, struct string_list *err)\n    +-static int print_default_remote(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tchar *remote;\n    +-\n    +-\tif (argc != 1)\n    +-\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n    +-\n    +-\tremote = get_default_remote();\n    +-\tif (remote)\n    +-\t\tprintf(\"%s\\n\", remote);\n    +-\n    +-\tfree(remote);\n    +-\treturn 0;\n    +-}\n    +-\n    + static int starts_with_dot_slash(const char *str)\n      {\n    - \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n    + \treturn str[0] == '.' && is_dir_sep(str[1]);\n    +@@ builtin/submodule--helper.c: static void determine_submodule_update_strategy(struct repository *r,\n    + \tfree(key);\n    + }\n      \n    +-static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tconst char *path, *update = NULL;\n    +-\tint just_cloned;\n    +-\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n    +-\n    +-\tif (argc < 3 || argc > 4)\n    +-\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n    +-\n    +-\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n    +-\tpath = argv[2];\n    +-\n    +-\tif (argc == 4)\n    +-\t\tupdate = argv[3];\n    +-\n    +-\tdetermine_submodule_update_strategy(the_repository,\n    +-\t\t\t\t\t    just_cloned, path, update,\n    +-\t\t\t\t\t    &update_strategy);\n    +-\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n    +-\n    +-\treturn 0;\n    +-}\n    +-\n    + struct update_clone_data {\n    + \tconst struct submodule *sub;\n    + \tstruct object_id oid;\n     @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_data *ud, struct string_list *e\n      \treturn run_update_command(ud, subforce, err);\n      }\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -\n     -\treturn 3;\n     -}\n    +-\n    +-static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tstruct strbuf sb = STRBUF_INIT;\n    +-\tif (argc != 3)\n    +-\t\tdie(\"submodule--helper relative-path takes exactly 2 arguments, got %d\", argc);\n    +-\n    +-\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n    +-\tstrbuf_release(&sb);\n    +-\treturn 0;\n    +-}\n     -\n      static const char *remote_submodule_branch(const char *path)\n      {\n      \tconst struct submodule *sub;\n    -@@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data)\n    +@@ builtin/submodule--helper.c: static void do_ensure_core_worktree(const char *path)\n      \t}\n    + }\n      \n    - \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n    --\t\tif (do_run_update_procedure(update_data, &err))\n    -+\t\tif (run_update_procedure(update_data, &err))\n    - \t\t\treturn 1;\n    - \n    - \tif (update_data->recursive) {\n    +-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tconst char *path;\n    +-\n    +-\tif (argc != 2)\n    +-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n    +-\n    +-\tpath = argv[1];\n    +-\tdo_ensure_core_worktree(path);\n    +-\n    +-\treturn 0;\n    +-}\n    +-\n    + static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n    + {\n    + \tint i;\n     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {\n      \t{\"clone\", module_clone, 0},\n      \t{\"add-clone\", add_clone, 0},\n      \t{\"update\", module_update, 0},\n    +-\t{\"update-module-mode\", module_update_module_mode, 0},\n     -\t{\"run-update-procedure\", run_update_procedure, 0},\n    +-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n    +-\t{\"relative-path\", resolve_relative_path, 0},\n      \t{\"resolve-relative-url\", resolve_relative_url, 0},\n      \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n      \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n    + \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n    + \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n    +-\t{\"print-default-remote\", print_default_remote, 0},\n    + \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n    + \t{\"deinit\", module_deinit, 0},\n    + \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n -:  ---------- >  8:  ca48dd452c submodule--helper: rename helper functions\n-- \n2.32.0\n\n"},{"id":"436098","messageId":"20210916103241.62376-2-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210916103241.62376-1-raykar.ath@gmail.com","subject":"[PATCH v2 1/8] submodule--helper: split up ensure_core_worktree()","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-16T10:32:34Z","receivedAt":"2021-09-16T10:33:09Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"Let's split up `ensure_core_worktree()` so that we can call it from C\ncode without needing to deal with command line arguments.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 80619361fc..97512ccf0b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2794,18 +2794,12 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+static void do_ensure_core_worktree(const char *path)\n {\n \tconst struct submodule *sub;\n-\tconst char *path;\n \tconst char *cw;\n \tstruct repository subrepo;\n \n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \tif (!sub)\n \t\tBUG(\"We could get the submodule handle before?\");\n@@ -2829,6 +2823,17 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n+}\n+\n+static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *path;\n+\n+\tif (argc != 2)\n+\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n+\n+\tpath = argv[1];\n+\tdo_ensure_core_worktree(path);\n \n \treturn 0;\n }\n-- \n2.32.0\n\n"},{"id":"436099","messageId":"20210916103241.62376-3-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210916103241.62376-1-raykar.ath@gmail.com","subject":"[PATCH v2 2/8] submodule--helper: get remote names from any repository","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-16T10:32:35Z","receivedAt":"2021-09-16T10:33:12Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"`get_default_remote()` retrieves the name of a remote by resolving the\nrefs from of the current repository's ref store.\n\nThus in order to use it for retrieving the remote name of a submodule,\nwe have to start a new subprocess which runs from the submodule\ndirectory.\n\nLet's instead introduce a function called `repo_get_default_remote()`\nwhich takes any repository object and retrieves the remote accordingly.\n\n`get_default_remote()` is then defined as a call to\n`repo_get_default_remote()` with 'the_repository' passed to it.\n\nNow that we have `repo_get_default_remote()`, we no longer have to start\na subprocess that called `submodule--helper get-default-remote` from\nwithin the submodule directory.\n\nSo let's make a function called `get_default_remote_submodule()` which\ntakes a submodule path, and returns the default remote for that\nsubmodule, all within the same process.\n\nWe can now use this function to save an unnecessary subprocess spawn in\n`sync_submodule()`, and also in the next patch, which will require this\nfunctionality.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 34 +++++++++++++++++++++++-----------\n 1 file changed, 23 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 97512ccf0b..f6c4fc349b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -29,11 +29,10 @@\n typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n \t\t\t\t  void *cb_data);\n \n-static char *get_default_remote(void)\n+static char *repo_get_default_remote(struct repository *repo, const char *refname)\n {\n \tchar *dest = NULL, *ret;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n \n \tif (!refname)\n \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n@@ -46,7 +45,7 @@ static char *get_default_remote(void)\n \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n \n \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n-\tif (git_config_get_string(sb.buf, &dest))\n+\tif (repo_config_get_string(repo, sb.buf, &dest))\n \t\tret = xstrdup(\"origin\");\n \telse\n \t\tret = dest;\n@@ -55,6 +54,25 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static char *get_default_remote_submodule(const char *module_path)\n+{\n+\tconst char *refname;\n+\tconst struct submodule *sub;\n+\tstruct repository subrepo;\n+\n+\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n+\t\t\t\t\t  \"HEAD\", 0, NULL, NULL);\n+\tsub = submodule_from_path(the_repository, null_oid(), module_path);\n+\trepo_submodule_init(&subrepo, the_repository, sub);\n+\treturn repo_get_default_remote(&subrepo, refname);\n+}\n+\n+static char *get_default_remote(void)\n+{\n+\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n+\treturn repo_get_default_remote(the_repository, refname);\n+}\n+\n static int print_default_remote(int argc, const char **argv, const char *prefix)\n {\n \tchar *remote;\n@@ -1369,7 +1387,6 @@ static void sync_submodule(const char *path, const char *prefix,\n \tchar *remote_key = NULL;\n \tchar *sub_origin_url, *super_config_url, *displaypath;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *sub_config_path = NULL;\n \n \tif (!is_submodule_active(the_repository, path))\n@@ -1418,14 +1435,9 @@ static void sync_submodule(const char *path, const char *prefix,\n \tif (!is_submodule_populated_gently(path, NULL))\n \t\tgoto cleanup;\n \n-\tprepare_submodule_repo_env(&cp.env_array);\n-\tcp.git_cmd = 1;\n-\tcp.dir = path;\n-\tstrvec_pushl(&cp.args, \"submodule--helper\",\n-\t\t     \"print-default-remote\", NULL);\n-\n \tstrbuf_reset(&sb);\n-\tif (capture_command(&cp, &sb, 0))\n+\tstrbuf_addstr(&sb, get_default_remote_submodule(path));\n+\tif (!sb.buf)\n \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n \t\t      path);\n \n-- \n2.32.0\n\n"},{"id":"436100","messageId":"20210916103241.62376-4-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210916103241.62376-1-raykar.ath@gmail.com","subject":"[PATCH v2 3/8] submodule--helper: rename helpers for update-clone","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-16T10:32:36Z","receivedAt":"2021-09-16T10:33:15Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"The `update-clone` subcommand helpers that perform the parallel clone\nand printing to stdout for shell script consumption, are renamed.\n\nThis lets us use the names `update_submodules()` and\n`update_submodule()` for the helpers in the next patch, when we create\nan `update` subcommand that does a full conversion.\n\nWe will get rid of these helpers in a cleanup patch at the end of this\nseries, when the `update-clone` command is no longer useful to us.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex f6c4fc349b..b0336b0377 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2499,7 +2499,7 @@ static int do_run_update_procedure(struct update_data *ud)\n \treturn run_update_command(ud, subforce);\n }\n \n-static void update_submodule(struct update_clone_data *ucd)\n+static void update_clone_submodule(struct update_clone_data *ucd)\n {\n \tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n \t\toid_to_hex(&ucd->oid),\n@@ -2507,7 +2507,7 @@ static void update_submodule(struct update_clone_data *ucd)\n \t\tucd->sub->path);\n }\n \n-static int update_submodules(struct submodule_update_clone *suc)\n+static int update_clone_submodules(struct submodule_update_clone *suc)\n {\n \tint i;\n \n@@ -2528,7 +2528,7 @@ static int update_submodules(struct submodule_update_clone *suc)\n \t\treturn 1;\n \n \tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_submodule(&suc->update_clone[i]);\n+\t\tupdate_clone_submodule(&suc->update_clone[i]);\n \n \treturn 0;\n }\n@@ -2593,7 +2593,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \tif (pathspec.nr)\n \t\tsuc.warn_if_uninitialized = 1;\n \n-\treturn update_submodules(&suc);\n+\treturn update_clone_submodules(&suc);\n }\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-- \n2.32.0\n\n"},{"id":"436101","messageId":"20210916103241.62376-5-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210916103241.62376-1-raykar.ath@gmail.com","subject":"[PATCH v2 4/8] submodule--helper: refactor get_submodule_displaypath()","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-16T10:32:37Z","receivedAt":"2021-09-16T10:33:20Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"We create a function called `do_get_submodule_displaypath()` that\ngenerates the display path required by several submodule functions, and\ntakes a custom superprefix parameter, instead of reading it from the\nenvironment.\n\nWe then redefine the existing `get_submodule_displaypath()` function\nas a call to this new function, where the superprefix is obtained from\nthe environment.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b0336b0377..10de01a1f7 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -269,11 +269,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\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 *do_get_submodule_displaypath(const char *path, const char *prefix, 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@@ -289,6 +286,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \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+\treturn do_get_submodule_displaypath(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-- \n2.32.0\n\n"},{"id":"436102","messageId":"20210916103241.62376-6-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210916103241.62376-1-raykar.ath@gmail.com","subject":"[PATCH v2 5/8] submodule: move core cmd_update() logic to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-16T10:32:38Z","receivedAt":"2021-09-16T10:33:26Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"This patch completes the conversion past the flag parsing of\n`submodule update` by introducing a helper subcommand called\n`submodule--helper update`. The behaviour of `submodule update` should\nremain the same after this patch.\n\nWe add more fields to the `struct update_data` that are required by\n`struct submodule_update_clone` to be able to perform a clone, when that\nis needed to be done.\n\nRecursing on a submodule is done by calling a subprocess that launches\n`submodule--helper update`, with a modified `--recursive-prefix` and\n`--prefix` parameter.\n\nWe also introduce `update_submodules()` and `update_submodule()` which\nare quite similar to `update_clone_submodules()` and\n`update_clone_submodule()`, and will supersede them.\n\nWhen the `--init` flag is passed to the subcommand, we do not spawn a\nnew subprocess and call `submodule--helper init` on the submodule paths,\nbecause the Git machinery is not able to pick up the configuration\nchanges introduced by that init call[1]. So we instead run the\n`init_submodule_cb()` callback over each submodule directly.\n\nThis introduces another problem, because there is no mechanism to pass\nthe superproject path prefix (ie, `--super-prefix`) without starting a\nnew git process. This field is required for obtaining the display path\nfor that is used by the command's output messages. So let's add a field\ninto the `init_cb` struct that lets us pass this information to\n`init_submodule()`, which will now also take an explicit 'superprefix'\nargument.\n\nWhile we are at it, we also remove the fetch_in_submodule() shell\nfunction since it is no longer used anywhere.\n\n[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 505 ++++++++++++++++++++++++++++++------\n git-submodule.sh            | 145 +----------\n 2 files changed, 433 insertions(+), 217 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 10de01a1f7..1eea626864 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -634,18 +634,22 @@ static char *compute_submodule_clone_url(const char *rel_url)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *superprefix;\n \tunsigned int flags;\n };\n-#define INIT_CB_INIT { NULL, 0 }\n+#define INIT_CB_INIT { 0 }\n \n static void init_submodule(const char *path, const char *prefix,\n-\t\t\t   unsigned int flags)\n+\t\t\t   const char *superprefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\t/* try superprefix from the environment, if it is not passed explicitly */\n+\tif (!superprefix)\n+\t\tsuperprefix = get_super_prefix();\n+\tdisplaypath = do_get_submodule_displaypath(path, prefix, superprefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -719,7 +723,7 @@ static void init_submodule(const char *path, const char *prefix,\n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct init_cb *info = cb_data;\n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n@@ -2039,7 +2043,6 @@ struct submodule_update_clone {\n \tconst char *prefix;\n \tint single_branch;\n \n-\t/* to be consumed by git-submodule.sh */\n \tstruct update_clone_data *update_clone;\n \tint update_clone_nr; int update_clone_alloc;\n \n@@ -2062,19 +2065,63 @@ struct submodule_update_clone {\n }\n \n struct update_data {\n+\tconst char *prefix;\n \tconst char *recursive_prefix;\n \tconst char *sm_path;\n \tconst char *displaypath;\n \tstruct object_id oid;\n \tstruct object_id suboid;\n-\tstruct submodule_update_strategy update_strategy;\n+\tint max_jobs;\n \tint depth;\n+\tint recommend_shallow;\n+\tint single_branch;\n+\tunsigned int init: 1;\n \tunsigned int force: 1;\n \tunsigned int quiet: 1;\n \tunsigned int nofetch: 1;\n-\tunsigned int just_cloned: 1;\n+\tunsigned int remote: 1;\n+\tunsigned int recursive: 1;\n+\tunsigned int progress: 1;\n+\tunsigned int dissociate: 1;\n+\tunsigned int require_init: 1;\n+\tunsigned warn_if_uninitialized : 1;\n+\tunsigned int just_cloned : 1;\n+\tstruct submodule_update_strategy update_strategy;\n+\tstruct string_list references;\n+\tstruct module_list list;\n };\n-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }\n+#define UPDATE_DATA_INIT { \\\n+\t.list = MODULE_LIST_INIT, \\\n+\t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+\t.recommend_shallow = -1, \\\n+\t.references = STRING_LIST_INIT_DUP, \\\n+\t.single_branch = -1, \\\n+\t.max_jobs = 1, \\\n+}\n+\n+static void update_clone_from_update_data(struct submodule_update_clone *suc,\n+\t\t\t\t\t  struct update_data *update_data)\n+{\n+\tsuc->prefix = update_data->prefix;\n+\tsuc->recursive_prefix = update_data->recursive_prefix;\n+\tsuc->max_jobs = update_data->max_jobs;\n+\tsuc->progress = update_data->progress;\n+\tsuc->quiet = update_data->quiet;\n+\tsuc->dissociate = update_data->dissociate;\n+\tsuc->require_init = update_data->require_init;\n+\tsuc->single_branch = update_data->single_branch;\n+\tsuc->warn_if_uninitialized = update_data->warn_if_uninitialized;\n+\tsuc->list = update_data->list;\n+\tsuc->update = update_data->update_strategy;\n+\tsuc->recommend_shallow = update_data->recommend_shallow;\n+\tif (update_data->depth)\n+\t\tsuc->depth = xstrfmt(\"--depth=%d\", update_data->depth);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstring_list_append(&suc->references, item->string);\n+\t}\n+}\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n \t\tstruct strbuf *out, const char *displaypath)\n@@ -2369,111 +2416,113 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \treturn run_command(&cp);\n }\n \n-static int run_update_command(struct update_data *ud, int subforce)\n+static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)\n {\n-\tstruct strvec args = STRVEC_INIT;\n-\tstruct strvec child_env = STRVEC_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n+\tstruct strbuf out = STRBUF_INIT;\n \tint must_die_on_failure = 0;\n-\tint git_cmd;\n+\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n \n-\tswitch (ud->update_strategy.type) {\n+\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n+\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n+\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n+\telse\n+\t\tstrategy = ud->update_strategy;\n+\n+\tcp.dir = xstrdup(ud->sm_path);\n+\tswitch (strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_pushl(&args, \"checkout\", \"-q\", NULL);\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n \t\tif (subforce)\n-\t\t\tstrvec_push(&args, \"-f\");\n+\t\t\tstrvec_push(&cp.args, \"-f\");\n \t\tbreak;\n \tcase SM_UPDATE_REBASE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"rebase\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_MERGE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"merge\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n-\t\tgit_cmd = 0;\n-\t\tstrvec_push(&args, ud->update_strategy.command);\n+\t\tcp.git_cmd = 0;\n+\t\tcp.use_shell = 1;\n+\t\tstrvec_push(&cp.args, strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t    submodule_strategy_to_string(&strategy));\n \t}\n-\tstrvec_push(&args, oid);\n+\tstrvec_push(&cp.args, oid);\n \n-\tprepare_submodule_repo_env(&child_env);\n-\tif (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,\n-\t\t\t\t     ud->sm_path, child_env.v)) {\n-\t\tswitch (ud->update_strategy.type) {\n-\t\tcase SM_UPDATE_CHECKOUT:\n-\t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tcase SM_UPDATE_REBASE:\n-\t\t\tprintf(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tcase SM_UPDATE_MERGE:\n-\t\t\tprintf(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tcase SM_UPDATE_COMMAND:\n-\t\t\tprintf(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n-\t\t\t       ud->update_strategy.command, oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tif (capture_command(&cp, &out, 0)) {\n+\t\tif (must_die_on_failure) {\n+\t\t\tswitch (strategy.type) {\n+\t\t\tcase SM_UPDATE_CHECKOUT:\n+\t\t\t\tdie(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_REBASE:\n+\t\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_MERGE:\n+\t\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_COMMAND:\n+\t\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\t\t    strategy.command, oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tBUG(\"unexpected update strategy type: %s\",\n+\t\t\t\t    submodule_strategy_to_string(&strategy));\n+\t\t\t}\n \t\t}\n-\t\t/*\n-\t\t * NEEDSWORK: We are currently printing to stdout with error\n-\t\t * return so that the shell caller handles the error output\n-\t\t * properly. Once we start handling the error messages within\n-\t\t * C, we should use die() instead.\n-\t\t */\n-\t\tif (must_die_on_failure)\n-\t\t\treturn 2;\n-\t\t/*\n-\t\t * This signifies to the caller in shell that the command\n-\t\t * failed without dying\n-\t\t */\n+\n+\t\t/* the command failed, but update must continue */\n+\t\tstring_list_append(err, out.buf);\n \t\treturn 1;\n \t}\n \n-\tswitch (ud->update_strategy.type) {\n-\tcase SM_UPDATE_CHECKOUT:\n-\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_REBASE:\n-\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_MERGE:\n-\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_COMMAND:\n-\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n-\t\t       ud->displaypath, ud->update_strategy.command, oid);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\tif (!ud->quiet) {\n+\t\tswitch (strategy.type) {\n+\t\tcase SM_UPDATE_CHECKOUT:\n+\t\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n+\t\t\tbreak;\n+\t\tcase SM_UPDATE_REBASE:\n+\t\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n+\t\t\tbreak;\n+\t\tcase SM_UPDATE_MERGE:\n+\t\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n+\t\t\tbreak;\n+\t\tcase SM_UPDATE_COMMAND:\n+\t\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n+\t\t\t       ud->displaypath, strategy.command, oid);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"unexpected update strategy type: %s\",\n+\t\t\t    submodule_strategy_to_string(&strategy));\n+\t\t}\n \t}\n \n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud)\n+static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2500,7 +2549,7 @@ static int do_run_update_procedure(struct update_data *ud)\n \t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n \t}\n \n-\treturn run_update_command(ud, subforce);\n+\treturn run_update_command(ud, subforce, err);\n }\n \n static void update_clone_submodule(struct update_clone_data *ucd)\n@@ -2605,6 +2654,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n \tchar *prefixed_path, *update = NULL;\n \tstruct update_data update_data = UPDATE_DATA_INIT;\n+\tstruct string_list err = STRING_LIST_INIT_DUP;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n@@ -2662,7 +2712,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tfree(prefixed_path);\n \n \tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data);\n+\t\treturn do_run_update_procedure(&update_data, &err);\n \n \treturn 3;\n }\n@@ -3038,6 +3088,291 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \treturn !!ret;\n }\n \n+static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n+{\n+\tconst char *update = submodule_strategy_to_string(&update_data->update_strategy);\n+\n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n+\tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n+\tif (update_data->prefix)\n+\t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n+\tif (update_data->recursive_prefix)\n+\t\tstrvec_pushl(args, \"--recursive-prefix\",\n+\t\t\t     update_data->recursive_prefix, NULL);\n+\tif (update_data->quiet)\n+\t\tstrvec_push(args, \"--quiet\");\n+\tif (update_data->force)\n+\t\tstrvec_push(args, \"--force\");\n+\tif (update_data->init)\n+\t\tstrvec_push(args, \"--init\");\n+\tif (update_data->remote)\n+\t\tstrvec_push(args, \"--remote\");\n+\tif (update_data->nofetch)\n+\t\tstrvec_push(args, \"--no-fetch\");\n+\tif (update_data->dissociate)\n+\t\tstrvec_push(args, \"--dissociate\");\n+\tif (update_data->progress)\n+\t\tstrvec_push(args, \"--progress\");\n+\tif (update_data->require_init)\n+\t\tstrvec_push(args, \"--require-init\");\n+\tif (update_data->depth)\n+\t\tstrvec_pushf(args, \"--depth=%d\", update_data->depth);\n+\tif (update)\n+\t\tstrvec_pushl(args, \"--update\", update, NULL);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n+\t}\n+\tif (update_data->recommend_shallow == 0)\n+\t\tstrvec_push(args, \"--no-recommend-shallow\");\n+\telse if (update_data->recommend_shallow == 1)\n+\t\tstrvec_push(args, \"--recommend-shallow\");\n+\tif (update_data->single_branch >= 0)\n+\t\tstrvec_push(args, \"--single-branch\");\n+}\n+\n+static int update_submodule(struct update_data *update_data)\n+{\n+\tchar *prefixed_path;\n+\tstruct string_list err = STRING_LIST_INIT_DUP;\n+\n+\tdo_ensure_core_worktree(update_data->sm_path);\n+\n+\tif (update_data->recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n+\t\t\t\t\tupdate_data->sm_path);\n+\telse\n+\t\tprefixed_path = xstrdup(update_data->sm_path);\n+\n+\tupdate_data->displaypath = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t     update_data->prefix);\n+\tfree(prefixed_path);\n+\n+\tif (update_data->just_cloned) {\n+\t\toidcpy(&update_data->suboid, null_oid());\n+\t} else {\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n+\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t}\n+\n+\tif (update_data->remote) {\n+\t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n+\t\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n+\t\tchar *remote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n+\n+\t\tif (!update_data->nofetch) {\n+\t\t\tif(fetch_in_submodule(update_data->sm_path, update_data->depth,\n+\t\t\t\t\t      0, NULL))\n+\t\t\t\tdie(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\t\t    update_data->sm_path);\n+\t\t}\n+\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))\n+\t\t\tdie(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t    remote_ref, update_data->sm_path);\n+\n+\t\tfree(remote_ref);\n+\t}\n+\n+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n+\t\tif (do_run_update_procedure(update_data, &err))\n+\t\t\treturn 1;\n+\n+\tif (update_data->recursive) {\n+\t\tint res;\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct update_data next = *update_data;\n+\t\tchar *die_msg = xstrfmt(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t\t\tupdate_data->displaypath);\n+\n+\t\tif (update_data->recursive_prefix)\n+\t\t\tprefixed_path = xstrfmt(\"%s%s/\", update_data->recursive_prefix,\n+\t\t\t\t\t\tupdate_data->sm_path);\n+\t\telse\n+\t\t\tprefixed_path = xstrfmt(\"%s/\", update_data->sm_path);\n+\n+\t\tnext.recursive_prefix = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t\t  update_data->prefix);\n+\t\tnext.prefix = NULL;\n+\t\toidcpy(&next.oid, null_oid());\n+\t\toidcpy(&next.suboid, null_oid());\n+\n+\t\tcp.dir = update_data->sm_path;\n+\t\tcp.git_cmd = 1;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tupdate_data_to_args(&next, &cp.args);\n+\n+\t\t/* die() if child process die()'d */\n+\t\tif ((res = run_command(&cp)) == 128)\n+\t\t\tdie(\"%s\", die_msg);\n+\t\tif (res)\n+\t\t\tstring_list_append(&err, die_msg);\n+\n+\t\tfree(die_msg);\n+\t}\n+\n+\tif (err.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &err)\n+\t\t\tfputs(item->string, stderr);\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int update_submodules(struct update_data *update_data)\n+{\n+\tint i, res = 0;\n+\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\n+\tupdate_clone_from_update_data(&suc, update_data);\n+\trun_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,\n+\t\t\t\t   update_clone_start_failure,\n+\t\t\t\t   update_clone_task_finished, &suc, \"submodule\",\n+\t\t\t\t   \"parallel/update\");\n+\n+\t/*\n+\t * We saved the output and put it out all at once now.\n+\t * That means:\n+\t * - the listener does not have to interleave their (checkout)\n+\t *   work with our fetching.  The writes involved in a\n+\t *   checkout involve more straightforward sequential I/O.\n+\t * - the listener can avoid doing any work if fetching failed.\n+\t */\n+\tif (suc.quickstop) {\n+\t\tstring_list_clear(&update_data->references, 0);\n+\t\treturn 1;\n+\t}\n+\n+\tfor (i = 0; i < suc.update_clone_nr; i++) {\n+\t\tstruct update_clone_data ucd = suc.update_clone[i];\n+\n+\t\toidcpy(&update_data->oid, &ucd.oid);\n+\t\tupdate_data->just_cloned = ucd.just_cloned;\n+\t\tupdate_data->sm_path = ucd.sub->path;\n+\n+\t\tif (update_submodule(update_data))\n+\t\t\tres = 1;\n+\t}\n+\n+\tstring_list_clear(&update_data->references, 0);\n+\treturn res;\n+}\n+\n+static int module_update(int argc, const char **argv, const char *prefix)\n+{\n+\tint init = 0, force = 0, quiet = 0, nofetch = 0;\n+\tint remote = 0, recursive = 0, dissociate = 0;\n+\tint progress = 0, require_init = 0;\n+\tconst char *update = NULL;\n+\tstruct pathspec pathspec;\n+\tstruct update_data update_data = UPDATE_DATA_INIT;\n+\n+\tstruct option module_update_clone_options[] = {\n+\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n+\t\tOPT_BOOL(0, \"init\", &init,\n+\t\t\t N_(\"initialize uninitialized submodules before update\")),\n+\t\tOPT_BOOL(0, \"remote\", &remote,\n+\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive,\n+\t\t\t N_(\"traverse submodules recursively\")),\n+\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n+\t\t\t N_(\"don't fetch new objects from the remote site\")),\n+\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree\")),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree, across nested \"\n+\t\t\t      \"submodule boundaries\")),\n+\t\tOPT_STRING(0, \"update\", &update,\n+\t\t\t   N_(\"string\"),\n+\t\t\t   N_(\"rebase, merge, checkout or none\")),\n+\t\tOPT_STRING_LIST(0, \"reference\", &update_data.references, N_(\"repo\"),\n+\t\t\t\tN_(\"reference repository\")),\n+\t\tOPT_BOOL(0, \"dissociate\", &dissociate,\n+\t\t\t N_(\"use --reference only while cloning\")),\n+\t\tOPT_INTEGER(0, \"depth\", &update_data.depth,\n+\t\t\t    N_(\"create a shallow clone truncated to the \"\n+\t\t\t       \"specified number of revisions\")),\n+\t\tOPT_INTEGER('j', \"jobs\", &update_data.max_jobs,\n+\t\t\t    N_(\"parallel jobs\")),\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &update_data.recommend_shallow,\n+\t\t\t N_(\"whether the initial clone should follow the shallow recommendation\")),\n+\t\tOPT__QUIET(&quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &progress,\n+\t\t\t N_(\"force cloning progress\")),\n+\t\tOPT_BOOL(0, \"require-init\", &require_init,\n+\t\t\t N_(\"disallow cloning into non-empty directory\")),\n+\t\tOPT_BOOL(0, \"single-branch\", &update_data.single_branch,\n+\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n+\t\tNULL\n+\t};\n+\n+\tupdate_clone_config_from_gitmodules(&update_data.max_jobs);\n+\tgit_config(git_update_clone_config, &update_data.max_jobs);\n+\n+\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\tupdate_data.prefix = prefix;\n+\n+\tupdate_data.force = !!force;\n+\tupdate_data.quiet = !!quiet;\n+\tupdate_data.nofetch = !!nofetch;\n+\tupdate_data.init = !!init;\n+\tupdate_data.require_init = !!require_init;\n+\tupdate_data.remote = !!remote;\n+\tupdate_data.recursive = !!recursive;\n+\tupdate_data.progress = !!progress;\n+\tupdate_data.dissociate = !!dissociate;\n+\toidcpy(&update_data.oid, null_oid());\n+\toidcpy(&update_data.suboid, null_oid());\n+\n+\tif (update)\n+\t\tif (parse_submodule_update_strategy(update,\n+\t\t\t\t\t\t    &update_data.update_strategy) < 0)\n+\t\t\tdie(_(\"bad value for update parameter\"));\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &update_data.list) < 0)\n+\t\treturn 1;\n+\n+\tif (pathspec.nr)\n+\t\tupdate_data.warn_if_uninitialized = 1;\n+\n+\tif (update_data.init) {\n+\t\tstruct module_list list = MODULE_LIST_INIT;\n+\t\tstruct init_cb info = INIT_CB_INIT;\n+\n+\t\tif (module_list_compute(argc, argv, update_data.prefix,\n+\t\t\t\t\t&pathspec, &list) < 0)\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * If there are no path args and submodule.active is set then,\n+\t\t * by default, only initialize 'active' modules.\n+\t\t */\n+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n+\t\t\tmodule_list_active(&list);\n+\n+\t\tinfo.prefix = update_data.prefix;\n+\t\tinfo.superprefix = update_data.recursive_prefix;\n+\t\tif (update_data.quiet)\n+\t\t\tinfo.flags |= OPT_QUIET;\n+\n+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n+\t}\n+\n+\treturn update_submodules(&update_data);\n+}\n+\n struct add_data {\n \tconst char *prefix;\n \tconst char *branch;\n@@ -3213,6 +3548,7 @@ static int add_clone(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+\n #define SUPPORT_SUPER_PREFIX (1<<0)\n \n struct cmd_struct {\n@@ -3226,6 +3562,7 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"add-clone\", add_clone, 0},\n+\t{\"update\", module_update, 0},\n \t{\"update-module-mode\", module_update_module_mode, 0},\n \t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex f703cddce8..5197de4551 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -369,20 +369,6 @@ cmd_deinit()\n \tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- \"$@\"\n }\n \n-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]\n-# Because arguments are positional, use an empty string to omit <depth>\n-# but include <sha1>.\n-fetch_in_submodule () (\n-\tsanitize_submodule_env &&\n-\tcd \"$1\" &&\n-\tif test $# -eq 3\n-\tthen\n-\t\techo \"$3\" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+\"$2\"}\n-\telse\n-\t\tgit fetch ${GIT_QUIET:+--quiet} ${2:+\"$2\"}\n-\tfi\n-)\n-\n #\n # Update each submodule path to correct revision, using clone and checkout as needed\n #\n@@ -484,133 +470,26 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\tif test -n \"$init\"\n-\tthen\n-\t\tcmd_init \"--\" \"$@\" || return\n-\tfi\n-\n-\t{\n-\tgit submodule--helper update-clone ${GIT_QUIET:+--quiet} \\\n-\t\t${progress:+\"--progress\"} \\\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n+\t\t${GIT_QUIET:+--quiet} \\\n+\t\t${force:+--force} \\\n+\t\t${progress:+--progress} \\\n+\t\t${dissociate:+--dissociate} \\\n+\t\t${remote:+--remote} \\\n+\t\t${recursive:+--recursive} \\\n+\t\t${init:+--init} \\\n+\t\t${require_init:+--require-init} \\\n+\t\t${nofetch:+--no-fetch} \\\n \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t${update:+--update \"$update\"} \\\n \t\t${reference:+\"$reference\"} \\\n-\t\t${dissociate:+\"--dissociate\"} \\\n-\t\t${depth:+--depth \"$depth\"} \\\n-\t\t${require_init:+--require-init} \\\n+\t\t${depth:+\"$depth\"} \\\n \t\t$single_branch \\\n \t\t$recommend_shallow \\\n \t\t$jobs \\\n \t\t-- \\\n-\t\t\"$@\" || echo \"#unmatched\" $?\n-\t} | {\n-\terr=\n-\twhile read -r quickabort sha1 just_cloned sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n-\n-\t\tgit submodule--helper ensure-core-worktree \"$sm_path\" || exit 1\n-\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\n-\t\tif test $just_cloned -eq 1\n-\t\tthen\n-\t\t\tsubsha1=\n-\t\telse\n-\t\t\tjust_cloned=\n-\t\t\tsubsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify HEAD) ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current revision in submodule path '\\$displaypath'\")\"\n-\t\tfi\n-\n-\t\tif test -n \"$remote\"\n-\t\tthen\n-\t\t\tbranch=$(git submodule--helper remote-branch \"$sm_path\")\n-\t\t\tif test -z \"$nofetch\"\n-\t\t\tthen\n-\t\t\t\t# Fetch remote before determining tracking $sha1\n-\t\t\t\tfetch_in_submodule \"$sm_path\" $depth ||\n-\t\t\t\tdie \"fatal: $(eval_gettext \"Unable to fetch in submodule path '\\$sm_path'\")\"\n-\t\t\tfi\n-\t\t\tremote_name=$(sanitize_submodule_env; cd \"$sm_path\" && git submodule--helper print-default-remote)\n-\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify \"${remote_name}/${branch}\") ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\n-\t\tout=$(git submodule--helper run-update-procedure \\\n-\t\t\t  ${wt_prefix:+--prefix \"$wt_prefix\"} \\\n-\t\t\t  ${GIT_QUIET:+--quiet} \\\n-\t\t\t  ${force:+--force} \\\n-\t\t\t  ${just_cloned:+--just-cloned} \\\n-\t\t\t  ${nofetch:+--no-fetch} \\\n-\t\t\t  ${depth:+\"$depth\"} \\\n-\t\t\t  ${update:+--update \"$update\"} \\\n-\t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n-\t\t\t  ${sha1:+--oid \"$sha1\"} \\\n-\t\t\t  ${subsha1:+--suboid \"$subsha1\"} \\\n-\t\t\t  \"--\" \\\n-\t\t\t  \"$sm_path\")\n-\n-\t\t# exit codes for run-update-procedure:\n-\t\t# 0: update was successful, say command output\n-\t\t# 1: update procedure failed, but should not die\n-\t\t# 2 or 128: subcommand died during execution\n-\t\t# 3: no update procedure was run\n-\t\tres=\"$?\"\n-\t\tcase $res in\n-\t\t0)\n-\t\t\tsay \"$out\"\n-\t\t\t;;\n-\t\t1)\n-\t\t\terr=\"${err};fatal: $out\"\n-\t\t\tcontinue\n-\t\t\t;;\n-\t\t2|128)\n-\t\t\tdie_with_status $res \"fatal: $out\"\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=$(git submodule--helper relative-path \"$prefix$sm_path/\" \"$wt_prefix\")\n-\t\t\t\twt_prefix=\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_update\n-\t\t\t)\n-\t\t\tres=$?\n-\t\t\tif test $res -gt 0\n-\t\t\tthen\n-\t\t\t\tdie_msg=\"fatal: $(eval_gettext \"Failed to recurse into submodule path '\\$displaypath'\")\"\n-\t\t\t\tif test $res -ne 2\n-\t\t\t\tthen\n-\t\t\t\t\terr=\"${err};$die_msg\"\n-\t\t\t\t\tcontinue\n-\t\t\t\telse\n-\t\t\t\t\tdie_with_status $res \"$die_msg\"\n-\t\t\t\tfi\n-\t\t\tfi\n-\t\tfi\n-\tdone\n-\n-\tif test -n \"$err\"\n-\tthen\n-\t\tOIFS=$IFS\n-\t\tIFS=';'\n-\t\tfor e in $err\n-\t\tdo\n-\t\t\tif test -n \"$e\"\n-\t\t\tthen\n-\t\t\t\techo >&2 \"$e\"\n-\t\t\tfi\n-\t\tdone\n-\t\tIFS=$OIFS\n-\t\texit 1\n-\tfi\n-\t}\n+\t\t\"$@\"\n }\n \n #\n-- \n2.32.0\n\n"},{"id":"436103","messageId":"20210916103241.62376-7-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210916103241.62376-1-raykar.ath@gmail.com","subject":"[PATCH v2 6/8] submodule--helper: remove update-clone subcommand","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-16T10:32:39Z","receivedAt":"2021-09-16T10:33:28Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"We no longer need this subcommand as the shell version calls the\n'update' subcommand instead, which does all the cloning within C itself.\n\nWe also no longer need the 'update_clone_submodules()' and\n'update_clone_submodule()' functions, so we remove those as well.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 98 -------------------------------------\n 1 file changed, 98 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 1eea626864..c1ce3981ad 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2552,103 +2552,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e\n \treturn run_update_command(ud, subforce, err);\n }\n \n-static void update_clone_submodule(struct update_clone_data *ucd)\n-{\n-\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n-\t\toid_to_hex(&ucd->oid),\n-\t\tucd->just_cloned,\n-\t\tucd->sub->path);\n-}\n-\n-static int update_clone_submodules(struct submodule_update_clone *suc)\n-{\n-\tint i;\n-\n-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n-\t\t\t\t   update_clone_start_failure,\n-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n-\t\t\t\t   \"parallel/update\");\n-\n-\t/*\n-\t * We saved the output and put it out all at once now.\n-\t * That means:\n-\t * - the listener does not have to interleave their (checkout)\n-\t *   work with our fetching.  The writes involved in a\n-\t *   checkout involve more straightforward sequential I/O.\n-\t * - the listener can avoid doing any work if fetching failed.\n-\t */\n-\tif (suc->quickstop)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_clone_submodule(&suc->update_clone[i]);\n-\n-\treturn 0;\n-}\n-\n-static int update_clone(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *update = NULL;\n-\tstruct pathspec pathspec;\n-\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n-\n-\tstruct option module_update_clone_options[] = {\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &suc.recursive_prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &suc.references, N_(\"repo\"),\n-\t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &suc.dissociate,\n-\t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &suc.depth, \"<depth>\",\n-\t\t\t   N_(\"create a shallow clone truncated to the \"\n-\t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &suc.max_jobs,\n-\t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &suc.recommend_shallow,\n-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&suc.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &suc.progress,\n-\t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &suc.require_init,\n-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &suc.single_branch,\n-\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\tsuc.prefix = prefix;\n-\n-\tupdate_clone_config_from_gitmodules(&suc.max_jobs);\n-\tgit_config(git_update_clone_config, &suc.max_jobs);\n-\n-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &suc.update) < 0)\n-\t\t\tdie(_(\"bad value for update parameter\"));\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)\n-\t\treturn 1;\n-\n-\tif (pathspec.nr)\n-\t\tsuc.warn_if_uninitialized = 1;\n-\n-\treturn update_clone_submodules(&suc);\n-}\n-\n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n@@ -3564,7 +3467,6 @@ static struct cmd_struct commands[] = {\n \t{\"add-clone\", add_clone, 0},\n \t{\"update\", module_update, 0},\n \t{\"update-module-mode\", module_update_module_mode, 0},\n-\t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n \t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n \t{\"relative-path\", resolve_relative_path, 0},\n-- \n2.32.0\n\n"},{"id":"436104","messageId":"20210916103241.62376-8-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210916103241.62376-1-raykar.ath@gmail.com","subject":"[PATCH v2 7/8] submodule--helper: remove unused helpers","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-16T10:32:40Z","receivedAt":"2021-09-16T10:33:33Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"These helpers were useful back when 'submodule update' had most of its\nlogic in shell. Now that they will never be invoked, let us remove them.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 135 ------------------------------------\n 1 file changed, 135 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c1ce3981ad..0910af9c71 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -73,21 +73,6 @@ static char *get_default_remote(void)\n \treturn repo_get_default_remote(the_repository, refname);\n }\n \n-static int print_default_remote(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remote;\n-\n-\tif (argc != 1)\n-\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n-\n-\tremote = get_default_remote();\n-\tif (remote)\n-\t\tprintf(\"%s\\n\", remote);\n-\n-\tfree(remote);\n-\treturn 0;\n-}\n-\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -1993,29 +1978,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n \tfree(key);\n }\n \n-static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path, *update = NULL;\n-\tint just_cloned;\n-\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n-\n-\tif (argc < 3 || argc > 4)\n-\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n-\n-\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n-\tpath = argv[2];\n-\n-\tif (argc == 4)\n-\t\tupdate = argv[3];\n-\n-\tdetermine_submodule_update_strategy(the_repository,\n-\t\t\t\t\t    just_cloned, path, update,\n-\t\t\t\t\t    &update_strategy);\n-\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n-\n-\treturn 0;\n-}\n-\n struct update_clone_data {\n \tconst struct submodule *sub;\n \tstruct object_id oid;\n@@ -2552,85 +2514,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e\n \treturn run_update_command(ud, subforce, err);\n }\n \n-static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-{\n-\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n-\tchar *prefixed_path, *update = NULL;\n-\tstruct update_data update_data = UPDATE_DATA_INIT;\n-\tstruct string_list err = STRING_LIST_INIT_DUP;\n-\n-\tstruct option options[] = {\n-\t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n-\t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n-\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n-\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n-\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const usage[] = {\n-\t\tN_(\"git submodule--helper run-update-procedure [<options>] <path>\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\n-\tif (argc != 1)\n-\t\tusage_with_options(usage, options);\n-\n-\tupdate_data.force = !!force;\n-\tupdate_data.quiet = !!quiet;\n-\tupdate_data.nofetch = !!nofetch;\n-\tupdate_data.just_cloned = !!just_cloned;\n-\tupdate_data.sm_path = argv[0];\n-\n-\tif (update_data.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n-\telse\n-\t\tprefixed_path = xstrdup(update_data.sm_path);\n-\n-\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n-\n-\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n-\t\t\t\t\t    update_data.sm_path, update,\n-\t\t\t\t\t    &update_data.update_strategy);\n-\n-\tfree(prefixed_path);\n-\n-\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data, &err);\n-\n-\treturn 3;\n-}\n-\n-static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 3)\n-\t\tdie(\"submodule--helper relative-path takes exactly 2 arguments, got %d\", argc);\n-\n-\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n-\tstrbuf_release(&sb);\n-\treturn 0;\n-}\n-\n static const char *remote_submodule_branch(const char *path)\n {\n \tconst struct submodule *sub;\n@@ -2794,19 +2677,6 @@ static void do_ensure_core_worktree(const char *path)\n \t}\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path;\n-\n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\tdo_ensure_core_worktree(path);\n-\n-\treturn 0;\n-}\n-\n static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n@@ -3466,16 +3336,11 @@ static struct cmd_struct commands[] = {\n \t{\"clone\", module_clone, 0},\n \t{\"add-clone\", add_clone, 0},\n \t{\"update\", module_update, 0},\n-\t{\"update-module-mode\", module_update_module_mode, 0},\n-\t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n-\t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n-\t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, 0},\n \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n-- \n2.32.0\n\n"},{"id":"436105","messageId":"20210916103241.62376-9-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210916103241.62376-1-raykar.ath@gmail.com","subject":"[PATCH v2 8/8] submodule--helper: rename helper functions","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-09-16T10:32:41Z","receivedAt":"2021-09-16T10:33:34Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"These two functions were prefixed with 'do' before the shell-to-C\nconversion because they were utility functions meant to be called by\ntheir non-prefixed counterpart.\n\nSince those callers don't exist anymore, and these functions can now be\nused directly, let's rename them to signal this fact.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 0910af9c71..e5e33be6ea 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2484,7 +2484,7 @@ static int run_update_command(struct update_data *ud, int subforce, struct strin\n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n+static int run_update_procedure(struct update_data *ud, struct string_list *err)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2646,7 +2646,7 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void do_ensure_core_worktree(const char *path)\n+static void ensure_core_worktree(const char *path)\n {\n \tconst struct submodule *sub;\n \tconst char *cw;\n@@ -2910,7 +2910,7 @@ static int update_submodule(struct update_data *update_data)\n \tchar *prefixed_path;\n \tstruct string_list err = STRING_LIST_INIT_DUP;\n \n-\tdo_ensure_core_worktree(update_data->sm_path);\n+\tensure_core_worktree(update_data->sm_path);\n \n \tif (update_data->recursive_prefix)\n \t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n@@ -2950,7 +2950,7 @@ static int update_submodule(struct update_data *update_data)\n \t}\n \n \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n-\t\tif (do_run_update_procedure(update_data, &err))\n+\t\tif (run_update_procedure(update_data, &err))\n \t\t\treturn 1;\n \n \tif (update_data->recursive) {\n-- \n2.32.0\n\n"},{"id":"436442","messageId":"xmqqr1djchp5.fsf@gitster.g","threadId":"56453","inReplyTo":"20210916103241.62376-3-raykar.ath@gmail.com","subject":"Re: [PATCH v2 2/8] submodule--helper: get remote names from any repository","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-09-20T16:52:54Z","receivedAt":"2021-09-20T16:54:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Atharva Raykar <raykar.ath@gmail.com> writes:\n\n> `get_default_remote()` retrieves the name of a remote by resolving the\n> refs from of the current repository's ref store.\n>\n> Thus in order to use it for retrieving the remote name of a submodule,\n> we have to start a new subprocess which runs from the submodule\n> directory.\n>\n> Let's instead introduce a function called `repo_get_default_remote()`\n> which takes any repository object and retrieves the remote accordingly.\n>\n> `get_default_remote()` is then defined as a call to\n> `repo_get_default_remote()` with 'the_repository' passed to it.\n>\n> Now that we have `repo_get_default_remote()`, we no longer have to start\n> a subprocess that called `submodule--helper get-default-remote` from\n> within the submodule directory.\n>\n> So let's make a function called `get_default_remote_submodule()` which\n> takes a submodule path, and returns the default remote for that\n> submodule, all within the same process.\n>\n> We can now use this function to save an unnecessary subprocess spawn in\n> `sync_submodule()`, and also in the next patch, which will require this\n> functionality.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 34 +++++++++++++++++++++++-----------\n>  1 file changed, 23 insertions(+), 11 deletions(-)\n\nThe above covers a lot of stuff, because this change does a lot of\nthings ;-)\n\nThe commit could be split into 3 logically distinct phases (two\nindependent, the third depends on the other two):\n\n - extract the part that uses the run-command() API to run\n   \"submodule--helper print-default-remote\" from sync_submodule()\n   and create get_default_remote_submodule() function out of it.\n\n - move bulk of get_default_remote() into repo_get_default_remote()\n   and reimplement the former as a thin wrapper of the latter.\n\n - using the repo_get_default_remote() created in the second step,\n   update the get_default_remote_submodule() created in the first\n   step to work in-process without a subprocess.\n\nbut a bit larger granularity used here is probably OK.\n\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 97512ccf0b..f6c4fc349b 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -29,11 +29,10 @@\n>  typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n>  \t\t\t\t  void *cb_data);\n>  \n> -static char *get_default_remote(void)\n> +static char *repo_get_default_remote(struct repository *repo, const char *refname)\n>  {\n>  \tchar *dest = NULL, *ret;\n>  \tstruct strbuf sb = STRBUF_INIT;\n> -\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n>  \n>  \tif (!refname)\n>  \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n> @@ -46,7 +45,7 @@ static char *get_default_remote(void)\n>  \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n>  \n>  \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n> -\tif (git_config_get_string(sb.buf, &dest))\n> +\tif (repo_config_get_string(repo, sb.buf, &dest))\n>  \t\tret = xstrdup(\"origin\");\n>  \telse\n>  \t\tret = dest;\n> @@ -55,6 +54,25 @@ static char *get_default_remote(void)\n>  \treturn ret;\n>  }\n>  \n> +static char *get_default_remote_submodule(const char *module_path)\n> +{\n> +\tconst char *refname;\n> +\tconst struct submodule *sub;\n> +\tstruct repository subrepo;\n> +\n> +\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n> +\t\t\t\t\t  \"HEAD\", 0, NULL, NULL);\n> +\tsub = submodule_from_path(the_repository, null_oid(), module_path);\n> +\trepo_submodule_init(&subrepo, the_repository, sub);\n> +\treturn repo_get_default_remote(&subrepo, refname);\n> +}\n> +\n> +static char *get_default_remote(void)\n> +{\n> +\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n> +\treturn repo_get_default_remote(the_repository, refname);\n> +}\n> +\n>  static int print_default_remote(int argc, const char **argv, const char *prefix)\n>  {\n>  \tchar *remote;\n> @@ -1369,7 +1387,6 @@ static void sync_submodule(const char *path, const char *prefix,\n>  \tchar *remote_key = NULL;\n>  \tchar *sub_origin_url, *super_config_url, *displaypath;\n>  \tstruct strbuf sb = STRBUF_INIT;\n> -\tstruct child_process cp = CHILD_PROCESS_INIT;\n>  \tchar *sub_config_path = NULL;\n>  \n>  \tif (!is_submodule_active(the_repository, path))\n> @@ -1418,14 +1435,9 @@ static void sync_submodule(const char *path, const char *prefix,\n>  \tif (!is_submodule_populated_gently(path, NULL))\n>  \t\tgoto cleanup;\n>  \n> -\tprepare_submodule_repo_env(&cp.env_array);\n> -\tcp.git_cmd = 1;\n> -\tcp.dir = path;\n> -\tstrvec_pushl(&cp.args, \"submodule--helper\",\n> -\t\t     \"print-default-remote\", NULL);\n> -\n>  \tstrbuf_reset(&sb);\n> -\tif (capture_command(&cp, &sb, 0))\n> +\tstrbuf_addstr(&sb, get_default_remote_submodule(path));\n> +\tif (!sb.buf)\n>  \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n>  \t\t      path);\n\nThere is this line after the post context presented here:\n\n        strbuf_strip_suffix(&sb, \"\\n\");\n        remote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n\nThe LF was expected to come from the capture_command(), but it no\nlonger is needed after get_default_remote_submodule() switches to\nuse the in-process method.  In fact, the use of sb for the purpose\nof forming remote_key is not needed.\n\n    tmp = get_default_remote_submodule(path);\n    if (!tmp)\n\tdie(_(\"failed to get...\"));\n    remote_key = xstrfmt(\"remote.%s.url\", tmp);\n    free(tmp);\n\nYes, I think the new code leaks, and makes it impossible not to\nleak, the returned value from get_default_remote_submodule() by\npassing the call as an argument to strbuf_addstr().\n\nBoth of the two bugs pointed out here would have been easier to spot\nif the commits were smaller, I would think, but as I said, a bit\nlarger granularity used here was still manageable.\n\nThanks.\n"},{"id":"436443","messageId":"xmqqk0jbcgqy.fsf@gitster.g","threadId":"56453","inReplyTo":"20210916103241.62376-6-raykar.ath@gmail.com","subject":"Re: [PATCH v2 5/8] submodule: move core cmd_update() logic to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-09-20T17:13:25Z","receivedAt":"2021-09-20T17:15:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Atharva Raykar <raykar.ath@gmail.com> writes:\n\n> This patch completes the conversion past the flag parsing of\n> `submodule update` by introducing a helper subcommand called\n> `submodule--helper update`. The behaviour of `submodule update` should\n> remain the same after this patch.\n>\n> We add more fields to the `struct update_data` that are required by\n> `struct submodule_update_clone` to be able to perform a clone, when that\n> is needed to be done.\n>\n> Recursing on a submodule is done by calling a subprocess that launches\n> `submodule--helper update`, with a modified `--recursive-prefix` and\n> `--prefix` parameter.\n>\n> We also introduce `update_submodules()` and `update_submodule()` which\n> are quite similar to `update_clone_submodules()` and\n> `update_clone_submodule()`, and will supersede them.\n>\n> When the `--init` flag is passed to the subcommand, we do not spawn a\n> new subprocess and call `submodule--helper init` on the submodule paths,\n> because the Git machinery is not able to pick up the configuration\n> changes introduced by that init call[1]. So we instead run the\n> `init_submodule_cb()` callback over each submodule directly.\n>\n> This introduces another problem, because there is no mechanism to pass\n> the superproject path prefix (ie, `--super-prefix`) without starting a\n> new git process. This field is required for obtaining the display path\n> for that is used by the command's output messages. So let's add a field\n> into the `init_cb` struct that lets us pass this information to\n> `init_submodule()`, which will now also take an explicit 'superprefix'\n> argument.\n>\n> While we are at it, we also remove the fetch_in_submodule() shell\n> function since it is no longer used anywhere.\n>\n> [1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 505 ++++++++++++++++++++++++++++++------\n>  git-submodule.sh            | 145 +----------\n>  2 files changed, 433 insertions(+), 217 deletions(-)\n\nIt seems that this step does too many things in one step and makes\nit harder than necessary for readers to understand what is going on.\n\nFor example, as far as I can see, the change to optionally allow\npassing superprefix to init_submodule() can be made without anything\nelse in this step (i.e. \"we allow superprefix from the parameter to\noverride what get_super_prefix() would give us, but at this step,\neverybody passes NULL and the behaviour is unchanged\" would be one\nsuch step), later to be followed by a change that involves passing a\nnon-NULL value there, and it would become a lot easier to see who\npasses a non-NULL super prefix, what value is passed and for what\npurpose, with such an organization.\n\nA 650+ lines single patch like this buries the details and forces\nthe readers to disect them out.  The change that teaches\nrun_update_command() to instead use capture_command() and gives the\nerror message to its callers may be another example of what may be\nbetter done as an independent step before tying the whole thing\ntogether.\n\nIt is larger than what I comfortably can spend my time on while\ntending patches from other topics, so I'll skip reviewing this step\nfor now.\n\nThanks.\n"},{"id":"436444","messageId":"xmqqfstzcggs.fsf@gitster.g","threadId":"56453","inReplyTo":"20210916103241.62376-8-raykar.ath@gmail.com","subject":"Re: [PATCH v2 7/8] submodule--helper: remove unused helpers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-09-20T17:19:31Z","receivedAt":"2021-09-20T17:21:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Atharva Raykar <raykar.ath@gmail.com> writes:\n\n> These helpers were useful back when 'submodule update' had most of its\n> logic in shell. Now that they will never be invoked, let us remove them.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 135 ------------------------------------\n>  1 file changed, 135 deletions(-)\n\nMakes sense.  I briefly hoped that print-default-remote could go\nafter 2/8 but there is another user that is in the cmd_update() that\nis not removed until 5/8 and removing them in a separate step after\nwe are all done like this patch does makes sense.  I am not sure\nwhere and how the line to separate the two \"remove\" patches is\ndrawn, though.  Is there a reason why they need to be two patches?\n"},{"id":"436445","messageId":"xmqqbl4ncgg5.fsf@gitster.g","threadId":"56453","inReplyTo":"20210916103241.62376-9-raykar.ath@gmail.com","subject":"Re: [PATCH v2 8/8] submodule--helper: rename helper functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-09-20T17:19:54Z","receivedAt":"2021-09-20T17:21:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Atharva Raykar <raykar.ath@gmail.com> writes:\n\n> These two functions were prefixed with 'do' before the shell-to-C\n> conversion because they were utility functions meant to be called by\n> their non-prefixed counterpart.\n>\n> Since those callers don't exist anymore, and these functions can now be\n> used directly, let's rename them to signal this fact.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 8 ++++----\n>  1 file changed, 4 insertions(+), 4 deletions(-)\n\nNice.\n"},{"id":"436455","messageId":"xmqqa6k7aujk.fsf@gitster.g","threadId":"56453","inReplyTo":"20210916103241.62376-6-raykar.ath@gmail.com","subject":"Re: [PATCH v2 5/8] submodule: move core cmd_update() logic to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-09-20T19:58:23Z","receivedAt":"2021-09-20T20:00:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Atharva Raykar <raykar.ath@gmail.com> writes:\n\n> This patch completes the conversion past the flag parsing of\n> `submodule update` by introducing a helper subcommand called\n> `submodule--helper update`. The behaviour of `submodule update` should\n> remain the same after this patch.\n> ...\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> ---\n\nThis seems to overlap with Emily's 242655f2 (submodule: record\nsuperproject gitdir during 'update', 2021-08-19) that came in\n<20210819200953.2105230-5-emilyshaffer@google.com>.\n\nShould I expect there probably needs a few more iterations for this\ntopic?  Depending, the \"a submodule knows which superproject it is\npart of\" topic may have to be done in C on top of this topic.\n\nI'll eject the 'es/superproject-aware-submodules' topic for now,\njust to get today's integration going.\n\nThanks.\n\n"},{"id":"436459","messageId":"xmqqk0jb9btp.fsf@gitster.g","threadId":"56453","inReplyTo":"20210916103241.62376-6-raykar.ath@gmail.com","subject":"Re: [PATCH v2 5/8] submodule: move core cmd_update() logic to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-09-20T21:28:02Z","receivedAt":"2021-09-20T21:30:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Atharva Raykar <raykar.ath@gmail.com> writes:\n\n> +static int update_submodules(struct update_data *update_data)\n> +{\n> +\tint i, res = 0;\n> +\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n> +\n> +\tupdate_clone_from_update_data(&suc, update_data);\n> +\trun_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,\n> +\t\t\t\t   update_clone_start_failure,\n> +\t\t\t\t   update_clone_task_finished, &suc, \"submodule\",\n> +\t\t\t\t   \"parallel/update\");\n> + ...\n\nAs ab/config-based-hooks-base topic from Ævar changes the way this\nhelper function gets called at 73367f2f (run-command: add stdin\ncallback for parallelization, 2021-09-02) and then again in 2aba2f5f\n(run-command: allow capturing of collated output, 2021-09-02), this\npart needs to be adjusted when the topics collide in 'seen'.\n\nI _think_ I've resolved conflict correctly, but please double-check\nthe result when today's integration result is pushed out later, both\nof you.\n\nThanks.\n"},{"id":"436460","messageId":"xmqqczp39bth.fsf@gitster.g","threadId":"56453","inReplyTo":"20210916103241.62376-3-raykar.ath@gmail.com","subject":"Re: [PATCH v2 2/8] submodule--helper: get remote names from any repository","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-09-20T21:28:10Z","receivedAt":"2021-09-20T21:30:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Atharva Raykar <raykar.ath@gmail.com> writes:\n\n> +static char *get_default_remote_submodule(const char *module_path)\n> +{\n> +\tconst char *refname;\n> +\tconst struct submodule *sub;\n> +\tstruct repository subrepo;\n> +\n> +\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n> +\t\t\t\t\t  \"HEAD\", 0, NULL, NULL);\n> +\tsub = submodule_from_path(the_repository, null_oid(), module_path);\n> +\trepo_submodule_init(&subrepo, the_repository, sub);\n> +\treturn repo_get_default_remote(&subrepo, refname);\n> +}\n\nThis call (and I think there is another call in this file) to\nrepo_submodule_init() is affected by what Jonathan's 8eb8dcf9\n(repository: support unabsorbed in repo_submodule_init, 2021-09-09)\nwants to do, namely to lose \"struct submodule sub\" as a parameter\nand instead take the path to the module and the treeish name as\nparameters to repo_submodule_init().\n\nI _think_ I resolved the conflict correctly, but please double check\nthe result when it is pushed out later today, both of you.\n\nThanks.\n"},{"id":"436632","messageId":"20210921163322.1640109-1-jonathantanmy@google.com","threadId":"56453","inReplyTo":"xmqqczp39bth.fsf@gitster.g","subject":"Re: [PATCH v2 2/8] submodule--helper: get remote names from any repository","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2021-09-21T16:33:22Z","receivedAt":"2021-09-21T16:33:35Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"> Atharva Raykar <raykar.ath@gmail.com> writes:\n> \n> > +static char *get_default_remote_submodule(const char *module_path)\n> > +{\n> > +\tconst char *refname;\n> > +\tconst struct submodule *sub;\n> > +\tstruct repository subrepo;\n> > +\n> > +\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n> > +\t\t\t\t\t  \"HEAD\", 0, NULL, NULL);\n> > +\tsub = submodule_from_path(the_repository, null_oid(), module_path);\n> > +\trepo_submodule_init(&subrepo, the_repository, sub);\n> > +\treturn repo_get_default_remote(&subrepo, refname);\n> > +}\n> \n> This call (and I think there is another call in this file) to\n> repo_submodule_init() is affected by what Jonathan's 8eb8dcf9\n> (repository: support unabsorbed in repo_submodule_init, 2021-09-09)\n> wants to do, namely to lose \"struct submodule sub\" as a parameter\n> and instead take the path to the module and the treeish name as\n> parameters to repo_submodule_init().\n> \n> I _think_ I resolved the conflict correctly, but please double check\n> the result when it is pushed out later today, both of you.\n> \n> Thanks.\n\nThanks for calling this out. There are indeed 2 such calls in 33cfc43433\n(\"Merge branch 'ar/submodule-update' into seen\", 2021-09-20) and both\nlook correct.\n"},{"id":"437808","messageId":"m2mtnqi9jj.fsf@gmail.com","threadId":"56453","inReplyTo":"xmqqk0jbcgqy.fsf@gitster.g","subject":"Re: [PATCH v2 5/8] submodule: move core cmd_update() logic to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-03T10:38:37Z","receivedAt":"2021-10-03T12:21:19Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"\nJunio C Hamano <gitster@pobox.com> writes:\n>\n> It seems that this step does too many things in one step and makes\n> it harder than necessary for readers to understand what is going on.\n>\n> For example, as far as I can see, the change to optionally allow\n> passing superprefix to init_submodule() can be made without anything\n> else in this step (i.e. \"we allow superprefix from the parameter to\n> override what get_super_prefix() would give us, but at this step,\n> everybody passes NULL and the behaviour is unchanged\" would be one\n> such step), later to be followed by a change that involves passing a\n> non-NULL value there, and it would become a lot easier to see who\n> passes a non-NULL super prefix, what value is passed and for what\n> purpose, with such an organization.\n>\n> A 650+ lines single patch like this buries the details and forces\n> the readers to disect them out.  The change that teaches\n> run_update_command() to instead use capture_command() and gives the\n> error message to its callers may be another example of what may be\n> better done as an independent step before tying the whole thing\n> together.\n>\n> It is larger than what I comfortably can spend my time on while\n> tending patches from other topics, so I'll skip reviewing this step\n> for now.\n>\n> Thanks.\n\nUnderstood. Apologies for the lack of updates on this topic, I will work\non organising this patch (and this series) better. I've taken a note of\nthe conflicts with other topics as well.\n\nI don't mind the other topics being prioritized over this one. At the\nmoment I am not too confident about being able to quickly iterate over\nthis series. I'll try my best anyway.\n"},{"id":"437813","messageId":"m2k0iui6by.fsf@gmail.com","threadId":"56453","inReplyTo":"xmqqr1djchp5.fsf@gitster.g","subject":"Re: [PATCH v2 2/8] submodule--helper: get remote names from any repository","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-03T13:22:51Z","receivedAt":"2021-10-03T13:30:33Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"\nJunio C Hamano <gitster@pobox.com> writes:\n\n> Atharva Raykar <raykar.ath@gmail.com> writes:\n>\n>> `get_default_remote()` retrieves the name of a remote by resolving the\n>> refs from of the current repository's ref store.\n>>\n>> Thus in order to use it for retrieving the remote name of a submodule,\n>> we have to start a new subprocess which runs from the submodule\n>> directory.\n>>\n>> Let's instead introduce a function called `repo_get_default_remote()`\n>> which takes any repository object and retrieves the remote accordingly.\n>>\n>> `get_default_remote()` is then defined as a call to\n>> `repo_get_default_remote()` with 'the_repository' passed to it.\n>>\n>> Now that we have `repo_get_default_remote()`, we no longer have to start\n>> a subprocess that called `submodule--helper get-default-remote` from\n>> within the submodule directory.\n>>\n>> So let's make a function called `get_default_remote_submodule()` which\n>> takes a submodule path, and returns the default remote for that\n>> submodule, all within the same process.\n>>\n>> We can now use this function to save an unnecessary subprocess spawn in\n>> `sync_submodule()`, and also in the next patch, which will require this\n>> functionality.\n>>\n>> Mentored-by: Christian Couder <christian.couder@gmail.com>\n>> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n>> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n>> ---\n>>  builtin/submodule--helper.c | 34 +++++++++++++++++++++++-----------\n>>  1 file changed, 23 insertions(+), 11 deletions(-)\n>\n> The above covers a lot of stuff, because this change does a lot of\n> things ;-)\n>\n> The commit could be split into 3 logically distinct phases (two\n> independent, the third depends on the other two):\n>\n>  - extract the part that uses the run-command() API to run\n>    \"submodule--helper print-default-remote\" from sync_submodule()\n>    and create get_default_remote_submodule() function out of it.\n>\n>  - move bulk of get_default_remote() into repo_get_default_remote()\n>    and reimplement the former as a thin wrapper of the latter.\n>\n>  - using the repo_get_default_remote() created in the second step,\n>    update the get_default_remote_submodule() created in the first\n>    step to work in-process without a subprocess.\n>\n> but a bit larger granularity used here is probably OK.\n>\n[...]\n>>  \tstrbuf_reset(&sb);\n>> -\tif (capture_command(&cp, &sb, 0))\n>> +\tstrbuf_addstr(&sb, get_default_remote_submodule(path));\n>> +\tif (!sb.buf)\n>>  \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n>>  \t\t      path);\n>\n> There is this line after the post context presented here:\n>\n>         strbuf_strip_suffix(&sb, \"\\n\");\n>         remote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n>\n> The LF was expected to come from the capture_command(), but it no\n> longer is needed after get_default_remote_submodule() switches to\n> use the in-process method.  In fact, the use of sb for the purpose\n> of forming remote_key is not needed.\n>\n>     tmp = get_default_remote_submodule(path);\n>     if (!tmp)\n> \tdie(_(\"failed to get...\"));\n>     remote_key = xstrfmt(\"remote.%s.url\", tmp);\n>     free(tmp);\n>\n> Yes, I think the new code leaks, and makes it impossible not to\n> leak, the returned value from get_default_remote_submodule() by\n> passing the call as an argument to strbuf_addstr().\n\nThanks, this was a good catch.\n\n> Both of the two bugs pointed out here would have been easier to spot\n> if the commits were smaller, I would think, but as I said, a bit\n> larger granularity used here was still manageable.\n\nMy initial series had this patch split up similar to what you suggested,\nbut I ultimately chose to favour the larger granularity to make the\nwhole series a bit shorter. This patch definitely towed the line a bit.\n\n> Thanks.\n"},{"id":"438629","messageId":"20211013051805.45662-1-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20210916103241.62376-1-raykar.ath@gmail.com","subject":"[PATCH v3 0/9] submodule: convert the rest of 'update' to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:17:56Z","receivedAt":"2021-10-13T05:18:34Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"Since v2:\n - Rebased this series on top of a more up-to-date master branch.\n\n - Reorganized this series to (hopefully) make it easier to review, as per\n   Junio's suggestions. I split up the patch that converts the rest of the\n   update shell script to C into multiple steps. I also squashed the patches\n   that removed unused helpers, as there was not clear criteria for it being two\n   patches.\n\n - Plugged a memory leak while refactoring sync_submodule() to use my new\n   helper.\n\nNote on conflicting series:\n--------------------------\n\nThis series currently conflicts with the work being done by Emily in\n'es/superproject-aware-submodules' [1], mainly in the part where they cache the\nsuperproject gitdir in the shell script that gets removed during conversion in\nthis series.\n\nI have attempted to make a version of this series that is based on that topic [2],\nand added the superproject gitdir caching code in C [3]. It passes the tests,\nbut I am not too confident about its correctness. I hope that branch can be\nhelpful in some way.\n\n[1] https://lore.kernel.org/git/20210819200953.2105230-1-emilyshaffer@google.com/\n[2] https://github.com/tfidfwastaken/git/commits/submodule-update-on-es-superproject-aware\n    (fetch-it-via: git fetch https://github.com/tfidfwastaken/git submodule-update-on-es-superproject-aware)\n[3] https://github.com/tfidfwastaken/git/blob/a74aaf2540c536970f2541d3042c825f82a69770/builtin/submodule--helper.c#L2922-L2930\n\nFetch-it-Via:\ngit fetch https://github.com/tfidfwastaken/git submodule-update-list-3\n\nAtharva Raykar (9):\n  submodule--helper: split up ensure_core_worktree()\n  submodule--helper: get remote names from any repository\n  submodule--helper: rename helpers for update-clone\n  submodule--helper: refactor get_submodule_displaypath()\n  submodule--helper: allow setting superprefix for init_submodule()\n  submodule--helper: run update using child process struct\n  submodule: move core cmd_update() logic to C\n  submodule--helper: remove unused helpers\n  submodule--helper: rename helper functions\n\n builtin/submodule--helper.c | 771 +++++++++++++++++++++---------------\n git-submodule.sh            | 145 +------\n 2 files changed, 458 insertions(+), 458 deletions(-)\n\nRange diff against the previous version:\n\n 1:  f83a5b7f34 !  1:  d057ba04bd submodule--helper: split up ensure_core_worktree()\n    @@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv,\n     -static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n     +static void do_ensure_core_worktree(const char *path)\n      {\n    - \tconst struct submodule *sub;\n     -\tconst char *path;\n      \tconst char *cw;\n      \tstruct repository subrepo;\n    @@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv,\n     -\n     -\tpath = argv[1];\n     -\n    - \tsub = submodule_from_path(the_repository, null_oid(), path);\n    - \tif (!sub)\n    - \t\tBUG(\"We could get the submodule handle before?\");\n    + \tif (repo_submodule_init(&subrepo, the_repository, path, null_oid()))\n    + \t\tdie(_(\"could not get a repository handle for submodule '%s'\"), path);\n    +\n     @@ builtin/submodule--helper.c: static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n      \t\tfree(abs_path);\n      \t\tstrbuf_release(&sb);\n 2:  7f4e24ce25 !  2:  895cc10b97 submodule--helper: get remote names from any repository\n    @@ builtin/submodule--helper.c: static char *get_default_remote(void)\n     +static char *get_default_remote_submodule(const char *module_path)\n     +{\n     +\tconst char *refname;\n    -+\tconst struct submodule *sub;\n     +\tstruct repository subrepo;\n     +\n     +\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n     +\t\t\t\t\t  \"HEAD\", 0, NULL, NULL);\n    -+\tsub = submodule_from_path(the_repository, null_oid(), module_path);\n    -+\trepo_submodule_init(&subrepo, the_repository, sub);\n    ++\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n     +\treturn repo_get_default_remote(&subrepo, refname);\n     +}\n     +\n    @@ builtin/submodule--helper.c: static char *get_default_remote(void)\n      {\n      \tchar *remote;\n     @@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const char *prefix,\n    + {\n    + \tconst struct submodule *sub;\n      \tchar *remote_key = NULL;\n    - \tchar *sub_origin_url, *super_config_url, *displaypath;\n    +-\tchar *sub_origin_url, *super_config_url, *displaypath;\n    ++\tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n      \tstruct strbuf sb = STRBUF_INIT;\n     -\tstruct child_process cp = CHILD_PROCESS_INIT;\n      \tchar *sub_config_path = NULL;\n    @@ builtin/submodule--helper.c: static void sync_submodule(const char *path, const\n     -\n      \tstrbuf_reset(&sb);\n     -\tif (capture_command(&cp, &sb, 0))\n    -+\tstrbuf_addstr(&sb, get_default_remote_submodule(path));\n    -+\tif (!sb.buf)\n    ++\tdefault_remote = get_default_remote_submodule(path);\n    ++\tif (!default_remote)\n      \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n      \t\t      path);\n\n    +-\tstrbuf_strip_suffix(&sb, \"\\n\");\n    +-\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n    ++\tremote_key = xstrfmt(\"remote.%s.url\", default_remote);\n    ++\tfree(default_remote);\n    +\n    +-\tstrbuf_reset(&sb);\n    + \tsubmodule_to_gitdir(&sb, path);\n    + \tstrbuf_addstr(&sb, \"/config\");\n    +\n 3:  390596ee7c =  3:  1defe3e0ca submodule--helper: rename helpers for update-clone\n 4:  2a2ddcac91 =  4:  693b23772a submodule--helper: refactor get_submodule_displaypath()\n -:  ---------- >  5:  d1fd902a2a submodule--helper: allow setting superprefix for init_submodule()\n -:  ---------- >  6:  19c6c4e81a submodule--helper: run update using child process struct\n 5:  832020a290 !  7:  7cc32ad6f9 submodule: move core cmd_update() logic to C\n    @@ Commit message\n         new subprocess and call `submodule--helper init` on the submodule paths,\n         because the Git machinery is not able to pick up the configuration\n         changes introduced by that init call[1]. So we instead run the\n    -    `init_submodule_cb()` callback over each submodule directly.\n    -\n    -    This introduces another problem, because there is no mechanism to pass\n    -    the superproject path prefix (ie, `--super-prefix`) without starting a\n    -    new git process. This field is required for obtaining the display path\n    -    for that is used by the command's output messages. So let's add a field\n    -    into the `init_cb` struct that lets us pass this information to\n    -    `init_submodule()`, which will now also take an explicit 'superprefix'\n    -    argument.\n    +    `init_submodule_cb()` callback over each submodule in the same process.\n\n         While we are at it, we also remove the fetch_in_submodule() shell\n         function since it is no longer used anywhere.\n    @@ Commit message\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n\n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static char *compute_submodule_clone_url(const char *rel_url)\n    -\n    - struct init_cb {\n    - \tconst char *prefix;\n    -+\tconst char *superprefix;\n    - \tunsigned int flags;\n    - };\n    --#define INIT_CB_INIT { NULL, 0 }\n    -+#define INIT_CB_INIT { 0 }\n    -\n    - static void init_submodule(const char *path, const char *prefix,\n    --\t\t\t   unsigned int flags)\n    -+\t\t\t   const char *superprefix, unsigned int flags)\n    - {\n    - \tconst struct submodule *sub;\n    - \tstruct strbuf sb = STRBUF_INIT;\n    - \tchar *upd = NULL, *url = NULL, *displaypath;\n    -\n    --\tdisplaypath = get_submodule_displaypath(path, prefix);\n    -+\t/* try superprefix from the environment, if it is not passed explicitly */\n    -+\tif (!superprefix)\n    -+\t\tsuperprefix = get_super_prefix();\n    -+\tdisplaypath = do_get_submodule_displaypath(path, prefix, superprefix);\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    - static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n    - {\n    - \tstruct init_cb *info = cb_data;\n    --\tinit_submodule(list_item->name, info->prefix, info->flags);\n    -+\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n    - }\n    -\n    - static int module_init(int argc, const char **argv, const char *prefix)\n     @@ builtin/submodule--helper.c: struct submodule_update_clone {\n      \tconst char *prefix;\n      \tint single_branch;\n    @@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_pa\n     -static int run_update_command(struct update_data *ud, int subforce)\n     +static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)\n      {\n    --\tstruct strvec args = STRVEC_INIT;\n    --\tstruct strvec child_env = STRVEC_INIT;\n    -+\tstruct child_process cp = CHILD_PROCESS_INIT;\n    + \tstruct child_process cp = CHILD_PROCESS_INIT;\n      \tchar *oid = oid_to_hex(&ud->oid);\n     +\tstruct strbuf out = STRBUF_INIT;\n      \tint must_die_on_failure = 0;\n    --\tint git_cmd;\n     +\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n    -+\n    +\n    +-\tswitch (ud->update_strategy.type) {\n     +\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n     +\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n     +\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n     +\telse\n     +\t\tstrategy = ud->update_strategy;\n    -\n    --\tswitch (ud->update_strategy.type) {\n    -+\tcp.dir = xstrdup(ud->sm_path);\n    ++\n     +\tswitch (strategy.type) {\n      \tcase SM_UPDATE_CHECKOUT:\n    --\t\tgit_cmd = 1;\n    --\t\tstrvec_pushl(&args, \"checkout\", \"-q\", NULL);\n    -+\t\tcp.git_cmd = 1;\n    -+\t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n    - \t\tif (subforce)\n    --\t\t\tstrvec_push(&args, \"-f\");\n    -+\t\t\tstrvec_push(&cp.args, \"-f\");\n    - \t\tbreak;\n    - \tcase SM_UPDATE_REBASE:\n    --\t\tgit_cmd = 1;\n    --\t\tstrvec_push(&args, \"rebase\");\n    -+\t\tcp.git_cmd = 1;\n    -+\t\tstrvec_push(&cp.args, \"rebase\");\n    - \t\tif (ud->quiet)\n    --\t\t\tstrvec_push(&args, \"--quiet\");\n    -+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n    - \t\tmust_die_on_failure = 1;\n    - \t\tbreak;\n    - \tcase SM_UPDATE_MERGE:\n    --\t\tgit_cmd = 1;\n    --\t\tstrvec_push(&args, \"merge\");\n    -+\t\tcp.git_cmd = 1;\n    -+\t\tstrvec_push(&cp.args, \"merge\");\n    - \t\tif (ud->quiet)\n    --\t\t\tstrvec_push(&args, \"--quiet\");\n    -+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n    - \t\tmust_die_on_failure = 1;\n    + \t\tcp.git_cmd = 1;\n    + \t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n    +@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n      \t\tbreak;\n      \tcase SM_UPDATE_COMMAND:\n    --\t\tgit_cmd = 0;\n    --\t\tstrvec_push(&args, ud->update_strategy.command);\n    -+\t\tcp.git_cmd = 0;\n    -+\t\tcp.use_shell = 1;\n    + \t\tcp.use_shell = 1;\n    +-\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n     +\t\tstrvec_push(&cp.args, strategy.command);\n      \t\tmust_die_on_failure = 1;\n      \t\tbreak;\n    @@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_pa\n     -\t\t    submodule_strategy_to_string(&ud->update_strategy));\n     +\t\t    submodule_strategy_to_string(&strategy));\n      \t}\n    --\tstrvec_push(&args, oid);\n    -+\tstrvec_push(&cp.args, oid);\n    + \tstrvec_push(&cp.args, oid);\n\n    --\tprepare_submodule_repo_env(&child_env);\n    --\tif (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,\n    --\t\t\t\t     ud->sm_path, child_env.v)) {\n    + \tcp.dir = xstrdup(ud->sm_path);\n    + \tprepare_submodule_repo_env(&cp.env_array);\n    +-\tif (run_command(&cp)) {\n     -\t\tswitch (ud->update_strategy.type) {\n    -+\tprepare_submodule_repo_env(&cp.env_array);\n     +\tif (capture_command(&cp, &out, 0)) {\n     +\t\tif (must_die_on_failure) {\n     +\t\t\tswitch (strategy.type) {\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n      struct add_data {\n      \tconst char *prefix;\n      \tconst char *branch;\n    -@@ builtin/submodule--helper.c: static int add_clone(int argc, const char **argv, const char *prefix)\n    +@@ builtin/submodule--helper.c: static int module_add(int argc, const char **argv, const char *prefix)\n      \treturn 0;\n      }\n\n    @@ builtin/submodule--helper.c: static int add_clone(int argc, const char **argv, c\n     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {\n      \t{\"name\", module_name, 0},\n      \t{\"clone\", module_clone, 0},\n    - \t{\"add-clone\", add_clone, 0},\n    + \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n     +\t{\"update\", module_update, 0},\n      \t{\"update-module-mode\", module_update_module_mode, 0},\n      \t{\"update-clone\", update_clone, 0},\n 6:  fb3fa8174a <  -:  ---------- submodule--helper: remove update-clone subcommand\n 7:  364f72f870 !  8:  486f9d0a0e submodule--helper: remove unused helpers\n    @@ Commit message\n         These helpers were useful back when 'submodule update' had most of its\n         logic in shell. Now that they will never be invoked, let us remove them.\n\n    +    We also no longer need the 'update_clone_submodules()' and\n    +    'update_clone_submodule()' functions, so we remove those as well.\n    +\n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n         Mentored-by: Shourya Shukla <periperidip@gmail.com>\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n      \treturn run_update_command(ud, subforce, err);\n      }\n\n    +-static void update_clone_submodule(struct update_clone_data *ucd)\n    +-{\n    +-\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n    +-\t\toid_to_hex(&ucd->oid),\n    +-\t\tucd->just_cloned,\n    +-\t\tucd->sub->path);\n    +-}\n    +-\n    +-static int update_clone_submodules(struct submodule_update_clone *suc)\n    +-{\n    +-\tint i;\n    +-\n    +-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n    +-\t\t\t\t   update_clone_start_failure,\n    +-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n    +-\t\t\t\t   \"parallel/update\");\n    +-\n    +-\t/*\n    +-\t * We saved the output and put it out all at once now.\n    +-\t * That means:\n    +-\t * - the listener does not have to interleave their (checkout)\n    +-\t *   work with our fetching.  The writes involved in a\n    +-\t *   checkout involve more straightforward sequential I/O.\n    +-\t * - the listener can avoid doing any work if fetching failed.\n    +-\t */\n    +-\tif (suc->quickstop)\n    +-\t\treturn 1;\n    +-\n    +-\tfor (i = 0; i < suc->update_clone_nr; i++)\n    +-\t\tupdate_clone_submodule(&suc->update_clone[i]);\n    +-\n    +-\treturn 0;\n    +-}\n    +-\n    +-static int update_clone(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tconst char *update = NULL;\n    +-\tstruct pathspec pathspec;\n    +-\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n    +-\n    +-\tstruct option module_update_clone_options[] = {\n    +-\t\tOPT_STRING(0, \"prefix\", &prefix,\n    +-\t\t\t   N_(\"path\"),\n    +-\t\t\t   N_(\"path into the working tree\")),\n    +-\t\tOPT_STRING(0, \"recursive-prefix\", &suc.recursive_prefix,\n    +-\t\t\t   N_(\"path\"),\n    +-\t\t\t   N_(\"path into the working tree, across nested \"\n    +-\t\t\t      \"submodule boundaries\")),\n    +-\t\tOPT_STRING(0, \"update\", &update,\n    +-\t\t\t   N_(\"string\"),\n    +-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n    +-\t\tOPT_STRING_LIST(0, \"reference\", &suc.references, N_(\"repo\"),\n    +-\t\t\t   N_(\"reference repository\")),\n    +-\t\tOPT_BOOL(0, \"dissociate\", &suc.dissociate,\n    +-\t\t\t   N_(\"use --reference only while cloning\")),\n    +-\t\tOPT_STRING(0, \"depth\", &suc.depth, \"<depth>\",\n    +-\t\t\t   N_(\"create a shallow clone truncated to the \"\n    +-\t\t\t      \"specified number of revisions\")),\n    +-\t\tOPT_INTEGER('j', \"jobs\", &suc.max_jobs,\n    +-\t\t\t    N_(\"parallel jobs\")),\n    +-\t\tOPT_BOOL(0, \"recommend-shallow\", &suc.recommend_shallow,\n    +-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n    +-\t\tOPT__QUIET(&suc.quiet, N_(\"don't print cloning progress\")),\n    +-\t\tOPT_BOOL(0, \"progress\", &suc.progress,\n    +-\t\t\t    N_(\"force cloning progress\")),\n    +-\t\tOPT_BOOL(0, \"require-init\", &suc.require_init,\n    +-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n    +-\t\tOPT_BOOL(0, \"single-branch\", &suc.single_branch,\n    +-\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n    +-\t\tOPT_END()\n    +-\t};\n    +-\n    +-\tconst char *const git_submodule_helper_usage[] = {\n    +-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n    +-\t\tNULL\n    +-\t};\n    +-\tsuc.prefix = prefix;\n    +-\n    +-\tupdate_clone_config_from_gitmodules(&suc.max_jobs);\n    +-\tgit_config(git_update_clone_config, &suc.max_jobs);\n    +-\n    +-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n    +-\t\t\t     git_submodule_helper_usage, 0);\n    +-\n    +-\tif (update)\n    +-\t\tif (parse_submodule_update_strategy(update, &suc.update) < 0)\n    +-\t\t\tdie(_(\"bad value for update parameter\"));\n    +-\n    +-\tif (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)\n    +-\t\treturn 1;\n    +-\n    +-\tif (pathspec.nr)\n    +-\t\tsuc.warn_if_uninitialized = 1;\n    +-\n    +-\treturn update_clone_submodules(&suc);\n    +-}\n    +-\n     -static int run_update_procedure(int argc, const char **argv, const char *prefix)\n     -{\n     -\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n    @@ builtin/submodule--helper.c: static void do_ensure_core_worktree(const char *pat\n      \tint i;\n     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {\n      \t{\"clone\", module_clone, 0},\n    - \t{\"add-clone\", add_clone, 0},\n    + \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n      \t{\"update\", module_update, 0},\n     -\t{\"update-module-mode\", module_update_module_mode, 0},\n    +-\t{\"update-clone\", update_clone, 0},\n     -\t{\"run-update-procedure\", run_update_procedure, 0},\n     -\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n     -\t{\"relative-path\", resolve_relative_path, 0},\n    - \t{\"resolve-relative-url\", resolve_relative_url, 0},\n      \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n      \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n      \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n 8:  ca48dd452c !  9:  7b5b2be1a0 submodule--helper: rename helper functions\n    @@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv,\n     -static void do_ensure_core_worktree(const char *path)\n     +static void ensure_core_worktree(const char *path)\n      {\n    - \tconst struct submodule *sub;\n      \tconst char *cw;\n    + \tstruct repository subrepo;\n     @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data)\n      \tchar *prefixed_path;\n      \tstruct string_list err = STRING_LIST_INIT_DUP;\n\n-- \n2.32.0\n"},{"id":"438630","messageId":"20211013051805.45662-2-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v3 1/9] submodule--helper: split up ensure_core_worktree()","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:17:57Z","receivedAt":"2021-10-13T05:18:37Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"Let's split up `ensure_core_worktree()` so that we can call it from C\ncode without needing to deal with command line arguments.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 88ce6be69c..764fcb7dba 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2764,17 +2764,11 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+static void do_ensure_core_worktree(const char *path)\n {\n-\tconst char *path;\n \tconst char *cw;\n \tstruct repository subrepo;\n \n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\n \tif (repo_submodule_init(&subrepo, the_repository, path, null_oid()))\n \t\tdie(_(\"could not get a repository handle for submodule '%s'\"), path);\n \n@@ -2794,6 +2788,17 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n+}\n+\n+static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *path;\n+\n+\tif (argc != 2)\n+\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n+\n+\tpath = argv[1];\n+\tdo_ensure_core_worktree(path);\n \n \treturn 0;\n }\n-- \n2.32.0\n\n"},{"id":"438631","messageId":"20211013051805.45662-3-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v3 2/9] submodule--helper: get remote names from any repository","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:17:58Z","receivedAt":"2021-10-13T05:18:44Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"`get_default_remote()` retrieves the name of a remote by resolving the\nrefs from of the current repository's ref store.\n\nThus in order to use it for retrieving the remote name of a submodule,\nwe have to start a new subprocess which runs from the submodule\ndirectory.\n\nLet's instead introduce a function called `repo_get_default_remote()`\nwhich takes any repository object and retrieves the remote accordingly.\n\n`get_default_remote()` is then defined as a call to\n`repo_get_default_remote()` with 'the_repository' passed to it.\n\nNow that we have `repo_get_default_remote()`, we no longer have to start\na subprocess that called `submodule--helper get-default-remote` from\nwithin the submodule directory.\n\nSo let's make a function called `get_default_remote_submodule()` which\ntakes a submodule path, and returns the default remote for that\nsubmodule, all within the same process.\n\nWe can now use this function to save an unnecessary subprocess spawn in\n`sync_submodule()`, and also in the next patch, which will require this\nfunctionality.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 39 +++++++++++++++++++++++--------------\n 1 file changed, 24 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 764fcb7dba..bbab43230b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -29,11 +29,10 @@\n typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n \t\t\t\t  void *cb_data);\n \n-static char *get_default_remote(void)\n+static char *repo_get_default_remote(struct repository *repo, const char *refname)\n {\n \tchar *dest = NULL, *ret;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n \n \tif (!refname)\n \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n@@ -46,7 +45,7 @@ static char *get_default_remote(void)\n \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n \n \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n-\tif (git_config_get_string(sb.buf, &dest))\n+\tif (repo_config_get_string(repo, sb.buf, &dest))\n \t\tret = xstrdup(\"origin\");\n \telse\n \t\tret = dest;\n@@ -55,6 +54,23 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static char *get_default_remote_submodule(const char *module_path)\n+{\n+\tconst char *refname;\n+\tstruct repository subrepo;\n+\n+\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n+\t\t\t\t\t  \"HEAD\", 0, NULL, NULL);\n+\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n+\treturn repo_get_default_remote(&subrepo, refname);\n+}\n+\n+static char *get_default_remote(void)\n+{\n+\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n+\treturn repo_get_default_remote(the_repository, refname);\n+}\n+\n static int print_default_remote(int argc, const char **argv, const char *prefix)\n {\n \tchar *remote;\n@@ -1341,9 +1357,8 @@ static void sync_submodule(const char *path, const char *prefix,\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n-\tchar *sub_origin_url, *super_config_url, *displaypath;\n+\tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *sub_config_path = NULL;\n \n \tif (!is_submodule_active(the_repository, path))\n@@ -1382,21 +1397,15 @@ static void sync_submodule(const char *path, const char *prefix,\n \tif (!is_submodule_populated_gently(path, NULL))\n \t\tgoto cleanup;\n \n-\tprepare_submodule_repo_env(&cp.env_array);\n-\tcp.git_cmd = 1;\n-\tcp.dir = path;\n-\tstrvec_pushl(&cp.args, \"submodule--helper\",\n-\t\t     \"print-default-remote\", NULL);\n-\n \tstrbuf_reset(&sb);\n-\tif (capture_command(&cp, &sb, 0))\n+\tdefault_remote = get_default_remote_submodule(path);\n+\tif (!default_remote)\n \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n \t\t      path);\n \n-\tstrbuf_strip_suffix(&sb, \"\\n\");\n-\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n+\tremote_key = xstrfmt(\"remote.%s.url\", default_remote);\n+\tfree(default_remote);\n \n-\tstrbuf_reset(&sb);\n \tsubmodule_to_gitdir(&sb, path);\n \tstrbuf_addstr(&sb, \"/config\");\n \n-- \n2.32.0\n\n"},{"id":"438632","messageId":"20211013051805.45662-4-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v3 3/9] submodule--helper: rename helpers for update-clone","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:17:59Z","receivedAt":"2021-10-13T05:18:45Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"The `update-clone` subcommand helpers that perform the parallel clone\nand printing to stdout for shell script consumption, are renamed.\n\nThis lets us use the names `update_submodules()` and\n`update_submodule()` for the helpers in the next patch, when we create\nan `update` subcommand that does a full conversion.\n\nWe will get rid of these helpers in a cleanup patch at the end of this\nseries, when the `update-clone` command is no longer useful to us.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex bbab43230b..f60db966ea 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2466,7 +2466,7 @@ static int do_run_update_procedure(struct update_data *ud)\n \treturn run_update_command(ud, subforce);\n }\n \n-static void update_submodule(struct update_clone_data *ucd)\n+static void update_clone_submodule(struct update_clone_data *ucd)\n {\n \tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n \t\toid_to_hex(&ucd->oid),\n@@ -2474,7 +2474,7 @@ static void update_submodule(struct update_clone_data *ucd)\n \t\tucd->sub->path);\n }\n \n-static int update_submodules(struct submodule_update_clone *suc)\n+static int update_clone_submodules(struct submodule_update_clone *suc)\n {\n \tint i;\n \n@@ -2495,7 +2495,7 @@ static int update_submodules(struct submodule_update_clone *suc)\n \t\treturn 1;\n \n \tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_submodule(&suc->update_clone[i]);\n+\t\tupdate_clone_submodule(&suc->update_clone[i]);\n \n \treturn 0;\n }\n@@ -2560,7 +2560,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \tif (pathspec.nr)\n \t\tsuc.warn_if_uninitialized = 1;\n \n-\treturn update_submodules(&suc);\n+\treturn update_clone_submodules(&suc);\n }\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-- \n2.32.0\n\n"},{"id":"438633","messageId":"20211013051805.45662-5-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v3 4/9] submodule--helper: refactor get_submodule_displaypath()","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:18:00Z","receivedAt":"2021-10-13T05:19:08Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"We create a function called `do_get_submodule_displaypath()` that\ngenerates the display path required by several submodule functions, and\ntakes a custom superprefix parameter, instead of reading it from the\nenvironment.\n\nWe then redefine the existing `get_submodule_displaypath()` function\nas a call to this new function, where the superprefix is obtained from\nthe environment.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex f60db966ea..5b4f1dbcbd 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -261,11 +261,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\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 *do_get_submodule_displaypath(const char *path, const char *prefix, 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@@ -281,6 +278,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \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+\treturn do_get_submodule_displaypath(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-- \n2.32.0\n\n"},{"id":"438634","messageId":"20211013051805.45662-9-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v3 8/9] submodule--helper: remove unused helpers","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:18:04Z","receivedAt":"2021-10-13T05:19:09Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"These helpers were useful back when 'submodule update' had most of its\nlogic in shell. Now that they will never be invoked, let us remove them.\n\nWe also no longer need the 'update_clone_submodules()' and\n'update_clone_submodule()' functions, so we remove those as well.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 233 ------------------------------------\n 1 file changed, 233 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 3049628f88..0d6e65bd6c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -71,21 +71,6 @@ static char *get_default_remote(void)\n \treturn repo_get_default_remote(the_repository, refname);\n }\n \n-static int print_default_remote(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remote;\n-\n-\tif (argc != 1)\n-\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n-\n-\tremote = get_default_remote();\n-\tif (remote)\n-\t\tprintf(\"%s\\n\", remote);\n-\n-\tfree(remote);\n-\treturn 0;\n-}\n-\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -1960,29 +1945,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n \tfree(key);\n }\n \n-static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path, *update = NULL;\n-\tint just_cloned;\n-\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n-\n-\tif (argc < 3 || argc > 4)\n-\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n-\n-\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n-\tpath = argv[2];\n-\n-\tif (argc == 4)\n-\t\tupdate = argv[3];\n-\n-\tdetermine_submodule_update_strategy(the_repository,\n-\t\t\t\t\t    just_cloned, path, update,\n-\t\t\t\t\t    &update_strategy);\n-\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n-\n-\treturn 0;\n-}\n-\n struct update_clone_data {\n \tconst struct submodule *sub;\n \tstruct object_id oid;\n@@ -2518,182 +2480,6 @@ static int do_run_update_procedure(struct update_data *ud, struct string_list *e\n \treturn run_update_command(ud, subforce, err);\n }\n \n-static void update_clone_submodule(struct update_clone_data *ucd)\n-{\n-\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n-\t\toid_to_hex(&ucd->oid),\n-\t\tucd->just_cloned,\n-\t\tucd->sub->path);\n-}\n-\n-static int update_clone_submodules(struct submodule_update_clone *suc)\n-{\n-\tint i;\n-\n-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n-\t\t\t\t   update_clone_start_failure,\n-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n-\t\t\t\t   \"parallel/update\");\n-\n-\t/*\n-\t * We saved the output and put it out all at once now.\n-\t * That means:\n-\t * - the listener does not have to interleave their (checkout)\n-\t *   work with our fetching.  The writes involved in a\n-\t *   checkout involve more straightforward sequential I/O.\n-\t * - the listener can avoid doing any work if fetching failed.\n-\t */\n-\tif (suc->quickstop)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_clone_submodule(&suc->update_clone[i]);\n-\n-\treturn 0;\n-}\n-\n-static int update_clone(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *update = NULL;\n-\tstruct pathspec pathspec;\n-\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n-\n-\tstruct option module_update_clone_options[] = {\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &suc.recursive_prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &suc.references, N_(\"repo\"),\n-\t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &suc.dissociate,\n-\t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &suc.depth, \"<depth>\",\n-\t\t\t   N_(\"create a shallow clone truncated to the \"\n-\t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &suc.max_jobs,\n-\t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &suc.recommend_shallow,\n-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&suc.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &suc.progress,\n-\t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &suc.require_init,\n-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &suc.single_branch,\n-\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\tsuc.prefix = prefix;\n-\n-\tupdate_clone_config_from_gitmodules(&suc.max_jobs);\n-\tgit_config(git_update_clone_config, &suc.max_jobs);\n-\n-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &suc.update) < 0)\n-\t\t\tdie(_(\"bad value for update parameter\"));\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)\n-\t\treturn 1;\n-\n-\tif (pathspec.nr)\n-\t\tsuc.warn_if_uninitialized = 1;\n-\n-\treturn update_clone_submodules(&suc);\n-}\n-\n-static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-{\n-\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n-\tchar *prefixed_path, *update = NULL;\n-\tstruct update_data update_data = UPDATE_DATA_INIT;\n-\tstruct string_list err = STRING_LIST_INIT_DUP;\n-\n-\tstruct option options[] = {\n-\t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n-\t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n-\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n-\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n-\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const usage[] = {\n-\t\tN_(\"git submodule--helper run-update-procedure [<options>] <path>\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\n-\tif (argc != 1)\n-\t\tusage_with_options(usage, options);\n-\n-\tupdate_data.force = !!force;\n-\tupdate_data.quiet = !!quiet;\n-\tupdate_data.nofetch = !!nofetch;\n-\tupdate_data.just_cloned = !!just_cloned;\n-\tupdate_data.sm_path = argv[0];\n-\n-\tif (update_data.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n-\telse\n-\t\tprefixed_path = xstrdup(update_data.sm_path);\n-\n-\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n-\n-\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n-\t\t\t\t\t    update_data.sm_path, update,\n-\t\t\t\t\t    &update_data.update_strategy);\n-\n-\tfree(prefixed_path);\n-\n-\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data, &err);\n-\n-\treturn 3;\n-}\n-\n-static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 3)\n-\t\tdie(\"submodule--helper relative-path takes exactly 2 arguments, got %d\", argc);\n-\n-\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n-\tstrbuf_release(&sb);\n-\treturn 0;\n-}\n-\n static const char *remote_submodule_branch(const char *path)\n {\n \tconst struct submodule *sub;\n@@ -2852,19 +2638,6 @@ static void do_ensure_core_worktree(const char *path)\n \t}\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path;\n-\n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\tdo_ensure_core_worktree(path);\n-\n-\treturn 0;\n-}\n-\n static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n@@ -3707,16 +3480,10 @@ static struct cmd_struct commands[] = {\n \t{\"clone\", module_clone, 0},\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n \t{\"update\", module_update, 0},\n-\t{\"update-module-mode\", module_update_module_mode, 0},\n-\t{\"update-clone\", update_clone, 0},\n-\t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n-\t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n-\t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, 0},\n \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n-- \n2.32.0\n\n"},{"id":"438635","messageId":"20211013051805.45662-7-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v3 6/9] submodule--helper: run update using child process struct","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:18:02Z","receivedAt":"2021-10-13T05:19:14Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"We switch to using the run-command API function that takes a\n'struct child process', since we are using a lot of the options. This\nwill also make it simple to switch over to using 'capture_command()'\nwhen we start handling the output of the command completely in C.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 34 ++++++++++++++++------------------\n 1 file changed, 16 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 74f084a9c9..640b3bd220 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2342,47 +2342,45 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \n static int run_update_command(struct update_data *ud, int subforce)\n {\n-\tstruct strvec args = STRVEC_INIT;\n-\tstruct strvec child_env = STRVEC_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n \tint must_die_on_failure = 0;\n-\tint git_cmd;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_pushl(&args, \"checkout\", \"-q\", NULL);\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n \t\tif (subforce)\n-\t\t\tstrvec_push(&args, \"-f\");\n+\t\t\tstrvec_push(&cp.args, \"-f\");\n \t\tbreak;\n \tcase SM_UPDATE_REBASE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"rebase\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_MERGE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"merge\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n-\t\tgit_cmd = 0;\n-\t\tstrvec_push(&args, ud->update_strategy.command);\n+\t\tcp.use_shell = 1;\n+\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n \t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t}\n-\tstrvec_push(&args, oid);\n+\tstrvec_push(&cp.args, oid);\n \n-\tprepare_submodule_repo_env(&child_env);\n-\tif (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,\n-\t\t\t\t     ud->sm_path, child_env.v)) {\n+\tcp.dir = xstrdup(ud->sm_path);\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tif (run_command(&cp)) {\n \t\tswitch (ud->update_strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n \t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-- \n2.32.0\n\n"},{"id":"438637","messageId":"20211013051805.45662-8-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v3 7/9] submodule: move core cmd_update() logic to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:18:03Z","receivedAt":"2021-10-13T05:19:16Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"This patch completes the conversion past the flag parsing of\n`submodule update` by introducing a helper subcommand called\n`submodule--helper update`. The behaviour of `submodule update` should\nremain the same after this patch.\n\nWe add more fields to the `struct update_data` that are required by\n`struct submodule_update_clone` to be able to perform a clone, when that\nis needed to be done.\n\nRecursing on a submodule is done by calling a subprocess that launches\n`submodule--helper update`, with a modified `--recursive-prefix` and\n`--prefix` parameter.\n\nWe also introduce `update_submodules()` and `update_submodule()` which\nare quite similar to `update_clone_submodules()` and\n`update_clone_submodule()`, and will supersede them.\n\nWhen the `--init` flag is passed to the subcommand, we do not spawn a\nnew subprocess and call `submodule--helper init` on the submodule paths,\nbecause the Git machinery is not able to pick up the configuration\nchanges introduced by that init call[1]. So we instead run the\n`init_submodule_cb()` callback over each submodule in the same process.\n\nWhile we are at it, we also remove the fetch_in_submodule() shell\nfunction since it is no longer used anywhere.\n\n[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 462 +++++++++++++++++++++++++++++++-----\n git-submodule.sh            | 145 +----------\n 2 files changed, 410 insertions(+), 197 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 640b3bd220..3049628f88 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2010,7 +2010,6 @@ struct submodule_update_clone {\n \tconst char *prefix;\n \tint single_branch;\n \n-\t/* to be consumed by git-submodule.sh */\n \tstruct update_clone_data *update_clone;\n \tint update_clone_nr; int update_clone_alloc;\n \n@@ -2033,19 +2032,63 @@ struct submodule_update_clone {\n }\n \n struct update_data {\n+\tconst char *prefix;\n \tconst char *recursive_prefix;\n \tconst char *sm_path;\n \tconst char *displaypath;\n \tstruct object_id oid;\n \tstruct object_id suboid;\n-\tstruct submodule_update_strategy update_strategy;\n+\tint max_jobs;\n \tint depth;\n+\tint recommend_shallow;\n+\tint single_branch;\n+\tunsigned int init: 1;\n \tunsigned int force: 1;\n \tunsigned int quiet: 1;\n \tunsigned int nofetch: 1;\n-\tunsigned int just_cloned: 1;\n+\tunsigned int remote: 1;\n+\tunsigned int recursive: 1;\n+\tunsigned int progress: 1;\n+\tunsigned int dissociate: 1;\n+\tunsigned int require_init: 1;\n+\tunsigned warn_if_uninitialized : 1;\n+\tunsigned int just_cloned : 1;\n+\tstruct submodule_update_strategy update_strategy;\n+\tstruct string_list references;\n+\tstruct module_list list;\n };\n-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }\n+#define UPDATE_DATA_INIT { \\\n+\t.list = MODULE_LIST_INIT, \\\n+\t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+\t.recommend_shallow = -1, \\\n+\t.references = STRING_LIST_INIT_DUP, \\\n+\t.single_branch = -1, \\\n+\t.max_jobs = 1, \\\n+}\n+\n+static void update_clone_from_update_data(struct submodule_update_clone *suc,\n+\t\t\t\t\t  struct update_data *update_data)\n+{\n+\tsuc->prefix = update_data->prefix;\n+\tsuc->recursive_prefix = update_data->recursive_prefix;\n+\tsuc->max_jobs = update_data->max_jobs;\n+\tsuc->progress = update_data->progress;\n+\tsuc->quiet = update_data->quiet;\n+\tsuc->dissociate = update_data->dissociate;\n+\tsuc->require_init = update_data->require_init;\n+\tsuc->single_branch = update_data->single_branch;\n+\tsuc->warn_if_uninitialized = update_data->warn_if_uninitialized;\n+\tsuc->list = update_data->list;\n+\tsuc->update = update_data->update_strategy;\n+\tsuc->recommend_shallow = update_data->recommend_shallow;\n+\tif (update_data->depth)\n+\t\tsuc->depth = xstrfmt(\"--depth=%d\", update_data->depth);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstring_list_append(&suc->references, item->string);\n+\t}\n+}\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n \t\tstruct strbuf *out, const char *displaypath)\n@@ -2340,13 +2383,21 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \treturn run_command(&cp);\n }\n \n-static int run_update_command(struct update_data *ud, int subforce)\n+static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n+\tstruct strbuf out = STRBUF_INIT;\n \tint must_die_on_failure = 0;\n+\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n \n-\tswitch (ud->update_strategy.type) {\n+\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n+\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n+\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n+\telse\n+\t\tstrategy = ud->update_strategy;\n+\n+\tswitch (strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\tcp.git_cmd = 1;\n \t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n@@ -2369,80 +2420,75 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n \t\tcp.use_shell = 1;\n-\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n+\t\tstrvec_push(&cp.args, strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t    submodule_strategy_to_string(&strategy));\n \t}\n \tstrvec_push(&cp.args, oid);\n \n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env_array);\n-\tif (run_command(&cp)) {\n-\t\tswitch (ud->update_strategy.type) {\n-\t\tcase SM_UPDATE_CHECKOUT:\n-\t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tcase SM_UPDATE_REBASE:\n-\t\t\tprintf(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tcase SM_UPDATE_MERGE:\n-\t\t\tprintf(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tcase SM_UPDATE_COMMAND:\n-\t\t\tprintf(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n-\t\t\t       ud->update_strategy.command, oid, ud->displaypath);\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\tif (capture_command(&cp, &out, 0)) {\n+\t\tif (must_die_on_failure) {\n+\t\t\tswitch (strategy.type) {\n+\t\t\tcase SM_UPDATE_CHECKOUT:\n+\t\t\t\tdie(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_REBASE:\n+\t\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_MERGE:\n+\t\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_COMMAND:\n+\t\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\t\t    strategy.command, oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tBUG(\"unexpected update strategy type: %s\",\n+\t\t\t\t    submodule_strategy_to_string(&strategy));\n+\t\t\t}\n \t\t}\n-\t\t/*\n-\t\t * NEEDSWORK: We are currently printing to stdout with error\n-\t\t * return so that the shell caller handles the error output\n-\t\t * properly. Once we start handling the error messages within\n-\t\t * C, we should use die() instead.\n-\t\t */\n-\t\tif (must_die_on_failure)\n-\t\t\treturn 2;\n-\t\t/*\n-\t\t * This signifies to the caller in shell that the command\n-\t\t * failed without dying\n-\t\t */\n+\n+\t\t/* the command failed, but update must continue */\n+\t\tstring_list_append(err, out.buf);\n \t\treturn 1;\n \t}\n \n-\tswitch (ud->update_strategy.type) {\n-\tcase SM_UPDATE_CHECKOUT:\n-\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_REBASE:\n-\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_MERGE:\n-\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_COMMAND:\n-\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n-\t\t       ud->displaypath, ud->update_strategy.command, oid);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\tif (!ud->quiet) {\n+\t\tswitch (strategy.type) {\n+\t\tcase SM_UPDATE_CHECKOUT:\n+\t\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n+\t\t\tbreak;\n+\t\tcase SM_UPDATE_REBASE:\n+\t\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n+\t\t\tbreak;\n+\t\tcase SM_UPDATE_MERGE:\n+\t\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n+\t\t\tbreak;\n+\t\tcase SM_UPDATE_COMMAND:\n+\t\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n+\t\t\t       ud->displaypath, strategy.command, oid);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"unexpected update strategy type: %s\",\n+\t\t\t    submodule_strategy_to_string(&strategy));\n+\t\t}\n \t}\n \n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud)\n+static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2469,7 +2515,7 @@ static int do_run_update_procedure(struct update_data *ud)\n \t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n \t}\n \n-\treturn run_update_command(ud, subforce);\n+\treturn run_update_command(ud, subforce, err);\n }\n \n static void update_clone_submodule(struct update_clone_data *ucd)\n@@ -2574,6 +2620,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n \tchar *prefixed_path, *update = NULL;\n \tstruct update_data update_data = UPDATE_DATA_INIT;\n+\tstruct string_list err = STRING_LIST_INIT_DUP;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n@@ -2631,7 +2678,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tfree(prefixed_path);\n \n \tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data);\n+\t\treturn do_run_update_procedure(&update_data, &err);\n \n \treturn 3;\n }\n@@ -3002,6 +3049,291 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \treturn !!ret;\n }\n \n+static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n+{\n+\tconst char *update = submodule_strategy_to_string(&update_data->update_strategy);\n+\n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n+\tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n+\tif (update_data->prefix)\n+\t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n+\tif (update_data->recursive_prefix)\n+\t\tstrvec_pushl(args, \"--recursive-prefix\",\n+\t\t\t     update_data->recursive_prefix, NULL);\n+\tif (update_data->quiet)\n+\t\tstrvec_push(args, \"--quiet\");\n+\tif (update_data->force)\n+\t\tstrvec_push(args, \"--force\");\n+\tif (update_data->init)\n+\t\tstrvec_push(args, \"--init\");\n+\tif (update_data->remote)\n+\t\tstrvec_push(args, \"--remote\");\n+\tif (update_data->nofetch)\n+\t\tstrvec_push(args, \"--no-fetch\");\n+\tif (update_data->dissociate)\n+\t\tstrvec_push(args, \"--dissociate\");\n+\tif (update_data->progress)\n+\t\tstrvec_push(args, \"--progress\");\n+\tif (update_data->require_init)\n+\t\tstrvec_push(args, \"--require-init\");\n+\tif (update_data->depth)\n+\t\tstrvec_pushf(args, \"--depth=%d\", update_data->depth);\n+\tif (update)\n+\t\tstrvec_pushl(args, \"--update\", update, NULL);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n+\t}\n+\tif (update_data->recommend_shallow == 0)\n+\t\tstrvec_push(args, \"--no-recommend-shallow\");\n+\telse if (update_data->recommend_shallow == 1)\n+\t\tstrvec_push(args, \"--recommend-shallow\");\n+\tif (update_data->single_branch >= 0)\n+\t\tstrvec_push(args, \"--single-branch\");\n+}\n+\n+static int update_submodule(struct update_data *update_data)\n+{\n+\tchar *prefixed_path;\n+\tstruct string_list err = STRING_LIST_INIT_DUP;\n+\n+\tdo_ensure_core_worktree(update_data->sm_path);\n+\n+\tif (update_data->recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n+\t\t\t\t\tupdate_data->sm_path);\n+\telse\n+\t\tprefixed_path = xstrdup(update_data->sm_path);\n+\n+\tupdate_data->displaypath = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t     update_data->prefix);\n+\tfree(prefixed_path);\n+\n+\tif (update_data->just_cloned) {\n+\t\toidcpy(&update_data->suboid, null_oid());\n+\t} else {\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n+\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t}\n+\n+\tif (update_data->remote) {\n+\t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n+\t\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n+\t\tchar *remote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n+\n+\t\tif (!update_data->nofetch) {\n+\t\t\tif(fetch_in_submodule(update_data->sm_path, update_data->depth,\n+\t\t\t\t\t      0, NULL))\n+\t\t\t\tdie(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\t\t    update_data->sm_path);\n+\t\t}\n+\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))\n+\t\t\tdie(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t    remote_ref, update_data->sm_path);\n+\n+\t\tfree(remote_ref);\n+\t}\n+\n+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n+\t\tif (do_run_update_procedure(update_data, &err))\n+\t\t\treturn 1;\n+\n+\tif (update_data->recursive) {\n+\t\tint res;\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct update_data next = *update_data;\n+\t\tchar *die_msg = xstrfmt(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t\t\tupdate_data->displaypath);\n+\n+\t\tif (update_data->recursive_prefix)\n+\t\t\tprefixed_path = xstrfmt(\"%s%s/\", update_data->recursive_prefix,\n+\t\t\t\t\t\tupdate_data->sm_path);\n+\t\telse\n+\t\t\tprefixed_path = xstrfmt(\"%s/\", update_data->sm_path);\n+\n+\t\tnext.recursive_prefix = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t\t  update_data->prefix);\n+\t\tnext.prefix = NULL;\n+\t\toidcpy(&next.oid, null_oid());\n+\t\toidcpy(&next.suboid, null_oid());\n+\n+\t\tcp.dir = update_data->sm_path;\n+\t\tcp.git_cmd = 1;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tupdate_data_to_args(&next, &cp.args);\n+\n+\t\t/* die() if child process die()'d */\n+\t\tif ((res = run_command(&cp)) == 128)\n+\t\t\tdie(\"%s\", die_msg);\n+\t\tif (res)\n+\t\t\tstring_list_append(&err, die_msg);\n+\n+\t\tfree(die_msg);\n+\t}\n+\n+\tif (err.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &err)\n+\t\t\tfputs(item->string, stderr);\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int update_submodules(struct update_data *update_data)\n+{\n+\tint i, res = 0;\n+\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\n+\tupdate_clone_from_update_data(&suc, update_data);\n+\trun_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,\n+\t\t\t\t   update_clone_start_failure,\n+\t\t\t\t   update_clone_task_finished, &suc, \"submodule\",\n+\t\t\t\t   \"parallel/update\");\n+\n+\t/*\n+\t * We saved the output and put it out all at once now.\n+\t * That means:\n+\t * - the listener does not have to interleave their (checkout)\n+\t *   work with our fetching.  The writes involved in a\n+\t *   checkout involve more straightforward sequential I/O.\n+\t * - the listener can avoid doing any work if fetching failed.\n+\t */\n+\tif (suc.quickstop) {\n+\t\tstring_list_clear(&update_data->references, 0);\n+\t\treturn 1;\n+\t}\n+\n+\tfor (i = 0; i < suc.update_clone_nr; i++) {\n+\t\tstruct update_clone_data ucd = suc.update_clone[i];\n+\n+\t\toidcpy(&update_data->oid, &ucd.oid);\n+\t\tupdate_data->just_cloned = ucd.just_cloned;\n+\t\tupdate_data->sm_path = ucd.sub->path;\n+\n+\t\tif (update_submodule(update_data))\n+\t\t\tres = 1;\n+\t}\n+\n+\tstring_list_clear(&update_data->references, 0);\n+\treturn res;\n+}\n+\n+static int module_update(int argc, const char **argv, const char *prefix)\n+{\n+\tint init = 0, force = 0, quiet = 0, nofetch = 0;\n+\tint remote = 0, recursive = 0, dissociate = 0;\n+\tint progress = 0, require_init = 0;\n+\tconst char *update = NULL;\n+\tstruct pathspec pathspec;\n+\tstruct update_data update_data = UPDATE_DATA_INIT;\n+\n+\tstruct option module_update_clone_options[] = {\n+\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n+\t\tOPT_BOOL(0, \"init\", &init,\n+\t\t\t N_(\"initialize uninitialized submodules before update\")),\n+\t\tOPT_BOOL(0, \"remote\", &remote,\n+\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive,\n+\t\t\t N_(\"traverse submodules recursively\")),\n+\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n+\t\t\t N_(\"don't fetch new objects from the remote site\")),\n+\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree\")),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree, across nested \"\n+\t\t\t      \"submodule boundaries\")),\n+\t\tOPT_STRING(0, \"update\", &update,\n+\t\t\t   N_(\"string\"),\n+\t\t\t   N_(\"rebase, merge, checkout or none\")),\n+\t\tOPT_STRING_LIST(0, \"reference\", &update_data.references, N_(\"repo\"),\n+\t\t\t\tN_(\"reference repository\")),\n+\t\tOPT_BOOL(0, \"dissociate\", &dissociate,\n+\t\t\t N_(\"use --reference only while cloning\")),\n+\t\tOPT_INTEGER(0, \"depth\", &update_data.depth,\n+\t\t\t    N_(\"create a shallow clone truncated to the \"\n+\t\t\t       \"specified number of revisions\")),\n+\t\tOPT_INTEGER('j', \"jobs\", &update_data.max_jobs,\n+\t\t\t    N_(\"parallel jobs\")),\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &update_data.recommend_shallow,\n+\t\t\t N_(\"whether the initial clone should follow the shallow recommendation\")),\n+\t\tOPT__QUIET(&quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &progress,\n+\t\t\t N_(\"force cloning progress\")),\n+\t\tOPT_BOOL(0, \"require-init\", &require_init,\n+\t\t\t N_(\"disallow cloning into non-empty directory\")),\n+\t\tOPT_BOOL(0, \"single-branch\", &update_data.single_branch,\n+\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n+\t\tNULL\n+\t};\n+\n+\tupdate_clone_config_from_gitmodules(&update_data.max_jobs);\n+\tgit_config(git_update_clone_config, &update_data.max_jobs);\n+\n+\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\tupdate_data.prefix = prefix;\n+\n+\tupdate_data.force = !!force;\n+\tupdate_data.quiet = !!quiet;\n+\tupdate_data.nofetch = !!nofetch;\n+\tupdate_data.init = !!init;\n+\tupdate_data.require_init = !!require_init;\n+\tupdate_data.remote = !!remote;\n+\tupdate_data.recursive = !!recursive;\n+\tupdate_data.progress = !!progress;\n+\tupdate_data.dissociate = !!dissociate;\n+\toidcpy(&update_data.oid, null_oid());\n+\toidcpy(&update_data.suboid, null_oid());\n+\n+\tif (update)\n+\t\tif (parse_submodule_update_strategy(update,\n+\t\t\t\t\t\t    &update_data.update_strategy) < 0)\n+\t\t\tdie(_(\"bad value for update parameter\"));\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &update_data.list) < 0)\n+\t\treturn 1;\n+\n+\tif (pathspec.nr)\n+\t\tupdate_data.warn_if_uninitialized = 1;\n+\n+\tif (update_data.init) {\n+\t\tstruct module_list list = MODULE_LIST_INIT;\n+\t\tstruct init_cb info = INIT_CB_INIT;\n+\n+\t\tif (module_list_compute(argc, argv, update_data.prefix,\n+\t\t\t\t\t&pathspec, &list) < 0)\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * If there are no path args and submodule.active is set then,\n+\t\t * by default, only initialize 'active' modules.\n+\t\t */\n+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n+\t\t\tmodule_list_active(&list);\n+\n+\t\tinfo.prefix = update_data.prefix;\n+\t\tinfo.superprefix = update_data.recursive_prefix;\n+\t\tif (update_data.quiet)\n+\t\t\tinfo.flags |= OPT_QUIET;\n+\n+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n+\t}\n+\n+\treturn update_submodules(&update_data);\n+}\n+\n struct add_data {\n \tconst char *prefix;\n \tconst char *branch;\n@@ -3360,6 +3692,7 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+\n #define SUPPORT_SUPER_PREFIX (1<<0)\n \n struct cmd_struct {\n@@ -3373,6 +3706,7 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n+\t{\"update\", module_update, 0},\n \t{\"update-module-mode\", module_update_module_mode, 0},\n \t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 652861aa66..bcd8b92aab 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -246,20 +246,6 @@ cmd_deinit()\n \tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- \"$@\"\n }\n \n-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]\n-# Because arguments are positional, use an empty string to omit <depth>\n-# but include <sha1>.\n-fetch_in_submodule () (\n-\tsanitize_submodule_env &&\n-\tcd \"$1\" &&\n-\tif test $# -eq 3\n-\tthen\n-\t\techo \"$3\" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+\"$2\"}\n-\telse\n-\t\tgit fetch ${GIT_QUIET:+--quiet} ${2:+\"$2\"}\n-\tfi\n-)\n-\n #\n # Update each submodule path to correct revision, using clone and checkout as needed\n #\n@@ -361,133 +347,26 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\tif test -n \"$init\"\n-\tthen\n-\t\tcmd_init \"--\" \"$@\" || return\n-\tfi\n-\n-\t{\n-\tgit submodule--helper update-clone ${GIT_QUIET:+--quiet} \\\n-\t\t${progress:+\"--progress\"} \\\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n+\t\t${GIT_QUIET:+--quiet} \\\n+\t\t${force:+--force} \\\n+\t\t${progress:+--progress} \\\n+\t\t${dissociate:+--dissociate} \\\n+\t\t${remote:+--remote} \\\n+\t\t${recursive:+--recursive} \\\n+\t\t${init:+--init} \\\n+\t\t${require_init:+--require-init} \\\n+\t\t${nofetch:+--no-fetch} \\\n \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t${update:+--update \"$update\"} \\\n \t\t${reference:+\"$reference\"} \\\n-\t\t${dissociate:+\"--dissociate\"} \\\n-\t\t${depth:+--depth \"$depth\"} \\\n-\t\t${require_init:+--require-init} \\\n+\t\t${depth:+\"$depth\"} \\\n \t\t$single_branch \\\n \t\t$recommend_shallow \\\n \t\t$jobs \\\n \t\t-- \\\n-\t\t\"$@\" || echo \"#unmatched\" $?\n-\t} | {\n-\terr=\n-\twhile read -r quickabort sha1 just_cloned sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n-\n-\t\tgit submodule--helper ensure-core-worktree \"$sm_path\" || exit 1\n-\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\n-\t\tif test $just_cloned -eq 1\n-\t\tthen\n-\t\t\tsubsha1=\n-\t\telse\n-\t\t\tjust_cloned=\n-\t\t\tsubsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify HEAD) ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current revision in submodule path '\\$displaypath'\")\"\n-\t\tfi\n-\n-\t\tif test -n \"$remote\"\n-\t\tthen\n-\t\t\tbranch=$(git submodule--helper remote-branch \"$sm_path\")\n-\t\t\tif test -z \"$nofetch\"\n-\t\t\tthen\n-\t\t\t\t# Fetch remote before determining tracking $sha1\n-\t\t\t\tfetch_in_submodule \"$sm_path\" $depth ||\n-\t\t\t\tdie \"fatal: $(eval_gettext \"Unable to fetch in submodule path '\\$sm_path'\")\"\n-\t\t\tfi\n-\t\t\tremote_name=$(sanitize_submodule_env; cd \"$sm_path\" && git submodule--helper print-default-remote)\n-\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify \"${remote_name}/${branch}\") ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\n-\t\tout=$(git submodule--helper run-update-procedure \\\n-\t\t\t  ${wt_prefix:+--prefix \"$wt_prefix\"} \\\n-\t\t\t  ${GIT_QUIET:+--quiet} \\\n-\t\t\t  ${force:+--force} \\\n-\t\t\t  ${just_cloned:+--just-cloned} \\\n-\t\t\t  ${nofetch:+--no-fetch} \\\n-\t\t\t  ${depth:+\"$depth\"} \\\n-\t\t\t  ${update:+--update \"$update\"} \\\n-\t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n-\t\t\t  ${sha1:+--oid \"$sha1\"} \\\n-\t\t\t  ${subsha1:+--suboid \"$subsha1\"} \\\n-\t\t\t  \"--\" \\\n-\t\t\t  \"$sm_path\")\n-\n-\t\t# exit codes for run-update-procedure:\n-\t\t# 0: update was successful, say command output\n-\t\t# 1: update procedure failed, but should not die\n-\t\t# 2 or 128: subcommand died during execution\n-\t\t# 3: no update procedure was run\n-\t\tres=\"$?\"\n-\t\tcase $res in\n-\t\t0)\n-\t\t\tsay \"$out\"\n-\t\t\t;;\n-\t\t1)\n-\t\t\terr=\"${err};fatal: $out\"\n-\t\t\tcontinue\n-\t\t\t;;\n-\t\t2|128)\n-\t\t\tdie_with_status $res \"fatal: $out\"\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=$(git submodule--helper relative-path \"$prefix$sm_path/\" \"$wt_prefix\")\n-\t\t\t\twt_prefix=\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_update\n-\t\t\t)\n-\t\t\tres=$?\n-\t\t\tif test $res -gt 0\n-\t\t\tthen\n-\t\t\t\tdie_msg=\"fatal: $(eval_gettext \"Failed to recurse into submodule path '\\$displaypath'\")\"\n-\t\t\t\tif test $res -ne 2\n-\t\t\t\tthen\n-\t\t\t\t\terr=\"${err};$die_msg\"\n-\t\t\t\t\tcontinue\n-\t\t\t\telse\n-\t\t\t\t\tdie_with_status $res \"$die_msg\"\n-\t\t\t\tfi\n-\t\t\tfi\n-\t\tfi\n-\tdone\n-\n-\tif test -n \"$err\"\n-\tthen\n-\t\tOIFS=$IFS\n-\t\tIFS=';'\n-\t\tfor e in $err\n-\t\tdo\n-\t\t\tif test -n \"$e\"\n-\t\t\tthen\n-\t\t\t\techo >&2 \"$e\"\n-\t\t\tfi\n-\t\tdone\n-\t\tIFS=$OIFS\n-\t\texit 1\n-\tfi\n-\t}\n+\t\t\"$@\"\n }\n \n #\n-- \n2.32.0\n\n"},{"id":"438636","messageId":"20211013051805.45662-6-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v3 5/9] submodule--helper: allow setting superprefix for init_submodule()","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:18:01Z","receivedAt":"2021-10-13T05:19:17Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"We allow callers of the `init_submodule()` function to optionally\noverride the superprefix from the environment.\n\nWe need to enable this option because in our conversion of the update\ncommand that will follow, the '--init' option will be handled through\nthis API. We will need to change the superprefix at that time to ensure\nthe display paths show correctly in the output messages.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5b4f1dbcbd..74f084a9c9 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -606,18 +606,22 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *superprefix;\n \tunsigned int flags;\n };\n-#define INIT_CB_INIT { NULL, 0 }\n+#define INIT_CB_INIT { 0 }\n \n static void init_submodule(const char *path, const char *prefix,\n-\t\t\t   unsigned int flags)\n+\t\t\t   const char *superprefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\t/* try superprefix from the environment, if it is not passed explicitly */\n+\tif (!superprefix)\n+\t\tsuperprefix = get_super_prefix();\n+\tdisplaypath = do_get_submodule_displaypath(path, prefix, superprefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -691,7 +695,7 @@ static void init_submodule(const char *path, const char *prefix,\n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct init_cb *info = cb_data;\n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n-- \n2.32.0\n\n"},{"id":"438638","messageId":"20211013051805.45662-10-raykar.ath@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v3 9/9] submodule--helper: rename helper functions","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-13T05:18:05Z","receivedAt":"2021-10-13T05:19:18Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"These two functions were prefixed with 'do' before the shell-to-C\nconversion because they were utility functions meant to be called by\ntheir non-prefixed counterpart.\n\nSince those callers don't exist anymore, and these functions can now be\nused directly, let's rename them to signal this fact.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\n---\n builtin/submodule--helper.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 0d6e65bd6c..82d68650e8 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2450,7 +2450,7 @@ static int run_update_command(struct update_data *ud, int subforce, struct strin\n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n+static int run_update_procedure(struct update_data *ud, struct string_list *err)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2612,7 +2612,7 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void do_ensure_core_worktree(const char *path)\n+static void ensure_core_worktree(const char *path)\n {\n \tconst char *cw;\n \tstruct repository subrepo;\n@@ -2871,7 +2871,7 @@ static int update_submodule(struct update_data *update_data)\n \tchar *prefixed_path;\n \tstruct string_list err = STRING_LIST_INIT_DUP;\n \n-\tdo_ensure_core_worktree(update_data->sm_path);\n+\tensure_core_worktree(update_data->sm_path);\n \n \tif (update_data->recursive_prefix)\n \t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n@@ -2911,7 +2911,7 @@ static int update_submodule(struct update_data *update_data)\n \t}\n \n \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n-\t\tif (do_run_update_procedure(update_data, &err))\n+\t\tif (run_update_procedure(update_data, &err))\n \t\t\treturn 1;\n \n \tif (update_data->recursive) {\n-- \n2.32.0\n\n"},{"id":"438717","messageId":"xmqqczo8eahl.fsf@gitster.g","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-10-14T00:05:58Z","receivedAt":"2021-10-14T00:06:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Atharva Raykar <raykar.ath@gmail.com> writes:\n\n> I have attempted to make a version of this series that is based on that topic [2],\n> and added the superproject gitdir caching code in C [3]. It passes the tests,\n> but I am not too confident about its correctness. I hope that branch can be\n> helpful in some way.\n>\n> [1] https://lore.kernel.org/git/20210819200953.2105230-1-emilyshaffer@google.com/\n> [2] https://github.com/tfidfwastaken/git/commits/submodule-update-on-es-superproject-aware\n>     (fetch-it-via: git fetch https://github.com/tfidfwastaken/git submodule-update-on-es-superproject-aware)\n> [3] https://github.com/tfidfwastaken/git/blob/a74aaf2540c536970f2541d3042c825f82a69770/builtin/submodule--helper.c#L2922-L2930\n\nThe \"C rewrite\" of the code [3] that unconditionally sets of the\nsubmodule.superprojectgitdir varible seems straightforward enough.\n\nEmily, how solid do you think your \"superproject aware submodule\"\ntopic already is?  Would it be stable enough to build other things\non top, or is it a bit too premature?\n"},{"id":"438791","messageId":"YWiXL+plA7GHfuVv@google.com","threadId":"56453","inReplyTo":"xmqqczo8eahl.fsf@gitster.g","subject":"Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2021-10-14T20:46:39Z","receivedAt":"2021-10-14T20:46:50Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Wed, Oct 13, 2021 at 05:05:58PM -0700, Junio C Hamano wrote:\n> \n> Atharva Raykar <raykar.ath@gmail.com> writes:\n> \n> > I have attempted to make a version of this series that is based on that topic [2],\n> > and added the superproject gitdir caching code in C [3]. It passes the tests,\n> > but I am not too confident about its correctness. I hope that branch can be\n> > helpful in some way.\n> >\n> > [1] https://lore.kernel.org/git/20210819200953.2105230-1-emilyshaffer@google.com/\n> > [2] https://github.com/tfidfwastaken/git/commits/submodule-update-on-es-superproject-aware\n> >     (fetch-it-via: git fetch https://github.com/tfidfwastaken/git submodule-update-on-es-superproject-aware)\n> > [3] https://github.com/tfidfwastaken/git/blob/a74aaf2540c536970f2541d3042c825f82a69770/builtin/submodule--helper.c#L2922-L2930\n> \n> The \"C rewrite\" of the code [3] that unconditionally sets of the\n> submodule.superprojectgitdir varible seems straightforward enough.\n> \n> Emily, how solid do you think your \"superproject aware submodule\"\n> topic already is?  Would it be stable enough to build other things\n> on top, or is it a bit too premature?\n\nAs of the version I sent today\n(https://lore.kernel.org/git/20211014203416.2802639-1-emilyshaffer%40google.com)\nI think it is stable enough to build on top of. There was general\nconsensus on the semantics of submodule.superprojectgitdir as it's sent\nin v4.\n\n - Emily\n"},{"id":"438793","messageId":"kl6la6jb1dk3.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"20210907115932.36068-1-raykar.ath@gmail.com","subject":"Re: [PATCH 00/13] submodule: convert the rest of 'update' to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2021-10-14T21:50:20Z","receivedAt":"2021-10-14T21:50:31Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"> This series builds upon the previous conversion work on 'submodule update' and\n> moves out all of that shell logic in 'git-submodule.sh' into\n> 'builtin/submodule--helper.c'.\n\nHey Atharva! I'm working on a series that will teach \"git branch\" how to\nhandle \"--recurse-submodules\". I plan to do this in-process because I\nthink this will take less overall effort than using child processes, and\nto make it happen, I'm planning to add a helper function like\n\"for_each_submodule()\", which would call a C callback function on each\nsubmodule.\n\nThis is conceptually similar to \"git submodule foreach\" and\nfor_each_listed_submodule() (though not exactly equivalent), so I'm\nreaching out to you in case this work is already on your radar. If so,\nand if it is coming soon, it might be easier to for me to base my work\noff yours instead of duplicating our efforts :)\n"},{"id":"438815","messageId":"m2o87q8wt2.fsf@gmail.com","threadId":"56453","inReplyTo":"kl6la6jb1dk3.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH 00/13] submodule: convert the rest of 'update' to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-10-15T09:13:20Z","receivedAt":"2021-10-15T09:25:14Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"\nGlen Choo <chooglen@google.com> writes:\n\n>> This series builds upon the previous conversion work on 'submodule update' and\n>> moves out all of that shell logic in 'git-submodule.sh' into\n>> 'builtin/submodule--helper.c'.\n>\n> Hey Atharva! I'm working on a series that will teach \"git branch\" how to\n> handle \"--recurse-submodules\". I plan to do this in-process because I\n> think this will take less overall effort than using child processes, and\n> to make it happen, I'm planning to add a helper function like\n> \"for_each_submodule()\", which would call a C callback function on each\n> submodule.\n>\n> This is conceptually similar to \"git submodule foreach\" and\n> for_each_listed_submodule() (though not exactly equivalent), so I'm\n> reaching out to you in case this work is already on your radar. If so,\n> and if it is coming soon, it might be easier to for me to base my work\n> off yours instead of duplicating our efforts :)\n\nThanks for reaching out. I don't have anything like this on my radar, so\nfeel free to go ahead with your plan :)\n"},{"id":"443016","messageId":"xmqqfsr9secx.fsf@gitster.g","threadId":"56453","inReplyTo":"YWiXL+plA7GHfuVv@google.com","subject":"Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-03T19:00:30Z","receivedAt":"2021-12-03T19:00:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> On Wed, Oct 13, 2021 at 05:05:58PM -0700, Junio C Hamano wrote:\n>> \n>> Atharva Raykar <raykar.ath@gmail.com> writes:\n>> \n>> > I have attempted to make a version of this series that is based on that topic [2],\n>> > and added the superproject gitdir caching code in C [3]. It passes the tests,\n>> > but I am not too confident about its correctness. I hope that branch can be\n>> > helpful in some way.\n>> ..\n>> The \"C rewrite\" of the code [3] that unconditionally sets of the\n>> submodule.superprojectgitdir varible seems straightforward enough.\n>> \n>> Emily, how solid do you think your \"superproject aware submodule\"\n>> topic already is?  Would it be stable enough to build other things\n>> on top, or is it a bit too premature?\n>\n> As of the version I sent today\n> (https://lore.kernel.org/git/20211014203416.2802639-1-emilyshaffer%40google.com)\n> I think it is stable enough to build on top of. There was general\n> consensus on the semantics of submodule.superprojectgitdir as it's sent\n> in v4.\n\nDoes the above statement still hold true today?\n\nAnd more importantly, Atharva, are you on board with the plan Emily\nsuggested to have this one built on top of her series?\n\nThanks.\n"},{"id":"443027","messageId":"211203.86o85xqw7o.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"xmqqfsr9secx.fsf@gitster.g","subject":"Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-03T20:15:42Z","receivedAt":"2021-12-03T20:17:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Dec 03 2021, Junio C Hamano wrote:\n\n> Emily Shaffer <emilyshaffer@google.com> writes:\n>\n>> On Wed, Oct 13, 2021 at 05:05:58PM -0700, Junio C Hamano wrote:\n>>> \n>>> Atharva Raykar <raykar.ath@gmail.com> writes:\n>>> \n>>> > I have attempted to make a version of this series that is based on that topic [2],\n>>> > and added the superproject gitdir caching code in C [3]. It passes the tests,\n>>> > but I am not too confident about its correctness. I hope that branch can be\n>>> > helpful in some way.\n>>> ..\n>>> The \"C rewrite\" of the code [3] that unconditionally sets of the\n>>> submodule.superprojectgitdir varible seems straightforward enough.\n>>> \n>>> Emily, how solid do you think your \"superproject aware submodule\"\n>>> topic already is?  Would it be stable enough to build other things\n>>> on top, or is it a bit too premature?\n>>\n>> As of the version I sent today\n>> (https://lore.kernel.org/git/20211014203416.2802639-1-emilyshaffer%40google.com)\n>> I think it is stable enough to build on top of. There was general\n>> consensus on the semantics of submodule.superprojectgitdir as it's sent\n>> in v4.\n>\n> Does the above statement still hold true today?\n>\n> And more importantly, Atharva, are you on board with the plan Emily\n> suggested to have this one built on top of her series?\n\nI think the current state of it is that Emily & I were having a\ndiscussion about the semantics of that series. See [1] and [2].\n\nThat's still outstanding. I.e. I haven't been able to reproduce cases\nwhere we actually need this caching for performance reasons (which is\nthe reason it exists), but even if we end up keeping it I'd think we'd\nwant something picked from the RFC patches I sent[1] to test the\n\"caching\" v.s. \"non-caching\" behavior, and assert that they're the same.\n\n1. https://lore.kernel.org/git/RFC-cover-0.2-00000000000-20211117T113134Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/211124.86a6hue2wk.gmgdl@evledraar.gmail.com/\n"},{"id":"443074","messageId":"m2ee6swt5p.fsf@gmail.com","threadId":"56453","inReplyTo":"xmqqfsr9secx.fsf@gitster.g","subject":"Re: [PATCH v3 0/9] submodule: convert the rest of 'update' to C","fromName":"Atharva Raykar","fromEmail":"raykar.ath@gmail.com","sentAt":"2021-12-04T10:38:41Z","receivedAt":"2021-12-04T10:39:44Z","isPatch":true,"sender":{"key":"raykar.ath@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24277692?v=4"},"body":"\nJunio C Hamano <gitster@pobox.com> writes:\n\n> Emily Shaffer <emilyshaffer@google.com> writes:\n>\n>> On Wed, Oct 13, 2021 at 05:05:58PM -0700, Junio C Hamano wrote:\n>>>\n>>> Atharva Raykar <raykar.ath@gmail.com> writes:\n>>>\n>>> > I have attempted to make a version of this series that is based on that topic [2],\n>>> > and added the superproject gitdir caching code in C [3]. It passes the tests,\n>>> > but I am not too confident about its correctness. I hope that branch can be\n>>> > helpful in some way.\n>>> ..\n>>> The \"C rewrite\" of the code [3] that unconditionally sets of the\n>>> submodule.superprojectgitdir varible seems straightforward enough.\n>>>\n>>> Emily, how solid do you think your \"superproject aware submodule\"\n>>> topic already is?  Would it be stable enough to build other things\n>>> on top, or is it a bit too premature?\n>>\n>> As of the version I sent today\n>> (https://lore.kernel.org/git/20211014203416.2802639-1-emilyshaffer%40google.com)\n>> I think it is stable enough to build on top of. There was general\n>> consensus on the semantics of submodule.superprojectgitdir as it's sent\n>> in v4.\n>\n> Does the above statement still hold true today?\n>\n> And more importantly, Atharva, are you on board with the plan Emily\n> suggested to have this one built on top of her series?\n\nYes, I am on board with that. I have not been closely following their\nseries, but the places where it clashes with this series are minimal,\nand look quite easy to port later to C. So I'm totally fine with it.\n\n> Thanks.\n"},{"id":"447089","messageId":"cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com","threadId":"56453","inReplyTo":"20211013051805.45662-1-raykar.ath@gmail.com","subject":"[PATCH v4 0/7] submodule: convert the rest of 'update' to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T16:22:49Z","receivedAt":"2022-01-27T16:23:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series rewrites \"git submodule update\" in C. It's a rebased and\nre-rolled version of v3[1] submitted back in October. Per [2] the\nauthor doesn't have time to push it forward now.\n\nThere was discussion in the thread at [2] about the interaction\nbetween this and es/superproject-aware-submodules.\n\nPer [3] I think it would be better to get this in first, as the big\noutstanding question about the superproject aware submodules[3] was\nwhether it was an optimization or not. It's currently an optimization,\nbut whether it's needed is muddied by \"git-submodule.sh\" being a\nshellscript and invoking \"git rev-parse\" in a loop, which a version\nrebased on this could do in C.\n\nPer the v3 CL of this series[1] there is a C version of the required\ncode for es/superproject-aware-submodules, but when I tried to rebase\nit it failed because it's based on an older version of\nes/superproject-aware-submodules which linked to the .git dir rather\nthan the working tree.\n\nI.e. the C code[4] produces \"../.git\" in the tests, but we're\nexpecting \"../..\". I couldn't find the right API to get that path from\npath.c et al, but it's presumably easy for someone more familiar with\nit.\n\nAs for changes in this v4:\n\n * Rebased on master, it didn't compile due to my changes to the\n   refs_resolve_ref_unsafe() API.\n\n * There was some back & forth about large patches v.s. split-up\n   commits in previous iterations. This version squashes several\n   patches together, because I thought a rename/add/removal of code\n   that's all related (and really can only be done as one logical step\n   without a major rewrite) was easier to look at than having to jump\n   back and forth in the series.\n\n   The resulting diff is large, but I think it's better than looking\n   at it piecemeal. You can see what new code replaces what old code.\n\n * There's new formatting-only changes in [56]/7 that I added to make\n   the 7/7 diff a tad smaller.\n\n   The gitster/ar/submodule-update~3..gitster/ar/submodule-update diff\n   (the real meat of the series) is \"402 insertions(+), 422\n   deletions(-)\", and 7/7 here is \"389 insertions(+), 418\n   deletions(-)\".\n\n   So it's not much, but thaht churn before 7/7 makes the big change a\n   bit logical change at the end easier to reason about.\n\n * I fixed a strbuf and string_list memory leak in the new code, and\n   simplified one codepath that freed correctly, but could use a \"goto\n   cleanup\" pattern to do away with duplication.\n\n   There's still a *lot* of memory leaks in\n   builtin/submodule--helper.c, but they're all (well, to the extent\n   that I can extract signal from the noise) in existing code, or in\n   generic APIs that uses which leak.\n\n1. https://lore.kernel.org/git/20211013051805.45662-1-raykar.ath@gmail.com/\n2. https://lore.kernel.org/git/CADi-XoThCqfvPnBd0p6yAhrtotK_3z2pQQMugWPsYpHLbXge7w@mail.gmail.com/\n3. https://lore.kernel.org/git/211203.86o85xqw7o.gmgdl@evledraar.gmail.com/\n4. https://github.com/tfidfwastaken/git/blob/a74aaf2540c536970f2541d3042c825f82a69770/builtin/submodule--helper.c#L2922-L2930\n\nAtharva Raykar (6):\n  submodule--helper: get remote names from any repository\n  submodule--helper: refactor get_submodule_displaypath()\n  submodule--helper: allow setting superprefix for init_submodule()\n  submodule--helper: run update using child process struct\n  builtin/submodule--helper.c: reformat designated initializers\n  submodule: move core cmd_update() logic to C\n\nÆvar Arnfjörð Bjarmason (1):\n  builtin/submodule--helper.c: rename \"suc\" variable to \"opt\"\n\n builtin/submodule--helper.c | 758 +++++++++++++++++++++---------------\n git-submodule.sh            | 145 +------\n 2 files changed, 449 insertions(+), 454 deletions(-)\n\nRange-diff against v3:\n 1:  775f7c01ddb <  -:  ----------- submodule--helper: split up ensure_core_worktree()\n 2:  fe3d30c1160 !  1:  1a0b1323cd7 submodule--helper: get remote names from any repository\n    @@ Commit message\n         Mentored-by: Shourya Shukla <periperidip@gmail.com>\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n         Signed-off-by: Junio C Hamano <gitster@pobox.com>\n    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n     @@\n    @@ builtin/submodule--helper.c: static char *get_default_remote(void)\n     +{\n     +\tconst char *refname;\n     +\tstruct repository subrepo;\n    ++\tint ignore_errno;\n     +\n     +\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n    -+\t\t\t\t\t  \"HEAD\", 0, NULL, NULL);\n    ++\t\t\t\t\t  \"HEAD\", 0, NULL, NULL,\n    ++\t\t\t\t\t  &ignore_errno);\n     +\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n     +\treturn repo_get_default_remote(&subrepo, refname);\n     +}\n 3:  8085571a7cb <  -:  ----------- submodule--helper: rename helpers for update-clone\n 4:  18c551543ed !  2:  7e2df3ff220 submodule--helper: refactor get_submodule_displaypath()\n    @@ Commit message\n         Mentored-by: Shourya Shukla <periperidip@gmail.com>\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n         Signed-off-by: Junio C Hamano <gitster@pobox.com>\n    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n     @@ builtin/submodule--helper.c: static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n 5:  2be0453750a !  3:  f31fd72fba2 submodule--helper: allow setting superprefix for init_submodule()\n    @@ Commit message\n         Mentored-by: Shourya Shukla <periperidip@gmail.com>\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n         Signed-off-by: Junio C Hamano <gitster@pobox.com>\n    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n     @@ builtin/submodule--helper.c: static int module_foreach(int argc, const char **argv, const char *prefix)\n    @@ builtin/submodule--helper.c: static int module_foreach(int argc, const char **ar\n     +\tconst char *superprefix;\n      \tunsigned int flags;\n      };\n    --#define INIT_CB_INIT { NULL, 0 }\n    -+#define INIT_CB_INIT { 0 }\n    + #define INIT_CB_INIT { 0 }\n      \n      static void init_submodule(const char *path, const char *prefix,\n     -\t\t\t   unsigned int flags)\n 6:  a882b53177d !  4:  76c5a826a80 submodule--helper: run update using child process struct\n    @@ Commit message\n         Mentored-by: Shourya Shukla <periperidip@gmail.com>\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n         Signed-off-by: Junio C Hamano <gitster@pobox.com>\n    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n     @@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n -:  ----------- >  5:  29aa2fc0851 builtin/submodule--helper.c: reformat designated initializers\n -:  ----------- >  6:  d3ad6e7a351 builtin/submodule--helper.c: rename \"suc\" variable to \"opt\"\n 7:  3092469f380 !  7:  02954603763 submodule: move core cmd_update() logic to C\n    @@ Commit message\n         `submodule--helper update`, with a modified `--recursive-prefix` and\n         `--prefix` parameter.\n     \n    -    We also introduce `update_submodules()` and `update_submodule()` which\n    -    are quite similar to `update_clone_submodules()` and\n    -    `update_clone_submodule()`, and will supersede them.\n    +    We also introduce `update_submodules2()` and `update_submodule2()`\n    +    which will supersede `update_submodules()` and `update_submodule()`.\n     \n         When the `--init` flag is passed to the subcommand, we do not spawn a\n         new subprocess and call `submodule--helper init` on the submodule paths,\n    @@ Commit message\n         Mentored-by: Shourya Shukla <periperidip@gmail.com>\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n         Signed-off-by: Junio C Hamano <gitster@pobox.com>\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_default_remote(void)\n    + \treturn repo_get_default_remote(the_repository, refname);\n    + }\n    + \n    +-static int print_default_remote(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tchar *remote;\n    +-\n    +-\tif (argc != 1)\n    +-\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n    +-\n    +-\tremote = get_default_remote();\n    +-\tif (remote)\n    +-\t\tprintf(\"%s\\n\", remote);\n    +-\n    +-\tfree(remote);\n    +-\treturn 0;\n    +-}\n    +-\n    + static int starts_with_dot_slash(const char *str)\n    + {\n    + \treturn str[0] == '.' && is_dir_sep(str[1]);\n    +@@ builtin/submodule--helper.c: static void determine_submodule_update_strategy(struct repository *r,\n    + \tfree(key);\n    + }\n    + \n    +-static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tconst char *path, *update = NULL;\n    +-\tint just_cloned;\n    +-\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n    +-\n    +-\tif (argc < 3 || argc > 4)\n    +-\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n    +-\n    +-\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n    +-\tpath = argv[2];\n    +-\n    +-\tif (argc == 4)\n    +-\t\tupdate = argv[3];\n    +-\n    +-\tdetermine_submodule_update_strategy(the_repository,\n    +-\t\t\t\t\t    just_cloned, path, update,\n    +-\t\t\t\t\t    &update_strategy);\n    +-\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n    +-\n    +-\treturn 0;\n    +-}\n    +-\n    + struct update_clone_data {\n    + \tconst struct submodule *sub;\n    + \tstruct object_id oid;\n     @@ builtin/submodule--helper.c: struct submodule_update_clone {\n      \tconst char *prefix;\n      \tint single_branch;\n    @@ builtin/submodule--helper.c: struct submodule_update_clone {\n      \tconst char *displaypath;\n      \tstruct object_id oid;\n      \tstruct object_id suboid;\n    --\tstruct submodule_update_strategy update_strategy;\n    + \tstruct submodule_update_strategy update_strategy;\n     +\tint max_jobs;\n      \tint depth;\n    +-\tunsigned int force: 1;\n    +-\tunsigned int quiet: 1;\n    +-\tunsigned int nofetch: 1;\n    +-\tunsigned int just_cloned: 1;\n     +\tint recommend_shallow;\n     +\tint single_branch;\n    -+\tunsigned int init: 1;\n    - \tunsigned int force: 1;\n    - \tunsigned int quiet: 1;\n    - \tunsigned int nofetch: 1;\n    --\tunsigned int just_cloned: 1;\n    -+\tunsigned int remote: 1;\n    -+\tunsigned int recursive: 1;\n    -+\tunsigned int progress: 1;\n    -+\tunsigned int dissociate: 1;\n    -+\tunsigned int require_init: 1;\n    -+\tunsigned warn_if_uninitialized : 1;\n    -+\tunsigned int just_cloned : 1;\n    -+\tstruct submodule_update_strategy update_strategy;\n    ++\tunsigned int init;\n    ++\tunsigned int force;\n    ++\tunsigned int quiet;\n    ++\tunsigned int nofetch;\n    ++\tunsigned int remote;\n    ++\tunsigned int recursive;\n    ++\tunsigned int progress;\n    ++\tunsigned int dissociate;\n    ++\tunsigned int require_init;\n    ++\tunsigned warn_if_uninitialized ;\n    ++\tunsigned int just_cloned ;\n     +\tstruct string_list references;\n     +\tstruct module_list list;\n      };\n    --#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }\n    -+#define UPDATE_DATA_INIT { \\\n    + #define UPDATE_DATA_INIT { \\\n     +\t.list = MODULE_LIST_INIT, \\\n    -+\t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n    + \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n     +\t.recommend_shallow = -1, \\\n     +\t.references = STRING_LIST_INIT_DUP, \\\n     +\t.single_branch = -1, \\\n    @@ builtin/submodule--helper.c: struct submodule_update_clone {\n     +\t\tfor_each_string_list_item(item, &update_data->references)\n     +\t\t\tstring_list_append(&suc->references, item->string);\n     +\t}\n    -+}\n    + }\n      \n      static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n    - \t\tstruct strbuf *out, const char *displaypath)\n     @@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n      \treturn run_command(&cp);\n      }\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n     +\t\t}\n     +\n     +\t\t/* the command failed, but update must continue */\n    -+\t\tstring_list_append(err, out.buf);\n    ++\t\tstring_list_append_nodup(err, strbuf_detach(&out, NULL));\n     +\t\treturn 1;\n     +\t}\n     +\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n     -\t\t    submodule_strategy_to_string(&ud->update_strategy));\n      \t}\n      \n    ++\tstrbuf_release(&out);\n      \treturn 0;\n      }\n      \n     -static int do_run_update_procedure(struct update_data *ud)\n    -+static int do_run_update_procedure(struct update_data *ud, struct string_list *err)\n    ++static int run_update_procedure(struct update_data *ud, struct string_list *err)\n      {\n      \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n      \n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n      \t}\n      \n     -\treturn run_update_command(ud, subforce);\n    +-}\n    +-\n    +-static void update_submodule(struct update_clone_data *ucd)\n    +-{\n    +-\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n    +-\t\toid_to_hex(&ucd->oid),\n    +-\t\tucd->just_cloned,\n    +-\t\tucd->sub->path);\n    +-}\n    +-\n    +-static int update_submodules(struct submodule_update_clone *suc)\n    +-{\n    +-\tint i;\n    +-\n    +-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n    +-\t\t\t\t   update_clone_start_failure,\n    +-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n    +-\t\t\t\t   \"parallel/update\");\n    +-\n    +-\t/*\n    +-\t * We saved the output and put it out all at once now.\n    +-\t * That means:\n    +-\t * - the listener does not have to interleave their (checkout)\n    +-\t *   work with our fetching.  The writes involved in a\n    +-\t *   checkout involve more straightforward sequential I/O.\n    +-\t * - the listener can avoid doing any work if fetching failed.\n    +-\t */\n    +-\tif (suc->quickstop)\n    +-\t\treturn 1;\n    +-\n    +-\tfor (i = 0; i < suc->update_clone_nr; i++)\n    +-\t\tupdate_submodule(&suc->update_clone[i]);\n    +-\n    +-\treturn 0;\n    +-}\n    +-\n    +-static int update_clone(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tconst char *update = NULL;\n    +-\tstruct pathspec pathspec;\n    +-\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n    +-\n    +-\tstruct option module_update_clone_options[] = {\n    +-\t\tOPT_STRING(0, \"prefix\", &prefix,\n    +-\t\t\t   N_(\"path\"),\n    +-\t\t\t   N_(\"path into the working tree\")),\n    +-\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n    +-\t\t\t   N_(\"path\"),\n    +-\t\t\t   N_(\"path into the working tree, across nested \"\n    +-\t\t\t      \"submodule boundaries\")),\n    +-\t\tOPT_STRING(0, \"update\", &update,\n    +-\t\t\t   N_(\"string\"),\n    +-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n    +-\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n    +-\t\t\t   N_(\"reference repository\")),\n    +-\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n    +-\t\t\t   N_(\"use --reference only while cloning\")),\n    +-\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n    +-\t\t\t   N_(\"create a shallow clone truncated to the \"\n    +-\t\t\t      \"specified number of revisions\")),\n    +-\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n    +-\t\t\t    N_(\"parallel jobs\")),\n    +-\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n    +-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n    +-\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n    +-\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n    +-\t\t\t    N_(\"force cloning progress\")),\n    +-\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n    +-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n    +-\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n    +-\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n    +-\t\tOPT_END()\n    +-\t};\n    +-\n    +-\tconst char *const git_submodule_helper_usage[] = {\n    +-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n    +-\t\tNULL\n    +-\t};\n    +-\topt.prefix = prefix;\n    +-\n    +-\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n    +-\tgit_config(git_update_clone_config, &opt.max_jobs);\n    +-\n    +-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n    +-\t\t\t     git_submodule_helper_usage, 0);\n    +-\n    +-\tif (update)\n    +-\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n    +-\t\t\tdie(_(\"bad value for update parameter\"));\n    +-\n    +-\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n    +-\t\treturn 1;\n    +-\n    +-\tif (pathspec.nr)\n    +-\t\topt.warn_if_uninitialized = 1;\n    +-\n    +-\treturn update_submodules(&opt);\n    +-}\n    +-\n    +-static int run_update_procedure(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n    +-\tchar *prefixed_path, *update = NULL;\n    +-\tstruct update_data update_data = UPDATE_DATA_INIT;\n    +-\n    +-\tstruct option options[] = {\n    +-\t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n    +-\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n    +-\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n    +-\t\t\t N_(\"don't fetch new objects from the remote site\")),\n    +-\t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n    +-\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n    +-\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n    +-\t\tOPT_STRING(0, \"prefix\", &prefix,\n    +-\t\t\t   N_(\"path\"),\n    +-\t\t\t   N_(\"path into the working tree\")),\n    +-\t\tOPT_STRING(0, \"update\", &update,\n    +-\t\t\t   N_(\"string\"),\n    +-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n    +-\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n    +-\t\t\t   N_(\"path into the working tree, across nested \"\n    +-\t\t\t      \"submodule boundaries\")),\n    +-\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n    +-\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n    +-\t\t\t       parse_opt_object_id),\n    +-\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n    +-\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n    +-\t\t\t       parse_opt_object_id),\n    +-\t\tOPT_END()\n    +-\t};\n    +-\n    +-\tconst char *const usage[] = {\n    +-\t\tN_(\"git submodule--helper run-update-procedure [<options>] <path>\"),\n    +-\t\tNULL\n    +-\t};\n    +-\n    +-\targc = parse_options(argc, argv, prefix, options, usage, 0);\n    +-\n    +-\tif (argc != 1)\n    +-\t\tusage_with_options(usage, options);\n    +-\n    +-\tupdate_data.force = !!force;\n    +-\tupdate_data.quiet = !!quiet;\n    +-\tupdate_data.nofetch = !!nofetch;\n    +-\tupdate_data.just_cloned = !!just_cloned;\n    +-\tupdate_data.sm_path = argv[0];\n    +-\n    +-\tif (update_data.recursive_prefix)\n    +-\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n    +-\telse\n    +-\t\tprefixed_path = xstrdup(update_data.sm_path);\n    +-\n    +-\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n    +-\n    +-\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n    +-\t\t\t\t\t    update_data.sm_path, update,\n    +-\t\t\t\t\t    &update_data.update_strategy);\n    +-\n    +-\tfree(prefixed_path);\n    +-\n    +-\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n    +-\t\treturn do_run_update_procedure(&update_data);\n    +-\n    +-\treturn 3;\n    +-}\n    +-\n    +-static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n    +-{\n    +-\tstruct strbuf sb = STRBUF_INIT;\n    +-\tif (argc != 3)\n    +-\t\tdie(\"submodule--helper relative-path takes exactly 2 arguments, got %d\", argc);\n    +-\n    +-\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n    +-\tstrbuf_release(&sb);\n    +-\treturn 0;\n     +\treturn run_update_command(ud, subforce, err);\n      }\n      \n    - static void update_clone_submodule(struct update_clone_data *ucd)\n    -@@ builtin/submodule--helper.c: static int run_update_procedure(int argc, const char **argv, const char *prefix)\n    - \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n    - \tchar *prefixed_path, *update = NULL;\n    - \tstruct update_data update_data = UPDATE_DATA_INIT;\n    -+\tstruct string_list err = STRING_LIST_INIT_DUP;\n    + static const char *remote_submodule_branch(const char *path)\n    +@@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv, const char *prefix)\n    + \treturn 0;\n    + }\n      \n    - \tstruct option options[] = {\n    - \t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n    -@@ builtin/submodule--helper.c: static int run_update_procedure(int argc, const char **argv, const char *prefix)\n    - \tfree(prefixed_path);\n    +-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n    ++static void ensure_core_worktree(const char *path)\n    + {\n    +-\tconst char *path;\n    + \tconst char *cw;\n    + \tstruct repository subrepo;\n      \n    - \tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n    --\t\treturn do_run_update_procedure(&update_data);\n    -+\t\treturn do_run_update_procedure(&update_data, &err);\n    +-\tif (argc != 2)\n    +-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n    +-\n    +-\tpath = argv[1];\n    +-\n    + \tif (repo_submodule_init(&subrepo, the_repository, path, null_oid()))\n    + \t\tdie(_(\"could not get a repository handle for submodule '%s'\"), path);\n      \n    - \treturn 3;\n    +@@ builtin/submodule--helper.c: static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n    + \t\tfree(abs_path);\n    + \t\tstrbuf_release(&sb);\n    + \t}\n    +-\n    +-\treturn 0;\n      }\n    + \n    + static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n     @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char **argv, const char *prefix)\n      \treturn !!ret;\n      }\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\tchar *prefixed_path;\n     +\tstruct string_list err = STRING_LIST_INIT_DUP;\n     +\n    -+\tdo_ensure_core_worktree(update_data->sm_path);\n    ++\tensure_core_worktree(update_data->sm_path);\n     +\n     +\tif (update_data->recursive_prefix)\n     +\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\tchar *remote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n     +\n     +\t\tif (!update_data->nofetch) {\n    -+\t\t\tif(fetch_in_submodule(update_data->sm_path, update_data->depth,\n    ++\t\t\tif (fetch_in_submodule(update_data->sm_path, update_data->depth,\n     +\t\t\t\t\t      0, NULL))\n     +\t\t\t\tdie(_(\"Unable to fetch in submodule path '%s'\"),\n     +\t\t\t\t    update_data->sm_path);\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t}\n     +\n     +\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n    -+\t\tif (do_run_update_procedure(update_data, &err))\n    ++\t\tif (run_update_procedure(update_data, &err))\n     +\t\t\treturn 1;\n     +\n     +\tif (update_data->recursive) {\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\tstruct string_list_item *item;\n     +\t\tfor_each_string_list_item(item, &err)\n     +\t\t\tfputs(item->string, stderr);\n    ++\t\tstring_list_clear(&err, 0);\n     +\t\treturn 1;\n     +\t}\n     +\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t * - the listener can avoid doing any work if fetching failed.\n     +\t */\n     +\tif (suc.quickstop) {\n    -+\t\tstring_list_clear(&update_data->references, 0);\n    -+\t\treturn 1;\n    ++\t\tres = 1;\n    ++\t\tgoto cleanup;\n     +\t}\n     +\n     +\tfor (i = 0; i < suc.update_clone_nr; i++) {\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\t\tres = 1;\n     +\t}\n     +\n    ++cleanup:\n     +\tstring_list_clear(&update_data->references, 0);\n     +\treturn res;\n     +}\n     +\n     +static int module_update(int argc, const char **argv, const char *prefix)\n     +{\n    -+\tint init = 0, force = 0, quiet = 0, nofetch = 0;\n    -+\tint remote = 0, recursive = 0, dissociate = 0;\n    -+\tint progress = 0, require_init = 0;\n     +\tconst char *update = NULL;\n     +\tstruct pathspec pathspec;\n    -+\tstruct update_data update_data = UPDATE_DATA_INIT;\n    ++\tstruct update_data opt = UPDATE_DATA_INIT;\n     +\n     +\tstruct option module_update_clone_options[] = {\n    -+\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n    -+\t\tOPT_BOOL(0, \"init\", &init,\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    -+\t\tOPT_BOOL(0, \"remote\", &remote,\n    ++\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n     +\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n    -+\t\tOPT_BOOL(0, \"recursive\", &recursive,\n    ++\t\tOPT_BOOL(0, \"recursive\", &opt.recursive,\n     +\t\t\t N_(\"traverse submodules recursively\")),\n    -+\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n    ++\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n     +\t\t\t N_(\"don't fetch new objects from the remote site\")),\n    -+\t\tOPT_STRING(0, \"prefix\", &prefix,\n    ++\t\tOPT_STRING(0, \"prefix\", &opt.prefix,\n     +\t\t\t   N_(\"path\"),\n     +\t\t\t   N_(\"path into the working tree\")),\n    -+\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix,\n    ++\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n     +\t\t\t   N_(\"path\"),\n     +\t\t\t   N_(\"path into the working tree, across nested \"\n     +\t\t\t      \"submodule boundaries\")),\n     +\t\tOPT_STRING(0, \"update\", &update,\n     +\t\t\t   N_(\"string\"),\n     +\t\t\t   N_(\"rebase, merge, checkout or none\")),\n    -+\t\tOPT_STRING_LIST(0, \"reference\", &update_data.references, N_(\"repo\"),\n    ++\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n     +\t\t\t\tN_(\"reference repository\")),\n    -+\t\tOPT_BOOL(0, \"dissociate\", &dissociate,\n    ++\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n     +\t\t\t N_(\"use --reference only while cloning\")),\n    -+\t\tOPT_INTEGER(0, \"depth\", &update_data.depth,\n    ++\t\tOPT_INTEGER(0, \"depth\", &opt.depth,\n     +\t\t\t    N_(\"create a shallow clone truncated to the \"\n     +\t\t\t       \"specified number of revisions\")),\n    -+\t\tOPT_INTEGER('j', \"jobs\", &update_data.max_jobs,\n    ++\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n     +\t\t\t    N_(\"parallel jobs\")),\n    -+\t\tOPT_BOOL(0, \"recommend-shallow\", &update_data.recommend_shallow,\n    ++\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n     +\t\t\t N_(\"whether the initial clone should follow the shallow recommendation\")),\n    -+\t\tOPT__QUIET(&quiet, N_(\"don't print cloning progress\")),\n    -+\t\tOPT_BOOL(0, \"progress\", &progress,\n    ++\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n    ++\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n     +\t\t\t N_(\"force cloning progress\")),\n    -+\t\tOPT_BOOL(0, \"require-init\", &require_init,\n    ++\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n     +\t\t\t N_(\"disallow cloning into non-empty directory\")),\n    -+\t\tOPT_BOOL(0, \"single-branch\", &update_data.single_branch,\n    ++\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n     +\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n     +\t\tOPT_END()\n     +\t};\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\tNULL\n     +\t};\n     +\n    -+\tupdate_clone_config_from_gitmodules(&update_data.max_jobs);\n    -+\tgit_config(git_update_clone_config, &update_data.max_jobs);\n    ++\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n    ++\tgit_config(git_update_clone_config, &opt.max_jobs);\n     +\n     +\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n     +\t\t\t     git_submodule_helper_usage, 0);\n    -+\tupdate_data.prefix = prefix;\n    -+\n    -+\tupdate_data.force = !!force;\n    -+\tupdate_data.quiet = !!quiet;\n    -+\tupdate_data.nofetch = !!nofetch;\n    -+\tupdate_data.init = !!init;\n    -+\tupdate_data.require_init = !!require_init;\n    -+\tupdate_data.remote = !!remote;\n    -+\tupdate_data.recursive = !!recursive;\n    -+\tupdate_data.progress = !!progress;\n    -+\tupdate_data.dissociate = !!dissociate;\n    -+\toidcpy(&update_data.oid, null_oid());\n    -+\toidcpy(&update_data.suboid, null_oid());\n    ++\toidcpy(&opt.oid, null_oid());\n    ++\toidcpy(&opt.suboid, null_oid());\n     +\n     +\tif (update)\n     +\t\tif (parse_submodule_update_strategy(update,\n    -+\t\t\t\t\t\t    &update_data.update_strategy) < 0)\n    ++\t\t\t\t\t\t    &opt.update_strategy) < 0)\n     +\t\t\tdie(_(\"bad value for update parameter\"));\n     +\n    -+\tif (module_list_compute(argc, argv, prefix, &pathspec, &update_data.list) < 0)\n    ++\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n     +\t\treturn 1;\n     +\n     +\tif (pathspec.nr)\n    -+\t\tupdate_data.warn_if_uninitialized = 1;\n    ++\t\topt.warn_if_uninitialized = 1;\n     +\n    -+\tif (update_data.init) {\n    ++\tif (opt.init) {\n     +\t\tstruct module_list list = MODULE_LIST_INIT;\n     +\t\tstruct init_cb info = INIT_CB_INIT;\n     +\n    -+\t\tif (module_list_compute(argc, argv, update_data.prefix,\n    ++\t\tif (module_list_compute(argc, argv, opt.prefix,\n     +\t\t\t\t\t&pathspec, &list) < 0)\n     +\t\t\treturn 1;\n     +\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n     +\t\t\tmodule_list_active(&list);\n     +\n    -+\t\tinfo.prefix = update_data.prefix;\n    -+\t\tinfo.superprefix = update_data.recursive_prefix;\n    -+\t\tif (update_data.quiet)\n    ++\t\tinfo.prefix = opt.prefix;\n    ++\t\tinfo.superprefix = opt.recursive_prefix;\n    ++\t\tif (opt.quiet)\n     +\t\t\tinfo.flags |= OPT_QUIET;\n     +\n     +\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n     +\t}\n     +\n    -+\treturn update_submodules(&update_data);\n    ++\treturn update_submodules(&opt);\n     +}\n     +\n      struct add_data {\n      \tconst char *prefix;\n      \tconst char *branch;\n    -@@ builtin/submodule--helper.c: static int module_add(int argc, const char **argv, const char *prefix)\n    - \treturn 0;\n    - }\n    - \n    -+\n    - #define SUPPORT_SUPER_PREFIX (1<<0)\n    - \n    - struct cmd_struct {\n     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {\n      \t{\"name\", module_name, 0},\n      \t{\"clone\", module_clone, 0},\n      \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n    +-\t{\"update-module-mode\", module_update_module_mode, 0},\n    +-\t{\"update-clone\", update_clone, 0},\n    +-\t{\"run-update-procedure\", run_update_procedure, 0},\n    +-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n    +-\t{\"relative-path\", resolve_relative_path, 0},\n     +\t{\"update\", module_update, 0},\n    - \t{\"update-module-mode\", module_update_module_mode, 0},\n    - \t{\"update-clone\", update_clone, 0},\n    - \t{\"run-update-procedure\", run_update_procedure, 0},\n    + \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n    + \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n    + \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n    + \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n    +-\t{\"print-default-remote\", print_default_remote, 0},\n    + \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n    + \t{\"deinit\", module_deinit, 0},\n    + \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n     \n      ## git-submodule.sh ##\n     @@ git-submodule.sh: cmd_deinit()\n 8:  cee4beb7abe <  -:  ----------- submodule--helper: remove unused helpers\n 9:  2194c1729f1 <  -:  ----------- submodule--helper: rename helper functions\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447090","messageId":"patch-v4-1.7-1a0b1323cd7-20220127T143552Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com","subject":"[PATCH v4 1/7] submodule--helper: get remote names from any repository","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T16:22:50Z","receivedAt":"2022-01-27T16:23:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\n`get_default_remote()` retrieves the name of a remote by resolving the\nrefs from of the current repository's ref store.\n\nThus in order to use it for retrieving the remote name of a submodule,\nwe have to start a new subprocess which runs from the submodule\ndirectory.\n\nLet's instead introduce a function called `repo_get_default_remote()`\nwhich takes any repository object and retrieves the remote accordingly.\n\n`get_default_remote()` is then defined as a call to\n`repo_get_default_remote()` with 'the_repository' passed to it.\n\nNow that we have `repo_get_default_remote()`, we no longer have to start\na subprocess that called `submodule--helper get-default-remote` from\nwithin the submodule directory.\n\nSo let's make a function called `get_default_remote_submodule()` which\ntakes a submodule path, and returns the default remote for that\nsubmodule, all within the same process.\n\nWe can now use this function to save an unnecessary subprocess spawn in\n`sync_submodule()`, and also in the next patch, which will require this\nfunctionality.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 41 +++++++++++++++++++++++--------------\n 1 file changed, 26 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c5d3fc3817f..965260edb22 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -29,11 +29,10 @@\n typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n \t\t\t\t  void *cb_data);\n \n-static char *get_default_remote(void)\n+static char *repo_get_default_remote(struct repository *repo, const char *refname)\n {\n \tchar *dest = NULL, *ret;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n \n \tif (!refname)\n \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n@@ -46,7 +45,7 @@ static char *get_default_remote(void)\n \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n \n \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n-\tif (git_config_get_string(sb.buf, &dest))\n+\tif (repo_config_get_string(repo, sb.buf, &dest))\n \t\tret = xstrdup(\"origin\");\n \telse\n \t\tret = dest;\n@@ -55,6 +54,25 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static char *get_default_remote_submodule(const char *module_path)\n+{\n+\tconst char *refname;\n+\tstruct repository subrepo;\n+\tint ignore_errno;\n+\n+\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n+\t\t\t\t\t  \"HEAD\", 0, NULL, NULL,\n+\t\t\t\t\t  &ignore_errno);\n+\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n+\treturn repo_get_default_remote(&subrepo, refname);\n+}\n+\n+static char *get_default_remote(void)\n+{\n+\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n+\treturn repo_get_default_remote(the_repository, refname);\n+}\n+\n static int print_default_remote(int argc, const char **argv, const char *prefix)\n {\n \tchar *remote;\n@@ -1341,9 +1359,8 @@ static void sync_submodule(const char *path, const char *prefix,\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n-\tchar *sub_origin_url, *super_config_url, *displaypath;\n+\tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *sub_config_path = NULL;\n \n \tif (!is_submodule_active(the_repository, path))\n@@ -1382,21 +1399,15 @@ static void sync_submodule(const char *path, const char *prefix,\n \tif (!is_submodule_populated_gently(path, NULL))\n \t\tgoto cleanup;\n \n-\tprepare_submodule_repo_env(&cp.env_array);\n-\tcp.git_cmd = 1;\n-\tcp.dir = path;\n-\tstrvec_pushl(&cp.args, \"submodule--helper\",\n-\t\t     \"print-default-remote\", NULL);\n-\n \tstrbuf_reset(&sb);\n-\tif (capture_command(&cp, &sb, 0))\n+\tdefault_remote = get_default_remote_submodule(path);\n+\tif (!default_remote)\n \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n \t\t      path);\n \n-\tstrbuf_strip_suffix(&sb, \"\\n\");\n-\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n+\tremote_key = xstrfmt(\"remote.%s.url\", default_remote);\n+\tfree(default_remote);\n \n-\tstrbuf_reset(&sb);\n \tsubmodule_to_gitdir(&sb, path);\n \tstrbuf_addstr(&sb, \"/config\");\n \n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447091","messageId":"patch-v4-2.7-7e2df3ff220-20220127T143552Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com","subject":"[PATCH v4 2/7] submodule--helper: refactor get_submodule_displaypath()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T16:22:51Z","receivedAt":"2022-01-27T16:23:10Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe create a function called `do_get_submodule_displaypath()` that\ngenerates the display path required by several submodule functions, and\ntakes a custom superprefix parameter, instead of reading it from the\nenvironment.\n\nWe then redefine the existing `get_submodule_displaypath()` function\nas a call to this new function, where the superprefix is obtained from\nthe environment.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 965260edb22..d38a64c7b7d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -263,11 +263,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\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 *do_get_submodule_displaypath(const char *path, const char *prefix, 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@@ -283,6 +280,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \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+\treturn do_get_submodule_displaypath(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-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447092","messageId":"patch-v4-3.7-f31fd72fba2-20220127T143552Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com","subject":"[PATCH v4 3/7] submodule--helper: allow setting superprefix for init_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T16:22:52Z","receivedAt":"2022-01-27T16:23:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe allow callers of the `init_submodule()` function to optionally\noverride the superprefix from the environment.\n\nWe need to enable this option because in our conversion of the update\ncommand that will follow, the '--init' option will be handled through\nthis API. We will need to change the superprefix at that time to ensure\nthe display paths show correctly in the output messages.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex d38a64c7b7d..f8e18820ace 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -608,18 +608,22 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *superprefix;\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   unsigned int flags)\n+\t\t\t   const char *superprefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\t/* try superprefix from the environment, if it is not passed explicitly */\n+\tif (!superprefix)\n+\t\tsuperprefix = get_super_prefix();\n+\tdisplaypath = do_get_submodule_displaypath(path, prefix, superprefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -693,7 +697,7 @@ static void init_submodule(const char *path, const char *prefix,\n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct init_cb *info = cb_data;\n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447093","messageId":"patch-v4-4.7-76c5a826a80-20220127T143552Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com","subject":"[PATCH v4 4/7] submodule--helper: run update using child process struct","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T16:22:53Z","receivedAt":"2022-01-27T16:23:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe switch to using the run-command API function that takes a\n'struct child process', since we are using a lot of the options. This\nwill also make it simple to switch over to using 'capture_command()'\nwhen we start handling the output of the command completely in C.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 34 ++++++++++++++++------------------\n 1 file changed, 16 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex f8e18820ace..328c6cc87cd 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2346,47 +2346,45 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \n static int run_update_command(struct update_data *ud, int subforce)\n {\n-\tstruct strvec args = STRVEC_INIT;\n-\tstruct strvec child_env = STRVEC_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n \tint must_die_on_failure = 0;\n-\tint git_cmd;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_pushl(&args, \"checkout\", \"-q\", NULL);\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n \t\tif (subforce)\n-\t\t\tstrvec_push(&args, \"-f\");\n+\t\t\tstrvec_push(&cp.args, \"-f\");\n \t\tbreak;\n \tcase SM_UPDATE_REBASE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"rebase\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_MERGE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"merge\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n-\t\tgit_cmd = 0;\n-\t\tstrvec_push(&args, ud->update_strategy.command);\n+\t\tcp.use_shell = 1;\n+\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n \t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t}\n-\tstrvec_push(&args, oid);\n+\tstrvec_push(&cp.args, oid);\n \n-\tprepare_submodule_repo_env(&child_env);\n-\tif (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,\n-\t\t\t\t     ud->sm_path, child_env.v)) {\n+\tcp.dir = xstrdup(ud->sm_path);\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tif (run_command(&cp)) {\n \t\tswitch (ud->update_strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n \t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447094","messageId":"patch-v4-5.7-29aa2fc0851-20220127T143552Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com","subject":"[PATCH v4 5/7] builtin/submodule--helper.c: reformat designated initializers","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T16:22:54Z","receivedAt":"2022-01-27T16:23:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nThe second hunk here will make a subsequent commit's diff smaller, and\nlet's do the first and third hunks while we're at it so that we\nconsistently format all of these.\n\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 13 ++++++++++---\n 1 file changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 328c6cc87cd..1553b318cc7 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1656,7 +1656,10 @@ struct module_clone_data {\n \tunsigned int require_init: 1;\n \tint single_branch;\n };\n-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }\n+#define MODULE_CLONE_DATA_INIT { \\\n+\t.reference = STRING_LIST_INIT_NODUP, \\\n+\t.single_branch = -1, \\\n+}\n \n struct submodule_alternate_setup {\n \tconst char *submodule_name;\n@@ -2049,7 +2052,9 @@ struct update_data {\n \tunsigned int nofetch: 1;\n \tunsigned int just_cloned: 1;\n };\n-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }\n+#define UPDATE_DATA_INIT { \\\n+\t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+}\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n \t\tstruct strbuf *out, const char *displaypath)\n@@ -3015,7 +3020,9 @@ struct add_data {\n \tunsigned int progress: 1;\n \tunsigned int dissociate: 1;\n };\n-#define ADD_DATA_INIT { .depth = -1 }\n+#define ADD_DATA_INIT { \\\n+\t.depth = -1, \\\n+}\n \n static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)\n {\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447095","messageId":"patch-v4-6.7-d3ad6e7a351-20220127T143552Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com","subject":"[PATCH v4 6/7] builtin/submodule--helper.c: rename \"suc\" variable to \"opt\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T16:22:55Z","receivedAt":"2022-01-27T16:23:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Rename the \"suc\" variable in \"builtin/submodule--helper.c\" to\n\"opt\". The only reason for this change is to make the subsequent\ncommit's diff smaller, by doing this rename we can \"anchor\" the diff\nbetter, as it \"borrow\" most of the options declared here as-is as far\nas the diff rename detection is concerned.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 36 ++++++++++++++++++------------------\n 1 file changed, 18 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 1553b318cc7..a96976b1772 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2519,36 +2519,36 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n {\n \tconst char *update = NULL;\n \tstruct pathspec pathspec;\n-\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n \n \tstruct option module_update_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &suc.recursive_prefix,\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree, across nested \"\n \t\t\t      \"submodule boundaries\")),\n \t\tOPT_STRING(0, \"update\", &update,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &suc.references, N_(\"repo\"),\n+\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n \t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &suc.dissociate,\n+\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n \t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &suc.depth, \"<depth>\",\n+\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n \t\t\t   N_(\"create a shallow clone truncated to the \"\n \t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &suc.max_jobs,\n+\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n \t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &suc.recommend_shallow,\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n \t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&suc.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &suc.progress,\n+\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n \t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &suc.require_init,\n+\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n \t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &suc.single_branch,\n+\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n \t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n \t\tOPT_END()\n \t};\n@@ -2557,25 +2557,25 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n \t\tNULL\n \t};\n-\tsuc.prefix = prefix;\n+\topt.prefix = prefix;\n \n-\tupdate_clone_config_from_gitmodules(&suc.max_jobs);\n-\tgit_config(git_update_clone_config, &suc.max_jobs);\n+\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n+\tgit_config(git_update_clone_config, &opt.max_jobs);\n \n \targc = parse_options(argc, argv, prefix, module_update_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n \tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &suc.update) < 0)\n+\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n \t\t\tdie(_(\"bad value for update parameter\"));\n \n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n \t\treturn 1;\n \n \tif (pathspec.nr)\n-\t\tsuc.warn_if_uninitialized = 1;\n+\t\topt.warn_if_uninitialized = 1;\n \n-\treturn update_submodules(&suc);\n+\treturn update_submodules(&opt);\n }\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447096","messageId":"patch-v4-7.7-02954603763-20220127T143552Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com","subject":"[PATCH v4 7/7] submodule: move core cmd_update() logic to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T16:22:56Z","receivedAt":"2022-01-27T16:23:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nThis patch completes the conversion past the flag parsing of\n`submodule update` by introducing a helper subcommand called\n`submodule--helper update`. The behaviour of `submodule update` should\nremain the same after this patch.\n\nWe add more fields to the `struct update_data` that are required by\n`struct submodule_update_clone` to be able to perform a clone, when that\nis needed to be done.\n\nRecursing on a submodule is done by calling a subprocess that launches\n`submodule--helper update`, with a modified `--recursive-prefix` and\n`--prefix` parameter.\n\nWe also introduce `update_submodules2()` and `update_submodule2()`\nwhich will supersede `update_submodules()` and `update_submodule()`.\n\nWhen the `--init` flag is passed to the subcommand, we do not spawn a\nnew subprocess and call `submodule--helper init` on the submodule paths,\nbecause the Git machinery is not able to pick up the configuration\nchanges introduced by that init call[1]. So we instead run the\n`init_submodule_cb()` callback over each submodule in the same process.\n\nWhile we are at it, we also remove the fetch_in_submodule() shell\nfunction since it is no longer used anywhere.\n\n[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 662 ++++++++++++++++++++----------------\n git-submodule.sh            | 145 +-------\n 2 files changed, 389 insertions(+), 418 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a96976b1772..916df6d9947 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -73,21 +73,6 @@ static char *get_default_remote(void)\n \treturn repo_get_default_remote(the_repository, refname);\n }\n \n-static int print_default_remote(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remote;\n-\n-\tif (argc != 1)\n-\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n-\n-\tremote = get_default_remote();\n-\tif (remote)\n-\t\tprintf(\"%s\\n\", remote);\n-\n-\tfree(remote);\n-\treturn 0;\n-}\n-\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -1967,29 +1952,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n \tfree(key);\n }\n \n-static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path, *update = NULL;\n-\tint just_cloned;\n-\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n-\n-\tif (argc < 3 || argc > 4)\n-\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n-\n-\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n-\tpath = argv[2];\n-\n-\tif (argc == 4)\n-\t\tupdate = argv[3];\n-\n-\tdetermine_submodule_update_strategy(the_repository,\n-\t\t\t\t\t    just_cloned, path, update,\n-\t\t\t\t\t    &update_strategy);\n-\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n-\n-\treturn 0;\n-}\n-\n struct update_clone_data {\n \tconst struct submodule *sub;\n \tstruct object_id oid;\n@@ -2017,7 +1979,6 @@ struct submodule_update_clone {\n \tconst char *prefix;\n \tint single_branch;\n \n-\t/* to be consumed by git-submodule.sh */\n \tstruct update_clone_data *update_clone;\n \tint update_clone_nr; int update_clone_alloc;\n \n@@ -2040,20 +2001,62 @@ struct submodule_update_clone {\n }\n \n struct update_data {\n+\tconst char *prefix;\n \tconst char *recursive_prefix;\n \tconst char *sm_path;\n \tconst char *displaypath;\n \tstruct object_id oid;\n \tstruct object_id suboid;\n \tstruct submodule_update_strategy update_strategy;\n+\tint max_jobs;\n \tint depth;\n-\tunsigned int force: 1;\n-\tunsigned int quiet: 1;\n-\tunsigned int nofetch: 1;\n-\tunsigned int just_cloned: 1;\n+\tint recommend_shallow;\n+\tint single_branch;\n+\tunsigned int init;\n+\tunsigned int force;\n+\tunsigned int quiet;\n+\tunsigned int nofetch;\n+\tunsigned int remote;\n+\tunsigned int recursive;\n+\tunsigned int progress;\n+\tunsigned int dissociate;\n+\tunsigned int require_init;\n+\tunsigned warn_if_uninitialized ;\n+\tunsigned int just_cloned ;\n+\tstruct string_list references;\n+\tstruct module_list list;\n };\n #define UPDATE_DATA_INIT { \\\n+\t.list = MODULE_LIST_INIT, \\\n \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+\t.recommend_shallow = -1, \\\n+\t.references = STRING_LIST_INIT_DUP, \\\n+\t.single_branch = -1, \\\n+\t.max_jobs = 1, \\\n+}\n+\n+static void update_clone_from_update_data(struct submodule_update_clone *suc,\n+\t\t\t\t\t  struct update_data *update_data)\n+{\n+\tsuc->prefix = update_data->prefix;\n+\tsuc->recursive_prefix = update_data->recursive_prefix;\n+\tsuc->max_jobs = update_data->max_jobs;\n+\tsuc->progress = update_data->progress;\n+\tsuc->quiet = update_data->quiet;\n+\tsuc->dissociate = update_data->dissociate;\n+\tsuc->require_init = update_data->require_init;\n+\tsuc->single_branch = update_data->single_branch;\n+\tsuc->warn_if_uninitialized = update_data->warn_if_uninitialized;\n+\tsuc->list = update_data->list;\n+\tsuc->update = update_data->update_strategy;\n+\tsuc->recommend_shallow = update_data->recommend_shallow;\n+\tif (update_data->depth)\n+\t\tsuc->depth = xstrfmt(\"--depth=%d\", update_data->depth);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstring_list_append(&suc->references, item->string);\n+\t}\n }\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n@@ -2349,13 +2352,21 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \treturn run_command(&cp);\n }\n \n-static int run_update_command(struct update_data *ud, int subforce)\n+static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n+\tstruct strbuf out = STRBUF_INIT;\n \tint must_die_on_failure = 0;\n+\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n \n-\tswitch (ud->update_strategy.type) {\n+\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n+\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n+\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n+\telse\n+\t\tstrategy = ud->update_strategy;\n+\n+\tswitch (strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\tcp.git_cmd = 1;\n \t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n@@ -2378,80 +2389,76 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n \t\tcp.use_shell = 1;\n-\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n+\t\tstrvec_push(&cp.args, strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t    submodule_strategy_to_string(&strategy));\n \t}\n \tstrvec_push(&cp.args, oid);\n \n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env_array);\n-\tif (run_command(&cp)) {\n-\t\tswitch (ud->update_strategy.type) {\n+\tif (capture_command(&cp, &out, 0)) {\n+\t\tif (must_die_on_failure) {\n+\t\t\tswitch (strategy.type) {\n+\t\t\tcase SM_UPDATE_CHECKOUT:\n+\t\t\t\tdie(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_REBASE:\n+\t\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_MERGE:\n+\t\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tcase SM_UPDATE_COMMAND:\n+\t\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\t\t    strategy.command, oid, ud->displaypath);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tBUG(\"unexpected update strategy type: %s\",\n+\t\t\t\t    submodule_strategy_to_string(&strategy));\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* the command failed, but update must continue */\n+\t\tstring_list_append_nodup(err, strbuf_detach(&out, NULL));\n+\t\treturn 1;\n+\t}\n+\n+\tif (!ud->quiet) {\n+\t\tswitch (strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n-\t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n-\t\t\tprintf(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_MERGE:\n-\t\t\tprintf(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n+\t\t\t       ud->displaypath, oid);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_COMMAND:\n-\t\t\tprintf(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n-\t\t\t       ud->update_strategy.command, oid, ud->displaypath);\n+\t\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n+\t\t\t       ud->displaypath, strategy.command, oid);\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t\t    submodule_strategy_to_string(&strategy));\n \t\t}\n-\t\t/*\n-\t\t * NEEDSWORK: We are currently printing to stdout with error\n-\t\t * return so that the shell caller handles the error output\n-\t\t * properly. Once we start handling the error messages within\n-\t\t * C, we should use die() instead.\n-\t\t */\n-\t\tif (must_die_on_failure)\n-\t\t\treturn 2;\n-\t\t/*\n-\t\t * This signifies to the caller in shell that the command\n-\t\t * failed without dying\n-\t\t */\n-\t\treturn 1;\n-\t}\n-\n-\tswitch (ud->update_strategy.type) {\n-\tcase SM_UPDATE_CHECKOUT:\n-\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_REBASE:\n-\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_MERGE:\n-\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n-\t\t       ud->displaypath, oid);\n-\t\tbreak;\n-\tcase SM_UPDATE_COMMAND:\n-\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n-\t\t       ud->displaypath, ud->update_strategy.command, oid);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t}\n \n+\tstrbuf_release(&out);\n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud)\n+static int run_update_procedure(struct update_data *ud, struct string_list *err)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2478,182 +2485,7 @@ static int do_run_update_procedure(struct update_data *ud)\n \t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n \t}\n \n-\treturn run_update_command(ud, subforce);\n-}\n-\n-static void update_submodule(struct update_clone_data *ucd)\n-{\n-\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n-\t\toid_to_hex(&ucd->oid),\n-\t\tucd->just_cloned,\n-\t\tucd->sub->path);\n-}\n-\n-static int update_submodules(struct submodule_update_clone *suc)\n-{\n-\tint i;\n-\n-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n-\t\t\t\t   update_clone_start_failure,\n-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n-\t\t\t\t   \"parallel/update\");\n-\n-\t/*\n-\t * We saved the output and put it out all at once now.\n-\t * That means:\n-\t * - the listener does not have to interleave their (checkout)\n-\t *   work with our fetching.  The writes involved in a\n-\t *   checkout involve more straightforward sequential I/O.\n-\t * - the listener can avoid doing any work if fetching failed.\n-\t */\n-\tif (suc->quickstop)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_submodule(&suc->update_clone[i]);\n-\n-\treturn 0;\n-}\n-\n-static int update_clone(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *update = NULL;\n-\tstruct pathspec pathspec;\n-\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n-\n-\tstruct option module_update_clone_options[] = {\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n-\t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n-\t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n-\t\t\t   N_(\"create a shallow clone truncated to the \"\n-\t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n-\t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n-\t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n-\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\topt.prefix = prefix;\n-\n-\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n-\tgit_config(git_update_clone_config, &opt.max_jobs);\n-\n-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n-\t\t\tdie(_(\"bad value for update parameter\"));\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n-\t\treturn 1;\n-\n-\tif (pathspec.nr)\n-\t\topt.warn_if_uninitialized = 1;\n-\n-\treturn update_submodules(&opt);\n-}\n-\n-static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-{\n-\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n-\tchar *prefixed_path, *update = NULL;\n-\tstruct update_data update_data = UPDATE_DATA_INIT;\n-\n-\tstruct option options[] = {\n-\t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n-\t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n-\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n-\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n-\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const usage[] = {\n-\t\tN_(\"git submodule--helper run-update-procedure [<options>] <path>\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\n-\tif (argc != 1)\n-\t\tusage_with_options(usage, options);\n-\n-\tupdate_data.force = !!force;\n-\tupdate_data.quiet = !!quiet;\n-\tupdate_data.nofetch = !!nofetch;\n-\tupdate_data.just_cloned = !!just_cloned;\n-\tupdate_data.sm_path = argv[0];\n-\n-\tif (update_data.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n-\telse\n-\t\tprefixed_path = xstrdup(update_data.sm_path);\n-\n-\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n-\n-\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n-\t\t\t\t\t    update_data.sm_path, update,\n-\t\t\t\t\t    &update_data.update_strategy);\n-\n-\tfree(prefixed_path);\n-\n-\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data);\n-\n-\treturn 3;\n-}\n-\n-static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 3)\n-\t\tdie(\"submodule--helper relative-path takes exactly 2 arguments, got %d\", argc);\n-\n-\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n-\tstrbuf_release(&sb);\n-\treturn 0;\n+\treturn run_update_command(ud, subforce, err);\n }\n \n static const char *remote_submodule_branch(const char *path)\n@@ -2788,17 +2620,11 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+static void ensure_core_worktree(const char *path)\n {\n-\tconst char *path;\n \tconst char *cw;\n \tstruct repository subrepo;\n \n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\n \tif (repo_submodule_init(&subrepo, the_repository, path, null_oid()))\n \t\tdie(_(\"could not get a repository handle for submodule '%s'\"), path);\n \n@@ -2818,8 +2644,6 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n-\n-\treturn 0;\n }\n \n static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n@@ -3006,6 +2830,279 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \treturn !!ret;\n }\n \n+static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n+{\n+\tconst char *update = submodule_strategy_to_string(&update_data->update_strategy);\n+\n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n+\tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n+\tif (update_data->prefix)\n+\t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n+\tif (update_data->recursive_prefix)\n+\t\tstrvec_pushl(args, \"--recursive-prefix\",\n+\t\t\t     update_data->recursive_prefix, NULL);\n+\tif (update_data->quiet)\n+\t\tstrvec_push(args, \"--quiet\");\n+\tif (update_data->force)\n+\t\tstrvec_push(args, \"--force\");\n+\tif (update_data->init)\n+\t\tstrvec_push(args, \"--init\");\n+\tif (update_data->remote)\n+\t\tstrvec_push(args, \"--remote\");\n+\tif (update_data->nofetch)\n+\t\tstrvec_push(args, \"--no-fetch\");\n+\tif (update_data->dissociate)\n+\t\tstrvec_push(args, \"--dissociate\");\n+\tif (update_data->progress)\n+\t\tstrvec_push(args, \"--progress\");\n+\tif (update_data->require_init)\n+\t\tstrvec_push(args, \"--require-init\");\n+\tif (update_data->depth)\n+\t\tstrvec_pushf(args, \"--depth=%d\", update_data->depth);\n+\tif (update)\n+\t\tstrvec_pushl(args, \"--update\", update, NULL);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n+\t}\n+\tif (update_data->recommend_shallow == 0)\n+\t\tstrvec_push(args, \"--no-recommend-shallow\");\n+\telse if (update_data->recommend_shallow == 1)\n+\t\tstrvec_push(args, \"--recommend-shallow\");\n+\tif (update_data->single_branch >= 0)\n+\t\tstrvec_push(args, \"--single-branch\");\n+}\n+\n+static int update_submodule(struct update_data *update_data)\n+{\n+\tchar *prefixed_path;\n+\tstruct string_list err = STRING_LIST_INIT_DUP;\n+\n+\tensure_core_worktree(update_data->sm_path);\n+\n+\tif (update_data->recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n+\t\t\t\t\tupdate_data->sm_path);\n+\telse\n+\t\tprefixed_path = xstrdup(update_data->sm_path);\n+\n+\tupdate_data->displaypath = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t     update_data->prefix);\n+\tfree(prefixed_path);\n+\n+\tif (update_data->just_cloned) {\n+\t\toidcpy(&update_data->suboid, null_oid());\n+\t} else {\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n+\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t}\n+\n+\tif (update_data->remote) {\n+\t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n+\t\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n+\t\tchar *remote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n+\n+\t\tif (!update_data->nofetch) {\n+\t\t\tif (fetch_in_submodule(update_data->sm_path, update_data->depth,\n+\t\t\t\t\t      0, NULL))\n+\t\t\t\tdie(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\t\t    update_data->sm_path);\n+\t\t}\n+\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))\n+\t\t\tdie(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t    remote_ref, update_data->sm_path);\n+\n+\t\tfree(remote_ref);\n+\t}\n+\n+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n+\t\tif (run_update_procedure(update_data, &err))\n+\t\t\treturn 1;\n+\n+\tif (update_data->recursive) {\n+\t\tint res;\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct update_data next = *update_data;\n+\t\tchar *die_msg = xstrfmt(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t\t\tupdate_data->displaypath);\n+\n+\t\tif (update_data->recursive_prefix)\n+\t\t\tprefixed_path = xstrfmt(\"%s%s/\", update_data->recursive_prefix,\n+\t\t\t\t\t\tupdate_data->sm_path);\n+\t\telse\n+\t\t\tprefixed_path = xstrfmt(\"%s/\", update_data->sm_path);\n+\n+\t\tnext.recursive_prefix = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t\t  update_data->prefix);\n+\t\tnext.prefix = NULL;\n+\t\toidcpy(&next.oid, null_oid());\n+\t\toidcpy(&next.suboid, null_oid());\n+\n+\t\tcp.dir = update_data->sm_path;\n+\t\tcp.git_cmd = 1;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tupdate_data_to_args(&next, &cp.args);\n+\n+\t\t/* die() if child process die()'d */\n+\t\tif ((res = run_command(&cp)) == 128)\n+\t\t\tdie(\"%s\", die_msg);\n+\t\tif (res)\n+\t\t\tstring_list_append(&err, die_msg);\n+\n+\t\tfree(die_msg);\n+\t}\n+\n+\tif (err.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &err)\n+\t\t\tfputs(item->string, stderr);\n+\t\tstring_list_clear(&err, 0);\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int update_submodules(struct update_data *update_data)\n+{\n+\tint i, res = 0;\n+\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\n+\tupdate_clone_from_update_data(&suc, update_data);\n+\trun_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,\n+\t\t\t\t   update_clone_start_failure,\n+\t\t\t\t   update_clone_task_finished, &suc, \"submodule\",\n+\t\t\t\t   \"parallel/update\");\n+\n+\t/*\n+\t * We saved the output and put it out all at once now.\n+\t * That means:\n+\t * - the listener does not have to interleave their (checkout)\n+\t *   work with our fetching.  The writes involved in a\n+\t *   checkout involve more straightforward sequential I/O.\n+\t * - the listener can avoid doing any work if fetching failed.\n+\t */\n+\tif (suc.quickstop) {\n+\t\tres = 1;\n+\t\tgoto cleanup;\n+\t}\n+\n+\tfor (i = 0; i < suc.update_clone_nr; i++) {\n+\t\tstruct update_clone_data ucd = suc.update_clone[i];\n+\n+\t\toidcpy(&update_data->oid, &ucd.oid);\n+\t\tupdate_data->just_cloned = ucd.just_cloned;\n+\t\tupdate_data->sm_path = ucd.sub->path;\n+\n+\t\tif (update_submodule(update_data))\n+\t\t\tres = 1;\n+\t}\n+\n+cleanup:\n+\tstring_list_clear(&update_data->references, 0);\n+\treturn res;\n+}\n+\n+static int module_update(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *update = NULL;\n+\tstruct pathspec pathspec;\n+\tstruct update_data opt = UPDATE_DATA_INIT;\n+\n+\tstruct option module_update_clone_options[] = {\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+\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n+\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n+\t\tOPT_BOOL(0, \"recursive\", &opt.recursive,\n+\t\t\t N_(\"traverse submodules recursively\")),\n+\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n+\t\t\t N_(\"don't fetch new objects from the remote site\")),\n+\t\tOPT_STRING(0, \"prefix\", &opt.prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree\")),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree, across nested \"\n+\t\t\t      \"submodule boundaries\")),\n+\t\tOPT_STRING(0, \"update\", &update,\n+\t\t\t   N_(\"string\"),\n+\t\t\t   N_(\"rebase, merge, checkout or none\")),\n+\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n+\t\t\t\tN_(\"reference repository\")),\n+\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n+\t\t\t N_(\"use --reference only while cloning\")),\n+\t\tOPT_INTEGER(0, \"depth\", &opt.depth,\n+\t\t\t    N_(\"create a shallow clone truncated to the \"\n+\t\t\t       \"specified number of revisions\")),\n+\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n+\t\t\t    N_(\"parallel jobs\")),\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n+\t\t\t N_(\"whether the initial clone should follow the shallow recommendation\")),\n+\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n+\t\t\t N_(\"force cloning progress\")),\n+\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n+\t\t\t N_(\"disallow cloning into non-empty directory\")),\n+\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n+\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n+\t\tNULL\n+\t};\n+\n+\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n+\tgit_config(git_update_clone_config, &opt.max_jobs);\n+\n+\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\toidcpy(&opt.oid, null_oid());\n+\toidcpy(&opt.suboid, null_oid());\n+\n+\tif (update)\n+\t\tif (parse_submodule_update_strategy(update,\n+\t\t\t\t\t\t    &opt.update_strategy) < 0)\n+\t\t\tdie(_(\"bad value for update parameter\"));\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n+\t\treturn 1;\n+\n+\tif (pathspec.nr)\n+\t\topt.warn_if_uninitialized = 1;\n+\n+\tif (opt.init) {\n+\t\tstruct module_list list = MODULE_LIST_INIT;\n+\t\tstruct init_cb info = INIT_CB_INIT;\n+\n+\t\tif (module_list_compute(argc, argv, opt.prefix,\n+\t\t\t\t\t&pathspec, &list) < 0)\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * If there are no path args and submodule.active is set then,\n+\t\t * by default, only initialize 'active' modules.\n+\t\t */\n+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n+\t\t\tmodule_list_active(&list);\n+\n+\t\tinfo.prefix = opt.prefix;\n+\t\tinfo.superprefix = opt.recursive_prefix;\n+\t\tif (opt.quiet)\n+\t\t\tinfo.flags |= OPT_QUIET;\n+\n+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n+\t}\n+\n+\treturn update_submodules(&opt);\n+}\n+\n struct add_data {\n \tconst char *prefix;\n \tconst char *branch;\n@@ -3393,16 +3490,11 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n-\t{\"update-module-mode\", module_update_module_mode, 0},\n-\t{\"update-clone\", update_clone, 0},\n-\t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n-\t{\"relative-path\", resolve_relative_path, 0},\n+\t{\"update\", module_update, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n-\t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, 0},\n \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 652861aa66a..bcd8b92aabd 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -246,20 +246,6 @@ cmd_deinit()\n \tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- \"$@\"\n }\n \n-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]\n-# Because arguments are positional, use an empty string to omit <depth>\n-# but include <sha1>.\n-fetch_in_submodule () (\n-\tsanitize_submodule_env &&\n-\tcd \"$1\" &&\n-\tif test $# -eq 3\n-\tthen\n-\t\techo \"$3\" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+\"$2\"}\n-\telse\n-\t\tgit fetch ${GIT_QUIET:+--quiet} ${2:+\"$2\"}\n-\tfi\n-)\n-\n #\n # Update each submodule path to correct revision, using clone and checkout as needed\n #\n@@ -361,133 +347,26 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\tif test -n \"$init\"\n-\tthen\n-\t\tcmd_init \"--\" \"$@\" || return\n-\tfi\n-\n-\t{\n-\tgit submodule--helper update-clone ${GIT_QUIET:+--quiet} \\\n-\t\t${progress:+\"--progress\"} \\\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n+\t\t${GIT_QUIET:+--quiet} \\\n+\t\t${force:+--force} \\\n+\t\t${progress:+--progress} \\\n+\t\t${dissociate:+--dissociate} \\\n+\t\t${remote:+--remote} \\\n+\t\t${recursive:+--recursive} \\\n+\t\t${init:+--init} \\\n+\t\t${require_init:+--require-init} \\\n+\t\t${nofetch:+--no-fetch} \\\n \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t${update:+--update \"$update\"} \\\n \t\t${reference:+\"$reference\"} \\\n-\t\t${dissociate:+\"--dissociate\"} \\\n-\t\t${depth:+--depth \"$depth\"} \\\n-\t\t${require_init:+--require-init} \\\n+\t\t${depth:+\"$depth\"} \\\n \t\t$single_branch \\\n \t\t$recommend_shallow \\\n \t\t$jobs \\\n \t\t-- \\\n-\t\t\"$@\" || echo \"#unmatched\" $?\n-\t} | {\n-\terr=\n-\twhile read -r quickabort sha1 just_cloned sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n-\n-\t\tgit submodule--helper ensure-core-worktree \"$sm_path\" || exit 1\n-\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\n-\t\tif test $just_cloned -eq 1\n-\t\tthen\n-\t\t\tsubsha1=\n-\t\telse\n-\t\t\tjust_cloned=\n-\t\t\tsubsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify HEAD) ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current revision in submodule path '\\$displaypath'\")\"\n-\t\tfi\n-\n-\t\tif test -n \"$remote\"\n-\t\tthen\n-\t\t\tbranch=$(git submodule--helper remote-branch \"$sm_path\")\n-\t\t\tif test -z \"$nofetch\"\n-\t\t\tthen\n-\t\t\t\t# Fetch remote before determining tracking $sha1\n-\t\t\t\tfetch_in_submodule \"$sm_path\" $depth ||\n-\t\t\t\tdie \"fatal: $(eval_gettext \"Unable to fetch in submodule path '\\$sm_path'\")\"\n-\t\t\tfi\n-\t\t\tremote_name=$(sanitize_submodule_env; cd \"$sm_path\" && git submodule--helper print-default-remote)\n-\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify \"${remote_name}/${branch}\") ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\n-\t\tout=$(git submodule--helper run-update-procedure \\\n-\t\t\t  ${wt_prefix:+--prefix \"$wt_prefix\"} \\\n-\t\t\t  ${GIT_QUIET:+--quiet} \\\n-\t\t\t  ${force:+--force} \\\n-\t\t\t  ${just_cloned:+--just-cloned} \\\n-\t\t\t  ${nofetch:+--no-fetch} \\\n-\t\t\t  ${depth:+\"$depth\"} \\\n-\t\t\t  ${update:+--update \"$update\"} \\\n-\t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n-\t\t\t  ${sha1:+--oid \"$sha1\"} \\\n-\t\t\t  ${subsha1:+--suboid \"$subsha1\"} \\\n-\t\t\t  \"--\" \\\n-\t\t\t  \"$sm_path\")\n-\n-\t\t# exit codes for run-update-procedure:\n-\t\t# 0: update was successful, say command output\n-\t\t# 1: update procedure failed, but should not die\n-\t\t# 2 or 128: subcommand died during execution\n-\t\t# 3: no update procedure was run\n-\t\tres=\"$?\"\n-\t\tcase $res in\n-\t\t0)\n-\t\t\tsay \"$out\"\n-\t\t\t;;\n-\t\t1)\n-\t\t\terr=\"${err};fatal: $out\"\n-\t\t\tcontinue\n-\t\t\t;;\n-\t\t2|128)\n-\t\t\tdie_with_status $res \"fatal: $out\"\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=$(git submodule--helper relative-path \"$prefix$sm_path/\" \"$wt_prefix\")\n-\t\t\t\twt_prefix=\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_update\n-\t\t\t)\n-\t\t\tres=$?\n-\t\t\tif test $res -gt 0\n-\t\t\tthen\n-\t\t\t\tdie_msg=\"fatal: $(eval_gettext \"Failed to recurse into submodule path '\\$displaypath'\")\"\n-\t\t\t\tif test $res -ne 2\n-\t\t\t\tthen\n-\t\t\t\t\terr=\"${err};$die_msg\"\n-\t\t\t\t\tcontinue\n-\t\t\t\telse\n-\t\t\t\t\tdie_with_status $res \"$die_msg\"\n-\t\t\t\tfi\n-\t\t\tfi\n-\t\tfi\n-\tdone\n-\n-\tif test -n \"$err\"\n-\tthen\n-\t\tOIFS=$IFS\n-\t\tIFS=';'\n-\t\tfor e in $err\n-\t\tdo\n-\t\t\tif test -n \"$e\"\n-\t\t\tthen\n-\t\t\t\techo >&2 \"$e\"\n-\t\t\tfi\n-\t\tdone\n-\t\tIFS=$OIFS\n-\t\texit 1\n-\tfi\n-\t}\n+\t\t\"$@\"\n }\n \n #\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447110","messageId":"kl6ltudpyq4b.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"patch-v4-1.7-1a0b1323cd7-20220127T143552Z-avarab@gmail.com","subject":"Re: [PATCH v4 1/7] submodule--helper: get remote names from any repository","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-01-27T18:45:24Z","receivedAt":"2022-01-27T18:45: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\nThis wasn't introduced by you (it was introduced in v1 [1]), but I think\nit's worth pointing out.\n\n> Let's instead introduce a function called `repo_get_default_remote()`\n> which takes any repository object and retrieves the remote accordingly.\n>\n> `get_default_remote()` is then defined as a call to\n> `repo_get_default_remote()` with 'the_repository' passed to it.\n\nWe say this, suggesting that repo_get_default_remote()'s signature is\njust get_default_remote()'s plus a \"struct repository *\" (like most\nrepo_*). But..\n\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index c5d3fc3817f..965260edb22 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -29,11 +29,10 @@\n>  typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n>  \t\t\t\t  void *cb_data);\n>  \n> -static char *get_default_remote(void)\n> +static char *repo_get_default_remote(struct repository *repo, const char *refname)\n>  {\n>  \tchar *dest = NULL, *ret;\n>  \tstruct strbuf sb = STRBUF_INIT;\n> -\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n>  \n>  \tif (!refname)\n>  \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n> @@ -46,7 +45,7 @@ static char *get_default_remote(void)\n>  \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n>  \n>  \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n> -\tif (git_config_get_string(sb.buf, &dest))\n> +\tif (repo_config_get_string(repo, sb.buf, &dest))\n>  \t\tret = xstrdup(\"origin\");\n>  \telse\n>  \t\tret = dest;\n> @@ -55,6 +54,25 @@ static char *get_default_remote(void)\n>  \treturn ret;\n>  }\n>  \n> +static char *get_default_remote_submodule(const char *module_path)\n> +{\n> +\tconst char *refname;\n> +\tstruct repository subrepo;\n> +\tint ignore_errno;\n> +\n> +\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n> +\t\t\t\t\t  \"HEAD\", 0, NULL, NULL,\n> +\t\t\t\t\t  &ignore_errno);\n> +\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n> +\treturn repo_get_default_remote(&subrepo, refname);\n> +}\n> +\n> +static char *get_default_remote(void)\n> +{\n> +\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n> +\treturn repo_get_default_remote(the_repository, refname);\n> +}\n> +\n\nrepo_get_default_remote() actually take yet another argument - refname.\n\nIt looks to me that repo_get_default_remote() shouldn't take the\nrefname argument at all and that we should be using\nrefs_resolve_ref_unsafe() instead, like:\n\n  +static char *repo_get_default_remote(struct repository *repo)\n    {\n    char *dest = NULL, *ret;\n    struct strbuf sb = STRBUF_INIT;\n  -\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n  +\tconst char *refname = refs_resolve_ref_unsafe(\n  +   get_main_ref_store(repo), \"HEAD\", 0, NULL, NULL /*, errno? */);\n\nthis makes the rest of the code a lot cleaner..\n\n  +static char *get_default_remote_submodule(const char *module_path)\n  +{\n  +\tstruct repository subrepo;\n  +\n  +\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n  +\treturn repo_get_default_remote(&subrepo);\n  +}\n  +\n  +static char *get_default_remote(void)\n  +{\n  +  return repo_get_default_remote(the_repository);\n  +}\n\nAnd because it's quite idiomatic to initialize the subrepo struct in\norder to can call repo_* functions, we could even drop\nget_default_remote_submodule() altogether.\n\nAs for why this wasn't the original approach, the only reason I can\nthink of is that we didn't realize get_main_ref_store(subrepo) was an\noption.\n\n[1] https://lore.kernel.org/git/20210907115932.36068-3-raykar.ath@gmail.com/\n\n"},{"id":"447137","messageId":"kl6lo83wzvv9.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"patch-v4-7.7-02954603763-20220127T143552Z-avarab@gmail.com","subject":"Re: [PATCH v4 7/7] submodule: move core cmd_update() logic to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-01-27T21:55:54Z","receivedAt":"2022-01-27T21:55:58Z","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: Atharva Raykar <raykar.ath@gmail.com>\n>\n> This patch completes the conversion past the flag parsing of\n> `submodule update` by introducing a helper subcommand called\n> `submodule--helper update`. The behaviour of `submodule update` should\n> remain the same after this patch.\n>\n> We add more fields to the `struct update_data` that are required by\n> `struct submodule_update_clone` to be able to perform a clone, when that\n> is needed to be done.\n>\n> Recursing on a submodule is done by calling a subprocess that launches\n> `submodule--helper update`, with a modified `--recursive-prefix` and\n> `--prefix` parameter.\n>\n> We also introduce `update_submodules2()` and `update_submodule2()`\n> which will supersede `update_submodules()` and `update_submodule()`.\n>\n> When the `--init` flag is passed to the subcommand, we do not spawn a\n> new subprocess and call `submodule--helper init` on the submodule paths,\n> because the Git machinery is not able to pick up the configuration\n> changes introduced by that init call[1]. So we instead run the\n> `init_submodule_cb()` callback over each submodule in the same process.\n>\n> While we are at it, we also remove the fetch_in_submodule() shell\n> function since it is no longer used anywhere.\n>\n> [1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n\nI've read through all of the patches besides this one - I hope to get\nthrough this one soon.\n\nThe diff is quite large, but I can't think of any way to shrink it down\nat the moment.\n"},{"id":"447204","messageId":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com","subject":"[PATCH v5 0/9] submodule: convert the rest of 'update' to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:31Z","receivedAt":"2022-01-28T12:56:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A rewrite of \"git submodule\" in C, except the trivial pass-through\nwrapping code (basically getopt etc.) in git-submodule.sh. For a\ngreater summary & context see v4's CL:\nhttps://lore.kernel.org/git/cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com/\n\nChanges in v5:\n\n * Took Glen Choo's suggestion for a code change in 1/8, thanks!\n\n * A bit more mid-series churn to make the large commit at the end\n   have a smaller diff. The result is that in v4/v5 we have in that\n   last commit (but see below).\n\n   - 2 files changed, 389 insertions(+), 418 deletions(-)\n   + 2 files changed, 357 insertions(+), 388 deletions(-)\n\n * There were some logic errors in v4 around how we handled error\n   reporting. A new 8/9 adds tests for the existing behavior, and\n   we're now bug-for-bug compatible.\n\n   It turned out that we were passing around string lists of errors\n   etc. in a way that wasn't needed, i.e. the initial code can just\n   report the error.\n\n   Much of this was also simplified with my recently added\n   die_message() function. I.e. sometimes we want to have a \"fatal: \"\n   message, but exit non-128.\n\nAtharva Raykar (6):\n  submodule--helper: get remote names from any repository\n  submodule--helper: refactor get_submodule_displaypath()\n  submodule--helper: allow setting superprefix for init_submodule()\n  submodule--helper: run update using child process struct\n  builtin/submodule--helper.c: reformat designated initializers\n  submodule: move core cmd_update() logic to C\n\nÆvar Arnfjörð Bjarmason (3):\n  builtin/submodule--helper.c: rename option variables to \"opt\"\n  submodule--helper: don't use bitfield indirection for parse_options()\n  submodule tests: test for init and update failure output\n\n builtin/submodule--helper.c    | 706 +++++++++++++++++++--------------\n git-submodule.sh               | 145 +------\n t/t7406-submodule-update.sh    |  14 +-\n t/t7408-submodule-reference.sh |  14 +-\n 4 files changed, 444 insertions(+), 435 deletions(-)\n\nRange-diff against v4:\n 1:  1a0b1323cd7 !  1:  088c7236a16 submodule--helper: get remote names from any repository\n    @@ Commit message\n     \n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n         Mentored-by: Shourya Shukla <periperidip@gmail.com>\n    +    Helped-by: Glen Choo <chooglen@google.com>\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n         Signed-off-by: Junio C Hamano <gitster@pobox.com>\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n    @@ builtin/submodule--helper.c\n      \t\t\t\t  void *cb_data);\n      \n     -static char *get_default_remote(void)\n    -+static char *repo_get_default_remote(struct repository *repo, const char *refname)\n    ++static char *repo_get_default_remote(struct repository *repo)\n      {\n      \tchar *dest = NULL, *ret;\n      \tstruct strbuf sb = STRBUF_INIT;\n     -\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n    ++\tstruct ref_store *store = get_main_ref_store(repo);\n    ++\tint ignore_errno;\n    ++\tconst char *refname = refs_resolve_ref_unsafe(store, \"HEAD\", 0, NULL,\n    ++\t\t\t\t\t\t      NULL, &ignore_errno);\n      \n      \tif (!refname)\n      \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n    @@ builtin/submodule--helper.c: static char *get_default_remote(void)\n      \n     +static char *get_default_remote_submodule(const char *module_path)\n     +{\n    -+\tconst char *refname;\n     +\tstruct repository subrepo;\n    -+\tint ignore_errno;\n     +\n    -+\trefname = refs_resolve_ref_unsafe(get_submodule_ref_store(module_path),\n    -+\t\t\t\t\t  \"HEAD\", 0, NULL, NULL,\n    -+\t\t\t\t\t  &ignore_errno);\n     +\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n    -+\treturn repo_get_default_remote(&subrepo, refname);\n    ++\treturn repo_get_default_remote(&subrepo);\n     +}\n     +\n     +static char *get_default_remote(void)\n     +{\n    -+\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n    -+\treturn repo_get_default_remote(the_repository, refname);\n    ++\treturn repo_get_default_remote(the_repository);\n     +}\n     +\n      static int print_default_remote(int argc, const char **argv, const char *prefix)\n 2:  7e2df3ff220 =  2:  bc694987893 submodule--helper: refactor get_submodule_displaypath()\n 3:  f31fd72fba2 =  3:  e2cc7f0e23b submodule--helper: allow setting superprefix for init_submodule()\n 4:  76c5a826a80 =  4:  e1df2dd4457 submodule--helper: run update using child process struct\n 5:  29aa2fc0851 =  5:  fa815e37f9f builtin/submodule--helper.c: reformat designated initializers\n 6:  d3ad6e7a351 !  6:  ef097f7ea51 builtin/submodule--helper.c: rename \"suc\" variable to \"opt\"\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    builtin/submodule--helper.c: rename \"suc\" variable to \"opt\"\n    +    builtin/submodule--helper.c: rename option variables to \"opt\"\n     \n    -    Rename the \"suc\" variable in \"builtin/submodule--helper.c\" to\n    -    \"opt\". The only reason for this change is to make the subsequent\n    -    commit's diff smaller, by doing this rename we can \"anchor\" the diff\n    -    better, as it \"borrow\" most of the options declared here as-is as far\n    -    as the diff rename detection is concerned.\n    +    Rename the \"suc\" variable in update_clone() to \"opt\", and do the same\n    +    for the \"update_data\" variable in run_update_procedure().\n    +\n    +    The only reason for this change is to make the subsequent commit's\n    +    diff smaller, by doing this rename we can \"anchor\" the diff better, as\n    +    it \"borrow\" most of the options declared here as-is as far as the diff\n    +    rename detection is concerned.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv\n      }\n      \n      static int run_update_procedure(int argc, const char **argv, const char *prefix)\n    + {\n    + \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n    + \tchar *prefixed_path, *update = NULL;\n    +-\tstruct update_data update_data = UPDATE_DATA_INIT;\n    ++\tstruct update_data opt = UPDATE_DATA_INIT;\n    + \n    + \tstruct option options[] = {\n    + \t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n    +@@ builtin/submodule--helper.c: static int run_update_procedure(int argc, const char **argv, const char *prefix)\n    + \t\t\t N_(\"don't fetch new objects from the remote site\")),\n    + \t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n    + \t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n    +-\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n    ++\t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n    + \t\tOPT_STRING(0, \"prefix\", &prefix,\n    + \t\t\t   N_(\"path\"),\n    + \t\t\t   N_(\"path into the working tree\")),\n    + \t\tOPT_STRING(0, \"update\", &update,\n    + \t\t\t   N_(\"string\"),\n    + \t\t\t   N_(\"rebase, merge, checkout or none\")),\n    +-\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n    ++\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n    + \t\t\t   N_(\"path into the working tree, across nested \"\n    + \t\t\t      \"submodule boundaries\")),\n    +-\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n    ++\t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n    + \t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n    + \t\t\t       parse_opt_object_id),\n    +-\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n    ++\t\tOPT_CALLBACK_F(0, \"suboid\", &opt.suboid, N_(\"subsha1\"),\n    + \t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n    + \t\t\t       parse_opt_object_id),\n    + \t\tOPT_END()\n    +@@ builtin/submodule--helper.c: static int run_update_procedure(int argc, const char **argv, const char *prefix)\n    + \tif (argc != 1)\n    + \t\tusage_with_options(usage, options);\n    + \n    +-\tupdate_data.force = !!force;\n    +-\tupdate_data.quiet = !!quiet;\n    +-\tupdate_data.nofetch = !!nofetch;\n    +-\tupdate_data.just_cloned = !!just_cloned;\n    +-\tupdate_data.sm_path = argv[0];\n    ++\topt.force = !!force;\n    ++\topt.quiet = !!quiet;\n    ++\topt.nofetch = !!nofetch;\n    ++\topt.just_cloned = !!just_cloned;\n    ++\topt.sm_path = argv[0];\n    + \n    +-\tif (update_data.recursive_prefix)\n    +-\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n    ++\tif (opt.recursive_prefix)\n    ++\t\tprefixed_path = xstrfmt(\"%s%s\", opt.recursive_prefix, opt.sm_path);\n    + \telse\n    +-\t\tprefixed_path = xstrdup(update_data.sm_path);\n    ++\t\tprefixed_path = xstrdup(opt.sm_path);\n    + \n    +-\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n    ++\topt.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n    + \n    +-\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n    +-\t\t\t\t\t    update_data.sm_path, update,\n    +-\t\t\t\t\t    &update_data.update_strategy);\n    ++\tdetermine_submodule_update_strategy(the_repository, opt.just_cloned,\n    ++\t\t\t\t\t    opt.sm_path, update,\n    ++\t\t\t\t\t    &opt.update_strategy);\n    + \n    + \tfree(prefixed_path);\n    + \n    +-\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n    +-\t\treturn do_run_update_procedure(&update_data);\n    ++\tif (!oideq(&opt.oid, &opt.suboid) || opt.force)\n    ++\t\treturn do_run_update_procedure(&opt);\n    + \n    + \treturn 3;\n    + }\n -:  ----------- >  7:  6b038f558c1 submodule--helper: don't use bitfield indirection for parse_options()\n -:  ----------- >  8:  b4f84132201 submodule tests: test for init and update failure output\n 7:  02954603763 !  9:  e8e57606ee9 submodule: move core cmd_update() logic to C\n    @@ Commit message\n     \n      ## builtin/submodule--helper.c ##\n     @@ builtin/submodule--helper.c: static char *get_default_remote(void)\n    - \treturn repo_get_default_remote(the_repository, refname);\n    + \treturn repo_get_default_remote(the_repository);\n      }\n      \n     -static int print_default_remote(int argc, const char **argv, const char *prefix)\n    @@ builtin/submodule--helper.c: struct submodule_update_clone {\n      \tconst char *recursive_prefix;\n      \tconst char *sm_path;\n      \tconst char *displaypath;\n    - \tstruct object_id oid;\n    +@@ builtin/submodule--helper.c: struct update_data {\n      \tstruct object_id suboid;\n      \tstruct submodule_update_strategy update_strategy;\n    -+\tint max_jobs;\n      \tint depth;\n    --\tunsigned int force: 1;\n    --\tunsigned int quiet: 1;\n    --\tunsigned int nofetch: 1;\n    --\tunsigned int just_cloned: 1;\n     +\tint recommend_shallow;\n     +\tint single_branch;\n    ++\tint max_jobs;\n     +\tunsigned int init;\n    -+\tunsigned int force;\n    -+\tunsigned int quiet;\n    -+\tunsigned int nofetch;\n    + \tunsigned int force;\n    + \tunsigned int quiet;\n    + \tunsigned int nofetch;\n    + \tunsigned int just_cloned;\n     +\tunsigned int remote;\n     +\tunsigned int recursive;\n     +\tunsigned int progress;\n     +\tunsigned int dissociate;\n     +\tunsigned int require_init;\n     +\tunsigned warn_if_uninitialized ;\n    -+\tunsigned int just_cloned ;\n     +\tstruct string_list references;\n     +\tstruct module_list list;\n      };\n    @@ builtin/submodule--helper.c: struct submodule_update_clone {\n      }\n      \n      static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n    -@@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n    - \treturn run_command(&cp);\n    - }\n    - \n    --static int run_update_command(struct update_data *ud, int subforce)\n    -+static int run_update_command(struct update_data *ud, int subforce, struct string_list *err)\n    - {\n    +@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n      \tstruct child_process cp = CHILD_PROCESS_INIT;\n      \tchar *oid = oid_to_hex(&ud->oid);\n    -+\tstruct strbuf out = STRBUF_INIT;\n      \tint must_die_on_failure = 0;\n     +\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n      \n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \n      \tcp.dir = xstrdup(ud->sm_path);\n      \tprepare_submodule_repo_env(&cp.env_array);\n    --\tif (run_command(&cp)) {\n    + \tif (run_command(&cp)) {\n     -\t\tswitch (ud->update_strategy.type) {\n    -+\tif (capture_command(&cp, &out, 0)) {\n    -+\t\tif (must_die_on_failure) {\n    -+\t\t\tswitch (strategy.type) {\n    -+\t\t\tcase SM_UPDATE_CHECKOUT:\n    -+\t\t\t\tdie(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n    -+\t\t\t\t    oid, ud->displaypath);\n    -+\t\t\t\tbreak;\n    -+\t\t\tcase SM_UPDATE_REBASE:\n    -+\t\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n    -+\t\t\t\t    oid, ud->displaypath);\n    -+\t\t\t\tbreak;\n    -+\t\t\tcase SM_UPDATE_MERGE:\n    -+\t\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n    -+\t\t\t\t    oid, ud->displaypath);\n    -+\t\t\t\tbreak;\n    -+\t\t\tcase SM_UPDATE_COMMAND:\n    -+\t\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n    -+\t\t\t\t    strategy.command, oid, ud->displaypath);\n    -+\t\t\t\tbreak;\n    -+\t\t\tdefault:\n    -+\t\t\t\tBUG(\"unexpected update strategy type: %s\",\n    -+\t\t\t\t    submodule_strategy_to_string(&strategy));\n    -+\t\t\t}\n    -+\t\t}\n    -+\n    -+\t\t/* the command failed, but update must continue */\n    -+\t\tstring_list_append_nodup(err, strbuf_detach(&out, NULL));\n    -+\t\treturn 1;\n    -+\t}\n    -+\n    -+\tif (!ud->quiet) {\n     +\t\tswitch (strategy.type) {\n      \t\tcase SM_UPDATE_CHECKOUT:\n     -\t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n     -\t\t\t       oid, ud->displaypath);\n    -+\t\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n    -+\t\t\t       ud->displaypath, oid);\n    ++\t\t\tdie_message(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n    ++\t\t\t\t    oid, ud->displaypath);\n      \t\t\tbreak;\n      \t\tcase SM_UPDATE_REBASE:\n     -\t\t\tprintf(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n     -\t\t\t       oid, ud->displaypath);\n    -+\t\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n    -+\t\t\t       ud->displaypath, oid);\n    ++\t\t\tif (!must_die_on_failure)\n    ++\t\t\t\tbreak;\n    ++\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n    ++\t\t\t    oid, ud->displaypath);\n      \t\t\tbreak;\n      \t\tcase SM_UPDATE_MERGE:\n     -\t\t\tprintf(_(\"Unable to merge '%s' in submodule path '%s'\"),\n     -\t\t\t       oid, ud->displaypath);\n    -+\t\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n    -+\t\t\t       ud->displaypath, oid);\n    ++\t\t\tif (!must_die_on_failure)\n    ++\t\t\t\tbreak;\n    ++\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n    ++\t\t\t    oid, ud->displaypath);\n      \t\t\tbreak;\n      \t\tcase SM_UPDATE_COMMAND:\n     -\t\t\tprintf(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n     -\t\t\t       ud->update_strategy.command, oid, ud->displaypath);\n    -+\t\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n    -+\t\t\t       ud->displaypath, strategy.command, oid);\n    ++\t\t\tif (!must_die_on_failure)\n    ++\t\t\t\tbreak;\n    ++\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n    ++\t\t\t    strategy.command, oid, ud->displaypath);\n      \t\t\tbreak;\n      \t\tdefault:\n      \t\t\tBUG(\"unexpected update strategy type: %s\",\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n     -\t\t * This signifies to the caller in shell that the command\n     -\t\t * failed without dying\n     -\t\t */\n    --\t\treturn 1;\n    --\t}\n    --\n    ++\n    ++\t\t/* the command failed, but update must continue */\n    + \t\treturn 1;\n    + \t}\n    + \n     -\tswitch (ud->update_strategy.type) {\n    --\tcase SM_UPDATE_CHECKOUT:\n    --\t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n    --\t\t       ud->displaypath, oid);\n    --\t\tbreak;\n    --\tcase SM_UPDATE_REBASE:\n    --\t\tprintf(_(\"Submodule path '%s': rebased into '%s'\\n\"),\n    --\t\t       ud->displaypath, oid);\n    --\t\tbreak;\n    --\tcase SM_UPDATE_MERGE:\n    --\t\tprintf(_(\"Submodule path '%s': merged in '%s'\\n\"),\n    --\t\t       ud->displaypath, oid);\n    --\t\tbreak;\n    --\tcase SM_UPDATE_COMMAND:\n    --\t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n    ++\tif (ud->quiet)\n    ++\t\treturn 0;\n    ++\n    ++\tswitch (strategy.type) {\n    + \tcase SM_UPDATE_CHECKOUT:\n    + \t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n    + \t\t       ud->displaypath, oid);\n    +@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    + \t\tbreak;\n    + \tcase SM_UPDATE_COMMAND:\n    + \t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n     -\t\t       ud->displaypath, ud->update_strategy.command, oid);\n    --\t\tbreak;\n    --\tdefault:\n    --\t\tBUG(\"unexpected update strategy type: %s\",\n    ++\t\t       ud->displaypath, strategy.command, oid);\n    + \t\tbreak;\n    + \tdefault:\n    + \t\tBUG(\"unexpected update strategy type: %s\",\n     -\t\t    submodule_strategy_to_string(&ud->update_strategy));\n    ++\t\t    submodule_strategy_to_string(&strategy));\n      \t}\n      \n    -+\tstrbuf_release(&out);\n      \treturn 0;\n      }\n      \n     -static int do_run_update_procedure(struct update_data *ud)\n    -+static int run_update_procedure(struct update_data *ud, struct string_list *err)\n    ++static int run_update_procedure(struct update_data *ud)\n      {\n      \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n      \n     @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_data *ud)\n    - \t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n    - \t}\n    + \treturn run_update_command(ud, subforce);\n    + }\n      \n    --\treturn run_update_command(ud, subforce);\n    --}\n    --\n     -static void update_submodule(struct update_clone_data *ucd)\n     -{\n     -\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -\n     -static int run_update_procedure(int argc, const char **argv, const char *prefix)\n     -{\n    --\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n     -\tchar *prefixed_path, *update = NULL;\n    --\tstruct update_data update_data = UPDATE_DATA_INIT;\n    +-\tstruct update_data opt = UPDATE_DATA_INIT;\n     -\n     -\tstruct option options[] = {\n    --\t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n    --\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n    --\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n    +-\t\tOPT__QUIET(&opt.quiet,\n    +-\t\t\t   N_(\"suppress output for update by rebase or merge\")),\n    +-\t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"),\n    +-\t\t\t   0),\n    +-\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n     -\t\t\t N_(\"don't fetch new objects from the remote site\")),\n    --\t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n    +-\t\tOPT_BOOL(0, \"just-cloned\", &opt.just_cloned,\n     -\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n    --\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n    +-\t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n     -\t\tOPT_STRING(0, \"prefix\", &prefix,\n     -\t\t\t   N_(\"path\"),\n     -\t\t\t   N_(\"path into the working tree\")),\n     -\t\tOPT_STRING(0, \"update\", &update,\n     -\t\t\t   N_(\"string\"),\n     -\t\t\t   N_(\"rebase, merge, checkout or none\")),\n    --\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n    +-\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n     -\t\t\t   N_(\"path into the working tree, across nested \"\n     -\t\t\t      \"submodule boundaries\")),\n    --\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n    +-\t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n     -\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n     -\t\t\t       parse_opt_object_id),\n    --\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n    +-\t\tOPT_CALLBACK_F(0, \"suboid\", &opt.suboid, N_(\"subsha1\"),\n     -\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n     -\t\t\t       parse_opt_object_id),\n     -\t\tOPT_END()\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -\tif (argc != 1)\n     -\t\tusage_with_options(usage, options);\n     -\n    --\tupdate_data.force = !!force;\n    --\tupdate_data.quiet = !!quiet;\n    --\tupdate_data.nofetch = !!nofetch;\n    --\tupdate_data.just_cloned = !!just_cloned;\n    --\tupdate_data.sm_path = argv[0];\n    +-\topt.sm_path = argv[0];\n     -\n    --\tif (update_data.recursive_prefix)\n    --\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n    +-\tif (opt.recursive_prefix)\n    +-\t\tprefixed_path = xstrfmt(\"%s%s\", opt.recursive_prefix, opt.sm_path);\n     -\telse\n    --\t\tprefixed_path = xstrdup(update_data.sm_path);\n    +-\t\tprefixed_path = xstrdup(opt.sm_path);\n     -\n    --\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n    +-\topt.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n     -\n    --\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n    --\t\t\t\t\t    update_data.sm_path, update,\n    --\t\t\t\t\t    &update_data.update_strategy);\n    +-\tdetermine_submodule_update_strategy(the_repository, opt.just_cloned,\n    +-\t\t\t\t\t    opt.sm_path, update,\n    +-\t\t\t\t\t    &opt.update_strategy);\n     -\n     -\tfree(prefixed_path);\n     -\n    --\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n    --\t\treturn do_run_update_procedure(&update_data);\n    +-\tif (!oideq(&opt.oid, &opt.suboid) || opt.force)\n    +-\t\treturn do_run_update_procedure(&opt);\n     -\n     -\treturn 3;\n     -}\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n     -\tstrbuf_release(&sb);\n     -\treturn 0;\n    -+\treturn run_update_command(ud, subforce, err);\n    - }\n    - \n    +-}\n    +-\n      static const char *remote_submodule_branch(const char *path)\n    + {\n    + \tconst struct submodule *sub;\n     @@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv, const char *prefix)\n      \treturn 0;\n      }\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +static int update_submodule(struct update_data *update_data)\n     +{\n     +\tchar *prefixed_path;\n    -+\tstruct string_list err = STRING_LIST_INIT_DUP;\n     +\n     +\tensure_core_worktree(update_data->sm_path);\n     +\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t}\n     +\n     +\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n    -+\t\tif (run_update_procedure(update_data, &err))\n    ++\t\tif (run_update_procedure(update_data))\n     +\t\t\treturn 1;\n     +\n     +\tif (update_data->recursive) {\n    -+\t\tint res;\n     +\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n     +\t\tstruct update_data next = *update_data;\n    -+\t\tchar *die_msg = xstrfmt(_(\"Failed to recurse into submodule path '%s'\"),\n    -+\t\t\t\t\tupdate_data->displaypath);\n    ++\t\tint res;\n     +\n     +\t\tif (update_data->recursive_prefix)\n     +\t\t\tprefixed_path = xstrfmt(\"%s%s/\", update_data->recursive_prefix,\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\tupdate_data_to_args(&next, &cp.args);\n     +\n     +\t\t/* die() if child process die()'d */\n    -+\t\tif ((res = run_command(&cp)) == 128)\n    -+\t\t\tdie(\"%s\", die_msg);\n    -+\t\tif (res)\n    -+\t\t\tstring_list_append(&err, die_msg);\n    -+\n    -+\t\tfree(die_msg);\n    -+\t}\n    -+\n    -+\tif (err.nr) {\n    -+\t\tstruct string_list_item *item;\n    -+\t\tfor_each_string_list_item(item, &err)\n    -+\t\t\tfputs(item->string, stderr);\n    -+\t\tstring_list_clear(&err, 0);\n    -+\t\treturn 1;\n    ++\t\tres = run_command(&cp);\n    ++\t\tif (!res)\n    ++\t\t\treturn 0;\n    ++\t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n    ++\t\t\t    update_data->displaypath);\n    ++\t\tif (res == 128)\n    ++\t\t\texit(res);\n    ++\t\telse if (res)\n    ++\t\t\treturn 1;\n     +\t}\n     +\n     +\treturn 0;\n-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447203","messageId":"patch-v5-1.9-088c7236a16-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v5 1/9] submodule--helper: get remote names from any repository","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:32Z","receivedAt":"2022-01-28T12:56:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\n`get_default_remote()` retrieves the name of a remote by resolving the\nrefs from of the current repository's ref store.\n\nThus in order to use it for retrieving the remote name of a submodule,\nwe have to start a new subprocess which runs from the submodule\ndirectory.\n\nLet's instead introduce a function called `repo_get_default_remote()`\nwhich takes any repository object and retrieves the remote accordingly.\n\n`get_default_remote()` is then defined as a call to\n`repo_get_default_remote()` with 'the_repository' passed to it.\n\nNow that we have `repo_get_default_remote()`, we no longer have to start\na subprocess that called `submodule--helper get-default-remote` from\nwithin the submodule directory.\n\nSo let's make a function called `get_default_remote_submodule()` which\ntakes a submodule path, and returns the default remote for that\nsubmodule, all within the same process.\n\nWe can now use this function to save an unnecessary subprocess spawn in\n`sync_submodule()`, and also in the next patch, which will require this\nfunctionality.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nHelped-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 39 +++++++++++++++++++++++--------------\n 1 file changed, 24 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c5d3fc3817f..4c7c1e1432d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -29,11 +29,14 @@\n typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n \t\t\t\t  void *cb_data);\n \n-static char *get_default_remote(void)\n+static char *repo_get_default_remote(struct repository *repo)\n {\n \tchar *dest = NULL, *ret;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n+\tstruct ref_store *store = get_main_ref_store(repo);\n+\tint ignore_errno;\n+\tconst char *refname = refs_resolve_ref_unsafe(store, \"HEAD\", 0, NULL,\n+\t\t\t\t\t\t      NULL, &ignore_errno);\n \n \tif (!refname)\n \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n@@ -46,7 +49,7 @@ static char *get_default_remote(void)\n \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n \n \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n-\tif (git_config_get_string(sb.buf, &dest))\n+\tif (repo_config_get_string(repo, sb.buf, &dest))\n \t\tret = xstrdup(\"origin\");\n \telse\n \t\tret = dest;\n@@ -55,6 +58,19 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static char *get_default_remote_submodule(const char *module_path)\n+{\n+\tstruct repository subrepo;\n+\n+\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n+\treturn repo_get_default_remote(&subrepo);\n+}\n+\n+static char *get_default_remote(void)\n+{\n+\treturn repo_get_default_remote(the_repository);\n+}\n+\n static int print_default_remote(int argc, const char **argv, const char *prefix)\n {\n \tchar *remote;\n@@ -1341,9 +1357,8 @@ static void sync_submodule(const char *path, const char *prefix,\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n-\tchar *sub_origin_url, *super_config_url, *displaypath;\n+\tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *sub_config_path = NULL;\n \n \tif (!is_submodule_active(the_repository, path))\n@@ -1382,21 +1397,15 @@ static void sync_submodule(const char *path, const char *prefix,\n \tif (!is_submodule_populated_gently(path, NULL))\n \t\tgoto cleanup;\n \n-\tprepare_submodule_repo_env(&cp.env_array);\n-\tcp.git_cmd = 1;\n-\tcp.dir = path;\n-\tstrvec_pushl(&cp.args, \"submodule--helper\",\n-\t\t     \"print-default-remote\", NULL);\n-\n \tstrbuf_reset(&sb);\n-\tif (capture_command(&cp, &sb, 0))\n+\tdefault_remote = get_default_remote_submodule(path);\n+\tif (!default_remote)\n \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n \t\t      path);\n \n-\tstrbuf_strip_suffix(&sb, \"\\n\");\n-\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n+\tremote_key = xstrfmt(\"remote.%s.url\", default_remote);\n+\tfree(default_remote);\n \n-\tstrbuf_reset(&sb);\n \tsubmodule_to_gitdir(&sb, path);\n \tstrbuf_addstr(&sb, \"/config\");\n \n-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447205","messageId":"patch-v5-2.9-bc694987893-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v5 2/9] submodule--helper: refactor get_submodule_displaypath()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:33Z","receivedAt":"2022-01-28T12:56:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe create a function called `do_get_submodule_displaypath()` that\ngenerates the display path required by several submodule functions, and\ntakes a custom superprefix parameter, instead of reading it from the\nenvironment.\n\nWe then redefine the existing `get_submodule_displaypath()` function\nas a call to this new function, where the superprefix is obtained from\nthe environment.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4c7c1e1432d..5efceb9d46c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -261,11 +261,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\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 *do_get_submodule_displaypath(const char *path, const char *prefix, 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@@ -281,6 +278,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \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+\treturn do_get_submodule_displaypath(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-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447206","messageId":"patch-v5-3.9-e2cc7f0e23b-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v5 3/9] submodule--helper: allow setting superprefix for init_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:34Z","receivedAt":"2022-01-28T12:56:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe allow callers of the `init_submodule()` function to optionally\noverride the superprefix from the environment.\n\nWe need to enable this option because in our conversion of the update\ncommand that will follow, the '--init' option will be handled through\nthis API. We will need to change the superprefix at that time to ensure\nthe display paths show correctly in the output messages.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5efceb9d46c..09cda67c1ea 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -606,18 +606,22 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *superprefix;\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   unsigned int flags)\n+\t\t\t   const char *superprefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\t/* try superprefix from the environment, if it is not passed explicitly */\n+\tif (!superprefix)\n+\t\tsuperprefix = get_super_prefix();\n+\tdisplaypath = do_get_submodule_displaypath(path, prefix, superprefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -691,7 +695,7 @@ static void init_submodule(const char *path, const char *prefix,\n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct init_cb *info = cb_data;\n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447207","messageId":"patch-v5-4.9-e1df2dd4457-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v5 4/9] submodule--helper: run update using child process struct","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:35Z","receivedAt":"2022-01-28T12:56:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe switch to using the run-command API function that takes a\n'struct child process', since we are using a lot of the options. This\nwill also make it simple to switch over to using 'capture_command()'\nwhen we start handling the output of the command completely in C.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 34 ++++++++++++++++------------------\n 1 file changed, 16 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 09cda67c1ea..db71e6f4ec8 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2344,47 +2344,45 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \n static int run_update_command(struct update_data *ud, int subforce)\n {\n-\tstruct strvec args = STRVEC_INIT;\n-\tstruct strvec child_env = STRVEC_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n \tint must_die_on_failure = 0;\n-\tint git_cmd;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_pushl(&args, \"checkout\", \"-q\", NULL);\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n \t\tif (subforce)\n-\t\t\tstrvec_push(&args, \"-f\");\n+\t\t\tstrvec_push(&cp.args, \"-f\");\n \t\tbreak;\n \tcase SM_UPDATE_REBASE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"rebase\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_MERGE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"merge\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n-\t\tgit_cmd = 0;\n-\t\tstrvec_push(&args, ud->update_strategy.command);\n+\t\tcp.use_shell = 1;\n+\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n \t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t}\n-\tstrvec_push(&args, oid);\n+\tstrvec_push(&cp.args, oid);\n \n-\tprepare_submodule_repo_env(&child_env);\n-\tif (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,\n-\t\t\t\t     ud->sm_path, child_env.v)) {\n+\tcp.dir = xstrdup(ud->sm_path);\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tif (run_command(&cp)) {\n \t\tswitch (ud->update_strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n \t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447208","messageId":"patch-v5-5.9-fa815e37f9f-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v5 5/9] builtin/submodule--helper.c: reformat designated initializers","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:36Z","receivedAt":"2022-01-28T12:57:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nThe second hunk here will make a subsequent commit's diff smaller, and\nlet's do the first and third hunks while we're at it so that we\nconsistently format all of these.\n\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 13 ++++++++++---\n 1 file changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex db71e6f4ec8..9f79bdf4d51 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1654,7 +1654,10 @@ struct module_clone_data {\n \tunsigned int require_init: 1;\n \tint single_branch;\n };\n-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }\n+#define MODULE_CLONE_DATA_INIT { \\\n+\t.reference = STRING_LIST_INIT_NODUP, \\\n+\t.single_branch = -1, \\\n+}\n \n struct submodule_alternate_setup {\n \tconst char *submodule_name;\n@@ -2047,7 +2050,9 @@ struct update_data {\n \tunsigned int nofetch: 1;\n \tunsigned int just_cloned: 1;\n };\n-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }\n+#define UPDATE_DATA_INIT { \\\n+\t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+}\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n \t\tstruct strbuf *out, const char *displaypath)\n@@ -3013,7 +3018,9 @@ struct add_data {\n \tunsigned int progress: 1;\n \tunsigned int dissociate: 1;\n };\n-#define ADD_DATA_INIT { .depth = -1 }\n+#define ADD_DATA_INIT { \\\n+\t.depth = -1, \\\n+}\n \n static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)\n {\n-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447209","messageId":"patch-v5-6.9-ef097f7ea51-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v5 6/9] builtin/submodule--helper.c: rename option variables to \"opt\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:37Z","receivedAt":"2022-01-28T12:57:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Rename the \"suc\" variable in update_clone() to \"opt\", and do the same\nfor the \"update_data\" variable in run_update_procedure().\n\nThe only reason for this change is to make the subsequent commit's\ndiff smaller, by doing this rename we can \"anchor\" the diff better, as\nit \"borrow\" most of the options declared here as-is as far as the diff\nrename detection is concerned.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 74 ++++++++++++++++++-------------------\n 1 file changed, 37 insertions(+), 37 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9f79bdf4d51..c2d4fd0347a 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2517,36 +2517,36 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n {\n \tconst char *update = NULL;\n \tstruct pathspec pathspec;\n-\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n \n \tstruct option module_update_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &suc.recursive_prefix,\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree, across nested \"\n \t\t\t      \"submodule boundaries\")),\n \t\tOPT_STRING(0, \"update\", &update,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &suc.references, N_(\"repo\"),\n+\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n \t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &suc.dissociate,\n+\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n \t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &suc.depth, \"<depth>\",\n+\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n \t\t\t   N_(\"create a shallow clone truncated to the \"\n \t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &suc.max_jobs,\n+\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n \t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &suc.recommend_shallow,\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n \t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&suc.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &suc.progress,\n+\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n \t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &suc.require_init,\n+\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n \t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &suc.single_branch,\n+\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n \t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n \t\tOPT_END()\n \t};\n@@ -2555,32 +2555,32 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n \t\tNULL\n \t};\n-\tsuc.prefix = prefix;\n+\topt.prefix = prefix;\n \n-\tupdate_clone_config_from_gitmodules(&suc.max_jobs);\n-\tgit_config(git_update_clone_config, &suc.max_jobs);\n+\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n+\tgit_config(git_update_clone_config, &opt.max_jobs);\n \n \targc = parse_options(argc, argv, prefix, module_update_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n \tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &suc.update) < 0)\n+\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n \t\t\tdie(_(\"bad value for update parameter\"));\n \n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n \t\treturn 1;\n \n \tif (pathspec.nr)\n-\t\tsuc.warn_if_uninitialized = 1;\n+\t\topt.warn_if_uninitialized = 1;\n \n-\treturn update_submodules(&suc);\n+\treturn update_submodules(&opt);\n }\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n \tchar *prefixed_path, *update = NULL;\n-\tstruct update_data update_data = UPDATE_DATA_INIT;\n+\tstruct update_data opt = UPDATE_DATA_INIT;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n@@ -2589,20 +2589,20 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"don't fetch new objects from the remote site\")),\n \t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n \t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n+\t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n \t\tOPT_STRING(0, \"update\", &update,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n \t\t\t   N_(\"path into the working tree, across nested \"\n \t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n+\t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n \t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n+\t\tOPT_CALLBACK_F(0, \"suboid\", &opt.suboid, N_(\"subsha1\"),\n \t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n \t\tOPT_END()\n@@ -2618,27 +2618,27 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tif (argc != 1)\n \t\tusage_with_options(usage, options);\n \n-\tupdate_data.force = !!force;\n-\tupdate_data.quiet = !!quiet;\n-\tupdate_data.nofetch = !!nofetch;\n-\tupdate_data.just_cloned = !!just_cloned;\n-\tupdate_data.sm_path = argv[0];\n+\topt.force = !!force;\n+\topt.quiet = !!quiet;\n+\topt.nofetch = !!nofetch;\n+\topt.just_cloned = !!just_cloned;\n+\topt.sm_path = argv[0];\n \n-\tif (update_data.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n+\tif (opt.recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", opt.recursive_prefix, opt.sm_path);\n \telse\n-\t\tprefixed_path = xstrdup(update_data.sm_path);\n+\t\tprefixed_path = xstrdup(opt.sm_path);\n \n-\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n+\topt.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n \n-\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n-\t\t\t\t\t    update_data.sm_path, update,\n-\t\t\t\t\t    &update_data.update_strategy);\n+\tdetermine_submodule_update_strategy(the_repository, opt.just_cloned,\n+\t\t\t\t\t    opt.sm_path, update,\n+\t\t\t\t\t    &opt.update_strategy);\n \n \tfree(prefixed_path);\n \n-\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data);\n+\tif (!oideq(&opt.oid, &opt.suboid) || opt.force)\n+\t\treturn do_run_update_procedure(&opt);\n \n \treturn 3;\n }\n-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447210","messageId":"patch-v5-7.9-6b038f558c1-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v5 7/9] submodule--helper: don't use bitfield indirection for parse_options()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:38Z","receivedAt":"2022-01-28T12:57:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Do away with the indirection of local variables added in\nc51f8f94e5b (submodule--helper: run update procedures from C,\n2021-08-24).\n\nThese were only needed because in C you can't get a pointer to a\nsingle bit, so we were using intermediate variables instead.\n\nThis will also make a subsequent large commit's diff smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 23 ++++++++++-------------\n 1 file changed, 10 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c2d4fd0347a..4a0890954e9 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2045,10 +2045,10 @@ struct update_data {\n \tstruct object_id suboid;\n \tstruct submodule_update_strategy update_strategy;\n \tint depth;\n-\tunsigned int force: 1;\n-\tunsigned int quiet: 1;\n-\tunsigned int nofetch: 1;\n-\tunsigned int just_cloned: 1;\n+\tunsigned int force;\n+\tunsigned int quiet;\n+\tunsigned int nofetch;\n+\tunsigned int just_cloned;\n };\n #define UPDATE_DATA_INIT { \\\n \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n@@ -2578,16 +2578,17 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n-\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n \tchar *prefixed_path, *update = NULL;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \n \tstruct option options[] = {\n-\t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n+\t\tOPT__QUIET(&opt.quiet,\n+\t\t\t   N_(\"suppress output for update by rebase or merge\")),\n+\t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"),\n+\t\t\t   0),\n+\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n \t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n+\t\tOPT_BOOL(0, \"just-cloned\", &opt.just_cloned,\n \t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n \t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n@@ -2618,10 +2619,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tif (argc != 1)\n \t\tusage_with_options(usage, options);\n \n-\topt.force = !!force;\n-\topt.quiet = !!quiet;\n-\topt.nofetch = !!nofetch;\n-\topt.just_cloned = !!just_cloned;\n \topt.sm_path = argv[0];\n \n \tif (opt.recursive_prefix)\n-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447211","messageId":"patch-v5-8.9-b4f84132201-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v5 8/9] submodule tests: test for init and update failure output","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:39Z","receivedAt":"2022-01-28T12:57:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend some submodule tests to test for the failure output of \"git\nsubmodule [update|init]\". The lack of such tests hid a regression in\nan earlier version of a subsequent commit.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7406-submodule-update.sh    | 14 ++++++++++++--\n t/t7408-submodule-reference.sh | 14 +++++++++++++-\n 2 files changed, 25 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh\nindex 11cccbb333b..7764c1c3cb6 100755\n--- a/t/t7406-submodule-update.sh\n+++ b/t/t7406-submodule-update.sh\n@@ -205,8 +205,18 @@ test_expect_success 'submodule update should fail due to local changes' '\n \t (cd submodule &&\n \t  compare_head\n \t ) &&\n-\t test_must_fail git submodule update submodule\n-\t)\n+\t test_must_fail git submodule update submodule 2>../actual.raw\n+\t) &&\n+\tsed \"s/^> //\" >expect <<-\\EOF &&\n+\t> error: Your local changes to the following files would be overwritten by checkout:\n+\t> \tfile\n+\t> Please commit your changes or stash them before you switch branches.\n+\t> Aborting\n+\t> fatal: Unable to checkout OID in submodule path '\\''submodule'\\''\n+\tEOF\n+\tsed -e \"s/checkout $SQ[^$SQ]*$SQ/checkout OID/\" <actual.raw >actual &&\n+\ttest_cmp expect actual\n+\n '\n test_expect_success 'submodule update should throw away changes with --force ' '\n \t(cd super &&\ndiff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh\nindex a3892f494b6..c3a45455106 100755\n--- a/t/t7408-submodule-reference.sh\n+++ b/t/t7408-submodule-reference.sh\n@@ -193,7 +193,19 @@ test_expect_success 'missing nested submodule alternate fails clone and submodul\n \t\tcd supersuper-clone &&\n \t\tcheck_that_two_of_three_alternates_are_used &&\n \t\t# update of the submodule fails\n-\t\ttest_must_fail git submodule update --init --recursive\n+\t\tcat >expect <<-\\EOF &&\n+\t\tfatal: submodule '\\''sub'\\'' cannot add alternate: path ... does not exist\n+\t\tFailed to clone '\\''sub'\\''. Retry scheduled\n+\t\tfatal: submodule '\\''sub-dissociate'\\'' cannot add alternate: path ... does not exist\n+\t\tFailed to clone '\\''sub-dissociate'\\''. Retry scheduled\n+\t\tfatal: submodule '\\''sub'\\'' cannot add alternate: path ... does not exist\n+\t\tFailed to clone '\\''sub'\\'' a second time, aborting\n+\t\tfatal: Failed to recurse into submodule path ...\n+\t\tEOF\n+\t\ttest_must_fail git submodule update --init --recursive 2>err &&\n+\t\tgrep -e fatal: -e ^Failed err >actual.raw &&\n+\t\tsed -e \"s/path $SQ[^$SQ]*$SQ/path .../\" <actual.raw >actual &&\n+\t\ttest_cmp expect actual\n \t)\n '\n \n-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447212","messageId":"patch-v5-9.9-e8e57606ee9-20220128T125206Z-avarab@gmail.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v5 9/9] submodule: move core cmd_update() logic to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-28T12:56:40Z","receivedAt":"2022-01-28T12:57:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nThis patch completes the conversion past the flag parsing of\n`submodule update` by introducing a helper subcommand called\n`submodule--helper update`. The behaviour of `submodule update` should\nremain the same after this patch.\n\nWe add more fields to the `struct update_data` that are required by\n`struct submodule_update_clone` to be able to perform a clone, when that\nis needed to be done.\n\nRecursing on a submodule is done by calling a subprocess that launches\n`submodule--helper update`, with a modified `--recursive-prefix` and\n`--prefix` parameter.\n\nWe also introduce `update_submodules2()` and `update_submodule2()`\nwhich will supersede `update_submodules()` and `update_submodule()`.\n\nWhen the `--init` flag is passed to the subcommand, we do not spawn a\nnew subprocess and call `submodule--helper init` on the submodule paths,\nbecause the Git machinery is not able to pick up the configuration\nchanges introduced by that init call[1]. So we instead run the\n`init_submodule_cb()` callback over each submodule in the same process.\n\nWhile we are at it, we also remove the fetch_in_submodule() shell\nfunction since it is no longer used anywhere.\n\n[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 599 +++++++++++++++++++++---------------\n git-submodule.sh            | 145 +--------\n 2 files changed, 356 insertions(+), 388 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4a0890954e9..1c28b6f479c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -71,21 +71,6 @@ static char *get_default_remote(void)\n \treturn repo_get_default_remote(the_repository);\n }\n \n-static int print_default_remote(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remote;\n-\n-\tif (argc != 1)\n-\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n-\n-\tremote = get_default_remote();\n-\tif (remote)\n-\t\tprintf(\"%s\\n\", remote);\n-\n-\tfree(remote);\n-\treturn 0;\n-}\n-\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -1965,29 +1950,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n \tfree(key);\n }\n \n-static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path, *update = NULL;\n-\tint just_cloned;\n-\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n-\n-\tif (argc < 3 || argc > 4)\n-\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n-\n-\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n-\tpath = argv[2];\n-\n-\tif (argc == 4)\n-\t\tupdate = argv[3];\n-\n-\tdetermine_submodule_update_strategy(the_repository,\n-\t\t\t\t\t    just_cloned, path, update,\n-\t\t\t\t\t    &update_strategy);\n-\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n-\n-\treturn 0;\n-}\n-\n struct update_clone_data {\n \tconst struct submodule *sub;\n \tstruct object_id oid;\n@@ -2015,7 +1977,6 @@ struct submodule_update_clone {\n \tconst char *prefix;\n \tint single_branch;\n \n-\t/* to be consumed by git-submodule.sh */\n \tstruct update_clone_data *update_clone;\n \tint update_clone_nr; int update_clone_alloc;\n \n@@ -2038,6 +1999,7 @@ struct submodule_update_clone {\n }\n \n struct update_data {\n+\tconst char *prefix;\n \tconst char *recursive_prefix;\n \tconst char *sm_path;\n \tconst char *displaypath;\n@@ -2045,13 +2007,54 @@ struct update_data {\n \tstruct object_id suboid;\n \tstruct submodule_update_strategy update_strategy;\n \tint depth;\n+\tint recommend_shallow;\n+\tint single_branch;\n+\tint max_jobs;\n+\tunsigned int init;\n \tunsigned int force;\n \tunsigned int quiet;\n \tunsigned int nofetch;\n \tunsigned int just_cloned;\n+\tunsigned int remote;\n+\tunsigned int recursive;\n+\tunsigned int progress;\n+\tunsigned int dissociate;\n+\tunsigned int require_init;\n+\tunsigned warn_if_uninitialized ;\n+\tstruct string_list references;\n+\tstruct module_list list;\n };\n #define UPDATE_DATA_INIT { \\\n+\t.list = MODULE_LIST_INIT, \\\n \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+\t.recommend_shallow = -1, \\\n+\t.references = STRING_LIST_INIT_DUP, \\\n+\t.single_branch = -1, \\\n+\t.max_jobs = 1, \\\n+}\n+\n+static void update_clone_from_update_data(struct submodule_update_clone *suc,\n+\t\t\t\t\t  struct update_data *update_data)\n+{\n+\tsuc->prefix = update_data->prefix;\n+\tsuc->recursive_prefix = update_data->recursive_prefix;\n+\tsuc->max_jobs = update_data->max_jobs;\n+\tsuc->progress = update_data->progress;\n+\tsuc->quiet = update_data->quiet;\n+\tsuc->dissociate = update_data->dissociate;\n+\tsuc->require_init = update_data->require_init;\n+\tsuc->single_branch = update_data->single_branch;\n+\tsuc->warn_if_uninitialized = update_data->warn_if_uninitialized;\n+\tsuc->list = update_data->list;\n+\tsuc->update = update_data->update_strategy;\n+\tsuc->recommend_shallow = update_data->recommend_shallow;\n+\tif (update_data->depth)\n+\t\tsuc->depth = xstrfmt(\"--depth=%d\", update_data->depth);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstring_list_append(&suc->references, item->string);\n+\t}\n }\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n@@ -2352,8 +2355,15 @@ static int run_update_command(struct update_data *ud, int subforce)\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n \tint must_die_on_failure = 0;\n+\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n \n-\tswitch (ud->update_strategy.type) {\n+\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n+\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n+\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n+\telse\n+\t\tstrategy = ud->update_strategy;\n+\n+\tswitch (strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\tcp.git_cmd = 1;\n \t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n@@ -2376,55 +2386,54 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n \t\tcp.use_shell = 1;\n-\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n+\t\tstrvec_push(&cp.args, strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t    submodule_strategy_to_string(&strategy));\n \t}\n \tstrvec_push(&cp.args, oid);\n \n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env_array);\n \tif (run_command(&cp)) {\n-\t\tswitch (ud->update_strategy.type) {\n+\t\tswitch (strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n-\t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tdie_message(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n-\t\t\tprintf(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tif (!must_die_on_failure)\n+\t\t\t\tbreak;\n+\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_MERGE:\n-\t\t\tprintf(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tif (!must_die_on_failure)\n+\t\t\t\tbreak;\n+\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_COMMAND:\n-\t\t\tprintf(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n-\t\t\t       ud->update_strategy.command, oid, ud->displaypath);\n+\t\t\tif (!must_die_on_failure)\n+\t\t\t\tbreak;\n+\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\t    strategy.command, oid, ud->displaypath);\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t\t    submodule_strategy_to_string(&strategy));\n \t\t}\n-\t\t/*\n-\t\t * NEEDSWORK: We are currently printing to stdout with error\n-\t\t * return so that the shell caller handles the error output\n-\t\t * properly. Once we start handling the error messages within\n-\t\t * C, we should use die() instead.\n-\t\t */\n-\t\tif (must_die_on_failure)\n-\t\t\treturn 2;\n-\t\t/*\n-\t\t * This signifies to the caller in shell that the command\n-\t\t * failed without dying\n-\t\t */\n+\n+\t\t/* the command failed, but update must continue */\n \t\treturn 1;\n \t}\n \n-\tswitch (ud->update_strategy.type) {\n+\tif (ud->quiet)\n+\t\treturn 0;\n+\n+\tswitch (strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n \t\t       ud->displaypath, oid);\n@@ -2439,17 +2448,17 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n \t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n-\t\t       ud->displaypath, ud->update_strategy.command, oid);\n+\t\t       ud->displaypath, strategy.command, oid);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t    submodule_strategy_to_string(&strategy));\n \t}\n \n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud)\n+static int run_update_procedure(struct update_data *ud)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2479,178 +2488,6 @@ static int do_run_update_procedure(struct update_data *ud)\n \treturn run_update_command(ud, subforce);\n }\n \n-static void update_submodule(struct update_clone_data *ucd)\n-{\n-\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n-\t\toid_to_hex(&ucd->oid),\n-\t\tucd->just_cloned,\n-\t\tucd->sub->path);\n-}\n-\n-static int update_submodules(struct submodule_update_clone *suc)\n-{\n-\tint i;\n-\n-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n-\t\t\t\t   update_clone_start_failure,\n-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n-\t\t\t\t   \"parallel/update\");\n-\n-\t/*\n-\t * We saved the output and put it out all at once now.\n-\t * That means:\n-\t * - the listener does not have to interleave their (checkout)\n-\t *   work with our fetching.  The writes involved in a\n-\t *   checkout involve more straightforward sequential I/O.\n-\t * - the listener can avoid doing any work if fetching failed.\n-\t */\n-\tif (suc->quickstop)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_submodule(&suc->update_clone[i]);\n-\n-\treturn 0;\n-}\n-\n-static int update_clone(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *update = NULL;\n-\tstruct pathspec pathspec;\n-\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n-\n-\tstruct option module_update_clone_options[] = {\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n-\t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n-\t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n-\t\t\t   N_(\"create a shallow clone truncated to the \"\n-\t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n-\t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n-\t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n-\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\topt.prefix = prefix;\n-\n-\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n-\tgit_config(git_update_clone_config, &opt.max_jobs);\n-\n-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n-\t\t\tdie(_(\"bad value for update parameter\"));\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n-\t\treturn 1;\n-\n-\tif (pathspec.nr)\n-\t\topt.warn_if_uninitialized = 1;\n-\n-\treturn update_submodules(&opt);\n-}\n-\n-static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *prefixed_path, *update = NULL;\n-\tstruct update_data opt = UPDATE_DATA_INIT;\n-\n-\tstruct option options[] = {\n-\t\tOPT__QUIET(&opt.quiet,\n-\t\t\t   N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"),\n-\t\t\t   0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n-\t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &opt.just_cloned,\n-\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n-\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &opt.suboid, N_(\"subsha1\"),\n-\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const usage[] = {\n-\t\tN_(\"git submodule--helper run-update-procedure [<options>] <path>\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\n-\tif (argc != 1)\n-\t\tusage_with_options(usage, options);\n-\n-\topt.sm_path = argv[0];\n-\n-\tif (opt.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", opt.recursive_prefix, opt.sm_path);\n-\telse\n-\t\tprefixed_path = xstrdup(opt.sm_path);\n-\n-\topt.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n-\n-\tdetermine_submodule_update_strategy(the_repository, opt.just_cloned,\n-\t\t\t\t\t    opt.sm_path, update,\n-\t\t\t\t\t    &opt.update_strategy);\n-\n-\tfree(prefixed_path);\n-\n-\tif (!oideq(&opt.oid, &opt.suboid) || opt.force)\n-\t\treturn do_run_update_procedure(&opt);\n-\n-\treturn 3;\n-}\n-\n-static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 3)\n-\t\tdie(\"submodule--helper relative-path takes exactly 2 arguments, got %d\", argc);\n-\n-\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n-\tstrbuf_release(&sb);\n-\treturn 0;\n-}\n-\n static const char *remote_submodule_branch(const char *path)\n {\n \tconst struct submodule *sub;\n@@ -2783,17 +2620,11 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+static void ensure_core_worktree(const char *path)\n {\n-\tconst char *path;\n \tconst char *cw;\n \tstruct repository subrepo;\n \n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\n \tif (repo_submodule_init(&subrepo, the_repository, path, null_oid()))\n \t\tdie(_(\"could not get a repository handle for submodule '%s'\"), path);\n \n@@ -2813,8 +2644,6 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n-\n-\treturn 0;\n }\n \n static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n@@ -3001,6 +2830,271 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \treturn !!ret;\n }\n \n+static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n+{\n+\tconst char *update = submodule_strategy_to_string(&update_data->update_strategy);\n+\n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n+\tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n+\tif (update_data->prefix)\n+\t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n+\tif (update_data->recursive_prefix)\n+\t\tstrvec_pushl(args, \"--recursive-prefix\",\n+\t\t\t     update_data->recursive_prefix, NULL);\n+\tif (update_data->quiet)\n+\t\tstrvec_push(args, \"--quiet\");\n+\tif (update_data->force)\n+\t\tstrvec_push(args, \"--force\");\n+\tif (update_data->init)\n+\t\tstrvec_push(args, \"--init\");\n+\tif (update_data->remote)\n+\t\tstrvec_push(args, \"--remote\");\n+\tif (update_data->nofetch)\n+\t\tstrvec_push(args, \"--no-fetch\");\n+\tif (update_data->dissociate)\n+\t\tstrvec_push(args, \"--dissociate\");\n+\tif (update_data->progress)\n+\t\tstrvec_push(args, \"--progress\");\n+\tif (update_data->require_init)\n+\t\tstrvec_push(args, \"--require-init\");\n+\tif (update_data->depth)\n+\t\tstrvec_pushf(args, \"--depth=%d\", update_data->depth);\n+\tif (update)\n+\t\tstrvec_pushl(args, \"--update\", update, NULL);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n+\t}\n+\tif (update_data->recommend_shallow == 0)\n+\t\tstrvec_push(args, \"--no-recommend-shallow\");\n+\telse if (update_data->recommend_shallow == 1)\n+\t\tstrvec_push(args, \"--recommend-shallow\");\n+\tif (update_data->single_branch >= 0)\n+\t\tstrvec_push(args, \"--single-branch\");\n+}\n+\n+static int update_submodule(struct update_data *update_data)\n+{\n+\tchar *prefixed_path;\n+\n+\tensure_core_worktree(update_data->sm_path);\n+\n+\tif (update_data->recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n+\t\t\t\t\tupdate_data->sm_path);\n+\telse\n+\t\tprefixed_path = xstrdup(update_data->sm_path);\n+\n+\tupdate_data->displaypath = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t     update_data->prefix);\n+\tfree(prefixed_path);\n+\n+\tif (update_data->just_cloned) {\n+\t\toidcpy(&update_data->suboid, null_oid());\n+\t} else {\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n+\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t}\n+\n+\tif (update_data->remote) {\n+\t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n+\t\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n+\t\tchar *remote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n+\n+\t\tif (!update_data->nofetch) {\n+\t\t\tif (fetch_in_submodule(update_data->sm_path, update_data->depth,\n+\t\t\t\t\t      0, NULL))\n+\t\t\t\tdie(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\t\t    update_data->sm_path);\n+\t\t}\n+\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))\n+\t\t\tdie(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t    remote_ref, update_data->sm_path);\n+\n+\t\tfree(remote_ref);\n+\t}\n+\n+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n+\t\tif (run_update_procedure(update_data))\n+\t\t\treturn 1;\n+\n+\tif (update_data->recursive) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct update_data next = *update_data;\n+\t\tint res;\n+\n+\t\tif (update_data->recursive_prefix)\n+\t\t\tprefixed_path = xstrfmt(\"%s%s/\", update_data->recursive_prefix,\n+\t\t\t\t\t\tupdate_data->sm_path);\n+\t\telse\n+\t\t\tprefixed_path = xstrfmt(\"%s/\", update_data->sm_path);\n+\n+\t\tnext.recursive_prefix = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t\t  update_data->prefix);\n+\t\tnext.prefix = NULL;\n+\t\toidcpy(&next.oid, null_oid());\n+\t\toidcpy(&next.suboid, null_oid());\n+\n+\t\tcp.dir = update_data->sm_path;\n+\t\tcp.git_cmd = 1;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tupdate_data_to_args(&next, &cp.args);\n+\n+\t\t/* die() if child process die()'d */\n+\t\tres = run_command(&cp);\n+\t\tif (!res)\n+\t\t\treturn 0;\n+\t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t\tif (res == 128)\n+\t\t\texit(res);\n+\t\telse if (res)\n+\t\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int update_submodules(struct update_data *update_data)\n+{\n+\tint i, res = 0;\n+\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\n+\tupdate_clone_from_update_data(&suc, update_data);\n+\trun_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,\n+\t\t\t\t   update_clone_start_failure,\n+\t\t\t\t   update_clone_task_finished, &suc, \"submodule\",\n+\t\t\t\t   \"parallel/update\");\n+\n+\t/*\n+\t * We saved the output and put it out all at once now.\n+\t * That means:\n+\t * - the listener does not have to interleave their (checkout)\n+\t *   work with our fetching.  The writes involved in a\n+\t *   checkout involve more straightforward sequential I/O.\n+\t * - the listener can avoid doing any work if fetching failed.\n+\t */\n+\tif (suc.quickstop) {\n+\t\tres = 1;\n+\t\tgoto cleanup;\n+\t}\n+\n+\tfor (i = 0; i < suc.update_clone_nr; i++) {\n+\t\tstruct update_clone_data ucd = suc.update_clone[i];\n+\n+\t\toidcpy(&update_data->oid, &ucd.oid);\n+\t\tupdate_data->just_cloned = ucd.just_cloned;\n+\t\tupdate_data->sm_path = ucd.sub->path;\n+\n+\t\tif (update_submodule(update_data))\n+\t\t\tres = 1;\n+\t}\n+\n+cleanup:\n+\tstring_list_clear(&update_data->references, 0);\n+\treturn res;\n+}\n+\n+static int module_update(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *update = NULL;\n+\tstruct pathspec pathspec;\n+\tstruct update_data opt = UPDATE_DATA_INIT;\n+\n+\tstruct option module_update_clone_options[] = {\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+\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n+\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n+\t\tOPT_BOOL(0, \"recursive\", &opt.recursive,\n+\t\t\t N_(\"traverse submodules recursively\")),\n+\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n+\t\t\t N_(\"don't fetch new objects from the remote site\")),\n+\t\tOPT_STRING(0, \"prefix\", &opt.prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree\")),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree, across nested \"\n+\t\t\t      \"submodule boundaries\")),\n+\t\tOPT_STRING(0, \"update\", &update,\n+\t\t\t   N_(\"string\"),\n+\t\t\t   N_(\"rebase, merge, checkout or none\")),\n+\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n+\t\t\t\tN_(\"reference repository\")),\n+\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n+\t\t\t N_(\"use --reference only while cloning\")),\n+\t\tOPT_INTEGER(0, \"depth\", &opt.depth,\n+\t\t\t    N_(\"create a shallow clone truncated to the \"\n+\t\t\t       \"specified number of revisions\")),\n+\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n+\t\t\t    N_(\"parallel jobs\")),\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n+\t\t\t N_(\"whether the initial clone should follow the shallow recommendation\")),\n+\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n+\t\t\t N_(\"force cloning progress\")),\n+\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n+\t\t\t N_(\"disallow cloning into non-empty directory\")),\n+\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n+\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n+\t\tNULL\n+\t};\n+\n+\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n+\tgit_config(git_update_clone_config, &opt.max_jobs);\n+\n+\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\toidcpy(&opt.oid, null_oid());\n+\toidcpy(&opt.suboid, null_oid());\n+\n+\tif (update)\n+\t\tif (parse_submodule_update_strategy(update,\n+\t\t\t\t\t\t    &opt.update_strategy) < 0)\n+\t\t\tdie(_(\"bad value for update parameter\"));\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n+\t\treturn 1;\n+\n+\tif (pathspec.nr)\n+\t\topt.warn_if_uninitialized = 1;\n+\n+\tif (opt.init) {\n+\t\tstruct module_list list = MODULE_LIST_INIT;\n+\t\tstruct init_cb info = INIT_CB_INIT;\n+\n+\t\tif (module_list_compute(argc, argv, opt.prefix,\n+\t\t\t\t\t&pathspec, &list) < 0)\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * If there are no path args and submodule.active is set then,\n+\t\t * by default, only initialize 'active' modules.\n+\t\t */\n+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n+\t\t\tmodule_list_active(&list);\n+\n+\t\tinfo.prefix = opt.prefix;\n+\t\tinfo.superprefix = opt.recursive_prefix;\n+\t\tif (opt.quiet)\n+\t\t\tinfo.flags |= OPT_QUIET;\n+\n+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n+\t}\n+\n+\treturn update_submodules(&opt);\n+}\n+\n struct add_data {\n \tconst char *prefix;\n \tconst char *branch;\n@@ -3388,16 +3482,11 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n-\t{\"update-module-mode\", module_update_module_mode, 0},\n-\t{\"update-clone\", update_clone, 0},\n-\t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n-\t{\"relative-path\", resolve_relative_path, 0},\n+\t{\"update\", module_update, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n-\t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, 0},\n \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 652861aa66a..bcd8b92aabd 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -246,20 +246,6 @@ cmd_deinit()\n \tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- \"$@\"\n }\n \n-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]\n-# Because arguments are positional, use an empty string to omit <depth>\n-# but include <sha1>.\n-fetch_in_submodule () (\n-\tsanitize_submodule_env &&\n-\tcd \"$1\" &&\n-\tif test $# -eq 3\n-\tthen\n-\t\techo \"$3\" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+\"$2\"}\n-\telse\n-\t\tgit fetch ${GIT_QUIET:+--quiet} ${2:+\"$2\"}\n-\tfi\n-)\n-\n #\n # Update each submodule path to correct revision, using clone and checkout as needed\n #\n@@ -361,133 +347,26 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\tif test -n \"$init\"\n-\tthen\n-\t\tcmd_init \"--\" \"$@\" || return\n-\tfi\n-\n-\t{\n-\tgit submodule--helper update-clone ${GIT_QUIET:+--quiet} \\\n-\t\t${progress:+\"--progress\"} \\\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n+\t\t${GIT_QUIET:+--quiet} \\\n+\t\t${force:+--force} \\\n+\t\t${progress:+--progress} \\\n+\t\t${dissociate:+--dissociate} \\\n+\t\t${remote:+--remote} \\\n+\t\t${recursive:+--recursive} \\\n+\t\t${init:+--init} \\\n+\t\t${require_init:+--require-init} \\\n+\t\t${nofetch:+--no-fetch} \\\n \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t${update:+--update \"$update\"} \\\n \t\t${reference:+\"$reference\"} \\\n-\t\t${dissociate:+\"--dissociate\"} \\\n-\t\t${depth:+--depth \"$depth\"} \\\n-\t\t${require_init:+--require-init} \\\n+\t\t${depth:+\"$depth\"} \\\n \t\t$single_branch \\\n \t\t$recommend_shallow \\\n \t\t$jobs \\\n \t\t-- \\\n-\t\t\"$@\" || echo \"#unmatched\" $?\n-\t} | {\n-\terr=\n-\twhile read -r quickabort sha1 just_cloned sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n-\n-\t\tgit submodule--helper ensure-core-worktree \"$sm_path\" || exit 1\n-\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\n-\t\tif test $just_cloned -eq 1\n-\t\tthen\n-\t\t\tsubsha1=\n-\t\telse\n-\t\t\tjust_cloned=\n-\t\t\tsubsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify HEAD) ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current revision in submodule path '\\$displaypath'\")\"\n-\t\tfi\n-\n-\t\tif test -n \"$remote\"\n-\t\tthen\n-\t\t\tbranch=$(git submodule--helper remote-branch \"$sm_path\")\n-\t\t\tif test -z \"$nofetch\"\n-\t\t\tthen\n-\t\t\t\t# Fetch remote before determining tracking $sha1\n-\t\t\t\tfetch_in_submodule \"$sm_path\" $depth ||\n-\t\t\t\tdie \"fatal: $(eval_gettext \"Unable to fetch in submodule path '\\$sm_path'\")\"\n-\t\t\tfi\n-\t\t\tremote_name=$(sanitize_submodule_env; cd \"$sm_path\" && git submodule--helper print-default-remote)\n-\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify \"${remote_name}/${branch}\") ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\n-\t\tout=$(git submodule--helper run-update-procedure \\\n-\t\t\t  ${wt_prefix:+--prefix \"$wt_prefix\"} \\\n-\t\t\t  ${GIT_QUIET:+--quiet} \\\n-\t\t\t  ${force:+--force} \\\n-\t\t\t  ${just_cloned:+--just-cloned} \\\n-\t\t\t  ${nofetch:+--no-fetch} \\\n-\t\t\t  ${depth:+\"$depth\"} \\\n-\t\t\t  ${update:+--update \"$update\"} \\\n-\t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n-\t\t\t  ${sha1:+--oid \"$sha1\"} \\\n-\t\t\t  ${subsha1:+--suboid \"$subsha1\"} \\\n-\t\t\t  \"--\" \\\n-\t\t\t  \"$sm_path\")\n-\n-\t\t# exit codes for run-update-procedure:\n-\t\t# 0: update was successful, say command output\n-\t\t# 1: update procedure failed, but should not die\n-\t\t# 2 or 128: subcommand died during execution\n-\t\t# 3: no update procedure was run\n-\t\tres=\"$?\"\n-\t\tcase $res in\n-\t\t0)\n-\t\t\tsay \"$out\"\n-\t\t\t;;\n-\t\t1)\n-\t\t\terr=\"${err};fatal: $out\"\n-\t\t\tcontinue\n-\t\t\t;;\n-\t\t2|128)\n-\t\t\tdie_with_status $res \"fatal: $out\"\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=$(git submodule--helper relative-path \"$prefix$sm_path/\" \"$wt_prefix\")\n-\t\t\t\twt_prefix=\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_update\n-\t\t\t)\n-\t\t\tres=$?\n-\t\t\tif test $res -gt 0\n-\t\t\tthen\n-\t\t\t\tdie_msg=\"fatal: $(eval_gettext \"Failed to recurse into submodule path '\\$displaypath'\")\"\n-\t\t\t\tif test $res -ne 2\n-\t\t\t\tthen\n-\t\t\t\t\terr=\"${err};$die_msg\"\n-\t\t\t\t\tcontinue\n-\t\t\t\telse\n-\t\t\t\t\tdie_with_status $res \"$die_msg\"\n-\t\t\t\tfi\n-\t\t\tfi\n-\t\tfi\n-\tdone\n-\n-\tif test -n \"$err\"\n-\tthen\n-\t\tOIFS=$IFS\n-\t\tIFS=';'\n-\t\tfor e in $err\n-\t\tdo\n-\t\t\tif test -n \"$e\"\n-\t\t\tthen\n-\t\t\t\techo >&2 \"$e\"\n-\t\t\tfi\n-\t\tdone\n-\t\tIFS=$OIFS\n-\t\texit 1\n-\tfi\n-\t}\n+\t\t\"$@\"\n }\n \n #\n-- \n2.35.0.914.ge5c8aab0d5b\n\n"},{"id":"447581","messageId":"kl6l4k5g246p.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"patch-v5-9.9-e8e57606ee9-20220128T125206Z-avarab@gmail.com","subject":"Re: [PATCH v5 9/9] submodule: move core cmd_update() logic to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-03T00:18:22Z","receivedAt":"2022-02-03T00:18:27Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"I mentioned (out-of-mailing-list) that I was still looking at this, but\nthat the big sh -> c conversion is quite challenging for me to parse\npersonally. I'm still looking at it, but it will take some time..\n\nI'm of the opinion that this patch would be a lot easier to review if it\nwere broken up into more patches, but it has always looked like this\n[1]. The only real difference from [1] to this version is that this also\nremoves all of the dead code, which doesn't really hinder reviewability.\n\nI don't think you have to go through the effort of splitting it up -\nafter all you were able to review [1], so given enough time I should\nbe able to read through this patch too :) That said, I wish that we\nalready had a split up patch for at least 2 other reasons:\n\n- Junio pointed out that this conflicts with\n  es/superproject-aware-submodules [2]. I'm not sure which should be\n  based on which. If this does end up being based on\n  es/superproject-aware-submodules, it would probably be easier to\n  rebase as a series of smaller patches. Atharva noted that the\n  conflicts are mild though, so maybe it's not so bad.\n\n- Besides making sure that the sh -> c is faithful, a thorough review\n  should hopefully catch unintentional mistakes. The size of this patch\n  makes such mistakes difficult to spot. For instance, here's something\n  I spotted only after trying to split the patch myself..\n\n  > +static int module_update(int argc, const char **argv, const char *prefix)\n  > +{\n  > +\tconst char *update = NULL;\n  > +\tstruct pathspec pathspec;\n  > +\tstruct update_data opt = UPDATE_DATA_INIT;\n  > +\n  > +\tstruct option module_update_clone_options[] = {\n  [...]\n  > +\t};\n  > +\n  > +\tconst char *const git_submodule_helper_usage[] = {\n  > +\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n  > +\t\tNULL\n  > +\t};\n  > +\n  > +\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n  > +\tgit_config(git_update_clone_config, &opt.max_jobs);\n\n  Notice that we copy-pasted the option parsing from update-clone into\n  module_update() but forgot to update the names.\n\nMy ideal patch organization would be something like:\n\n- wrap some existing command in \"git submodule--helper update\" (probably\n  run-update-procedure)\n- absorb the surrounding sh code into \"git submodule--helper\n  update\" one command at-a-time i.e. deprecating and removing the\n  commands one at a time - instead of deprecating and removing them all\n  at once (like this patch), or deprecating all at once and removing\n  them one at a time (like v1).\n\nI don't know if it's feasible or not; Atharva noted upthread that there\nare some technical reasons why some things can be done in-process and\nsome cannot, but it might be a useful exercise.\n\nHere's what I propose:\n\n- If you think this alternative organization would be helpful for you\n  too, I will attempt it. This will take a while, but by the end you and\n  I will have effectively reviewed all of the code, so it should be easy\n  to finish up the review.\n\n- Otherwise e.g. maybe this is a huge waste of time, or you're already\n  really confident in the correctness of the sh -> c when you reviewed\n  the original patch, etc, I'll just review this patch as-is. I'd\n  appreciate any tips and tricks that might help :)\n\n- Orthogonal to patch organization, I'm still not sure if this will be\n  rebased on es/superproject-aware-submodules or vice-versa, and I don't\n  want either of us to sink too much effort before knowing the answer.\n\n[1] https://lore.kernel.org/git/20210907115932.36068-7-raykar.ath@gmail.com/\n[2] https://lore.kernel.org/git/YWiXL+plA7GHfuVv@google.com/\n\n"},{"id":"447587","messageId":"220203.865ypw7jw6.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"kl6l4k5g246p.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v5 9/9] submodule: move core cmd_update() logic to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-03T02:26:28Z","receivedAt":"2022-02-03T02:40:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Feb 02 2022, Glen Choo wrote:\n\n> - Junio pointed out that this conflicts with\n>   es/superproject-aware-submodules [2]. I'm not sure which should be\n>   based on which. If this does end up being based on\n>   es/superproject-aware-submodules, it would probably be easier to\n>   rebase as a series of smaller patches. Atharva noted that the\n>   conflicts are mild though, so maybe it's not so bad.\n\nI think it makes sense to get this series through first, i.e. the\n(supposedly) no-behavior-changing one, and then one that introduces new\nsubmodule behavior.\n\nParticularly because for es/superproject-aware-submodules the main\nselling point is a performance improvement, which as I noted in the\nreview for it I've been unable to observe once the C<->sh layer goes\naway.\n\nI'm not saying it's not there, just that I don't think it's been shown\nso far, IIRC there was some reference to some Google-internal network FS\nthat might or might not be helped by it...\n\n> - Besides making sure that the sh -> c is faithful, a thorough review\n>   should hopefully catch unintentional mistakes. The size of this patch\n>   makes such mistakes difficult to spot. For instance, here's something\n>   I spotted only after trying to split the patch myself..\n>\n>   > +static int module_update(int argc, const char **argv, const char *prefix)\n>   > +{\n>   > +\tconst char *update = NULL;\n>   > +\tstruct pathspec pathspec;\n>   > +\tstruct update_data opt = UPDATE_DATA_INIT;\n>   > +\n>   > +\tstruct option module_update_clone_options[] = {\n>   [...]\n>   > +\t};\n>   > +\n>   > +\tconst char *const git_submodule_helper_usage[] = {\n>   > +\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n>   > +\t\tNULL\n>   > +\t};\n>   > +\n>   > +\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n>   > +\tgit_config(git_update_clone_config, &opt.max_jobs);\n>\n>   Notice that we copy-pasted the option parsing from update-clone into\n>   module_update() but forgot to update the names.\n>\n> My ideal patch organization would be something like:\n>\n> - wrap some existing command in \"git submodule--helper update\" (probably\n>   run-update-procedure)\n> - absorb the surrounding sh code into \"git submodule--helper\n>   update\" one command at-a-time i.e. deprecating and removing the\n>   commands one at a time - instead of deprecating and removing them all\n>   at once (like this patch), or deprecating all at once and removing\n>   them one at a time (like v1).\n\nI do think atomic changes that don't leave dead code for removal later\nare easier to read & reason about, whatever else is reorganized.\n\nI.e. not to have something where we replace all the running code, and\nthen remove already-unused code later.\n\nOn that topic, I noticed this series could/should have [1] fixed up into\nit.\n\n> - If you think this alternative organization would be helpful for you\n>   too, I will attempt it. This will take a while, but by the end you and\n>   I will have effectively reviewed all of the code, so it should be easy\n>   to finish up the review.\n\nI think it might, but I really don't know. We'll just have to see, so if\nyou want to take a stab at it that would be great.\n\nMaybe it's a good way forward. E.g. as af first small step we could turn:\n\n    while read -r quickabort sha1 just_cloned sm_path\n    [...]\n    die_if_unmatched \"$quickabort\" \"$sha1\"\n\ninto version where we fold that die_if_unmatched() logic into the C\ncode, and then ensure-core-worktree etc.\n\n> - Otherwise e.g. maybe this is a huge waste of time, or you're already\n>   really confident in the correctness of the sh -> c when you reviewed\n>   the original patch, etc, I'll just review this patch as-is. I'd\n>   appreciate any tips and tricks that might help :)\n\nI'm not really confident in it.\n\nI've read it, tested it as well as I could manage etc. but it's still a\nvery large change.\n\n1.\n\ndiff --git a/git-sh-setup.sh b/git-sh-setup.sh\nindex b93f39288ce..756c2a67c72 100644\n--- a/git-sh-setup.sh\n+++ b/git-sh-setup.sh\n@@ -286,13 +286,6 @@ get_author_ident_from_commit () {\n \tparse_ident_from_commit author AUTHOR\n }\n \n-# Clear repo-local GIT_* environment variables. Useful when switching to\n-# another repository (e.g. when entering a submodule). See also the env\n-# list in git_connect()\n-clear_local_git_env() {\n-\tunset $(git rev-parse --local-env-vars)\n-}\n-\n # Generate a virtual base file for a two-file merge. Uses git apply to\n # remove lines from $1 that are not in $2, leaving only common lines.\n create_virtual_base() {\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex bcd8b92aabd..6c91b9e2403 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -50,30 +50,11 @@ single_branch=\n jobs=\n recommend_shallow=\n \n-die_if_unmatched ()\n-{\n-\tif test \"$1\" = \"#unmatched\"\n-\tthen\n-\t\texit ${2:-1}\n-\tfi\n-}\n-\n isnumber()\n {\n \tn=$(($1 + 0)) 2>/dev/null && test \"$n\" = \"$1\"\n }\n \n-# Sanitize the local git environment for use within a submodule. We\n-# can't simply use clear_local_git_env since we want to preserve some\n-# of the settings from GIT_CONFIG_PARAMETERS.\n-sanitize_submodule_env()\n-{\n-\tsave_config=$GIT_CONFIG_PARAMETERS\n-\tclear_local_git_env\n-\tGIT_CONFIG_PARAMETERS=$save_config\n-\texport GIT_CONFIG_PARAMETERS\n-}\n-\n #\n # Add a new submodule to the working tree, .gitmodules and the index\n #\n"},{"id":"447590","messageId":"220203.861r0k74bz.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"220203.865ypw7jw6.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v5 9/9] submodule: move core cmd_update() logic to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-03T08:15:19Z","receivedAt":"2022-02-03T08:16:22Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 03 2022, Ævar Arnfjörð Bjarmason wrote:\n\n> On Wed, Feb 02 2022, Glen Choo wrote:\n>\n>> - Junio pointed out that this conflicts with\n>>   es/superproject-aware-submodules [2]. I'm not sure which should be\n>>   based on which. If this does end up being based on\n>>   es/superproject-aware-submodules, it would probably be easier to\n>>   rebase as a series of smaller patches. Atharva noted that the\n>>   conflicts are mild though, so maybe it's not so bad.\n>\n> I think it makes sense to get this series through first, i.e. the\n> (supposedly) no-behavior-changing one, and then one that introduces new\n> submodule behavior.\n>\n> Particularly because for es/superproject-aware-submodules the main\n> selling point is a performance improvement, which as I noted in the\n> review for it I've been unable to observe once the C<->sh layer goes\n> away.\n>\n> I'm not saying it's not there, just that I don't think it's been shown\n> so far, IIRC there was some reference to some Google-internal network FS\n> that might or might not be helped by it...\n>\n>> - Besides making sure that the sh -> c is faithful, a thorough review\n>>   should hopefully catch unintentional mistakes. The size of this patch\n>>   makes such mistakes difficult to spot. For instance, here's something\n>>   I spotted only after trying to split the patch myself..\n>>\n>>   > +static int module_update(int argc, const char **argv, const char *prefix)\n>>   > +{\n>>   > +\tconst char *update = NULL;\n>>   > +\tstruct pathspec pathspec;\n>>   > +\tstruct update_data opt = UPDATE_DATA_INIT;\n>>   > +\n>>   > +\tstruct option module_update_clone_options[] = {\n>>   [...]\n>>   > +\t};\n>>   > +\n>>   > +\tconst char *const git_submodule_helper_usage[] = {\n>>   > +\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n>>   > +\t\tNULL\n>>   > +\t};\n>>   > +\n>>   > +\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n>>   > +\tgit_config(git_update_clone_config, &opt.max_jobs);\n>>\n>>   Notice that we copy-pasted the option parsing from update-clone into\n>>   module_update() but forgot to update the names.\n>>\n>> My ideal patch organization would be something like:\n>>\n>> - wrap some existing command in \"git submodule--helper update\" (probably\n>>   run-update-procedure)\n>> - absorb the surrounding sh code into \"git submodule--helper\n>>   update\" one command at-a-time i.e. deprecating and removing the\n>>   commands one at a time - instead of deprecating and removing them all\n>>   at once (like this patch), or deprecating all at once and removing\n>>   them one at a time (like v1).\n>\n> I do think atomic changes that don't leave dead code for removal later\n> are easier to read & reason about, whatever else is reorganized.\n>\n> I.e. not to have something where we replace all the running code, and\n> then remove already-unused code later.\n>\n> On that topic, I noticed this series could/should have [1] fixed up into\n> it.\n>\n>> - If you think this alternative organization would be helpful for you\n>>   too, I will attempt it. This will take a while, but by the end you and\n>>   I will have effectively reviewed all of the code, so it should be easy\n>>   to finish up the review.\n>\n> I think it might, but I really don't know. We'll just have to see, so if\n> you want to take a stab at it that would be great.\n>\n> Maybe it's a good way forward. E.g. as af first small step we could turn:\n>\n>     while read -r quickabort sha1 just_cloned sm_path\n>     [...]\n>     die_if_unmatched \"$quickabort\" \"$sha1\"\n>\n> into version where we fold that die_if_unmatched() logic into the C\n> code, and then ensure-core-worktree etc.\n\nSorry, that one makes no sense since it's an artifact of the shellscript\nimplementation.\n\nBut I tested the below on top of master, and it passes all tests, which\nisn't very promising...\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4a0890954e9..e749008f13a 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2783,40 +2783,6 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path;\n-\tconst char *cw;\n-\tstruct repository subrepo;\n-\n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\n-\tif (repo_submodule_init(&subrepo, the_repository, path, null_oid()))\n-\t\tdie(_(\"could not get a repository handle for submodule '%s'\"), path);\n-\n-\tif (!repo_config_get_string_tmp(&subrepo, \"core.worktree\", &cw)) {\n-\t\tchar *cfg_file, *abs_path;\n-\t\tconst char *rel_path;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tcfg_file = repo_git_path(&subrepo, \"config\");\n-\n-\t\tabs_path = absolute_pathdup(path);\n-\t\trel_path = relative_path(abs_path, subrepo.gitdir, &sb);\n-\n-\t\tgit_config_set_in_file(cfg_file, \"core.worktree\", rel_path);\n-\n-\t\tfree(cfg_file);\n-\t\tfree(abs_path);\n-\t\tstrbuf_release(&sb);\n-\t}\n-\n-\treturn 0;\n-}\n-\n static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n@@ -3391,7 +3357,6 @@ static struct cmd_struct commands[] = {\n \t{\"update-module-mode\", module_update_module_mode, 0},\n \t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 652861aa66a..460cbd4e265 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -387,8 +387,6 @@ cmd_update()\n \tdo\n \t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n \n-\t\tgit submodule--helper ensure-core-worktree \"$sm_path\" || exit 1\n-\n \t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n \n \t\tif test $just_cloned -eq 1\n"},{"id":"447622","messageId":"kl6l1r0j26qq.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"220203.861r0k74bz.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v5 9/9] submodule: move core cmd_update() logic to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-03T17:35:25Z","receivedAt":"2022-02-03T17:35: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> On Thu, Feb 03 2022, Ævar Arnfjörð Bjarmason wrote:\n>\n>> On Wed, Feb 02 2022, Glen Choo wrote:\n>>\n>>> - Junio pointed out that this conflicts with\n>>>   es/superproject-aware-submodules [2]. I'm not sure which should be\n>>>   based on which. If this does end up being based on\n>>>   es/superproject-aware-submodules, it would probably be easier to\n>>>   rebase as a series of smaller patches. Atharva noted that the\n>>>   conflicts are mild though, so maybe it's not so bad.\n>>\n>> I think it makes sense to get this series through first, i.e. the\n>> (supposedly) no-behavior-changing one, and then one that introduces new\n>> submodule behavior.\n>>\n>> Particularly because for es/superproject-aware-submodules the main\n>> selling point is a performance improvement, which as I noted in the\n>> review for it I've been unable to observe once the C<->sh layer goes\n>> away.\n>>\n>> I'm not saying it's not there, just that I don't think it's been shown\n>> so far, IIRC there was some reference to some Google-internal network FS\n>> that might or might not be helped by it...\n\nI'll let the experts chime in, I don't think I can add anything useful\nto the discussion.\n\n>>> My ideal patch organization would be something like:\n>>>\n>>> - wrap some existing command in \"git submodule--helper update\" (probably\n>>>   run-update-procedure)\n>>> - absorb the surrounding sh code into \"git submodule--helper\n>>>   update\" one command at-a-time i.e. deprecating and removing the\n>>>   commands one at a time - instead of deprecating and removing them all\n>>>   at once (like this patch), or deprecating all at once and removing\n>>>   them one at a time (like v1).\n>>\n>> I do think atomic changes that don't leave dead code for removal later\n>> are easier to read & reason about, whatever else is reorganized.\n>>\n>> I.e. not to have something where we replace all the running code, and\n>> then remove already-unused code later.\n\nI agree - otherwise patches aren't self-contianed and harder to merge.\n\n>>> - If you think this alternative organization would be helpful for you\n>>>   too, I will attempt it. This will take a while, but by the end you and\n>>>   I will have effectively reviewed all of the code, so it should be easy\n>>>   to finish up the review.\n>>\n>> I think it might, but I really don't know. We'll just have to see, so if\n>> you want to take a stab at it that would be great.\n>>\n>> Maybe it's a good way forward. E.g. as af first small step we could turn:\n>>\n>>     while read -r quickabort sha1 just_cloned sm_path\n>>     [...]\n>>     die_if_unmatched \"$quickabort\" \"$sha1\"\n>>\n>> into version where we fold that die_if_unmatched() logic into the C\n>> code, and then ensure-core-worktree etc.\n>\n> Sorry, that one makes no sense since it's an artifact of the shellscript\n> implementation.\n\nWhether or not it makes sense, I think it gets the point across i.e.\nthat we think folding into C can be done incrementally.\n\n>>> - Otherwise e.g. maybe this is a huge waste of time, or you're already\n>>>   really confident in the correctness of the sh -> c when you reviewed\n>>>   the original patch, etc, I'll just review this patch as-is. I'd\n>>>   appreciate any tips and tricks that might help :)\n>>\n>> I'm not really confident in it.\n>>\n>> I've read it, tested it as well as I could manage etc. but it's still a\n>> very large change.\n[...]\n> But I tested the below on top of master, and it passes all tests, which\n> isn't very promising...\n\nA good enough (i.e. extremely comprehensive) test suite will all but\nguarantee that no behavior has changed. Our test suite is nowhere near\nthat level and probably never will be, so we can't trust that things are\ncorrect even if it passes tests.\n\nSo, for the sake of reviewability, I'll take a stab at reorganizing.\nI'll be taking a long flight anyway, so I'll have big chunk of\nnon-company time to spend on this ;)\n"},{"id":"447947","messageId":"20220208083952.35036-1-chooglen@google.com","threadId":"56453","inReplyTo":"cover-v5-0.9-00000000000-20220128T125206Z-avarab@gmail.com","subject":"[PATCH v6 00/16] submodule: convert the rest of 'update' to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:36Z","receivedAt":"2022-02-08T08:40:02Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Here is a split-up of the last patch as I promised :) The intent was to\nminimize the diff vs v5 instead of getting to a perfect end state; this\nwill almost certainly need a reroll.\n\nThis split-up isn't as complete as I had hoped - the last patch is still\nrather large, but breaking that up already took more time than\neverything else combined, and I think this organization is already\neasier to review than v5. I'd appreciate any suggestions on how this\ncould be done [1] :) If inspiration strikes, I'll break it up further in\na reroll, but as of right now, I'm out of ideas.\n\nI did some minimal review of the implementation, but I plan to do more\nafter sending this to the list e.g. I have not revisited the earlier\npreparatory patches to see if my patches make sense with them. Where I\nfound issues, I left NEEDSWORK comments instead of fixing them because\nthe result would be easier to diff with v5 (the only differences between\nthis tree and v5's is the NEEDSWORK comments). I plan to fix\nimplementation issues (once we've spotted them in reivew) and the\nNEEDSWORKs in the next reroll.\n\nLet me know if the trailers make sense - this is my first time reworking\nsomeone else's changes, so I don't think I did a perfect job at\nattributing work. I also had to fiddle with the Signed-off-by to make\nthem resemble the v5 patches' Signed-off-by (ar/submodule-update seemed\nto order them differently from v5, I'm not sure why).\n\n[1] The difficulty in the last patch comes from the fact that we have\nthe --recursive flag handling in shell, and we are piping update-clone\ninto {run-update-procedure + --recursive flag handling}. Because of how\n\"git submodule\" parses args, it is tricky to implement --recursive\nwithout bypassing \"git submodule\" with \"git submodule--helper update\"\n(the final patch does this bypass). On the other hand, it's difficult to\nleave --recursive for last, because we would need to mimic the piping\nand exiting behavior around update-clone and run-update-procedure.\n\nChanges in v6:\n- Split up last patch of v5 into patches 9-16.\n- Patches 9-10 are preparatory work on submodule--helper.c.\n- Patches 11-14 contain sh -> c conversions of the git-submodule.sh code\n  surrounding update-clone and run-update-procedure.\n- Patch 15 moves functions around in order to shrink patch 16's diff\n  - If reviewers prefer, we could choose _not_ to move the functions\n    around. If so, we can drop patch 15.\n- Patch 16 introduces \"submodule--helper update\". Change the commit\n  message to drop references to work done in previous patches.\n- Add NEEDSWORK comments for potential issues. These will be cleaned up\n  in the next version.\n\nAtharva Raykar (6):\n  submodule--helper: get remote names from any repository\n  submodule--helper: refactor get_submodule_displaypath()\n  submodule--helper: allow setting superprefix for init_submodule()\n  submodule--helper: run update using child process struct\n  builtin/submodule--helper.c: reformat designated initializers\n  submodule: move core cmd_update() logic to C\n\nGlen Choo (7):\n  submodule--helper: remove update-module-mode\n  submodule--helper: reorganize code for sh to C conversion\n  submodule--helper run-update-procedure: remove --suboid\n  submodule--helper run-update-procedure: learn --remote\n  submodule--helper: remove ensure-core-worktree\n  submodule--helper update-clone: learn --init\n  submodule--helper: move functions around\n\nÆvar Arnfjörð Bjarmason (3):\n  builtin/submodule--helper.c: rename option variables to \"opt\"\n  submodule--helper: don't use bitfield indirection for parse_options()\n  submodule tests: test for init and update failure output\n\n builtin/submodule--helper.c    | 709 +++++++++++++++++++--------------\n git-submodule.sh               | 145 +------\n t/t7406-submodule-update.sh    |  14 +-\n t/t7408-submodule-reference.sh |  14 +-\n 4 files changed, 447 insertions(+), 435 deletions(-)\n\nRange-diff against v5:\n 1:  b45e49810a =  1:  86ffb53742 submodule--helper: get remote names from any repository\n 2:  8974329fc5 =  2:  2a40266b7a submodule--helper: refactor get_submodule_displaypath()\n 3:  bd92e00c05 =  3:  cd851c8eb5 submodule--helper: allow setting superprefix for init_submodule()\n 4:  909cb60cd4 =  4:  bfe5cad136 submodule--helper: run update using child process struct\n 5:  36575b2f25 =  5:  72c257fdbf builtin/submodule--helper.c: reformat designated initializers\n 6:  a743003e09 =  6:  4b5f703fde builtin/submodule--helper.c: rename option variables to \"opt\"\n 7:  3a449d00b9 =  7:  f1d21f5b1c submodule--helper: don't use bitfield indirection for parse_options()\n 8:  7da45dde67 =  8:  9d32a73fc3 submodule tests: test for init and update failure output\n -:  ---------- >  9:  087bf43aba submodule--helper: remove update-module-mode\n -:  ---------- > 10:  4eb2893a19 submodule--helper: reorganize code for sh to C conversion\n -:  ---------- > 11:  c08e7781e3 submodule--helper run-update-procedure: remove --suboid\n -:  ---------- > 12:  2419c37184 submodule--helper run-update-procedure: learn --remote\n -:  ---------- > 13:  6691fd3648 submodule--helper: remove ensure-core-worktree\n -:  ---------- > 14:  d2c9c356e9 submodule--helper update-clone: learn --init\n -:  ---------- > 15:  a5cde5e084 submodule--helper: move functions around\n 9:  251a0b4241 ! 16:  f0551a37e5 submodule: move core cmd_update() logic to C\n    @@ Commit message\n         `submodule--helper update`, with a modified `--recursive-prefix` and\n         `--prefix` parameter.\n     \n    -    We also introduce `update_submodules2()` and `update_submodule2()`\n    -    which will supersede `update_submodules()` and `update_submodule()`.\n    -\n    -    When the `--init` flag is passed to the subcommand, we do not spawn a\n    -    new subprocess and call `submodule--helper init` on the submodule paths,\n    -    because the Git machinery is not able to pick up the configuration\n    -    changes introduced by that init call[1]. So we instead run the\n    -    `init_submodule_cb()` callback over each submodule in the same process.\n    -\n    -    While we are at it, we also remove the fetch_in_submodule() shell\n    -    function since it is no longer used anywhere.\n    -\n    -    [1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n    -\n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n         Mentored-by: Shourya Shukla <periperidip@gmail.com>\n         Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n         Signed-off-by: Junio C Hamano <gitster@pobox.com>\n    +    Signed-off-by: Glen Choo <chooglen@google.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static char *get_default_remote(void)\n    - \treturn repo_get_default_remote(the_repository);\n    - }\n    - \n    --static int print_default_remote(int argc, const char **argv, const char *prefix)\n    --{\n    --\tchar *remote;\n    --\n    --\tif (argc != 1)\n    --\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n    --\n    --\tremote = get_default_remote();\n    --\tif (remote)\n    --\t\tprintf(\"%s\\n\", remote);\n    --\n    --\tfree(remote);\n    --\treturn 0;\n    --}\n    --\n    - static int starts_with_dot_slash(const char *str)\n    - {\n    - \treturn str[0] == '.' && is_dir_sep(str[1]);\n    -@@ builtin/submodule--helper.c: static void determine_submodule_update_strategy(struct repository *r,\n    - \tfree(key);\n    - }\n    - \n    --static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n    --{\n    --\tconst char *path, *update = NULL;\n    --\tint just_cloned;\n    --\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n    --\n    --\tif (argc < 3 || argc > 4)\n    --\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n    --\n    --\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n    --\tpath = argv[2];\n    --\n    --\tif (argc == 4)\n    --\t\tupdate = argv[3];\n    --\n    --\tdetermine_submodule_update_strategy(the_repository,\n    --\t\t\t\t\t    just_cloned, path, update,\n    --\t\t\t\t\t    &update_strategy);\n    --\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n    --\n    --\treturn 0;\n    --}\n    --\n    - struct update_clone_data {\n    - \tconst struct submodule *sub;\n    - \tstruct object_id oid;\n     @@ builtin/submodule--helper.c: struct submodule_update_clone {\n      \tconst char *prefix;\n      \tint single_branch;\n    @@ builtin/submodule--helper.c: struct submodule_update_clone {\n      \tstruct update_clone_data *update_clone;\n      \tint update_clone_nr; int update_clone_alloc;\n      \n    +@@ builtin/submodule--helper.c: struct submodule_update_clone {\n    + \tint failed_clones_nr, failed_clones_alloc;\n    + \n    + \tint max_jobs;\n    +-\tunsigned int init;\n    + };\n    + #define SUBMODULE_UPDATE_CLONE_INIT { \\\n    + \t.list = MODULE_LIST_INIT, \\\n     @@ builtin/submodule--helper.c: struct submodule_update_clone {\n      }\n      \n    @@ builtin/submodule--helper.c: struct update_data {\n      \tunsigned int quiet;\n      \tunsigned int nofetch;\n      \tunsigned int just_cloned;\n    -+\tunsigned int remote;\n    + \tunsigned int remote;\n     +\tunsigned int recursive;\n     +\tunsigned int progress;\n     +\tunsigned int dissociate;\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \tchar *oid = oid_to_hex(&ud->oid);\n      \tint must_die_on_failure = 0;\n     +\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n    - \n    --\tswitch (ud->update_strategy.type) {\n    ++\n     +\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n     +\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n     +\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n     +\telse\n     +\t\tstrategy = ud->update_strategy;\n    -+\n    + \n    +-\tswitch (ud->update_strategy.type) {\n     +\tswitch (strategy.type) {\n      \tcase SM_UPDATE_CHECKOUT:\n      \t\tcp.git_cmd = 1;\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -\t\tucd->sub->path);\n     -}\n     -\n    --static int update_submodules(struct submodule_update_clone *suc)\n    --{\n    --\tint i;\n    --\n    --\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n    --\t\t\t\t   update_clone_start_failure,\n    --\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n    --\t\t\t\t   \"parallel/update\");\n    --\n    --\t/*\n    --\t * We saved the output and put it out all at once now.\n    --\t * That means:\n    --\t * - the listener does not have to interleave their (checkout)\n    --\t *   work with our fetching.  The writes involved in a\n    --\t *   checkout involve more straightforward sequential I/O.\n    --\t * - the listener can avoid doing any work if fetching failed.\n    --\t */\n    --\tif (suc->quickstop)\n    --\t\treturn 1;\n    --\n    --\tfor (i = 0; i < suc->update_clone_nr; i++)\n    --\t\tupdate_submodule(&suc->update_clone[i]);\n    --\n    --\treturn 0;\n    --}\n    --\n    --static int update_clone(int argc, const char **argv, const char *prefix)\n    --{\n    --\tconst char *update = NULL;\n    --\tstruct pathspec pathspec;\n    --\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n    --\n    --\tstruct option module_update_clone_options[] = {\n    --\t\tOPT_STRING(0, \"prefix\", &prefix,\n    --\t\t\t   N_(\"path\"),\n    --\t\t\t   N_(\"path into the working tree\")),\n    --\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n    --\t\t\t   N_(\"path\"),\n    --\t\t\t   N_(\"path into the working tree, across nested \"\n    --\t\t\t      \"submodule boundaries\")),\n    --\t\tOPT_STRING(0, \"update\", &update,\n    --\t\t\t   N_(\"string\"),\n    --\t\t\t   N_(\"rebase, merge, checkout or none\")),\n    --\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n    --\t\t\t   N_(\"reference repository\")),\n    --\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n    --\t\t\t   N_(\"use --reference only while cloning\")),\n    --\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n    --\t\t\t   N_(\"create a shallow clone truncated to the \"\n    --\t\t\t      \"specified number of revisions\")),\n    --\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n    --\t\t\t    N_(\"parallel jobs\")),\n    --\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n    --\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n    --\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n    --\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n    --\t\t\t    N_(\"force cloning progress\")),\n    --\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n    --\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n    --\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n    --\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n    --\t\tOPT_END()\n    --\t};\n    --\n    --\tconst char *const git_submodule_helper_usage[] = {\n    --\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n    --\t\tNULL\n    --\t};\n    --\topt.prefix = prefix;\n    --\n    --\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n    --\tgit_config(git_update_clone_config, &opt.max_jobs);\n    --\n    --\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n    --\t\t\t     git_submodule_helper_usage, 0);\n    --\n    --\tif (update)\n    --\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n    --\t\t\tdie(_(\"bad value for update parameter\"));\n    --\n    --\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n    --\t\treturn 1;\n    --\n    --\tif (pathspec.nr)\n    --\t\topt.warn_if_uninitialized = 1;\n    --\n    --\treturn update_submodules(&opt);\n    --}\n    --\n    +-/*\n    +- * NEEDSWORK: Use a forward declaration to avoid moving\n    +- * run_update_procedure() (which will be removed soon).\n    +- */\n    +-static int update_submodule2(struct update_data *update_data);\n     -static int run_update_procedure(int argc, const char **argv, const char *prefix)\n     -{\n     -\tchar *prefixed_path, *update = NULL;\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -\t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n     -\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n     -\t\t\t       parse_opt_object_id),\n    --\t\tOPT_CALLBACK_F(0, \"suboid\", &opt.suboid, N_(\"subsha1\"),\n    --\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n    --\t\t\t       parse_opt_object_id),\n    +-\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n    +-\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n     -\t\tOPT_END()\n     -\t};\n     -\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -\t\t\t\t\t    &opt.update_strategy);\n     -\n     -\tfree(prefixed_path);\n    --\n    --\tif (!oideq(&opt.oid, &opt.suboid) || opt.force)\n    --\t\treturn do_run_update_procedure(&opt);\n    --\n    --\treturn 3;\n    +-\treturn update_submodule2(&opt);\n     -}\n     -\n     -static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n      static const char *remote_submodule_branch(const char *path)\n      {\n      \tconst struct submodule *sub;\n    -@@ builtin/submodule--helper.c: static int push_check(int argc, const char **argv, const char *prefix)\n    - \treturn 0;\n    - }\n    - \n    --static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n    -+static void ensure_core_worktree(const char *path)\n    - {\n    --\tconst char *path;\n    - \tconst char *cw;\n    - \tstruct repository subrepo;\n    - \n    --\tif (argc != 2)\n    --\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n    --\n    --\tpath = argv[1];\n    --\n    - \tif (repo_submodule_init(&subrepo, the_repository, path, null_oid()))\n    - \t\tdie(_(\"could not get a repository handle for submodule '%s'\"), path);\n    - \n    -@@ builtin/submodule--helper.c: static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n    - \t\tfree(abs_path);\n    - \t\tstrbuf_release(&sb);\n    - \t}\n    --\n    --\treturn 0;\n    - }\n    - \n    - static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n     @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char **argv, const char *prefix)\n      \treturn !!ret;\n      }\n      \n    +-/* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n    +-static int update_submodule2(struct update_data *update_data)\n     +static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n     +{\n     +\tconst char *update = submodule_strategy_to_string(&update_data->update_strategy);\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +}\n     +\n     +static int update_submodule(struct update_data *update_data)\n    -+{\n    + {\n     +\tchar *prefixed_path;\n     +\n    -+\tensure_core_worktree(update_data->sm_path);\n    -+\n    + \tensure_core_worktree(update_data->sm_path);\n    + \n     +\tif (update_data->recursive_prefix)\n     +\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n     +\t\t\t\t\tupdate_data->sm_path);\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\t\t\t\t\t\t     update_data->prefix);\n     +\tfree(prefixed_path);\n     +\n    -+\tif (update_data->just_cloned) {\n    -+\t\toidcpy(&update_data->suboid, null_oid());\n    -+\t} else {\n    -+\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n    -+\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n    -+\t\t\t    update_data->displaypath);\n    -+\t}\n    -+\n    -+\tif (update_data->remote) {\n    -+\t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n    -+\t\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n    -+\t\tchar *remote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n    -+\n    -+\t\tif (!update_data->nofetch) {\n    -+\t\t\tif (fetch_in_submodule(update_data->sm_path, update_data->depth,\n    -+\t\t\t\t\t      0, NULL))\n    -+\t\t\t\tdie(_(\"Unable to fetch in submodule path '%s'\"),\n    -+\t\t\t\t    update_data->sm_path);\n    -+\t\t}\n    -+\n    -+\t\tif (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))\n    -+\t\t\tdie(_(\"Unable to find %s revision in submodule path '%s'\"),\n    -+\t\t\t    remote_ref, update_data->sm_path);\n    -+\n    -+\t\tfree(remote_ref);\n    -+\t}\n    -+\n    -+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n    + \t/* NEEDSWORK: fix the style issues e.g. braces */\n    + \tif (update_data->just_cloned) {\n    + \t\toidcpy(&update_data->suboid, null_oid());\n    +@@ builtin/submodule--helper.c: static int update_submodule2(struct update_data *update_data)\n    + \t}\n    + \n    + \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n    +-\t\treturn do_run_update_procedure(update_data);\n     +\t\tif (run_update_procedure(update_data))\n     +\t\t\treturn 1;\n    -+\n    + \n    +-\treturn 3;\n     +\tif (update_data->recursive) {\n     +\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n     +\t\tstruct update_data next = *update_data;\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t}\n     +\n     +\treturn 0;\n    -+}\n    -+\n    + }\n    + \n    +-static int update_submodules(struct submodule_update_clone *suc)\n     +static int update_submodules(struct update_data *update_data)\n    -+{\n    + {\n    +-\tint i;\n     +\tint i, res = 0;\n     +\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n    -+\n    + \n    +-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n     +\tupdate_clone_from_update_data(&suc, update_data);\n     +\trun_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,\n    -+\t\t\t\t   update_clone_start_failure,\n    + \t\t\t\t   update_clone_start_failure,\n    +-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n     +\t\t\t\t   update_clone_task_finished, &suc, \"submodule\",\n    -+\t\t\t\t   \"parallel/update\");\n    -+\n    -+\t/*\n    -+\t * We saved the output and put it out all at once now.\n    -+\t * That means:\n    -+\t * - the listener does not have to interleave their (checkout)\n    -+\t *   work with our fetching.  The writes involved in a\n    -+\t *   checkout involve more straightforward sequential I/O.\n    -+\t * - the listener can avoid doing any work if fetching failed.\n    -+\t */\n    + \t\t\t\t   \"parallel/update\");\n    + \n    + \t/*\n    +@@ builtin/submodule--helper.c: static int update_submodules(struct submodule_update_clone *suc)\n    + \t *   checkout involve more straightforward sequential I/O.\n    + \t * - the listener can avoid doing any work if fetching failed.\n    + \t */\n    +-\tif (suc->quickstop)\n    +-\t\treturn 1;\n     +\tif (suc.quickstop) {\n     +\t\tres = 1;\n     +\t\tgoto cleanup;\n     +\t}\n    -+\n    + \n    +-\tfor (i = 0; i < suc->update_clone_nr; i++)\n    +-\t\tupdate_submodule(&suc->update_clone[i]);\n     +\tfor (i = 0; i < suc.update_clone_nr; i++) {\n     +\t\tstruct update_clone_data ucd = suc.update_clone[i];\n    -+\n    + \n    +-\treturn 0;\n     +\t\toidcpy(&update_data->oid, &ucd.oid);\n     +\t\tupdate_data->just_cloned = ucd.just_cloned;\n     +\t\tupdate_data->sm_path = ucd.sub->path;\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +cleanup:\n     +\tstring_list_clear(&update_data->references, 0);\n     +\treturn res;\n    -+}\n    -+\n    + }\n    + \n    +-static int update_clone(int argc, const char **argv, const char *prefix)\n     +static int module_update(int argc, const char **argv, const char *prefix)\n    -+{\n    -+\tconst char *update = NULL;\n    -+\tstruct pathspec pathspec;\n    + {\n    + \tconst char *update = NULL;\n    + \tstruct pathspec pathspec;\n    +-\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n     +\tstruct update_data opt = UPDATE_DATA_INIT;\n    -+\n    -+\tstruct option module_update_clone_options[] = {\n    + \n    ++\t/* NEEDSWORK: update names and strings */\n    + \tstruct option module_update_clone_options[] = {\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    + \t\tOPT_BOOL(0, \"init\", &opt.init,\n    + \t\t\t N_(\"initialize uninitialized submodules before update\")),\n    +-\t\tOPT_STRING(0, \"prefix\", &prefix,\n     +\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n     +\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n     +\t\tOPT_BOOL(0, \"recursive\", &opt.recursive,\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n     +\t\t\t N_(\"don't fetch new objects from the remote site\")),\n     +\t\tOPT_STRING(0, \"prefix\", &opt.prefix,\n    -+\t\t\t   N_(\"path\"),\n    -+\t\t\t   N_(\"path into the working tree\")),\n    -+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n    -+\t\t\t   N_(\"path\"),\n    -+\t\t\t   N_(\"path into the working tree, across nested \"\n    -+\t\t\t      \"submodule boundaries\")),\n    -+\t\tOPT_STRING(0, \"update\", &update,\n    -+\t\t\t   N_(\"string\"),\n    -+\t\t\t   N_(\"rebase, merge, checkout or none\")),\n    -+\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n    + \t\t\t   N_(\"path\"),\n    + \t\t\t   N_(\"path into the working tree\")),\n    + \t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n    +@@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv, const char *prefix)\n    + \t\t\t   N_(\"string\"),\n    + \t\t\t   N_(\"rebase, merge, checkout or none\")),\n    + \t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n    +-\t\t\t   N_(\"reference repository\")),\n     +\t\t\t\tN_(\"reference repository\")),\n    -+\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n    + \t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n    +-\t\t\t   N_(\"use --reference only while cloning\")),\n    +-\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n    +-\t\t\t   N_(\"create a shallow clone truncated to the \"\n    +-\t\t\t      \"specified number of revisions\")),\n     +\t\t\t N_(\"use --reference only while cloning\")),\n     +\t\tOPT_INTEGER(0, \"depth\", &opt.depth,\n     +\t\t\t    N_(\"create a shallow clone truncated to the \"\n     +\t\t\t       \"specified number of revisions\")),\n    -+\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n    -+\t\t\t    N_(\"parallel jobs\")),\n    -+\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n    + \t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n    + \t\t\t    N_(\"parallel jobs\")),\n    + \t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n    +-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n     +\t\t\t N_(\"whether the initial clone should follow the shallow recommendation\")),\n    -+\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n    -+\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n    + \t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n    + \t\tOPT_BOOL(0, \"progress\", &opt.progress,\n    +-\t\t\t    N_(\"force cloning progress\")),\n     +\t\t\t N_(\"force cloning progress\")),\n    -+\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n    + \t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n    +-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n     +\t\t\t N_(\"disallow cloning into non-empty directory\")),\n    -+\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n    -+\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n    -+\t\tOPT_END()\n    -+\t};\n    -+\n    -+\tconst char *const git_submodule_helper_usage[] = {\n    -+\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n    -+\t\tNULL\n    -+\t};\n    -+\n    -+\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n    -+\tgit_config(git_update_clone_config, &opt.max_jobs);\n    -+\n    -+\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n    -+\t\t\t     git_submodule_helper_usage, 0);\n    + \t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n    + \t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n    + \t\tOPT_END()\n    +@@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv, const char *prefix)\n    + \t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n    + \t\tNULL\n    + \t};\n    +-\topt.prefix = prefix;\n    + \n    + \tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n    + \tgit_config(git_update_clone_config, &opt.max_jobs);\n    + \n    + \targc = parse_options(argc, argv, prefix, module_update_clone_options,\n    + \t\t\t     git_submodule_helper_usage, 0);\n     +\toidcpy(&opt.oid, null_oid());\n     +\toidcpy(&opt.suboid, null_oid());\n    -+\n    -+\tif (update)\n    + \n    + \tif (update)\n    +-\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n     +\t\tif (parse_submodule_update_strategy(update,\n     +\t\t\t\t\t\t    &opt.update_strategy) < 0)\n    -+\t\t\tdie(_(\"bad value for update parameter\"));\n    -+\n    -+\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n    -+\t\treturn 1;\n    -+\n    -+\tif (pathspec.nr)\n    -+\t\topt.warn_if_uninitialized = 1;\n    -+\n    -+\tif (opt.init) {\n    -+\t\tstruct module_list list = MODULE_LIST_INIT;\n    -+\t\tstruct init_cb info = INIT_CB_INIT;\n    -+\n    -+\t\tif (module_list_compute(argc, argv, opt.prefix,\n    -+\t\t\t\t\t&pathspec, &list) < 0)\n    -+\t\t\treturn 1;\n    -+\n    -+\t\t/*\n    -+\t\t * If there are no path args and submodule.active is set then,\n    -+\t\t * by default, only initialize 'active' modules.\n    -+\t\t */\n    -+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n    -+\t\t\tmodule_list_active(&list);\n    -+\n    -+\t\tinfo.prefix = opt.prefix;\n    -+\t\tinfo.superprefix = opt.recursive_prefix;\n    -+\t\tif (opt.quiet)\n    -+\t\t\tinfo.flags |= OPT_QUIET;\n    -+\n    -+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n    -+\t}\n    -+\n    -+\treturn update_submodules(&opt);\n    -+}\n    -+\n    - struct add_data {\n    - \tconst char *prefix;\n    - \tconst char *branch;\n    + \t\t\tdie(_(\"bad value for update parameter\"));\n    + \n    + \tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n     @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {\n      \t{\"name\", module_name, 0},\n      \t{\"clone\", module_clone, 0},\n      \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n    --\t{\"update-module-mode\", module_update_module_mode, 0},\n     -\t{\"update-clone\", update_clone, 0},\n     -\t{\"run-update-procedure\", run_update_procedure, 0},\n    --\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n     -\t{\"relative-path\", resolve_relative_path, 0},\n     +\t{\"update\", module_update, 0},\n      \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n      \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n      \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n    - \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n    --\t{\"print-default-remote\", print_default_remote, 0},\n    - \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n    - \t{\"deinit\", module_deinit, 0},\n    - \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n     \n      ## git-submodule.sh ##\n    -@@ git-submodule.sh: cmd_deinit()\n    - \tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- \"$@\"\n    - }\n    - \n    --# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]\n    --# Because arguments are positional, use an empty string to omit <depth>\n    --# but include <sha1>.\n    --fetch_in_submodule () (\n    --\tsanitize_submodule_env &&\n    --\tcd \"$1\" &&\n    --\tif test $# -eq 3\n    --\tthen\n    --\t\techo \"$3\" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+\"$2\"}\n    --\telse\n    --\t\tgit fetch ${GIT_QUIET:+--quiet} ${2:+\"$2\"}\n    --\tfi\n    --)\n    --\n    - #\n    - # Update each submodule path to correct revision, using clone and checkout as needed\n    - #\n     @@ git-submodule.sh: cmd_update()\n      \t\tshift\n      \tdone\n      \n    --\tif test -n \"$init\"\n    --\tthen\n    --\t\tcmd_init \"--\" \"$@\" || return\n    --\tfi\n    --\n     -\t{\n    --\tgit submodule--helper update-clone ${GIT_QUIET:+--quiet} \\\n    --\t\t${progress:+\"--progress\"} \\\n    +-\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper update-clone \\\n     +\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n    -+\t\t${GIT_QUIET:+--quiet} \\\n    + \t\t${GIT_QUIET:+--quiet} \\\n    +-\t\t${progress:+\"--progress\"} \\\n     +\t\t${force:+--force} \\\n     +\t\t${progress:+--progress} \\\n     +\t\t${dissociate:+--dissociate} \\\n     +\t\t${remote:+--remote} \\\n     +\t\t${recursive:+--recursive} \\\n    -+\t\t${init:+--init} \\\n    + \t\t${init:+--init} \\\n     +\t\t${require_init:+--require-init} \\\n     +\t\t${nofetch:+--no-fetch} \\\n      \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n    @@ git-submodule.sh: cmd_update()\n     -\tdo\n     -\t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n     -\n    --\t\tgit submodule--helper ensure-core-worktree \"$sm_path\" || exit 1\n    --\n     -\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n     -\n    --\t\tif test $just_cloned -eq 1\n    +-\t\tif test $just_cloned -eq 0\n     -\t\tthen\n    --\t\t\tsubsha1=\n    --\t\telse\n     -\t\t\tjust_cloned=\n    --\t\t\tsubsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n    --\t\t\t\tgit rev-parse --verify HEAD) ||\n    --\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current revision in submodule path '\\$displaypath'\")\"\n    --\t\tfi\n    --\n    --\t\tif test -n \"$remote\"\n    --\t\tthen\n    --\t\t\tbranch=$(git submodule--helper remote-branch \"$sm_path\")\n    --\t\t\tif test -z \"$nofetch\"\n    --\t\t\tthen\n    --\t\t\t\t# Fetch remote before determining tracking $sha1\n    --\t\t\t\tfetch_in_submodule \"$sm_path\" $depth ||\n    --\t\t\t\tdie \"fatal: $(eval_gettext \"Unable to fetch in submodule path '\\$sm_path'\")\"\n    --\t\t\tfi\n    --\t\t\tremote_name=$(sanitize_submodule_env; cd \"$sm_path\" && git submodule--helper print-default-remote)\n    --\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n    --\t\t\t\tgit rev-parse --verify \"${remote_name}/${branch}\") ||\n    --\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n     -\t\tfi\n     -\n     -\t\tout=$(git submodule--helper run-update-procedure \\\n    @@ git-submodule.sh: cmd_update()\n     -\t\t\t  ${update:+--update \"$update\"} \\\n     -\t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n     -\t\t\t  ${sha1:+--oid \"$sha1\"} \\\n    --\t\t\t  ${subsha1:+--suboid \"$subsha1\"} \\\n    +-\t\t\t  ${remote:+--remote} \\\n     -\t\t\t  \"--\" \\\n     -\t\t\t  \"$sm_path\")\n     -\n\nbase-commit: b23dac905bde28da47543484320db16312c87551\n-- \n2.33.GIT\n\n"},{"id":"447948","messageId":"20220208083952.35036-2-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 01/16] submodule--helper: get remote names from any repository","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:37Z","receivedAt":"2022-02-08T08:40:04Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\n`get_default_remote()` retrieves the name of a remote by resolving the\nrefs from of the current repository's ref store.\n\nThus in order to use it for retrieving the remote name of a submodule,\nwe have to start a new subprocess which runs from the submodule\ndirectory.\n\nLet's instead introduce a function called `repo_get_default_remote()`\nwhich takes any repository object and retrieves the remote accordingly.\n\n`get_default_remote()` is then defined as a call to\n`repo_get_default_remote()` with 'the_repository' passed to it.\n\nNow that we have `repo_get_default_remote()`, we no longer have to start\na subprocess that called `submodule--helper get-default-remote` from\nwithin the submodule directory.\n\nSo let's make a function called `get_default_remote_submodule()` which\ntakes a submodule path, and returns the default remote for that\nsubmodule, all within the same process.\n\nWe can now use this function to save an unnecessary subprocess spawn in\n`sync_submodule()`, and also in the next patch, which will require this\nfunctionality.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nHelped-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 39 +++++++++++++++++++++++--------------\n 1 file changed, 24 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c5d3fc3817..4c7c1e1432 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -29,11 +29,14 @@\n typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n \t\t\t\t  void *cb_data);\n \n-static char *get_default_remote(void)\n+static char *repo_get_default_remote(struct repository *repo)\n {\n \tchar *dest = NULL, *ret;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n+\tstruct ref_store *store = get_main_ref_store(repo);\n+\tint ignore_errno;\n+\tconst char *refname = refs_resolve_ref_unsafe(store, \"HEAD\", 0, NULL,\n+\t\t\t\t\t\t      NULL, &ignore_errno);\n \n \tif (!refname)\n \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n@@ -46,7 +49,7 @@ static char *get_default_remote(void)\n \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n \n \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n-\tif (git_config_get_string(sb.buf, &dest))\n+\tif (repo_config_get_string(repo, sb.buf, &dest))\n \t\tret = xstrdup(\"origin\");\n \telse\n \t\tret = dest;\n@@ -55,6 +58,19 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static char *get_default_remote_submodule(const char *module_path)\n+{\n+\tstruct repository subrepo;\n+\n+\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n+\treturn repo_get_default_remote(&subrepo);\n+}\n+\n+static char *get_default_remote(void)\n+{\n+\treturn repo_get_default_remote(the_repository);\n+}\n+\n static int print_default_remote(int argc, const char **argv, const char *prefix)\n {\n \tchar *remote;\n@@ -1341,9 +1357,8 @@ static void sync_submodule(const char *path, const char *prefix,\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n-\tchar *sub_origin_url, *super_config_url, *displaypath;\n+\tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *sub_config_path = NULL;\n \n \tif (!is_submodule_active(the_repository, path))\n@@ -1382,21 +1397,15 @@ static void sync_submodule(const char *path, const char *prefix,\n \tif (!is_submodule_populated_gently(path, NULL))\n \t\tgoto cleanup;\n \n-\tprepare_submodule_repo_env(&cp.env_array);\n-\tcp.git_cmd = 1;\n-\tcp.dir = path;\n-\tstrvec_pushl(&cp.args, \"submodule--helper\",\n-\t\t     \"print-default-remote\", NULL);\n-\n \tstrbuf_reset(&sb);\n-\tif (capture_command(&cp, &sb, 0))\n+\tdefault_remote = get_default_remote_submodule(path);\n+\tif (!default_remote)\n \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n \t\t      path);\n \n-\tstrbuf_strip_suffix(&sb, \"\\n\");\n-\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n+\tremote_key = xstrfmt(\"remote.%s.url\", default_remote);\n+\tfree(default_remote);\n \n-\tstrbuf_reset(&sb);\n \tsubmodule_to_gitdir(&sb, path);\n \tstrbuf_addstr(&sb, \"/config\");\n \n-- \n2.33.GIT\n\n"},{"id":"447949","messageId":"20220208083952.35036-3-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 02/16] submodule--helper: refactor get_submodule_displaypath()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:38Z","receivedAt":"2022-02-08T08:40:14Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe create a function called `do_get_submodule_displaypath()` that\ngenerates the display path required by several submodule functions, and\ntakes a custom superprefix parameter, instead of reading it from the\nenvironment.\n\nWe then redefine the existing `get_submodule_displaypath()` function\nas a call to this new function, where the superprefix is obtained from\nthe environment.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4c7c1e1432..5efceb9d46 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -261,11 +261,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\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 *do_get_submodule_displaypath(const char *path, const char *prefix, 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@@ -281,6 +278,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \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+\treturn do_get_submodule_displaypath(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-- \n2.33.GIT\n\n"},{"id":"447950","messageId":"20220208083952.35036-5-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 04/16] submodule--helper: run update using child process struct","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:40Z","receivedAt":"2022-02-08T08:40:21Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe switch to using the run-command API function that takes a\n'struct child process', since we are using a lot of the options. This\nwill also make it simple to switch over to using 'capture_command()'\nwhen we start handling the output of the command completely in C.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 34 ++++++++++++++++------------------\n 1 file changed, 16 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 09cda67c1e..db71e6f4ec 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2344,47 +2344,45 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \n static int run_update_command(struct update_data *ud, int subforce)\n {\n-\tstruct strvec args = STRVEC_INIT;\n-\tstruct strvec child_env = STRVEC_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n \tint must_die_on_failure = 0;\n-\tint git_cmd;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_pushl(&args, \"checkout\", \"-q\", NULL);\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n \t\tif (subforce)\n-\t\t\tstrvec_push(&args, \"-f\");\n+\t\t\tstrvec_push(&cp.args, \"-f\");\n \t\tbreak;\n \tcase SM_UPDATE_REBASE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"rebase\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_MERGE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"merge\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n-\t\tgit_cmd = 0;\n-\t\tstrvec_push(&args, ud->update_strategy.command);\n+\t\tcp.use_shell = 1;\n+\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n \t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t}\n-\tstrvec_push(&args, oid);\n+\tstrvec_push(&cp.args, oid);\n \n-\tprepare_submodule_repo_env(&child_env);\n-\tif (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,\n-\t\t\t\t     ud->sm_path, child_env.v)) {\n+\tcp.dir = xstrdup(ud->sm_path);\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tif (run_command(&cp)) {\n \t\tswitch (ud->update_strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n \t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-- \n2.33.GIT\n\n"},{"id":"447951","messageId":"20220208083952.35036-4-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 03/16] submodule--helper: allow setting superprefix for init_submodule()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:39Z","receivedAt":"2022-02-08T08:40:23Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe allow callers of the `init_submodule()` function to optionally\noverride the superprefix from the environment.\n\nWe need to enable this option because in our conversion of the update\ncommand that will follow, the '--init' option will be handled through\nthis API. We will need to change the superprefix at that time to ensure\nthe display paths show correctly in the output messages.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5efceb9d46..09cda67c1e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -606,18 +606,22 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *superprefix;\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   unsigned int flags)\n+\t\t\t   const char *superprefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\t/* try superprefix from the environment, if it is not passed explicitly */\n+\tif (!superprefix)\n+\t\tsuperprefix = get_super_prefix();\n+\tdisplaypath = do_get_submodule_displaypath(path, prefix, superprefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -691,7 +695,7 @@ static void init_submodule(const char *path, const char *prefix,\n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct init_cb *info = cb_data;\n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n-- \n2.33.GIT\n\n"},{"id":"447952","messageId":"20220208083952.35036-6-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 05/16] builtin/submodule--helper.c: reformat designated initializers","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:41Z","receivedAt":"2022-02-08T08:40:23Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nThe second hunk here will make a subsequent commit's diff smaller, and\nlet's do the first and third hunks while we're at it so that we\nconsistently format all of these.\n\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 13 ++++++++++---\n 1 file changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex db71e6f4ec..9f79bdf4d5 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1654,7 +1654,10 @@ struct module_clone_data {\n \tunsigned int require_init: 1;\n \tint single_branch;\n };\n-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }\n+#define MODULE_CLONE_DATA_INIT { \\\n+\t.reference = STRING_LIST_INIT_NODUP, \\\n+\t.single_branch = -1, \\\n+}\n \n struct submodule_alternate_setup {\n \tconst char *submodule_name;\n@@ -2047,7 +2050,9 @@ struct update_data {\n \tunsigned int nofetch: 1;\n \tunsigned int just_cloned: 1;\n };\n-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }\n+#define UPDATE_DATA_INIT { \\\n+\t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+}\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n \t\tstruct strbuf *out, const char *displaypath)\n@@ -3013,7 +3018,9 @@ struct add_data {\n \tunsigned int progress: 1;\n \tunsigned int dissociate: 1;\n };\n-#define ADD_DATA_INIT { .depth = -1 }\n+#define ADD_DATA_INIT { \\\n+\t.depth = -1, \\\n+}\n \n static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)\n {\n-- \n2.33.GIT\n\n"},{"id":"447953","messageId":"20220208083952.35036-8-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 07/16] submodule--helper: don't use bitfield indirection for parse_options()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:43Z","receivedAt":"2022-02-08T08:40:25Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nDo away with the indirection of local variables added in\nc51f8f94e5b (submodule--helper: run update procedures from C,\n2021-08-24).\n\nThese were only needed because in C you can't get a pointer to a\nsingle bit, so we were using intermediate variables instead.\n\nThis will also make a subsequent large commit's diff smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 23 ++++++++++-------------\n 1 file changed, 10 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c2d4fd0347..4a0890954e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2045,10 +2045,10 @@ struct update_data {\n \tstruct object_id suboid;\n \tstruct submodule_update_strategy update_strategy;\n \tint depth;\n-\tunsigned int force: 1;\n-\tunsigned int quiet: 1;\n-\tunsigned int nofetch: 1;\n-\tunsigned int just_cloned: 1;\n+\tunsigned int force;\n+\tunsigned int quiet;\n+\tunsigned int nofetch;\n+\tunsigned int just_cloned;\n };\n #define UPDATE_DATA_INIT { \\\n \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n@@ -2578,16 +2578,17 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n-\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n \tchar *prefixed_path, *update = NULL;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \n \tstruct option options[] = {\n-\t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n+\t\tOPT__QUIET(&opt.quiet,\n+\t\t\t   N_(\"suppress output for update by rebase or merge\")),\n+\t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"),\n+\t\t\t   0),\n+\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n \t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n+\t\tOPT_BOOL(0, \"just-cloned\", &opt.just_cloned,\n \t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n \t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n@@ -2618,10 +2619,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tif (argc != 1)\n \t\tusage_with_options(usage, options);\n \n-\topt.force = !!force;\n-\topt.quiet = !!quiet;\n-\topt.nofetch = !!nofetch;\n-\topt.just_cloned = !!just_cloned;\n \topt.sm_path = argv[0];\n \n \tif (opt.recursive_prefix)\n-- \n2.33.GIT\n\n"},{"id":"447954","messageId":"20220208083952.35036-9-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 08/16] submodule tests: test for init and update failure output","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:44Z","receivedAt":"2022-02-08T08:40:27Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nAmend some submodule tests to test for the failure output of \"git\nsubmodule [update|init]\". The lack of such tests hid a regression in\nan earlier version of a subsequent commit.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7406-submodule-update.sh    | 14 ++++++++++++--\n t/t7408-submodule-reference.sh | 14 +++++++++++++-\n 2 files changed, 25 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh\nindex 11cccbb333..7764c1c3cb 100755\n--- a/t/t7406-submodule-update.sh\n+++ b/t/t7406-submodule-update.sh\n@@ -205,8 +205,18 @@ test_expect_success 'submodule update should fail due to local changes' '\n \t (cd submodule &&\n \t  compare_head\n \t ) &&\n-\t test_must_fail git submodule update submodule\n-\t)\n+\t test_must_fail git submodule update submodule 2>../actual.raw\n+\t) &&\n+\tsed \"s/^> //\" >expect <<-\\EOF &&\n+\t> error: Your local changes to the following files would be overwritten by checkout:\n+\t> \tfile\n+\t> Please commit your changes or stash them before you switch branches.\n+\t> Aborting\n+\t> fatal: Unable to checkout OID in submodule path '\\''submodule'\\''\n+\tEOF\n+\tsed -e \"s/checkout $SQ[^$SQ]*$SQ/checkout OID/\" <actual.raw >actual &&\n+\ttest_cmp expect actual\n+\n '\n test_expect_success 'submodule update should throw away changes with --force ' '\n \t(cd super &&\ndiff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh\nindex a3892f494b..c3a4545510 100755\n--- a/t/t7408-submodule-reference.sh\n+++ b/t/t7408-submodule-reference.sh\n@@ -193,7 +193,19 @@ test_expect_success 'missing nested submodule alternate fails clone and submodul\n \t\tcd supersuper-clone &&\n \t\tcheck_that_two_of_three_alternates_are_used &&\n \t\t# update of the submodule fails\n-\t\ttest_must_fail git submodule update --init --recursive\n+\t\tcat >expect <<-\\EOF &&\n+\t\tfatal: submodule '\\''sub'\\'' cannot add alternate: path ... does not exist\n+\t\tFailed to clone '\\''sub'\\''. Retry scheduled\n+\t\tfatal: submodule '\\''sub-dissociate'\\'' cannot add alternate: path ... does not exist\n+\t\tFailed to clone '\\''sub-dissociate'\\''. Retry scheduled\n+\t\tfatal: submodule '\\''sub'\\'' cannot add alternate: path ... does not exist\n+\t\tFailed to clone '\\''sub'\\'' a second time, aborting\n+\t\tfatal: Failed to recurse into submodule path ...\n+\t\tEOF\n+\t\ttest_must_fail git submodule update --init --recursive 2>err &&\n+\t\tgrep -e fatal: -e ^Failed err >actual.raw &&\n+\t\tsed -e \"s/path $SQ[^$SQ]*$SQ/path .../\" <actual.raw >actual &&\n+\t\ttest_cmp expect actual\n \t)\n '\n \n-- \n2.33.GIT\n\n"},{"id":"447955","messageId":"20220208083952.35036-10-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 09/16] submodule--helper: remove update-module-mode","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:45Z","receivedAt":"2022-02-08T08:40:30Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"This is dead code - it has not been used since c51f8f94e5\n(submodule--helper: run update procedures from C, 2021-08-24).\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 24 ------------------------\n 1 file changed, 24 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4a0890954e..e0cc1c1b79 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1965,29 +1965,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n \tfree(key);\n }\n \n-static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path, *update = NULL;\n-\tint just_cloned;\n-\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n-\n-\tif (argc < 3 || argc > 4)\n-\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n-\n-\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n-\tpath = argv[2];\n-\n-\tif (argc == 4)\n-\t\tupdate = argv[3];\n-\n-\tdetermine_submodule_update_strategy(the_repository,\n-\t\t\t\t\t    just_cloned, path, update,\n-\t\t\t\t\t    &update_strategy);\n-\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n-\n-\treturn 0;\n-}\n-\n struct update_clone_data {\n \tconst struct submodule *sub;\n \tstruct object_id oid;\n@@ -3388,7 +3365,6 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n-\t{\"update-module-mode\", module_update_module_mode, 0},\n \t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n \t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n-- \n2.33.GIT\n\n"},{"id":"447956","messageId":"20220208083952.35036-7-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 06/16] builtin/submodule--helper.c: rename option variables to \"opt\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:42Z","receivedAt":"2022-02-08T08:40:33Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nRename the \"suc\" variable in update_clone() to \"opt\", and do the same\nfor the \"update_data\" variable in run_update_procedure().\n\nThe only reason for this change is to make the subsequent commit's\ndiff smaller, by doing this rename we can \"anchor\" the diff better, as\nit \"borrow\" most of the options declared here as-is as far as the diff\nrename detection is concerned.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 74 ++++++++++++++++++-------------------\n 1 file changed, 37 insertions(+), 37 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9f79bdf4d5..c2d4fd0347 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2517,36 +2517,36 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n {\n \tconst char *update = NULL;\n \tstruct pathspec pathspec;\n-\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n \n \tstruct option module_update_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &suc.recursive_prefix,\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree, across nested \"\n \t\t\t      \"submodule boundaries\")),\n \t\tOPT_STRING(0, \"update\", &update,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &suc.references, N_(\"repo\"),\n+\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n \t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &suc.dissociate,\n+\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n \t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &suc.depth, \"<depth>\",\n+\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n \t\t\t   N_(\"create a shallow clone truncated to the \"\n \t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &suc.max_jobs,\n+\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n \t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &suc.recommend_shallow,\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n \t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&suc.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &suc.progress,\n+\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n \t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &suc.require_init,\n+\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n \t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &suc.single_branch,\n+\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n \t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n \t\tOPT_END()\n \t};\n@@ -2555,32 +2555,32 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n \t\tNULL\n \t};\n-\tsuc.prefix = prefix;\n+\topt.prefix = prefix;\n \n-\tupdate_clone_config_from_gitmodules(&suc.max_jobs);\n-\tgit_config(git_update_clone_config, &suc.max_jobs);\n+\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n+\tgit_config(git_update_clone_config, &opt.max_jobs);\n \n \targc = parse_options(argc, argv, prefix, module_update_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n \tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &suc.update) < 0)\n+\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n \t\t\tdie(_(\"bad value for update parameter\"));\n \n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n \t\treturn 1;\n \n \tif (pathspec.nr)\n-\t\tsuc.warn_if_uninitialized = 1;\n+\t\topt.warn_if_uninitialized = 1;\n \n-\treturn update_submodules(&suc);\n+\treturn update_submodules(&opt);\n }\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n \tchar *prefixed_path, *update = NULL;\n-\tstruct update_data update_data = UPDATE_DATA_INIT;\n+\tstruct update_data opt = UPDATE_DATA_INIT;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n@@ -2589,20 +2589,20 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"don't fetch new objects from the remote site\")),\n \t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n \t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n+\t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n \t\tOPT_STRING(0, \"update\", &update,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n \t\t\t   N_(\"path into the working tree, across nested \"\n \t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n+\t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n \t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n+\t\tOPT_CALLBACK_F(0, \"suboid\", &opt.suboid, N_(\"subsha1\"),\n \t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n \t\tOPT_END()\n@@ -2618,27 +2618,27 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tif (argc != 1)\n \t\tusage_with_options(usage, options);\n \n-\tupdate_data.force = !!force;\n-\tupdate_data.quiet = !!quiet;\n-\tupdate_data.nofetch = !!nofetch;\n-\tupdate_data.just_cloned = !!just_cloned;\n-\tupdate_data.sm_path = argv[0];\n+\topt.force = !!force;\n+\topt.quiet = !!quiet;\n+\topt.nofetch = !!nofetch;\n+\topt.just_cloned = !!just_cloned;\n+\topt.sm_path = argv[0];\n \n-\tif (update_data.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n+\tif (opt.recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", opt.recursive_prefix, opt.sm_path);\n \telse\n-\t\tprefixed_path = xstrdup(update_data.sm_path);\n+\t\tprefixed_path = xstrdup(opt.sm_path);\n \n-\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n+\topt.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n \n-\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n-\t\t\t\t\t    update_data.sm_path, update,\n-\t\t\t\t\t    &update_data.update_strategy);\n+\tdetermine_submodule_update_strategy(the_repository, opt.just_cloned,\n+\t\t\t\t\t    opt.sm_path, update,\n+\t\t\t\t\t    &opt.update_strategy);\n \n \tfree(prefixed_path);\n \n-\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data);\n+\tif (!oideq(&opt.oid, &opt.suboid) || opt.force)\n+\t\treturn do_run_update_procedure(&opt);\n \n \treturn 3;\n }\n-- \n2.33.GIT\n\n"},{"id":"447957","messageId":"20220208083952.35036-11-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 10/16] submodule--helper: reorganize code for sh to C conversion","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:46Z","receivedAt":"2022-02-08T08:40:35Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Introduce a function, update_submodule2(), that performs an update for\none submodule. This function will implement the functionality of\nrun-update-procedure and its surrounding shell code in submodule.sh.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 20 +++++++++++++++-----\n 1 file changed, 15 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e0cc1c1b79..0b5120734a 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2553,6 +2553,11 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \treturn update_submodules(&opt);\n }\n \n+/*\n+ * NEEDSWORK: Use a forward declaration to avoid moving\n+ * run_update_procedure() (which will be removed soon).\n+ */\n+static int update_submodule2(struct update_data *update_data);\n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n \tchar *prefixed_path, *update = NULL;\n@@ -2610,11 +2615,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\t\t\t\t    &opt.update_strategy);\n \n \tfree(prefixed_path);\n-\n-\tif (!oideq(&opt.oid, &opt.suboid) || opt.force)\n-\t\treturn do_run_update_procedure(&opt);\n-\n-\treturn 3;\n+\treturn update_submodule2(&opt);\n }\n \n static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n@@ -2978,6 +2979,15 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \treturn !!ret;\n }\n \n+/* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n+static int update_submodule2(struct update_data *update_data)\n+{\n+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n+\t\treturn do_run_update_procedure(update_data);\n+\n+\treturn 3;\n+}\n+\n struct add_data {\n \tconst char *prefix;\n \tconst char *branch;\n-- \n2.33.GIT\n\n"},{"id":"447958","messageId":"20220208083952.35036-13-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 12/16] submodule--helper run-update-procedure: learn --remote","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:48Z","receivedAt":"2022-02-08T08:40:39Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Teach run-update-procedure to handle --remote instead of parsing\n--remote in git-submodule.sh. As a result, \"git submodule--helper\nprint-default-remote\" has no more callers, so remove it.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 39 ++++++++++++++++++++++---------------\n git-submodule.sh            | 30 +---------------------------\n 2 files changed, 24 insertions(+), 45 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a26477ce04..15ae986692 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -71,21 +71,6 @@ static char *get_default_remote(void)\n \treturn repo_get_default_remote(the_repository);\n }\n \n-static int print_default_remote(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remote;\n-\n-\tif (argc != 1)\n-\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n-\n-\tremote = get_default_remote();\n-\tif (remote)\n-\t\tprintf(\"%s\\n\", remote);\n-\n-\tfree(remote);\n-\treturn 0;\n-}\n-\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -2026,6 +2011,7 @@ struct update_data {\n \tunsigned int quiet;\n \tunsigned int nofetch;\n \tunsigned int just_cloned;\n+\tunsigned int remote;\n };\n #define UPDATE_DATA_INIT { \\\n \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n@@ -2585,6 +2571,8 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n \t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n+\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n+\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n \t\tOPT_END()\n \t};\n \n@@ -2988,6 +2976,25 @@ static int update_submodule2(struct update_data *update_data)\n \t\t\t    update_data->displaypath);\n \t}\n \n+\tif (update_data->remote) {\n+\t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n+\t\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n+\t\tchar *remote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n+\n+\t\tif (!update_data->nofetch) {\n+\t\t\tif (fetch_in_submodule(update_data->sm_path, update_data->depth,\n+\t\t\t\t\t      0, NULL))\n+\t\t\t\tdie(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\t\t    update_data->sm_path);\n+\t\t}\n+\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))\n+\t\t\tdie(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t    remote_ref, update_data->sm_path);\n+\n+\t\tfree(remote_ref);\n+\t}\n+\n \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n \t\treturn do_run_update_procedure(update_data);\n \n@@ -3389,10 +3396,10 @@ static struct cmd_struct commands[] = {\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n-\t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, 0},\n \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n+\t/* NEEDSWORK: remote-branch is also obsolete */\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex d48c314f01..29fd69250d 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -246,20 +246,6 @@ cmd_deinit()\n \tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- \"$@\"\n }\n \n-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]\n-# Because arguments are positional, use an empty string to omit <depth>\n-# but include <sha1>.\n-fetch_in_submodule () (\n-\tsanitize_submodule_env &&\n-\tcd \"$1\" &&\n-\tif test $# -eq 3\n-\tthen\n-\t\techo \"$3\" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+\"$2\"}\n-\telse\n-\t\tgit fetch ${GIT_QUIET:+--quiet} ${2:+\"$2\"}\n-\tfi\n-)\n-\n #\n # Update each submodule path to correct revision, using clone and checkout as needed\n #\n@@ -396,21 +382,6 @@ cmd_update()\n \t\t\tjust_cloned=\n \t\tfi\n \n-\t\tif test -n \"$remote\"\n-\t\tthen\n-\t\t\tbranch=$(git submodule--helper remote-branch \"$sm_path\")\n-\t\t\tif test -z \"$nofetch\"\n-\t\t\tthen\n-\t\t\t\t# Fetch remote before determining tracking $sha1\n-\t\t\t\tfetch_in_submodule \"$sm_path\" $depth ||\n-\t\t\t\tdie \"fatal: $(eval_gettext \"Unable to fetch in submodule path '\\$sm_path'\")\"\n-\t\t\tfi\n-\t\t\tremote_name=$(sanitize_submodule_env; cd \"$sm_path\" && git submodule--helper print-default-remote)\n-\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify \"${remote_name}/${branch}\") ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\n \t\tout=$(git submodule--helper run-update-procedure \\\n \t\t\t  ${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t\t  ${GIT_QUIET:+--quiet} \\\n@@ -421,6 +392,7 @@ cmd_update()\n \t\t\t  ${update:+--update \"$update\"} \\\n \t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t\t  ${sha1:+--oid \"$sha1\"} \\\n+\t\t\t  ${remote:+--remote} \\\n \t\t\t  \"--\" \\\n \t\t\t  \"$sm_path\")\n \n-- \n2.33.GIT\n\n"},{"id":"447959","messageId":"20220208083952.35036-14-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 13/16] submodule--helper: remove ensure-core-worktree","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:49Z","receivedAt":"2022-02-08T08:41:02Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Move the logic of \"git submodule--helper ensure-core-worktree\" into\nrun-update-procedure. Since the ensure-core-worktree command is\nobsolete, remove it.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 13 +++----------\n git-submodule.sh            |  2 --\n 2 files changed, 3 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 15ae986692..a05aea5cd6 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2746,17 +2746,11 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+static void ensure_core_worktree(const char *path)\n {\n-\tconst char *path;\n \tconst char *cw;\n \tstruct repository subrepo;\n \n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\n \tif (repo_submodule_init(&subrepo, the_repository, path, null_oid()))\n \t\tdie(_(\"could not get a repository handle for submodule '%s'\"), path);\n \n@@ -2776,8 +2770,6 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n-\n-\treturn 0;\n }\n \n static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n@@ -2967,6 +2959,8 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n /* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n static int update_submodule2(struct update_data *update_data)\n {\n+\tensure_core_worktree(update_data->sm_path);\n+\n \t/* NEEDSWORK: fix the style issues e.g. braces */\n \tif (update_data->just_cloned) {\n \t\toidcpy(&update_data->suboid, null_oid());\n@@ -3390,7 +3384,6 @@ static struct cmd_struct commands[] = {\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n \t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 29fd69250d..aa9c898e1c 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -373,8 +373,6 @@ cmd_update()\n \tdo\n \t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n \n-\t\tgit submodule--helper ensure-core-worktree \"$sm_path\" || exit 1\n-\n \t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n \n \t\tif test $just_cloned -eq 0\n-- \n2.33.GIT\n\n"},{"id":"447960","messageId":"20220208083952.35036-12-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 11/16] submodule--helper run-update-procedure: remove --suboid","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:47Z","receivedAt":"2022-02-08T08:41:02Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Teach run-update-procedure to determine the oid of the submodule's HEAD\ninstead of doing it in git-subomdule.sh.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 12 +++++++++---\n git-submodule.sh            |  8 +-------\n 2 files changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 0b5120734a..a26477ce04 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2585,9 +2585,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n \t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &opt.suboid, N_(\"subsha1\"),\n-\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n \t\tOPT_END()\n \t};\n \n@@ -2982,6 +2979,15 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n /* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n static int update_submodule2(struct update_data *update_data)\n {\n+\t/* NEEDSWORK: fix the style issues e.g. braces */\n+\tif (update_data->just_cloned) {\n+\t\toidcpy(&update_data->suboid, null_oid());\n+\t} else {\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n+\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t}\n+\n \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n \t\treturn do_run_update_procedure(update_data);\n \ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 652861aa66..d48c314f01 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -391,14 +391,9 @@ cmd_update()\n \n \t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n \n-\t\tif test $just_cloned -eq 1\n+\t\tif test $just_cloned -eq 0\n \t\tthen\n-\t\t\tsubsha1=\n-\t\telse\n \t\t\tjust_cloned=\n-\t\t\tsubsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify HEAD) ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current revision in submodule path '\\$displaypath'\")\"\n \t\tfi\n \n \t\tif test -n \"$remote\"\n@@ -426,7 +421,6 @@ cmd_update()\n \t\t\t  ${update:+--update \"$update\"} \\\n \t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t\t  ${sha1:+--oid \"$sha1\"} \\\n-\t\t\t  ${subsha1:+--suboid \"$subsha1\"} \\\n \t\t\t  \"--\" \\\n \t\t\t  \"$sm_path\")\n \n-- \n2.33.GIT\n\n"},{"id":"447961","messageId":"20220208083952.35036-15-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 14/16] submodule--helper update-clone: learn --init","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:50Z","receivedAt":"2022-02-08T08:41:07Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Teach \"git submodule--helper update-clone\" the --init flag and remove\nthe corresponding shell code.\n\nWhen the `--init` flag is passed to the subcommand, we do not spawn a\nnew subprocess and call `submodule--helper init` on the submodule paths,\nbecause the Git machinery is not able to pick up the configuration\nchanges introduced by that init call. So we instead run the\n`init_submodule_cb()` callback over each submodule in the same process.\n\n[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 26 ++++++++++++++++++++++++++\n git-submodule.sh            |  9 +++------\n 2 files changed, 29 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a05aea5cd6..5635f0c48b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1989,6 +1989,7 @@ struct submodule_update_clone {\n \tint failed_clones_nr, failed_clones_alloc;\n \n \tint max_jobs;\n+\tunsigned int init;\n };\n #define SUBMODULE_UPDATE_CLONE_INIT { \\\n \t.list = MODULE_LIST_INIT, \\\n@@ -2483,6 +2484,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n \n \tstruct option module_update_clone_options[] = {\n+\t\tOPT_BOOL(0, \"init\", &opt.init,\n+\t\t\t N_(\"initialize uninitialized submodules before update\")),\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n@@ -2536,6 +2539,29 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \tif (pathspec.nr)\n \t\topt.warn_if_uninitialized = 1;\n \n+\tif (opt.init) {\n+\t\tstruct module_list list = MODULE_LIST_INIT;\n+\t\tstruct init_cb info = INIT_CB_INIT;\n+\n+\t\tif (module_list_compute(argc, argv, opt.prefix,\n+\t\t\t\t\t&pathspec, &list) < 0)\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * If there are no path args and submodule.active is set then,\n+\t\t * by default, only initialize 'active' modules.\n+\t\t */\n+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n+\t\t\tmodule_list_active(&list);\n+\n+\t\tinfo.prefix = opt.prefix;\n+\t\tinfo.superprefix = opt.recursive_prefix;\n+\t\tif (opt.quiet)\n+\t\t\tinfo.flags |= OPT_QUIET;\n+\n+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n+\t}\n+\n \treturn update_submodules(&opt);\n }\n \ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex aa9c898e1c..3ccf2388bf 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -347,14 +347,11 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\tif test -n \"$init\"\n-\tthen\n-\t\tcmd_init \"--\" \"$@\" || return\n-\tfi\n-\n \t{\n-\tgit submodule--helper update-clone ${GIT_QUIET:+--quiet} \\\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper update-clone \\\n+\t\t${GIT_QUIET:+--quiet} \\\n \t\t${progress:+\"--progress\"} \\\n+\t\t${init:+--init} \\\n \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t${update:+--update \"$update\"} \\\n-- \n2.33.GIT\n\n"},{"id":"447962","messageId":"20220208083952.35036-16-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 15/16] submodule--helper: move functions around","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:51Z","receivedAt":"2022-02-08T08:41:09Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"The next commit will change the internals of several functions and\narrange them in a more logical manner. Move these functions to their\nfinal positions so that the diff is smaller.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 228 ++++++++++++++++++------------------\n 1 file changed, 114 insertions(+), 114 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5635f0c48b..0ab8f9d49f 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2451,120 +2451,6 @@ static void update_submodule(struct update_clone_data *ucd)\n \t\tucd->sub->path);\n }\n \n-static int update_submodules(struct submodule_update_clone *suc)\n-{\n-\tint i;\n-\n-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n-\t\t\t\t   update_clone_start_failure,\n-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n-\t\t\t\t   \"parallel/update\");\n-\n-\t/*\n-\t * We saved the output and put it out all at once now.\n-\t * That means:\n-\t * - the listener does not have to interleave their (checkout)\n-\t *   work with our fetching.  The writes involved in a\n-\t *   checkout involve more straightforward sequential I/O.\n-\t * - the listener can avoid doing any work if fetching failed.\n-\t */\n-\tif (suc->quickstop)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_submodule(&suc->update_clone[i]);\n-\n-\treturn 0;\n-}\n-\n-static int update_clone(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *update = NULL;\n-\tstruct pathspec pathspec;\n-\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n-\n-\tstruct option module_update_clone_options[] = {\n-\t\tOPT_BOOL(0, \"init\", &opt.init,\n-\t\t\t N_(\"initialize uninitialized submodules before update\")),\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n-\t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n-\t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n-\t\t\t   N_(\"create a shallow clone truncated to the \"\n-\t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n-\t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n-\t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n-\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\topt.prefix = prefix;\n-\n-\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n-\tgit_config(git_update_clone_config, &opt.max_jobs);\n-\n-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n-\t\t\tdie(_(\"bad value for update parameter\"));\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n-\t\treturn 1;\n-\n-\tif (pathspec.nr)\n-\t\topt.warn_if_uninitialized = 1;\n-\n-\tif (opt.init) {\n-\t\tstruct module_list list = MODULE_LIST_INIT;\n-\t\tstruct init_cb info = INIT_CB_INIT;\n-\n-\t\tif (module_list_compute(argc, argv, opt.prefix,\n-\t\t\t\t\t&pathspec, &list) < 0)\n-\t\t\treturn 1;\n-\n-\t\t/*\n-\t\t * If there are no path args and submodule.active is set then,\n-\t\t * by default, only initialize 'active' modules.\n-\t\t */\n-\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n-\t\t\tmodule_list_active(&list);\n-\n-\t\tinfo.prefix = opt.prefix;\n-\t\tinfo.superprefix = opt.recursive_prefix;\n-\t\tif (opt.quiet)\n-\t\t\tinfo.flags |= OPT_QUIET;\n-\n-\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n-\t}\n-\n-\treturn update_submodules(&opt);\n-}\n-\n /*\n  * NEEDSWORK: Use a forward declaration to avoid moving\n  * run_update_procedure() (which will be removed soon).\n@@ -3021,6 +2907,120 @@ static int update_submodule2(struct update_data *update_data)\n \treturn 3;\n }\n \n+static int update_submodules(struct submodule_update_clone *suc)\n+{\n+\tint i;\n+\n+\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n+\t\t\t\t   update_clone_start_failure,\n+\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n+\t\t\t\t   \"parallel/update\");\n+\n+\t/*\n+\t * We saved the output and put it out all at once now.\n+\t * That means:\n+\t * - the listener does not have to interleave their (checkout)\n+\t *   work with our fetching.  The writes involved in a\n+\t *   checkout involve more straightforward sequential I/O.\n+\t * - the listener can avoid doing any work if fetching failed.\n+\t */\n+\tif (suc->quickstop)\n+\t\treturn 1;\n+\n+\tfor (i = 0; i < suc->update_clone_nr; i++)\n+\t\tupdate_submodule(&suc->update_clone[i]);\n+\n+\treturn 0;\n+}\n+\n+static int update_clone(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *update = NULL;\n+\tstruct pathspec pathspec;\n+\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n+\n+\tstruct option module_update_clone_options[] = {\n+\t\tOPT_BOOL(0, \"init\", &opt.init,\n+\t\t\t N_(\"initialize uninitialized submodules before update\")),\n+\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree\")),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree, across nested \"\n+\t\t\t      \"submodule boundaries\")),\n+\t\tOPT_STRING(0, \"update\", &update,\n+\t\t\t   N_(\"string\"),\n+\t\t\t   N_(\"rebase, merge, checkout or none\")),\n+\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n+\t\t\t   N_(\"reference repository\")),\n+\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n+\t\t\t   N_(\"use --reference only while cloning\")),\n+\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n+\t\t\t   N_(\"create a shallow clone truncated to the \"\n+\t\t\t      \"specified number of revisions\")),\n+\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n+\t\t\t    N_(\"parallel jobs\")),\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n+\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n+\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n+\t\t\t    N_(\"force cloning progress\")),\n+\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n+\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n+\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n+\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n+\t\tNULL\n+\t};\n+\topt.prefix = prefix;\n+\n+\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n+\tgit_config(git_update_clone_config, &opt.max_jobs);\n+\n+\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (update)\n+\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n+\t\t\tdie(_(\"bad value for update parameter\"));\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n+\t\treturn 1;\n+\n+\tif (pathspec.nr)\n+\t\topt.warn_if_uninitialized = 1;\n+\n+\tif (opt.init) {\n+\t\tstruct module_list list = MODULE_LIST_INIT;\n+\t\tstruct init_cb info = INIT_CB_INIT;\n+\n+\t\tif (module_list_compute(argc, argv, opt.prefix,\n+\t\t\t\t\t&pathspec, &list) < 0)\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * If there are no path args and submodule.active is set then,\n+\t\t * by default, only initialize 'active' modules.\n+\t\t */\n+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n+\t\t\tmodule_list_active(&list);\n+\n+\t\tinfo.prefix = opt.prefix;\n+\t\tinfo.superprefix = opt.recursive_prefix;\n+\t\tif (opt.quiet)\n+\t\t\tinfo.flags |= OPT_QUIET;\n+\n+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n+\t}\n+\n+\treturn update_submodules(&opt);\n+}\n+\n struct add_data {\n \tconst char *prefix;\n \tconst char *branch;\n-- \n2.33.GIT\n\n"},{"id":"447963","messageId":"20220208083952.35036-17-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v6 16/16] submodule: move core cmd_update() logic to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-08T08:39:52Z","receivedAt":"2022-02-08T08:41:11Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nThis patch completes the conversion past the flag parsing of\n`submodule update` by introducing a helper subcommand called\n`submodule--helper update`. The behaviour of `submodule update` should\nremain the same after this patch.\n\nWe add more fields to the `struct update_data` that are required by\n`struct submodule_update_clone` to be able to perform a clone, when that\nis needed to be done.\n\nRecursing on a submodule is done by calling a subprocess that launches\n`submodule--helper update`, with a modified `--recursive-prefix` and\n`--prefix` parameter.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 360 ++++++++++++++++++++++--------------\n git-submodule.sh            | 102 +---------\n 2 files changed, 227 insertions(+), 235 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 0ab8f9d49f..5085b28a2d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1977,7 +1977,6 @@ struct submodule_update_clone {\n \tconst char *prefix;\n \tint single_branch;\n \n-\t/* to be consumed by git-submodule.sh */\n \tstruct update_clone_data *update_clone;\n \tint update_clone_nr; int update_clone_alloc;\n \n@@ -1989,7 +1988,6 @@ struct submodule_update_clone {\n \tint failed_clones_nr, failed_clones_alloc;\n \n \tint max_jobs;\n-\tunsigned int init;\n };\n #define SUBMODULE_UPDATE_CLONE_INIT { \\\n \t.list = MODULE_LIST_INIT, \\\n@@ -2001,6 +1999,7 @@ struct submodule_update_clone {\n }\n \n struct update_data {\n+\tconst char *prefix;\n \tconst char *recursive_prefix;\n \tconst char *sm_path;\n \tconst char *displaypath;\n@@ -2008,14 +2007,54 @@ struct update_data {\n \tstruct object_id suboid;\n \tstruct submodule_update_strategy update_strategy;\n \tint depth;\n+\tint recommend_shallow;\n+\tint single_branch;\n+\tint max_jobs;\n+\tunsigned int init;\n \tunsigned int force;\n \tunsigned int quiet;\n \tunsigned int nofetch;\n \tunsigned int just_cloned;\n \tunsigned int remote;\n+\tunsigned int recursive;\n+\tunsigned int progress;\n+\tunsigned int dissociate;\n+\tunsigned int require_init;\n+\tunsigned warn_if_uninitialized ;\n+\tstruct string_list references;\n+\tstruct module_list list;\n };\n #define UPDATE_DATA_INIT { \\\n+\t.list = MODULE_LIST_INIT, \\\n \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+\t.recommend_shallow = -1, \\\n+\t.references = STRING_LIST_INIT_DUP, \\\n+\t.single_branch = -1, \\\n+\t.max_jobs = 1, \\\n+}\n+\n+static void update_clone_from_update_data(struct submodule_update_clone *suc,\n+\t\t\t\t\t  struct update_data *update_data)\n+{\n+\tsuc->prefix = update_data->prefix;\n+\tsuc->recursive_prefix = update_data->recursive_prefix;\n+\tsuc->max_jobs = update_data->max_jobs;\n+\tsuc->progress = update_data->progress;\n+\tsuc->quiet = update_data->quiet;\n+\tsuc->dissociate = update_data->dissociate;\n+\tsuc->require_init = update_data->require_init;\n+\tsuc->single_branch = update_data->single_branch;\n+\tsuc->warn_if_uninitialized = update_data->warn_if_uninitialized;\n+\tsuc->list = update_data->list;\n+\tsuc->update = update_data->update_strategy;\n+\tsuc->recommend_shallow = update_data->recommend_shallow;\n+\tif (update_data->depth)\n+\t\tsuc->depth = xstrfmt(\"--depth=%d\", update_data->depth);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstring_list_append(&suc->references, item->string);\n+\t}\n }\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n@@ -2316,8 +2355,15 @@ static int run_update_command(struct update_data *ud, int subforce)\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n \tint must_die_on_failure = 0;\n+\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n+\n+\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n+\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n+\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n+\telse\n+\t\tstrategy = ud->update_strategy;\n \n-\tswitch (ud->update_strategy.type) {\n+\tswitch (strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\tcp.git_cmd = 1;\n \t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n@@ -2340,55 +2386,54 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n \t\tcp.use_shell = 1;\n-\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n+\t\tstrvec_push(&cp.args, strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t    submodule_strategy_to_string(&strategy));\n \t}\n \tstrvec_push(&cp.args, oid);\n \n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env_array);\n \tif (run_command(&cp)) {\n-\t\tswitch (ud->update_strategy.type) {\n+\t\tswitch (strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n-\t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tdie_message(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n-\t\t\tprintf(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tif (!must_die_on_failure)\n+\t\t\t\tbreak;\n+\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_MERGE:\n-\t\t\tprintf(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tif (!must_die_on_failure)\n+\t\t\t\tbreak;\n+\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_COMMAND:\n-\t\t\tprintf(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n-\t\t\t       ud->update_strategy.command, oid, ud->displaypath);\n+\t\t\tif (!must_die_on_failure)\n+\t\t\t\tbreak;\n+\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\t    strategy.command, oid, ud->displaypath);\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t\t    submodule_strategy_to_string(&strategy));\n \t\t}\n-\t\t/*\n-\t\t * NEEDSWORK: We are currently printing to stdout with error\n-\t\t * return so that the shell caller handles the error output\n-\t\t * properly. Once we start handling the error messages within\n-\t\t * C, we should use die() instead.\n-\t\t */\n-\t\tif (must_die_on_failure)\n-\t\t\treturn 2;\n-\t\t/*\n-\t\t * This signifies to the caller in shell that the command\n-\t\t * failed without dying\n-\t\t */\n+\n+\t\t/* the command failed, but update must continue */\n \t\treturn 1;\n \t}\n \n-\tswitch (ud->update_strategy.type) {\n+\tif (ud->quiet)\n+\t\treturn 0;\n+\n+\tswitch (strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n \t\t       ud->displaypath, oid);\n@@ -2403,17 +2448,17 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n \t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n-\t\t       ud->displaypath, ud->update_strategy.command, oid);\n+\t\t       ud->displaypath, strategy.command, oid);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&ud->update_strategy));\n+\t\t    submodule_strategy_to_string(&strategy));\n \t}\n \n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud)\n+static int run_update_procedure(struct update_data *ud)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2443,89 +2488,6 @@ static int do_run_update_procedure(struct update_data *ud)\n \treturn run_update_command(ud, subforce);\n }\n \n-static void update_submodule(struct update_clone_data *ucd)\n-{\n-\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n-\t\toid_to_hex(&ucd->oid),\n-\t\tucd->just_cloned,\n-\t\tucd->sub->path);\n-}\n-\n-/*\n- * NEEDSWORK: Use a forward declaration to avoid moving\n- * run_update_procedure() (which will be removed soon).\n- */\n-static int update_submodule2(struct update_data *update_data);\n-static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *prefixed_path, *update = NULL;\n-\tstruct update_data opt = UPDATE_DATA_INIT;\n-\n-\tstruct option options[] = {\n-\t\tOPT__QUIET(&opt.quiet,\n-\t\t\t   N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"),\n-\t\t\t   0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n-\t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &opt.just_cloned,\n-\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n-\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n-\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const usage[] = {\n-\t\tN_(\"git submodule--helper run-update-procedure [<options>] <path>\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\n-\tif (argc != 1)\n-\t\tusage_with_options(usage, options);\n-\n-\topt.sm_path = argv[0];\n-\n-\tif (opt.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", opt.recursive_prefix, opt.sm_path);\n-\telse\n-\t\tprefixed_path = xstrdup(opt.sm_path);\n-\n-\topt.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n-\n-\tdetermine_submodule_update_strategy(the_repository, opt.just_cloned,\n-\t\t\t\t\t    opt.sm_path, update,\n-\t\t\t\t\t    &opt.update_strategy);\n-\n-\tfree(prefixed_path);\n-\treturn update_submodule2(&opt);\n-}\n-\n-static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 3)\n-\t\tdie(\"submodule--helper relative-path takes exactly 2 arguments, got %d\", argc);\n-\n-\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n-\tstrbuf_release(&sb);\n-\treturn 0;\n-}\n-\n static const char *remote_submodule_branch(const char *path)\n {\n \tconst struct submodule *sub;\n@@ -2868,11 +2830,66 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \treturn !!ret;\n }\n \n-/* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n-static int update_submodule2(struct update_data *update_data)\n+static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n+{\n+\tconst char *update = submodule_strategy_to_string(&update_data->update_strategy);\n+\n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n+\tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n+\tif (update_data->prefix)\n+\t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n+\tif (update_data->recursive_prefix)\n+\t\tstrvec_pushl(args, \"--recursive-prefix\",\n+\t\t\t     update_data->recursive_prefix, NULL);\n+\tif (update_data->quiet)\n+\t\tstrvec_push(args, \"--quiet\");\n+\tif (update_data->force)\n+\t\tstrvec_push(args, \"--force\");\n+\tif (update_data->init)\n+\t\tstrvec_push(args, \"--init\");\n+\tif (update_data->remote)\n+\t\tstrvec_push(args, \"--remote\");\n+\tif (update_data->nofetch)\n+\t\tstrvec_push(args, \"--no-fetch\");\n+\tif (update_data->dissociate)\n+\t\tstrvec_push(args, \"--dissociate\");\n+\tif (update_data->progress)\n+\t\tstrvec_push(args, \"--progress\");\n+\tif (update_data->require_init)\n+\t\tstrvec_push(args, \"--require-init\");\n+\tif (update_data->depth)\n+\t\tstrvec_pushf(args, \"--depth=%d\", update_data->depth);\n+\tif (update)\n+\t\tstrvec_pushl(args, \"--update\", update, NULL);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n+\t}\n+\tif (update_data->recommend_shallow == 0)\n+\t\tstrvec_push(args, \"--no-recommend-shallow\");\n+\telse if (update_data->recommend_shallow == 1)\n+\t\tstrvec_push(args, \"--recommend-shallow\");\n+\tif (update_data->single_branch >= 0)\n+\t\tstrvec_push(args, \"--single-branch\");\n+}\n+\n+static int update_submodule(struct update_data *update_data)\n {\n+\tchar *prefixed_path;\n+\n \tensure_core_worktree(update_data->sm_path);\n \n+\tif (update_data->recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n+\t\t\t\t\tupdate_data->sm_path);\n+\telse\n+\t\tprefixed_path = xstrdup(update_data->sm_path);\n+\n+\tupdate_data->displaypath = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t     update_data->prefix);\n+\tfree(prefixed_path);\n+\n \t/* NEEDSWORK: fix the style issues e.g. braces */\n \tif (update_data->just_cloned) {\n \t\toidcpy(&update_data->suboid, null_oid());\n@@ -2902,18 +2919,55 @@ static int update_submodule2(struct update_data *update_data)\n \t}\n \n \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n-\t\treturn do_run_update_procedure(update_data);\n+\t\tif (run_update_procedure(update_data))\n+\t\t\treturn 1;\n \n-\treturn 3;\n+\tif (update_data->recursive) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct update_data next = *update_data;\n+\t\tint res;\n+\n+\t\tif (update_data->recursive_prefix)\n+\t\t\tprefixed_path = xstrfmt(\"%s%s/\", update_data->recursive_prefix,\n+\t\t\t\t\t\tupdate_data->sm_path);\n+\t\telse\n+\t\t\tprefixed_path = xstrfmt(\"%s/\", update_data->sm_path);\n+\n+\t\tnext.recursive_prefix = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t\t  update_data->prefix);\n+\t\tnext.prefix = NULL;\n+\t\toidcpy(&next.oid, null_oid());\n+\t\toidcpy(&next.suboid, null_oid());\n+\n+\t\tcp.dir = update_data->sm_path;\n+\t\tcp.git_cmd = 1;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tupdate_data_to_args(&next, &cp.args);\n+\n+\t\t/* die() if child process die()'d */\n+\t\tres = run_command(&cp);\n+\t\tif (!res)\n+\t\t\treturn 0;\n+\t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t\tif (res == 128)\n+\t\t\texit(res);\n+\t\telse if (res)\n+\t\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n }\n \n-static int update_submodules(struct submodule_update_clone *suc)\n+static int update_submodules(struct update_data *update_data)\n {\n-\tint i;\n+\tint i, res = 0;\n+\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n \n-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n+\tupdate_clone_from_update_data(&suc, update_data);\n+\trun_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,\n \t\t\t\t   update_clone_start_failure,\n-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n+\t\t\t\t   update_clone_task_finished, &suc, \"submodule\",\n \t\t\t\t   \"parallel/update\");\n \n \t/*\n@@ -2924,25 +2978,45 @@ static int update_submodules(struct submodule_update_clone *suc)\n \t *   checkout involve more straightforward sequential I/O.\n \t * - the listener can avoid doing any work if fetching failed.\n \t */\n-\tif (suc->quickstop)\n-\t\treturn 1;\n+\tif (suc.quickstop) {\n+\t\tres = 1;\n+\t\tgoto cleanup;\n+\t}\n \n-\tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_submodule(&suc->update_clone[i]);\n+\tfor (i = 0; i < suc.update_clone_nr; i++) {\n+\t\tstruct update_clone_data ucd = suc.update_clone[i];\n \n-\treturn 0;\n+\t\toidcpy(&update_data->oid, &ucd.oid);\n+\t\tupdate_data->just_cloned = ucd.just_cloned;\n+\t\tupdate_data->sm_path = ucd.sub->path;\n+\n+\t\tif (update_submodule(update_data))\n+\t\t\tres = 1;\n+\t}\n+\n+cleanup:\n+\tstring_list_clear(&update_data->references, 0);\n+\treturn res;\n }\n \n-static int update_clone(int argc, const char **argv, const char *prefix)\n+static int module_update(int argc, const char **argv, const char *prefix)\n {\n \tconst char *update = NULL;\n \tstruct pathspec pathspec;\n-\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n+\tstruct update_data opt = UPDATE_DATA_INIT;\n \n+\t/* NEEDSWORK: update names and strings */\n \tstruct option module_update_clone_options[] = {\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-\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n+\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n+\t\tOPT_BOOL(0, \"recursive\", &opt.recursive,\n+\t\t\t N_(\"traverse submodules recursively\")),\n+\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n+\t\t\t N_(\"don't fetch new objects from the remote site\")),\n+\t\tOPT_STRING(0, \"prefix\", &opt.prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n \t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n@@ -2953,21 +3027,21 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n \t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n-\t\t\t   N_(\"reference repository\")),\n+\t\t\t\tN_(\"reference repository\")),\n \t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n-\t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n-\t\t\t   N_(\"create a shallow clone truncated to the \"\n-\t\t\t      \"specified number of revisions\")),\n+\t\t\t N_(\"use --reference only while cloning\")),\n+\t\tOPT_INTEGER(0, \"depth\", &opt.depth,\n+\t\t\t    N_(\"create a shallow clone truncated to the \"\n+\t\t\t       \"specified number of revisions\")),\n \t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n \t\t\t    N_(\"parallel jobs\")),\n \t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n+\t\t\t N_(\"whether the initial clone should follow the shallow recommendation\")),\n \t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n \t\tOPT_BOOL(0, \"progress\", &opt.progress,\n-\t\t\t    N_(\"force cloning progress\")),\n+\t\t\t N_(\"force cloning progress\")),\n \t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n+\t\t\t N_(\"disallow cloning into non-empty directory\")),\n \t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n \t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n \t\tOPT_END()\n@@ -2977,16 +3051,18 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n \t\tNULL\n \t};\n-\topt.prefix = prefix;\n \n \tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n \tgit_config(git_update_clone_config, &opt.max_jobs);\n \n \targc = parse_options(argc, argv, prefix, module_update_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n+\toidcpy(&opt.oid, null_oid());\n+\toidcpy(&opt.suboid, null_oid());\n \n \tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n+\t\tif (parse_submodule_update_strategy(update,\n+\t\t\t\t\t\t    &opt.update_strategy) < 0)\n \t\t\tdie(_(\"bad value for update parameter\"));\n \n \tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n@@ -3408,9 +3484,7 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n-\t{\"update-clone\", update_clone, 0},\n-\t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"relative-path\", resolve_relative_path, 0},\n+\t{\"update\", module_update, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 3ccf2388bf..bcd8b92aab 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -347,108 +347,26 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\t{\n-\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper update-clone \\\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n \t\t${GIT_QUIET:+--quiet} \\\n-\t\t${progress:+\"--progress\"} \\\n+\t\t${force:+--force} \\\n+\t\t${progress:+--progress} \\\n+\t\t${dissociate:+--dissociate} \\\n+\t\t${remote:+--remote} \\\n+\t\t${recursive:+--recursive} \\\n \t\t${init:+--init} \\\n+\t\t${require_init:+--require-init} \\\n+\t\t${nofetch:+--no-fetch} \\\n \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t${update:+--update \"$update\"} \\\n \t\t${reference:+\"$reference\"} \\\n-\t\t${dissociate:+\"--dissociate\"} \\\n-\t\t${depth:+--depth \"$depth\"} \\\n-\t\t${require_init:+--require-init} \\\n+\t\t${depth:+\"$depth\"} \\\n \t\t$single_branch \\\n \t\t$recommend_shallow \\\n \t\t$jobs \\\n \t\t-- \\\n-\t\t\"$@\" || echo \"#unmatched\" $?\n-\t} | {\n-\terr=\n-\twhile read -r quickabort sha1 just_cloned sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n-\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\n-\t\tif test $just_cloned -eq 0\n-\t\tthen\n-\t\t\tjust_cloned=\n-\t\tfi\n-\n-\t\tout=$(git submodule--helper run-update-procedure \\\n-\t\t\t  ${wt_prefix:+--prefix \"$wt_prefix\"} \\\n-\t\t\t  ${GIT_QUIET:+--quiet} \\\n-\t\t\t  ${force:+--force} \\\n-\t\t\t  ${just_cloned:+--just-cloned} \\\n-\t\t\t  ${nofetch:+--no-fetch} \\\n-\t\t\t  ${depth:+\"$depth\"} \\\n-\t\t\t  ${update:+--update \"$update\"} \\\n-\t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n-\t\t\t  ${sha1:+--oid \"$sha1\"} \\\n-\t\t\t  ${remote:+--remote} \\\n-\t\t\t  \"--\" \\\n-\t\t\t  \"$sm_path\")\n-\n-\t\t# exit codes for run-update-procedure:\n-\t\t# 0: update was successful, say command output\n-\t\t# 1: update procedure failed, but should not die\n-\t\t# 2 or 128: subcommand died during execution\n-\t\t# 3: no update procedure was run\n-\t\tres=\"$?\"\n-\t\tcase $res in\n-\t\t0)\n-\t\t\tsay \"$out\"\n-\t\t\t;;\n-\t\t1)\n-\t\t\terr=\"${err};fatal: $out\"\n-\t\t\tcontinue\n-\t\t\t;;\n-\t\t2|128)\n-\t\t\tdie_with_status $res \"fatal: $out\"\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=$(git submodule--helper relative-path \"$prefix$sm_path/\" \"$wt_prefix\")\n-\t\t\t\twt_prefix=\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_update\n-\t\t\t)\n-\t\t\tres=$?\n-\t\t\tif test $res -gt 0\n-\t\t\tthen\n-\t\t\t\tdie_msg=\"fatal: $(eval_gettext \"Failed to recurse into submodule path '\\$displaypath'\")\"\n-\t\t\t\tif test $res -ne 2\n-\t\t\t\tthen\n-\t\t\t\t\terr=\"${err};$die_msg\"\n-\t\t\t\t\tcontinue\n-\t\t\t\telse\n-\t\t\t\t\tdie_with_status $res \"$die_msg\"\n-\t\t\t\tfi\n-\t\t\tfi\n-\t\tfi\n-\tdone\n-\n-\tif test -n \"$err\"\n-\tthen\n-\t\tOIFS=$IFS\n-\t\tIFS=';'\n-\t\tfor e in $err\n-\t\tdo\n-\t\t\tif test -n \"$e\"\n-\t\t\tthen\n-\t\t\t\techo >&2 \"$e\"\n-\t\t\tfi\n-\t\tdone\n-\t\tIFS=$OIFS\n-\t\texit 1\n-\tfi\n-\t}\n+\t\t\"$@\"\n }\n \n #\n-- \n2.33.GIT\n\n"},{"id":"448107","messageId":"20220210092833.55360-1-chooglen@google.com","threadId":"56453","inReplyTo":"20220208083952.35036-1-chooglen@google.com","subject":"[PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:13Z","receivedAt":"2022-02-10T09:28:51Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"This reroll contains another 'easy' preparatory patch and the fixups I\nalluded to in v6 [1]. This isn't the split-up I described in the\nfootnote of v6, but it gets the big patch (patch 17) to what I think is\na reviewable state.\n\nThe diff between v7 and v5 is no longer just NEEDSWORK comments, but I\nthink it is easier to reason about. Patch 17 resembles v5 the most (I\nwill include a diff in a reply to that patch); everything after patch 17\nis fixups (I did not squash them in because they would grow the diff\neven more).\n\nI will also leave a review on patch 17 since the changes were not\noriginally authored by me.\n\n[1] https://lore.kernel.org/git/20220208083952.35036-1-chooglen@google.com\n\nChanges in v7:\n- Split the last patch of v6 (the big one) into patches 16-17.\n- Patch 16 moves logic out of run_update_procedure() (because the\n  command is going away), removing some noise from patch 17. This makes\n  the update_strategy parsing easier to reason about, but at the cost of\n  growing the diff vis-a-vis v5\n- Patches 18-20 are fixups that address NEEDSWORK comments from earlier\n  patches. Once maintaining a small diff vis-a-vis v5 stops making\n  sense, I will squash them in.\n\nAtharva Raykar (6):\n  submodule--helper: get remote names from any repository\n  submodule--helper: refactor get_submodule_displaypath()\n  submodule--helper: allow setting superprefix for init_submodule()\n  submodule--helper: run update using child process struct\n  builtin/submodule--helper.c: reformat designated initializers\n  submodule: move core cmd_update() logic to C\n\nGlen Choo (11):\n  submodule--helper: remove update-module-mode\n  submodule--helper: reorganize code for sh to C conversion\n  submodule--helper run-update-procedure: remove --suboid\n  submodule--helper run-update-procedure: learn --remote\n  submodule--helper: remove ensure-core-worktree\n  submodule--helper update-clone: learn --init\n  submodule--helper: move functions around\n  submodule--helper: reduce logic in run_update_procedure()\n  fixup! submodule--helper run-update-procedure: remove --suboid\n  fixup! submodule--helper run-update-procedure: learn --remote\n  fixup! submodule: move core cmd_update() logic to C\n\nÆvar Arnfjörð Bjarmason (3):\n  builtin/submodule--helper.c: rename option variables to \"opt\"\n  submodule--helper: don't use bitfield indirection for parse_options()\n  submodule tests: test for init and update failure output\n\n builtin/submodule--helper.c    | 695 ++++++++++++++++++---------------\n git-submodule.sh               | 153 +-------\n t/t7406-submodule-update.sh    |  14 +-\n t/t7408-submodule-reference.sh |  14 +-\n 4 files changed, 423 insertions(+), 453 deletions(-)\n\nRange-diff against v6:\n 1:  79c522cf56 =  1:  86ffb53742 submodule--helper: get remote names from any repository\n 2:  0b97034d89 =  2:  2a40266b7a submodule--helper: refactor get_submodule_displaypath()\n 3:  fedbed87a3 =  3:  cd851c8eb5 submodule--helper: allow setting superprefix for init_submodule()\n 4:  8e7868c5d1 =  4:  bfe5cad136 submodule--helper: run update using child process struct\n 5:  3dee4b9b15 =  5:  72c257fdbf builtin/submodule--helper.c: reformat designated initializers\n 6:  e2cc866e6b =  6:  4b5f703fde builtin/submodule--helper.c: rename option variables to \"opt\"\n 7:  4831695dc6 =  7:  f1d21f5b1c submodule--helper: don't use bitfield indirection for parse_options()\n 8:  c2dadfffb2 =  8:  9d32a73fc3 submodule tests: test for init and update failure output\n 9:  79ceb88dee =  9:  087bf43aba submodule--helper: remove update-module-mode\n10:  6fe25e24da = 10:  4eb2893a19 submodule--helper: reorganize code for sh to C conversion\n11:  52c997f97b = 11:  c08e7781e3 submodule--helper run-update-procedure: remove --suboid\n12:  61a5b02472 = 12:  2419c37184 submodule--helper run-update-procedure: learn --remote\n13:  f76627a078 = 13:  6691fd3648 submodule--helper: remove ensure-core-worktree\n14:  2d93c4232b = 14:  d2c9c356e9 submodule--helper update-clone: learn --init\n15:  d4899c5635 ! 15:  c8945fcc6f submodule--helper: move functions around\n    @@ Metadata\n      ## Commit message ##\n         submodule--helper: move functions around\n     \n    -    The next commit will change the internals of several functions and\n    +    A subsequent commit will change the internals of several functions and\n         arrange them in a more logical manner. Move these functions to their\n         final positions so that the diff is smaller.\n     \n -:  ---------- > 16:  10af533ae0 submodule--helper: reduce logic in run_update_procedure()\n16:  edf752da8d ! 17:  19143f6009 submodule: move core cmd_update() logic to C\n    @@ builtin/submodule--helper.c: struct submodule_update_clone {\n      };\n      #define SUBMODULE_UPDATE_CLONE_INIT { \\\n      \t.list = MODULE_LIST_INIT, \\\n    -@@ builtin/submodule--helper.c: struct submodule_update_clone {\n    - }\n    - \n    - struct update_data {\n    -+\tconst char *prefix;\n    - \tconst char *recursive_prefix;\n    - \tconst char *sm_path;\n    - \tconst char *displaypath;\n     @@ builtin/submodule--helper.c: struct update_data {\n      \tstruct object_id suboid;\n      \tstruct submodule_update_strategy update_strategy;\n    @@ builtin/submodule--helper.c: struct update_data {\n      \n      static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n     @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    - \tstruct child_process cp = CHILD_PROCESS_INIT;\n    - \tchar *oid = oid_to_hex(&ud->oid);\n    - \tint must_die_on_failure = 0;\n    -+\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n    -+\n    -+\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n    -+\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n    -+\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n    -+\telse\n    -+\t\tstrategy = ud->update_strategy;\n    - \n    --\tswitch (ud->update_strategy.type) {\n    -+\tswitch (strategy.type) {\n    - \tcase SM_UPDATE_CHECKOUT:\n    - \t\tcp.git_cmd = 1;\n    - \t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    - \t\tbreak;\n    - \tcase SM_UPDATE_COMMAND:\n    - \t\tcp.use_shell = 1;\n    --\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n    -+\t\tstrvec_push(&cp.args, strategy.command);\n    - \t\tmust_die_on_failure = 1;\n    - \t\tbreak;\n    - \tdefault:\n    - \t\tBUG(\"unexpected update strategy type: %s\",\n    --\t\t    submodule_strategy_to_string(&ud->update_strategy));\n    -+\t\t    submodule_strategy_to_string(&strategy));\n    - \t}\n    - \tstrvec_push(&cp.args, oid);\n    - \n    - \tcp.dir = xstrdup(ud->sm_path);\n    - \tprepare_submodule_repo_env(&cp.env_array);\n      \tif (run_command(&cp)) {\n    --\t\tswitch (ud->update_strategy.type) {\n    -+\t\tswitch (strategy.type) {\n    + \t\tswitch (ud->update_strategy.type) {\n      \t\tcase SM_UPDATE_CHECKOUT:\n     -\t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n     -\t\t\t       oid, ud->displaypath);\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \t\tcase SM_UPDATE_REBASE:\n     -\t\t\tprintf(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n     -\t\t\t       oid, ud->displaypath);\n    -+\t\t\tif (!must_die_on_failure)\n    -+\t\t\t\tbreak;\n    -+\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n    ++\t\t\tdie_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n     +\t\t\t    oid, ud->displaypath);\n      \t\t\tbreak;\n      \t\tcase SM_UPDATE_MERGE:\n     -\t\t\tprintf(_(\"Unable to merge '%s' in submodule path '%s'\"),\n     -\t\t\t       oid, ud->displaypath);\n    -+\t\t\tif (!must_die_on_failure)\n    -+\t\t\t\tbreak;\n    -+\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n    ++\t\t\tdie_message(_(\"Unable to merge '%s' in submodule path '%s'\"),\n     +\t\t\t    oid, ud->displaypath);\n      \t\t\tbreak;\n      \t\tcase SM_UPDATE_COMMAND:\n     -\t\t\tprintf(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n     -\t\t\t       ud->update_strategy.command, oid, ud->displaypath);\n    -+\t\t\tif (!must_die_on_failure)\n    -+\t\t\t\tbreak;\n    -+\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n    -+\t\t\t    strategy.command, oid, ud->displaypath);\n    ++\t\t\tdie_message(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n    ++\t\t\t    ud->update_strategy.command, oid, ud->displaypath);\n      \t\t\tbreak;\n      \t\tdefault:\n      \t\t\tBUG(\"unexpected update strategy type: %s\",\n    --\t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n    -+\t\t\t    submodule_strategy_to_string(&strategy));\n    + \t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n      \t\t}\n     -\t\t/*\n     -\t\t * NEEDSWORK: We are currently printing to stdout with error\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n     -\t\t * properly. Once we start handling the error messages within\n     -\t\t * C, we should use die() instead.\n     -\t\t */\n    --\t\tif (must_die_on_failure)\n    + \t\tif (must_die_on_failure)\n     -\t\t\treturn 2;\n     -\t\t/*\n     -\t\t * This signifies to the caller in shell that the command\n     -\t\t * failed without dying\n     -\t\t */\n    ++\t\t\texit(128);\n     +\n     +\t\t/* the command failed, but update must continue */\n      \t\treturn 1;\n      \t}\n      \n    --\tswitch (ud->update_strategy.type) {\n     +\tif (ud->quiet)\n     +\t\treturn 0;\n     +\n    -+\tswitch (strategy.type) {\n    + \tswitch (ud->update_strategy.type) {\n      \tcase SM_UPDATE_CHECKOUT:\n      \t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n    - \t\t       ud->displaypath, oid);\n     @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    - \t\tbreak;\n    - \tcase SM_UPDATE_COMMAND:\n    - \t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n    --\t\t       ud->displaypath, ud->update_strategy.command, oid);\n    -+\t\t       ud->displaypath, strategy.command, oid);\n    - \t\tbreak;\n    - \tdefault:\n    - \t\tBUG(\"unexpected update strategy type: %s\",\n    --\t\t    submodule_strategy_to_string(&ud->update_strategy));\n    -+\t\t    submodule_strategy_to_string(&strategy));\n    - \t}\n    - \n      \treturn 0;\n      }\n      \n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -static int update_submodule2(struct update_data *update_data);\n     -static int run_update_procedure(int argc, const char **argv, const char *prefix)\n     -{\n    --\tchar *prefixed_path, *update = NULL;\n     -\tstruct update_data opt = UPDATE_DATA_INIT;\n     -\n     -\tstruct option options[] = {\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -\t\tOPT_BOOL(0, \"just-cloned\", &opt.just_cloned,\n     -\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n     -\t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n    --\t\tOPT_STRING(0, \"prefix\", &prefix,\n    +-\t\tOPT_STRING(0, \"prefix\", &opt.prefix,\n     -\t\t\t   N_(\"path\"),\n     -\t\t\t   N_(\"path into the working tree\")),\n    --\t\tOPT_STRING(0, \"update\", &update,\n    +-\t\tOPT_STRING(0, \"update\", &opt.update_default,\n     -\t\t\t   N_(\"string\"),\n     -\t\t\t   N_(\"rebase, merge, checkout or none\")),\n     -\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n    @@ builtin/submodule--helper.c: static int do_run_update_procedure(struct update_da\n     -\n     -\topt.sm_path = argv[0];\n     -\n    --\tif (opt.recursive_prefix)\n    --\t\tprefixed_path = xstrfmt(\"%s%s\", opt.recursive_prefix, opt.sm_path);\n    --\telse\n    --\t\tprefixed_path = xstrdup(opt.sm_path);\n    --\n    --\topt.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n    --\n    --\tdetermine_submodule_update_strategy(the_repository, opt.just_cloned,\n    --\t\t\t\t\t    opt.sm_path, update,\n    --\t\t\t\t\t    &opt.update_strategy);\n    --\n    --\tfree(prefixed_path);\n     -\treturn update_submodule2(&opt);\n     -}\n     -\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     -static int update_submodule2(struct update_data *update_data)\n     +static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n     +{\n    -+\tconst char *update = submodule_strategy_to_string(&update_data->update_strategy);\n    -+\n     +\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n     +\tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n    ++\t/*\n    ++\t * NEEDSWORK: the equivalent code in git-submodule.sh does not\n    ++\t * pass --prefix, so this shouldn't either\n    ++\t*/\n     +\tif (update_data->prefix)\n     +\t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n     +\tif (update_data->recursive_prefix)\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\t\tstrvec_push(args, \"--require-init\");\n     +\tif (update_data->depth)\n     +\t\tstrvec_pushf(args, \"--depth=%d\", update_data->depth);\n    -+\tif (update)\n    -+\t\tstrvec_pushl(args, \"--update\", update, NULL);\n    ++\tif (update_data->update_default)\n    ++\t\tstrvec_pushl(args, \"--update\", update_data->update_default, NULL);\n     +\tif (update_data->references.nr) {\n     +\t\tstruct string_list_item *item;\n     +\t\tfor_each_string_list_item(item, &update_data->references)\n    @@ builtin/submodule--helper.c: static int module_set_branch(int argc, const char *\n     +\n     +static int update_submodule(struct update_data *update_data)\n      {\n    -+\tchar *prefixed_path;\n    -+\n    - \tensure_core_worktree(update_data->sm_path);\n    + \tchar *prefixed_path;\n      \n    -+\tif (update_data->recursive_prefix)\n    -+\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n    -+\t\t\t\t\tupdate_data->sm_path);\n    -+\telse\n    -+\t\tprefixed_path = xstrdup(update_data->sm_path);\n    -+\n    -+\tupdate_data->displaypath = get_submodule_displaypath(prefixed_path,\n    -+\t\t\t\t\t\t\t     update_data->prefix);\n    -+\tfree(prefixed_path);\n    -+\n    - \t/* NEEDSWORK: fix the style issues e.g. braces */\n    - \tif (update_data->just_cloned) {\n    - \t\toidcpy(&update_data->suboid, null_oid());\n     @@ builtin/submodule--helper.c: static int update_submodule2(struct update_data *update_data)\n      \t}\n      \n    @@ builtin/submodule--helper.c: static int update_submodule2(struct update_data *up\n     -\t\treturn do_run_update_procedure(update_data);\n     +\t\tif (run_update_procedure(update_data))\n     +\t\t\treturn 1;\n    - \n    --\treturn 3;\n    ++\n     +\tif (update_data->recursive) {\n     +\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n     +\t\tstruct update_data next = *update_data;\n    @@ builtin/submodule--helper.c: static int update_submodule2(struct update_data *up\n     +\t\tcp.git_cmd = 1;\n     +\t\tprepare_submodule_repo_env(&cp.env_array);\n     +\t\tupdate_data_to_args(&next, &cp.args);\n    -+\n    + \n    +-\treturn 3;\n     +\t\t/* die() if child process die()'d */\n     +\t\tres = run_command(&cp);\n     +\t\tif (!res)\n    @@ builtin/submodule--helper.c: static int update_submodules(struct submodule_updat\n     -static int update_clone(int argc, const char **argv, const char *prefix)\n     +static int module_update(int argc, const char **argv, const char *prefix)\n      {\n    - \tconst char *update = NULL;\n    +-\tconst char *update = NULL;\n      \tstruct pathspec pathspec;\n     -\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n     +\tstruct update_data opt = UPDATE_DATA_INIT;\n    @@ builtin/submodule--helper.c: static int update_submodules(struct submodule_updat\n      \t\t\t   N_(\"path\"),\n      \t\t\t   N_(\"path into the working tree\")),\n      \t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n    -@@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv, const char *prefix)\n    + \t\t\t   N_(\"path\"),\n    + \t\t\t   N_(\"path into the working tree, across nested \"\n    + \t\t\t      \"submodule boundaries\")),\n    +-\t\tOPT_STRING(0, \"update\", &update,\n    ++\t\tOPT_STRING(0, \"update\", &opt.update_default,\n      \t\t\t   N_(\"string\"),\n      \t\t\t   N_(\"rebase, merge, checkout or none\")),\n      \t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n    @@ builtin/submodule--helper.c: static int update_clone(int argc, const char **argv\n     +\toidcpy(&opt.oid, null_oid());\n     +\toidcpy(&opt.suboid, null_oid());\n      \n    - \tif (update)\n    +-\tif (update)\n     -\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n    -+\t\tif (parse_submodule_update_strategy(update,\n    ++\tif (opt.update_default)\n    ++\t\tif (parse_submodule_update_strategy(opt.update_default,\n     +\t\t\t\t\t\t    &opt.update_strategy) < 0)\n      \t\t\tdie(_(\"bad value for update parameter\"));\n      \n    @@ builtin/submodule--helper.c: static struct cmd_struct commands[] = {\n      \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n     \n      ## git-submodule.sh ##\n    +@@ git-submodule.sh: single_branch=\n    + jobs=\n    + recommend_shallow=\n    + \n    ++# NEEDSWORK this is now unused\n    + die_if_unmatched ()\n    + {\n    + \tif test \"$1\" = \"#unmatched\"\n     @@ git-submodule.sh: cmd_update()\n      \t\tshift\n      \tdone\n      \n     -\t{\n     -\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper update-clone \\\n    ++\t# NEEDSWORK --super-prefix isn't actually supported by this\n    ++\t# command - we just pass the $prefix to --recursive-prefix.\n     +\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n      \t\t${GIT_QUIET:+--quiet} \\\n     -\t\t${progress:+\"--progress\"} \\\n -:  ---------- > 18:  9d0afc60ec fixup! submodule--helper run-update-procedure: remove --suboid\n -:  ---------- > 19:  e700861239 fixup! submodule--helper run-update-procedure: learn --remote\n -:  ---------- > 20:  aef1a03b44 fixup! submodule: move core cmd_update() logic to C\n\nbase-commit: b23dac905bde28da47543484320db16312c87551\n-- \n2.33.GIT\n\n"},{"id":"448108","messageId":"20220210092833.55360-2-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 01/20] submodule--helper: get remote names from any repository","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:14Z","receivedAt":"2022-02-10T09:28:56Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\n`get_default_remote()` retrieves the name of a remote by resolving the\nrefs from of the current repository's ref store.\n\nThus in order to use it for retrieving the remote name of a submodule,\nwe have to start a new subprocess which runs from the submodule\ndirectory.\n\nLet's instead introduce a function called `repo_get_default_remote()`\nwhich takes any repository object and retrieves the remote accordingly.\n\n`get_default_remote()` is then defined as a call to\n`repo_get_default_remote()` with 'the_repository' passed to it.\n\nNow that we have `repo_get_default_remote()`, we no longer have to start\na subprocess that called `submodule--helper get-default-remote` from\nwithin the submodule directory.\n\nSo let's make a function called `get_default_remote_submodule()` which\ntakes a submodule path, and returns the default remote for that\nsubmodule, all within the same process.\n\nWe can now use this function to save an unnecessary subprocess spawn in\n`sync_submodule()`, and also in the next patch, which will require this\nfunctionality.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nHelped-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 39 +++++++++++++++++++++++--------------\n 1 file changed, 24 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c5d3fc3817..4c7c1e1432 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -29,11 +29,14 @@\n typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n \t\t\t\t  void *cb_data);\n \n-static char *get_default_remote(void)\n+static char *repo_get_default_remote(struct repository *repo)\n {\n \tchar *dest = NULL, *ret;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n+\tstruct ref_store *store = get_main_ref_store(repo);\n+\tint ignore_errno;\n+\tconst char *refname = refs_resolve_ref_unsafe(store, \"HEAD\", 0, NULL,\n+\t\t\t\t\t\t      NULL, &ignore_errno);\n \n \tif (!refname)\n \t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n@@ -46,7 +49,7 @@ static char *get_default_remote(void)\n \t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n \n \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n-\tif (git_config_get_string(sb.buf, &dest))\n+\tif (repo_config_get_string(repo, sb.buf, &dest))\n \t\tret = xstrdup(\"origin\");\n \telse\n \t\tret = dest;\n@@ -55,6 +58,19 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static char *get_default_remote_submodule(const char *module_path)\n+{\n+\tstruct repository subrepo;\n+\n+\trepo_submodule_init(&subrepo, the_repository, module_path, null_oid());\n+\treturn repo_get_default_remote(&subrepo);\n+}\n+\n+static char *get_default_remote(void)\n+{\n+\treturn repo_get_default_remote(the_repository);\n+}\n+\n static int print_default_remote(int argc, const char **argv, const char *prefix)\n {\n \tchar *remote;\n@@ -1341,9 +1357,8 @@ static void sync_submodule(const char *path, const char *prefix,\n {\n \tconst struct submodule *sub;\n \tchar *remote_key = NULL;\n-\tchar *sub_origin_url, *super_config_url, *displaypath;\n+\tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *sub_config_path = NULL;\n \n \tif (!is_submodule_active(the_repository, path))\n@@ -1382,21 +1397,15 @@ static void sync_submodule(const char *path, const char *prefix,\n \tif (!is_submodule_populated_gently(path, NULL))\n \t\tgoto cleanup;\n \n-\tprepare_submodule_repo_env(&cp.env_array);\n-\tcp.git_cmd = 1;\n-\tcp.dir = path;\n-\tstrvec_pushl(&cp.args, \"submodule--helper\",\n-\t\t     \"print-default-remote\", NULL);\n-\n \tstrbuf_reset(&sb);\n-\tif (capture_command(&cp, &sb, 0))\n+\tdefault_remote = get_default_remote_submodule(path);\n+\tif (!default_remote)\n \t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n \t\t      path);\n \n-\tstrbuf_strip_suffix(&sb, \"\\n\");\n-\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n+\tremote_key = xstrfmt(\"remote.%s.url\", default_remote);\n+\tfree(default_remote);\n \n-\tstrbuf_reset(&sb);\n \tsubmodule_to_gitdir(&sb, path);\n \tstrbuf_addstr(&sb, \"/config\");\n \n-- \n2.33.GIT\n\n"},{"id":"448109","messageId":"20220210092833.55360-3-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 02/20] submodule--helper: refactor get_submodule_displaypath()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:15Z","receivedAt":"2022-02-10T09:28:58Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe create a function called `do_get_submodule_displaypath()` that\ngenerates the display path required by several submodule functions, and\ntakes a custom superprefix parameter, instead of reading it from the\nenvironment.\n\nWe then redefine the existing `get_submodule_displaypath()` function\nas a call to this new function, where the superprefix is obtained from\nthe environment.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4c7c1e1432..5efceb9d46 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -261,11 +261,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\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 *do_get_submodule_displaypath(const char *path, const char *prefix, 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@@ -281,6 +278,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \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+\treturn do_get_submodule_displaypath(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-- \n2.33.GIT\n\n"},{"id":"448110","messageId":"20220210092833.55360-4-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 03/20] submodule--helper: allow setting superprefix for init_submodule()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:16Z","receivedAt":"2022-02-10T09:28:59Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe allow callers of the `init_submodule()` function to optionally\noverride the superprefix from the environment.\n\nWe need to enable this option because in our conversion of the update\ncommand that will follow, the '--init' option will be handled through\nthis API. We will need to change the superprefix at that time to ensure\nthe display paths show correctly in the output messages.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5efceb9d46..09cda67c1e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -606,18 +606,22 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \n struct init_cb {\n \tconst char *prefix;\n+\tconst char *superprefix;\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   unsigned int flags)\n+\t\t\t   const char *superprefix, unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\t/* try superprefix from the environment, if it is not passed explicitly */\n+\tif (!superprefix)\n+\t\tsuperprefix = get_super_prefix();\n+\tdisplaypath = do_get_submodule_displaypath(path, prefix, superprefix);\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \n@@ -691,7 +695,7 @@ static void init_submodule(const char *path, const char *prefix,\n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct init_cb *info = cb_data;\n-\tinit_submodule(list_item->name, info->prefix, info->flags);\n+\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n }\n \n static int module_init(int argc, const char **argv, const char *prefix)\n-- \n2.33.GIT\n\n"},{"id":"448111","messageId":"20220210092833.55360-5-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 04/20] submodule--helper: run update using child process struct","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:17Z","receivedAt":"2022-02-10T09:29:01Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nWe switch to using the run-command API function that takes a\n'struct child process', since we are using a lot of the options. This\nwill also make it simple to switch over to using 'capture_command()'\nwhen we start handling the output of the command completely in C.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 34 ++++++++++++++++------------------\n 1 file changed, 16 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 09cda67c1e..db71e6f4ec 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2344,47 +2344,45 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \n static int run_update_command(struct update_data *ud, int subforce)\n {\n-\tstruct strvec args = STRVEC_INIT;\n-\tstruct strvec child_env = STRVEC_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n \tint must_die_on_failure = 0;\n-\tint git_cmd;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_pushl(&args, \"checkout\", \"-q\", NULL);\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n \t\tif (subforce)\n-\t\t\tstrvec_push(&args, \"-f\");\n+\t\t\tstrvec_push(&cp.args, \"-f\");\n \t\tbreak;\n \tcase SM_UPDATE_REBASE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"rebase\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_MERGE:\n-\t\tgit_cmd = 1;\n-\t\tstrvec_push(&args, \"merge\");\n+\t\tcp.git_cmd = 1;\n+\t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->quiet)\n-\t\t\tstrvec_push(&args, \"--quiet\");\n+\t\t\tstrvec_push(&cp.args, \"--quiet\");\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n-\t\tgit_cmd = 0;\n-\t\tstrvec_push(&args, ud->update_strategy.command);\n+\t\tcp.use_shell = 1;\n+\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n \t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t}\n-\tstrvec_push(&args, oid);\n+\tstrvec_push(&cp.args, oid);\n \n-\tprepare_submodule_repo_env(&child_env);\n-\tif (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,\n-\t\t\t\t     ud->sm_path, child_env.v)) {\n+\tcp.dir = xstrdup(ud->sm_path);\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tif (run_command(&cp)) {\n \t\tswitch (ud->update_strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n \t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-- \n2.33.GIT\n\n"},{"id":"448112","messageId":"20220210092833.55360-6-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 05/20] builtin/submodule--helper.c: reformat designated initializers","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:18Z","receivedAt":"2022-02-10T09:29:07Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nThe second hunk here will make a subsequent commit's diff smaller, and\nlet's do the first and third hunks while we're at it so that we\nconsistently format all of these.\n\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 13 ++++++++++---\n 1 file changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex db71e6f4ec..9f79bdf4d5 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1654,7 +1654,10 @@ struct module_clone_data {\n \tunsigned int require_init: 1;\n \tint single_branch;\n };\n-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }\n+#define MODULE_CLONE_DATA_INIT { \\\n+\t.reference = STRING_LIST_INIT_NODUP, \\\n+\t.single_branch = -1, \\\n+}\n \n struct submodule_alternate_setup {\n \tconst char *submodule_name;\n@@ -2047,7 +2050,9 @@ struct update_data {\n \tunsigned int nofetch: 1;\n \tunsigned int just_cloned: 1;\n };\n-#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }\n+#define UPDATE_DATA_INIT { \\\n+\t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+}\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n \t\tstruct strbuf *out, const char *displaypath)\n@@ -3013,7 +3018,9 @@ struct add_data {\n \tunsigned int progress: 1;\n \tunsigned int dissociate: 1;\n };\n-#define ADD_DATA_INIT { .depth = -1 }\n+#define ADD_DATA_INIT { \\\n+\t.depth = -1, \\\n+}\n \n static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)\n {\n-- \n2.33.GIT\n\n"},{"id":"448113","messageId":"20220210092833.55360-7-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 06/20] builtin/submodule--helper.c: rename option variables to \"opt\"","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:19Z","receivedAt":"2022-02-10T09:29:09Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nRename the \"suc\" variable in update_clone() to \"opt\", and do the same\nfor the \"update_data\" variable in run_update_procedure().\n\nThe only reason for this change is to make the subsequent commit's\ndiff smaller, by doing this rename we can \"anchor\" the diff better, as\nit \"borrow\" most of the options declared here as-is as far as the diff\nrename detection is concerned.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 74 ++++++++++++++++++-------------------\n 1 file changed, 37 insertions(+), 37 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9f79bdf4d5..c2d4fd0347 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2517,36 +2517,36 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n {\n \tconst char *update = NULL;\n \tstruct pathspec pathspec;\n-\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n+\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n \n \tstruct option module_update_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &suc.recursive_prefix,\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree, across nested \"\n \t\t\t      \"submodule boundaries\")),\n \t\tOPT_STRING(0, \"update\", &update,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &suc.references, N_(\"repo\"),\n+\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n \t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &suc.dissociate,\n+\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n \t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &suc.depth, \"<depth>\",\n+\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n \t\t\t   N_(\"create a shallow clone truncated to the \"\n \t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &suc.max_jobs,\n+\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n \t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &suc.recommend_shallow,\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n \t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&suc.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &suc.progress,\n+\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n \t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &suc.require_init,\n+\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n \t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &suc.single_branch,\n+\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n \t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n \t\tOPT_END()\n \t};\n@@ -2555,32 +2555,32 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n \t\tNULL\n \t};\n-\tsuc.prefix = prefix;\n+\topt.prefix = prefix;\n \n-\tupdate_clone_config_from_gitmodules(&suc.max_jobs);\n-\tgit_config(git_update_clone_config, &suc.max_jobs);\n+\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n+\tgit_config(git_update_clone_config, &opt.max_jobs);\n \n \targc = parse_options(argc, argv, prefix, module_update_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n \tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &suc.update) < 0)\n+\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n \t\t\tdie(_(\"bad value for update parameter\"));\n \n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n \t\treturn 1;\n \n \tif (pathspec.nr)\n-\t\tsuc.warn_if_uninitialized = 1;\n+\t\topt.warn_if_uninitialized = 1;\n \n-\treturn update_submodules(&suc);\n+\treturn update_submodules(&opt);\n }\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n \tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n \tchar *prefixed_path, *update = NULL;\n-\tstruct update_data update_data = UPDATE_DATA_INIT;\n+\tstruct update_data opt = UPDATE_DATA_INIT;\n \n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n@@ -2589,20 +2589,20 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"don't fetch new objects from the remote site\")),\n \t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n \t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &update_data.depth, N_(\"depth for shallow fetch\")),\n+\t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n \t\tOPT_STRING(0, \"update\", &update,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &update_data.recursive_prefix, N_(\"path\"),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n \t\t\t   N_(\"path into the working tree, across nested \"\n \t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &update_data.oid, N_(\"sha1\"),\n+\t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n \t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &update_data.suboid, N_(\"subsha1\"),\n+\t\tOPT_CALLBACK_F(0, \"suboid\", &opt.suboid, N_(\"subsha1\"),\n \t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n \t\tOPT_END()\n@@ -2618,27 +2618,27 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tif (argc != 1)\n \t\tusage_with_options(usage, options);\n \n-\tupdate_data.force = !!force;\n-\tupdate_data.quiet = !!quiet;\n-\tupdate_data.nofetch = !!nofetch;\n-\tupdate_data.just_cloned = !!just_cloned;\n-\tupdate_data.sm_path = argv[0];\n+\topt.force = !!force;\n+\topt.quiet = !!quiet;\n+\topt.nofetch = !!nofetch;\n+\topt.just_cloned = !!just_cloned;\n+\topt.sm_path = argv[0];\n \n-\tif (update_data.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", update_data.recursive_prefix, update_data.sm_path);\n+\tif (opt.recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", opt.recursive_prefix, opt.sm_path);\n \telse\n-\t\tprefixed_path = xstrdup(update_data.sm_path);\n+\t\tprefixed_path = xstrdup(opt.sm_path);\n \n-\tupdate_data.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n+\topt.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n \n-\tdetermine_submodule_update_strategy(the_repository, update_data.just_cloned,\n-\t\t\t\t\t    update_data.sm_path, update,\n-\t\t\t\t\t    &update_data.update_strategy);\n+\tdetermine_submodule_update_strategy(the_repository, opt.just_cloned,\n+\t\t\t\t\t    opt.sm_path, update,\n+\t\t\t\t\t    &opt.update_strategy);\n \n \tfree(prefixed_path);\n \n-\tif (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)\n-\t\treturn do_run_update_procedure(&update_data);\n+\tif (!oideq(&opt.oid, &opt.suboid) || opt.force)\n+\t\treturn do_run_update_procedure(&opt);\n \n \treturn 3;\n }\n-- \n2.33.GIT\n\n"},{"id":"448114","messageId":"20220210092833.55360-8-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 07/20] submodule--helper: don't use bitfield indirection for parse_options()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:20Z","receivedAt":"2022-02-10T09:29:10Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nDo away with the indirection of local variables added in\nc51f8f94e5b (submodule--helper: run update procedures from C,\n2021-08-24).\n\nThese were only needed because in C you can't get a pointer to a\nsingle bit, so we were using intermediate variables instead.\n\nThis will also make a subsequent large commit's diff smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/submodule--helper.c | 23 ++++++++++-------------\n 1 file changed, 10 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c2d4fd0347..4a0890954e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2045,10 +2045,10 @@ struct update_data {\n \tstruct object_id suboid;\n \tstruct submodule_update_strategy update_strategy;\n \tint depth;\n-\tunsigned int force: 1;\n-\tunsigned int quiet: 1;\n-\tunsigned int nofetch: 1;\n-\tunsigned int just_cloned: 1;\n+\tunsigned int force;\n+\tunsigned int quiet;\n+\tunsigned int nofetch;\n+\tunsigned int just_cloned;\n };\n #define UPDATE_DATA_INIT { \\\n \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n@@ -2578,16 +2578,17 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n-\tint force = 0, quiet = 0, nofetch = 0, just_cloned = 0;\n \tchar *prefixed_path, *update = NULL;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \n \tstruct option options[] = {\n-\t\tOPT__QUIET(&quiet, N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&force, N_(\"force checkout updates\"), 0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &nofetch,\n+\t\tOPT__QUIET(&opt.quiet,\n+\t\t\t   N_(\"suppress output for update by rebase or merge\")),\n+\t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"),\n+\t\t\t   0),\n+\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n \t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &just_cloned,\n+\t\tOPT_BOOL(0, \"just-cloned\", &opt.just_cloned,\n \t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n \t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n@@ -2618,10 +2619,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \tif (argc != 1)\n \t\tusage_with_options(usage, options);\n \n-\topt.force = !!force;\n-\topt.quiet = !!quiet;\n-\topt.nofetch = !!nofetch;\n-\topt.just_cloned = !!just_cloned;\n \topt.sm_path = argv[0];\n \n \tif (opt.recursive_prefix)\n-- \n2.33.GIT\n\n"},{"id":"448115","messageId":"20220210092833.55360-9-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 08/20] submodule tests: test for init and update failure output","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:21Z","receivedAt":"2022-02-10T09:29:12Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nAmend some submodule tests to test for the failure output of \"git\nsubmodule [update|init]\". The lack of such tests hid a regression in\nan earlier version of a subsequent commit.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7406-submodule-update.sh    | 14 ++++++++++++--\n t/t7408-submodule-reference.sh | 14 +++++++++++++-\n 2 files changed, 25 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh\nindex 11cccbb333..7764c1c3cb 100755\n--- a/t/t7406-submodule-update.sh\n+++ b/t/t7406-submodule-update.sh\n@@ -205,8 +205,18 @@ test_expect_success 'submodule update should fail due to local changes' '\n \t (cd submodule &&\n \t  compare_head\n \t ) &&\n-\t test_must_fail git submodule update submodule\n-\t)\n+\t test_must_fail git submodule update submodule 2>../actual.raw\n+\t) &&\n+\tsed \"s/^> //\" >expect <<-\\EOF &&\n+\t> error: Your local changes to the following files would be overwritten by checkout:\n+\t> \tfile\n+\t> Please commit your changes or stash them before you switch branches.\n+\t> Aborting\n+\t> fatal: Unable to checkout OID in submodule path '\\''submodule'\\''\n+\tEOF\n+\tsed -e \"s/checkout $SQ[^$SQ]*$SQ/checkout OID/\" <actual.raw >actual &&\n+\ttest_cmp expect actual\n+\n '\n test_expect_success 'submodule update should throw away changes with --force ' '\n \t(cd super &&\ndiff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh\nindex a3892f494b..c3a4545510 100755\n--- a/t/t7408-submodule-reference.sh\n+++ b/t/t7408-submodule-reference.sh\n@@ -193,7 +193,19 @@ test_expect_success 'missing nested submodule alternate fails clone and submodul\n \t\tcd supersuper-clone &&\n \t\tcheck_that_two_of_three_alternates_are_used &&\n \t\t# update of the submodule fails\n-\t\ttest_must_fail git submodule update --init --recursive\n+\t\tcat >expect <<-\\EOF &&\n+\t\tfatal: submodule '\\''sub'\\'' cannot add alternate: path ... does not exist\n+\t\tFailed to clone '\\''sub'\\''. Retry scheduled\n+\t\tfatal: submodule '\\''sub-dissociate'\\'' cannot add alternate: path ... does not exist\n+\t\tFailed to clone '\\''sub-dissociate'\\''. Retry scheduled\n+\t\tfatal: submodule '\\''sub'\\'' cannot add alternate: path ... does not exist\n+\t\tFailed to clone '\\''sub'\\'' a second time, aborting\n+\t\tfatal: Failed to recurse into submodule path ...\n+\t\tEOF\n+\t\ttest_must_fail git submodule update --init --recursive 2>err &&\n+\t\tgrep -e fatal: -e ^Failed err >actual.raw &&\n+\t\tsed -e \"s/path $SQ[^$SQ]*$SQ/path .../\" <actual.raw >actual &&\n+\t\ttest_cmp expect actual\n \t)\n '\n \n-- \n2.33.GIT\n\n"},{"id":"448116","messageId":"20220210092833.55360-10-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 09/20] submodule--helper: remove update-module-mode","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:22Z","receivedAt":"2022-02-10T09:29:23Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"This is dead code - it has not been used since c51f8f94e5\n(submodule--helper: run update procedures from C, 2021-08-24).\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 24 ------------------------\n 1 file changed, 24 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4a0890954e..e0cc1c1b79 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1965,29 +1965,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n \tfree(key);\n }\n \n-static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *path, *update = NULL;\n-\tint just_cloned;\n-\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n-\n-\tif (argc < 3 || argc > 4)\n-\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n-\n-\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n-\tpath = argv[2];\n-\n-\tif (argc == 4)\n-\t\tupdate = argv[3];\n-\n-\tdetermine_submodule_update_strategy(the_repository,\n-\t\t\t\t\t    just_cloned, path, update,\n-\t\t\t\t\t    &update_strategy);\n-\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n-\n-\treturn 0;\n-}\n-\n struct update_clone_data {\n \tconst struct submodule *sub;\n \tstruct object_id oid;\n@@ -3388,7 +3365,6 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n-\t{\"update-module-mode\", module_update_module_mode, 0},\n \t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n \t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n-- \n2.33.GIT\n\n"},{"id":"448117","messageId":"20220210092833.55360-12-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 11/20] submodule--helper run-update-procedure: remove --suboid","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:24Z","receivedAt":"2022-02-10T09:29:26Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Teach run-update-procedure to determine the oid of the submodule's HEAD\ninstead of doing it in git-subomdule.sh.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 12 +++++++++---\n git-submodule.sh            |  8 +-------\n 2 files changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 0b5120734a..a26477ce04 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2585,9 +2585,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n \t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n-\t\tOPT_CALLBACK_F(0, \"suboid\", &opt.suboid, N_(\"subsha1\"),\n-\t\t\t       N_(\"SHA1 of submodule's HEAD\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n \t\tOPT_END()\n \t};\n \n@@ -2982,6 +2979,15 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n /* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n static int update_submodule2(struct update_data *update_data)\n {\n+\t/* NEEDSWORK: fix the style issues e.g. braces */\n+\tif (update_data->just_cloned) {\n+\t\toidcpy(&update_data->suboid, null_oid());\n+\t} else {\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n+\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t}\n+\n \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n \t\treturn do_run_update_procedure(update_data);\n \ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 652861aa66..d48c314f01 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -391,14 +391,9 @@ cmd_update()\n \n \t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n \n-\t\tif test $just_cloned -eq 1\n+\t\tif test $just_cloned -eq 0\n \t\tthen\n-\t\t\tsubsha1=\n-\t\telse\n \t\t\tjust_cloned=\n-\t\t\tsubsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify HEAD) ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current revision in submodule path '\\$displaypath'\")\"\n \t\tfi\n \n \t\tif test -n \"$remote\"\n@@ -426,7 +421,6 @@ cmd_update()\n \t\t\t  ${update:+--update \"$update\"} \\\n \t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t\t  ${sha1:+--oid \"$sha1\"} \\\n-\t\t\t  ${subsha1:+--suboid \"$subsha1\"} \\\n \t\t\t  \"--\" \\\n \t\t\t  \"$sm_path\")\n \n-- \n2.33.GIT\n\n"},{"id":"448118","messageId":"20220210092833.55360-11-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 10/20] submodule--helper: reorganize code for sh to C conversion","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:23Z","receivedAt":"2022-02-10T09:29:28Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Introduce a function, update_submodule2(), that performs an update for\none submodule. This function will implement the functionality of\nrun-update-procedure and its surrounding shell code in submodule.sh.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 20 +++++++++++++++-----\n 1 file changed, 15 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e0cc1c1b79..0b5120734a 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2553,6 +2553,11 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \treturn update_submodules(&opt);\n }\n \n+/*\n+ * NEEDSWORK: Use a forward declaration to avoid moving\n+ * run_update_procedure() (which will be removed soon).\n+ */\n+static int update_submodule2(struct update_data *update_data);\n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n \tchar *prefixed_path, *update = NULL;\n@@ -2610,11 +2615,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\t\t\t\t    &opt.update_strategy);\n \n \tfree(prefixed_path);\n-\n-\tif (!oideq(&opt.oid, &opt.suboid) || opt.force)\n-\t\treturn do_run_update_procedure(&opt);\n-\n-\treturn 3;\n+\treturn update_submodule2(&opt);\n }\n \n static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n@@ -2978,6 +2979,15 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \treturn !!ret;\n }\n \n+/* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n+static int update_submodule2(struct update_data *update_data)\n+{\n+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n+\t\treturn do_run_update_procedure(update_data);\n+\n+\treturn 3;\n+}\n+\n struct add_data {\n \tconst char *prefix;\n \tconst char *branch;\n-- \n2.33.GIT\n\n"},{"id":"448119","messageId":"20220210092833.55360-13-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 12/20] submodule--helper run-update-procedure: learn --remote","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:25Z","receivedAt":"2022-02-10T09:29:35Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Teach run-update-procedure to handle --remote instead of parsing\n--remote in git-submodule.sh. As a result, \"git submodule--helper\nprint-default-remote\" has no more callers, so remove it.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 39 ++++++++++++++++++++++---------------\n git-submodule.sh            | 30 +---------------------------\n 2 files changed, 24 insertions(+), 45 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a26477ce04..15ae986692 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -71,21 +71,6 @@ static char *get_default_remote(void)\n \treturn repo_get_default_remote(the_repository);\n }\n \n-static int print_default_remote(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remote;\n-\n-\tif (argc != 1)\n-\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n-\n-\tremote = get_default_remote();\n-\tif (remote)\n-\t\tprintf(\"%s\\n\", remote);\n-\n-\tfree(remote);\n-\treturn 0;\n-}\n-\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -2026,6 +2011,7 @@ struct update_data {\n \tunsigned int quiet;\n \tunsigned int nofetch;\n \tunsigned int just_cloned;\n+\tunsigned int remote;\n };\n #define UPDATE_DATA_INIT { \\\n \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n@@ -2585,6 +2571,8 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n \t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n \t\t\t       parse_opt_object_id),\n+\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n+\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n \t\tOPT_END()\n \t};\n \n@@ -2988,6 +2976,25 @@ static int update_submodule2(struct update_data *update_data)\n \t\t\t    update_data->displaypath);\n \t}\n \n+\tif (update_data->remote) {\n+\t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n+\t\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n+\t\tchar *remote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n+\n+\t\tif (!update_data->nofetch) {\n+\t\t\tif (fetch_in_submodule(update_data->sm_path, update_data->depth,\n+\t\t\t\t\t      0, NULL))\n+\t\t\t\tdie(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\t\t    update_data->sm_path);\n+\t\t}\n+\n+\t\tif (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))\n+\t\t\tdie(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t    remote_ref, update_data->sm_path);\n+\n+\t\tfree(remote_ref);\n+\t}\n+\n \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n \t\treturn do_run_update_procedure(update_data);\n \n@@ -3389,10 +3396,10 @@ static struct cmd_struct commands[] = {\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n-\t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, 0},\n \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n+\t/* NEEDSWORK: remote-branch is also obsolete */\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex d48c314f01..29fd69250d 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -246,20 +246,6 @@ cmd_deinit()\n \tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- \"$@\"\n }\n \n-# usage: fetch_in_submodule <module_path> [<depth>] [<sha1>]\n-# Because arguments are positional, use an empty string to omit <depth>\n-# but include <sha1>.\n-fetch_in_submodule () (\n-\tsanitize_submodule_env &&\n-\tcd \"$1\" &&\n-\tif test $# -eq 3\n-\tthen\n-\t\techo \"$3\" | git fetch ${GIT_QUIET:+--quiet} --stdin ${2:+\"$2\"}\n-\telse\n-\t\tgit fetch ${GIT_QUIET:+--quiet} ${2:+\"$2\"}\n-\tfi\n-)\n-\n #\n # Update each submodule path to correct revision, using clone and checkout as needed\n #\n@@ -396,21 +382,6 @@ cmd_update()\n \t\t\tjust_cloned=\n \t\tfi\n \n-\t\tif test -n \"$remote\"\n-\t\tthen\n-\t\t\tbranch=$(git submodule--helper remote-branch \"$sm_path\")\n-\t\t\tif test -z \"$nofetch\"\n-\t\t\tthen\n-\t\t\t\t# Fetch remote before determining tracking $sha1\n-\t\t\t\tfetch_in_submodule \"$sm_path\" $depth ||\n-\t\t\t\tdie \"fatal: $(eval_gettext \"Unable to fetch in submodule path '\\$sm_path'\")\"\n-\t\t\tfi\n-\t\t\tremote_name=$(sanitize_submodule_env; cd \"$sm_path\" && git submodule--helper print-default-remote)\n-\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" &&\n-\t\t\t\tgit rev-parse --verify \"${remote_name}/${branch}\") ||\n-\t\t\tdie \"fatal: $(eval_gettext \"Unable to find current \\${remote_name}/\\${branch} revision in submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\n \t\tout=$(git submodule--helper run-update-procedure \\\n \t\t\t  ${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t\t  ${GIT_QUIET:+--quiet} \\\n@@ -421,6 +392,7 @@ cmd_update()\n \t\t\t  ${update:+--update \"$update\"} \\\n \t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t\t  ${sha1:+--oid \"$sha1\"} \\\n+\t\t\t  ${remote:+--remote} \\\n \t\t\t  \"--\" \\\n \t\t\t  \"$sm_path\")\n \n-- \n2.33.GIT\n\n"},{"id":"448120","messageId":"20220210092833.55360-14-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 13/20] submodule--helper: remove ensure-core-worktree","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:26Z","receivedAt":"2022-02-10T09:29:38Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Move the logic of \"git submodule--helper ensure-core-worktree\" into\nrun-update-procedure. Since the ensure-core-worktree command is\nobsolete, remove it.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 13 +++----------\n git-submodule.sh            |  2 --\n 2 files changed, 3 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 15ae986692..a05aea5cd6 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2746,17 +2746,11 @@ static int push_check(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n+static void ensure_core_worktree(const char *path)\n {\n-\tconst char *path;\n \tconst char *cw;\n \tstruct repository subrepo;\n \n-\tif (argc != 2)\n-\t\tBUG(\"submodule--helper ensure-core-worktree <path>\");\n-\n-\tpath = argv[1];\n-\n \tif (repo_submodule_init(&subrepo, the_repository, path, null_oid()))\n \t\tdie(_(\"could not get a repository handle for submodule '%s'\"), path);\n \n@@ -2776,8 +2770,6 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n-\n-\treturn 0;\n }\n \n static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n@@ -2967,6 +2959,8 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n /* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n static int update_submodule2(struct update_data *update_data)\n {\n+\tensure_core_worktree(update_data->sm_path);\n+\n \t/* NEEDSWORK: fix the style issues e.g. braces */\n \tif (update_data->just_cloned) {\n \t\toidcpy(&update_data->suboid, null_oid());\n@@ -3390,7 +3384,6 @@ static struct cmd_struct commands[] = {\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n \t{\"update-clone\", update_clone, 0},\n \t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 29fd69250d..aa9c898e1c 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -373,8 +373,6 @@ cmd_update()\n \tdo\n \t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n \n-\t\tgit submodule--helper ensure-core-worktree \"$sm_path\" || exit 1\n-\n \t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n \n \t\tif test $just_cloned -eq 0\n-- \n2.33.GIT\n\n"},{"id":"448121","messageId":"20220210092833.55360-15-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 14/20] submodule--helper update-clone: learn --init","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:27Z","receivedAt":"2022-02-10T09:29:40Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Teach \"git submodule--helper update-clone\" the --init flag and remove\nthe corresponding shell code.\n\nWhen the `--init` flag is passed to the subcommand, we do not spawn a\nnew subprocess and call `submodule--helper init` on the submodule paths,\nbecause the Git machinery is not able to pick up the configuration\nchanges introduced by that init call. So we instead run the\n`init_submodule_cb()` callback over each submodule in the same process.\n\n[1] https://lore.kernel.org/git/CAP8UFD0NCQ5w_3GtT_xHr35i7h8BuLX4UcHNY6VHPGREmDVObA@mail.gmail.com/\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 26 ++++++++++++++++++++++++++\n git-submodule.sh            |  9 +++------\n 2 files changed, 29 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a05aea5cd6..5635f0c48b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1989,6 +1989,7 @@ struct submodule_update_clone {\n \tint failed_clones_nr, failed_clones_alloc;\n \n \tint max_jobs;\n+\tunsigned int init;\n };\n #define SUBMODULE_UPDATE_CLONE_INIT { \\\n \t.list = MODULE_LIST_INIT, \\\n@@ -2483,6 +2484,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n \n \tstruct option module_update_clone_options[] = {\n+\t\tOPT_BOOL(0, \"init\", &opt.init,\n+\t\t\t N_(\"initialize uninitialized submodules before update\")),\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n@@ -2536,6 +2539,29 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \tif (pathspec.nr)\n \t\topt.warn_if_uninitialized = 1;\n \n+\tif (opt.init) {\n+\t\tstruct module_list list = MODULE_LIST_INIT;\n+\t\tstruct init_cb info = INIT_CB_INIT;\n+\n+\t\tif (module_list_compute(argc, argv, opt.prefix,\n+\t\t\t\t\t&pathspec, &list) < 0)\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * If there are no path args and submodule.active is set then,\n+\t\t * by default, only initialize 'active' modules.\n+\t\t */\n+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n+\t\t\tmodule_list_active(&list);\n+\n+\t\tinfo.prefix = opt.prefix;\n+\t\tinfo.superprefix = opt.recursive_prefix;\n+\t\tif (opt.quiet)\n+\t\t\tinfo.flags |= OPT_QUIET;\n+\n+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n+\t}\n+\n \treturn update_submodules(&opt);\n }\n \ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex aa9c898e1c..3ccf2388bf 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -347,14 +347,11 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\tif test -n \"$init\"\n-\tthen\n-\t\tcmd_init \"--\" \"$@\" || return\n-\tfi\n-\n \t{\n-\tgit submodule--helper update-clone ${GIT_QUIET:+--quiet} \\\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper update-clone \\\n+\t\t${GIT_QUIET:+--quiet} \\\n \t\t${progress:+\"--progress\"} \\\n+\t\t${init:+--init} \\\n \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t${update:+--update \"$update\"} \\\n-- \n2.33.GIT\n\n"},{"id":"448122","messageId":"20220210092833.55360-16-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 15/20] submodule--helper: move functions around","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:28Z","receivedAt":"2022-02-10T09:29:49Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"A subsequent commit will change the internals of several functions and\narrange them in a more logical manner. Move these functions to their\nfinal positions so that the diff is smaller.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 228 ++++++++++++++++++------------------\n 1 file changed, 114 insertions(+), 114 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5635f0c48b..0ab8f9d49f 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2451,120 +2451,6 @@ static void update_submodule(struct update_clone_data *ucd)\n \t\tucd->sub->path);\n }\n \n-static int update_submodules(struct submodule_update_clone *suc)\n-{\n-\tint i;\n-\n-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n-\t\t\t\t   update_clone_start_failure,\n-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n-\t\t\t\t   \"parallel/update\");\n-\n-\t/*\n-\t * We saved the output and put it out all at once now.\n-\t * That means:\n-\t * - the listener does not have to interleave their (checkout)\n-\t *   work with our fetching.  The writes involved in a\n-\t *   checkout involve more straightforward sequential I/O.\n-\t * - the listener can avoid doing any work if fetching failed.\n-\t */\n-\tif (suc->quickstop)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_submodule(&suc->update_clone[i]);\n-\n-\treturn 0;\n-}\n-\n-static int update_clone(int argc, const char **argv, const char *prefix)\n-{\n-\tconst char *update = NULL;\n-\tstruct pathspec pathspec;\n-\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n-\n-\tstruct option module_update_clone_options[] = {\n-\t\tOPT_BOOL(0, \"init\", &opt.init,\n-\t\t\t N_(\"initialize uninitialized submodules before update\")),\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n-\t\t\t   N_(\"reference repository\")),\n-\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n-\t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n-\t\t\t   N_(\"create a shallow clone truncated to the \"\n-\t\t\t      \"specified number of revisions\")),\n-\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n-\t\t\t    N_(\"parallel jobs\")),\n-\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n-\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n-\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n-\t\t\t    N_(\"force cloning progress\")),\n-\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n-\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n-\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\topt.prefix = prefix;\n-\n-\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n-\tgit_config(git_update_clone_config, &opt.max_jobs);\n-\n-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n-\t\t\tdie(_(\"bad value for update parameter\"));\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n-\t\treturn 1;\n-\n-\tif (pathspec.nr)\n-\t\topt.warn_if_uninitialized = 1;\n-\n-\tif (opt.init) {\n-\t\tstruct module_list list = MODULE_LIST_INIT;\n-\t\tstruct init_cb info = INIT_CB_INIT;\n-\n-\t\tif (module_list_compute(argc, argv, opt.prefix,\n-\t\t\t\t\t&pathspec, &list) < 0)\n-\t\t\treturn 1;\n-\n-\t\t/*\n-\t\t * If there are no path args and submodule.active is set then,\n-\t\t * by default, only initialize 'active' modules.\n-\t\t */\n-\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n-\t\t\tmodule_list_active(&list);\n-\n-\t\tinfo.prefix = opt.prefix;\n-\t\tinfo.superprefix = opt.recursive_prefix;\n-\t\tif (opt.quiet)\n-\t\t\tinfo.flags |= OPT_QUIET;\n-\n-\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n-\t}\n-\n-\treturn update_submodules(&opt);\n-}\n-\n /*\n  * NEEDSWORK: Use a forward declaration to avoid moving\n  * run_update_procedure() (which will be removed soon).\n@@ -3021,6 +2907,120 @@ static int update_submodule2(struct update_data *update_data)\n \treturn 3;\n }\n \n+static int update_submodules(struct submodule_update_clone *suc)\n+{\n+\tint i;\n+\n+\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n+\t\t\t\t   update_clone_start_failure,\n+\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n+\t\t\t\t   \"parallel/update\");\n+\n+\t/*\n+\t * We saved the output and put it out all at once now.\n+\t * That means:\n+\t * - the listener does not have to interleave their (checkout)\n+\t *   work with our fetching.  The writes involved in a\n+\t *   checkout involve more straightforward sequential I/O.\n+\t * - the listener can avoid doing any work if fetching failed.\n+\t */\n+\tif (suc->quickstop)\n+\t\treturn 1;\n+\n+\tfor (i = 0; i < suc->update_clone_nr; i++)\n+\t\tupdate_submodule(&suc->update_clone[i]);\n+\n+\treturn 0;\n+}\n+\n+static int update_clone(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *update = NULL;\n+\tstruct pathspec pathspec;\n+\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n+\n+\tstruct option module_update_clone_options[] = {\n+\t\tOPT_BOOL(0, \"init\", &opt.init,\n+\t\t\t N_(\"initialize uninitialized submodules before update\")),\n+\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree\")),\n+\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n+\t\t\t   N_(\"path\"),\n+\t\t\t   N_(\"path into the working tree, across nested \"\n+\t\t\t      \"submodule boundaries\")),\n+\t\tOPT_STRING(0, \"update\", &update,\n+\t\t\t   N_(\"string\"),\n+\t\t\t   N_(\"rebase, merge, checkout or none\")),\n+\t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n+\t\t\t   N_(\"reference repository\")),\n+\t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n+\t\t\t   N_(\"use --reference only while cloning\")),\n+\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n+\t\t\t   N_(\"create a shallow clone truncated to the \"\n+\t\t\t      \"specified number of revisions\")),\n+\t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n+\t\t\t    N_(\"parallel jobs\")),\n+\t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n+\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n+\t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n+\t\tOPT_BOOL(0, \"progress\", &opt.progress,\n+\t\t\t    N_(\"force cloning progress\")),\n+\t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n+\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n+\t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n+\t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n+\t\tNULL\n+\t};\n+\topt.prefix = prefix;\n+\n+\tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n+\tgit_config(git_update_clone_config, &opt.max_jobs);\n+\n+\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (update)\n+\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n+\t\t\tdie(_(\"bad value for update parameter\"));\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n+\t\treturn 1;\n+\n+\tif (pathspec.nr)\n+\t\topt.warn_if_uninitialized = 1;\n+\n+\tif (opt.init) {\n+\t\tstruct module_list list = MODULE_LIST_INIT;\n+\t\tstruct init_cb info = INIT_CB_INIT;\n+\n+\t\tif (module_list_compute(argc, argv, opt.prefix,\n+\t\t\t\t\t&pathspec, &list) < 0)\n+\t\t\treturn 1;\n+\n+\t\t/*\n+\t\t * If there are no path args and submodule.active is set then,\n+\t\t * by default, only initialize 'active' modules.\n+\t\t */\n+\t\tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n+\t\t\tmodule_list_active(&list);\n+\n+\t\tinfo.prefix = opt.prefix;\n+\t\tinfo.superprefix = opt.recursive_prefix;\n+\t\tif (opt.quiet)\n+\t\t\tinfo.flags |= OPT_QUIET;\n+\n+\t\tfor_each_listed_submodule(&list, init_submodule_cb, &info);\n+\t}\n+\n+\treturn update_submodules(&opt);\n+}\n+\n struct add_data {\n \tconst char *prefix;\n \tconst char *branch;\n-- \n2.33.GIT\n\n"},{"id":"448123","messageId":"20220210092833.55360-17-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 16/20] submodule--helper: reduce logic in run_update_procedure()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:29Z","receivedAt":"2022-02-10T09:29:51Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"A later commit will combine the \"update-clone\" and\n\"run-update-procedure\" commands, so run_update_procedure() will be\nremoved. Prepare for this by moving as much logic as possible out of\nrun_update_procedure() and into update_submodule2().\n\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 35 ++++++++++++++++++++---------------\n 1 file changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 0ab8f9d49f..ff7ee73e1a 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2001,9 +2001,11 @@ struct submodule_update_clone {\n }\n \n struct update_data {\n+\tconst char *prefix;\n \tconst char *recursive_prefix;\n \tconst char *sm_path;\n \tconst char *displaypath;\n+\tconst char *update_default;\n \tstruct object_id oid;\n \tstruct object_id suboid;\n \tstruct submodule_update_strategy update_strategy;\n@@ -2458,7 +2460,6 @@ static void update_submodule(struct update_clone_data *ucd)\n static int update_submodule2(struct update_data *update_data);\n static int run_update_procedure(int argc, const char **argv, const char *prefix)\n {\n-\tchar *prefixed_path, *update = NULL;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \n \tstruct option options[] = {\n@@ -2471,10 +2472,10 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"just-cloned\", &opt.just_cloned,\n \t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n \t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\tOPT_STRING(0, \"prefix\", &opt.prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n+\t\tOPT_STRING(0, \"update\", &opt.update_default,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n \t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n@@ -2500,18 +2501,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n \n \topt.sm_path = argv[0];\n \n-\tif (opt.recursive_prefix)\n-\t\tprefixed_path = xstrfmt(\"%s%s\", opt.recursive_prefix, opt.sm_path);\n-\telse\n-\t\tprefixed_path = xstrdup(opt.sm_path);\n-\n-\topt.displaypath = get_submodule_displaypath(prefixed_path, prefix);\n-\n-\tdetermine_submodule_update_strategy(the_repository, opt.just_cloned,\n-\t\t\t\t\t    opt.sm_path, update,\n-\t\t\t\t\t    &opt.update_strategy);\n-\n-\tfree(prefixed_path);\n \treturn update_submodule2(&opt);\n }\n \n@@ -2871,8 +2860,24 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n /* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n static int update_submodule2(struct update_data *update_data)\n {\n+\tchar *prefixed_path;\n+\n \tensure_core_worktree(update_data->sm_path);\n \n+\tif (update_data->recursive_prefix)\n+\t\tprefixed_path = xstrfmt(\"%s%s\", update_data->recursive_prefix,\n+\t\t\t\t\tupdate_data->sm_path);\n+\telse\n+\t\tprefixed_path = xstrdup(update_data->sm_path);\n+\n+\tupdate_data->displaypath = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t     update_data->prefix);\n+\tfree(prefixed_path);\n+\n+\tdetermine_submodule_update_strategy(the_repository, update_data->just_cloned,\n+\t\t\t\t\t    update_data->sm_path, update_data->update_default,\n+\t\t\t\t\t    &update_data->update_strategy);\n+\n \t/* NEEDSWORK: fix the style issues e.g. braces */\n \tif (update_data->just_cloned) {\n \t\toidcpy(&update_data->suboid, null_oid());\n-- \n2.33.GIT\n\n"},{"id":"448124","messageId":"20220210092833.55360-18-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 17/20] submodule: move core cmd_update() logic to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:30Z","receivedAt":"2022-02-10T09:29:53Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"From: Atharva Raykar <raykar.ath@gmail.com>\n\nThis patch completes the conversion past the flag parsing of\n`submodule update` by introducing a helper subcommand called\n`submodule--helper update`. The behaviour of `submodule update` should\nremain the same after this patch.\n\nWe add more fields to the `struct update_data` that are required by\n`struct submodule_update_clone` to be able to perform a clone, when that\nis needed to be done.\n\nRecursing on a submodule is done by calling a subprocess that launches\n`submodule--helper update`, with a modified `--recursive-prefix` and\n`--prefix` parameter.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Shourya Shukla <periperidip@gmail.com>\nSigned-off-by: Atharva Raykar <raykar.ath@gmail.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 312 ++++++++++++++++++++++--------------\n git-submodule.sh            | 105 ++----------\n 2 files changed, 201 insertions(+), 216 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex ff7ee73e1a..b895e88a64 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1977,7 +1977,6 @@ struct submodule_update_clone {\n \tconst char *prefix;\n \tint single_branch;\n \n-\t/* to be consumed by git-submodule.sh */\n \tstruct update_clone_data *update_clone;\n \tint update_clone_nr; int update_clone_alloc;\n \n@@ -1989,7 +1988,6 @@ struct submodule_update_clone {\n \tint failed_clones_nr, failed_clones_alloc;\n \n \tint max_jobs;\n-\tunsigned int init;\n };\n #define SUBMODULE_UPDATE_CLONE_INIT { \\\n \t.list = MODULE_LIST_INIT, \\\n@@ -2010,14 +2008,54 @@ struct update_data {\n \tstruct object_id suboid;\n \tstruct submodule_update_strategy update_strategy;\n \tint depth;\n+\tint recommend_shallow;\n+\tint single_branch;\n+\tint max_jobs;\n+\tunsigned int init;\n \tunsigned int force;\n \tunsigned int quiet;\n \tunsigned int nofetch;\n \tunsigned int just_cloned;\n \tunsigned int remote;\n+\tunsigned int recursive;\n+\tunsigned int progress;\n+\tunsigned int dissociate;\n+\tunsigned int require_init;\n+\tunsigned warn_if_uninitialized ;\n+\tstruct string_list references;\n+\tstruct module_list list;\n };\n #define UPDATE_DATA_INIT { \\\n+\t.list = MODULE_LIST_INIT, \\\n \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n+\t.recommend_shallow = -1, \\\n+\t.references = STRING_LIST_INIT_DUP, \\\n+\t.single_branch = -1, \\\n+\t.max_jobs = 1, \\\n+}\n+\n+static void update_clone_from_update_data(struct submodule_update_clone *suc,\n+\t\t\t\t\t  struct update_data *update_data)\n+{\n+\tsuc->prefix = update_data->prefix;\n+\tsuc->recursive_prefix = update_data->recursive_prefix;\n+\tsuc->max_jobs = update_data->max_jobs;\n+\tsuc->progress = update_data->progress;\n+\tsuc->quiet = update_data->quiet;\n+\tsuc->dissociate = update_data->dissociate;\n+\tsuc->require_init = update_data->require_init;\n+\tsuc->single_branch = update_data->single_branch;\n+\tsuc->warn_if_uninitialized = update_data->warn_if_uninitialized;\n+\tsuc->list = update_data->list;\n+\tsuc->update = update_data->update_strategy;\n+\tsuc->recommend_shallow = update_data->recommend_shallow;\n+\tif (update_data->depth)\n+\t\tsuc->depth = xstrfmt(\"--depth=%d\", update_data->depth);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstring_list_append(&suc->references, item->string);\n+\t}\n }\n \n static void next_submodule_warn_missing(struct submodule_update_clone *suc,\n@@ -2356,40 +2394,35 @@ static int run_update_command(struct update_data *ud, int subforce)\n \tif (run_command(&cp)) {\n \t\tswitch (ud->update_strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n-\t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tdie_message(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n+\t\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n-\t\t\tprintf(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tdie_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_MERGE:\n-\t\t\tprintf(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t       oid, ud->displaypath);\n+\t\t\tdie_message(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_COMMAND:\n-\t\t\tprintf(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n-\t\t\t       ud->update_strategy.command, oid, ud->displaypath);\n+\t\t\tdie_message(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\t    ud->update_strategy.command, oid, ud->displaypath);\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(\"unexpected update strategy type: %s\",\n \t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t\t}\n-\t\t/*\n-\t\t * NEEDSWORK: We are currently printing to stdout with error\n-\t\t * return so that the shell caller handles the error output\n-\t\t * properly. Once we start handling the error messages within\n-\t\t * C, we should use die() instead.\n-\t\t */\n \t\tif (must_die_on_failure)\n-\t\t\treturn 2;\n-\t\t/*\n-\t\t * This signifies to the caller in shell that the command\n-\t\t * failed without dying\n-\t\t */\n+\t\t\texit(128);\n+\n+\t\t/* the command failed, but update must continue */\n \t\treturn 1;\n \t}\n \n+\tif (ud->quiet)\n+\t\treturn 0;\n+\n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n@@ -2415,7 +2448,7 @@ static int run_update_command(struct update_data *ud, int subforce)\n \treturn 0;\n }\n \n-static int do_run_update_procedure(struct update_data *ud)\n+static int run_update_procedure(struct update_data *ud)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2445,76 +2478,6 @@ static int do_run_update_procedure(struct update_data *ud)\n \treturn run_update_command(ud, subforce);\n }\n \n-static void update_submodule(struct update_clone_data *ucd)\n-{\n-\tfprintf(stdout, \"dummy %s %d\\t%s\\n\",\n-\t\toid_to_hex(&ucd->oid),\n-\t\tucd->just_cloned,\n-\t\tucd->sub->path);\n-}\n-\n-/*\n- * NEEDSWORK: Use a forward declaration to avoid moving\n- * run_update_procedure() (which will be removed soon).\n- */\n-static int update_submodule2(struct update_data *update_data);\n-static int run_update_procedure(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct update_data opt = UPDATE_DATA_INIT;\n-\n-\tstruct option options[] = {\n-\t\tOPT__QUIET(&opt.quiet,\n-\t\t\t   N_(\"suppress output for update by rebase or merge\")),\n-\t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"),\n-\t\t\t   0),\n-\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n-\t\t\t N_(\"don't fetch new objects from the remote site\")),\n-\t\tOPT_BOOL(0, \"just-cloned\", &opt.just_cloned,\n-\t\t\t N_(\"overrides update mode in case the repository is a fresh clone\")),\n-\t\tOPT_INTEGER(0, \"depth\", &opt.depth, N_(\"depth for shallow fetch\")),\n-\t\tOPT_STRING(0, \"prefix\", &opt.prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree\")),\n-\t\tOPT_STRING(0, \"update\", &opt.update_default,\n-\t\t\t   N_(\"string\"),\n-\t\t\t   N_(\"rebase, merge, checkout or none\")),\n-\t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix, N_(\"path\"),\n-\t\t\t   N_(\"path into the working tree, across nested \"\n-\t\t\t      \"submodule boundaries\")),\n-\t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n-\t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n-\t\t\t       parse_opt_object_id),\n-\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n-\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const usage[] = {\n-\t\tN_(\"git submodule--helper run-update-procedure [<options>] <path>\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\n-\tif (argc != 1)\n-\t\tusage_with_options(usage, options);\n-\n-\topt.sm_path = argv[0];\n-\n-\treturn update_submodule2(&opt);\n-}\n-\n-static int resolve_relative_path(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 3)\n-\t\tdie(\"submodule--helper relative-path takes exactly 2 arguments, got %d\", argc);\n-\n-\tprintf(\"%s\", relative_path(argv[1], argv[2], &sb));\n-\tstrbuf_release(&sb);\n-\treturn 0;\n-}\n-\n static const char *remote_submodule_branch(const char *path)\n {\n \tconst struct submodule *sub;\n@@ -2857,8 +2820,53 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \treturn !!ret;\n }\n \n-/* NEEDSWORK: this is a temporary name until we delete update_submodule() */\n-static int update_submodule2(struct update_data *update_data)\n+static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n+{\n+\tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n+\tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n+\t/*\n+\t * NEEDSWORK: the equivalent code in git-submodule.sh does not\n+\t * pass --prefix, so this shouldn't either\n+\t*/\n+\tif (update_data->prefix)\n+\t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n+\tif (update_data->recursive_prefix)\n+\t\tstrvec_pushl(args, \"--recursive-prefix\",\n+\t\t\t     update_data->recursive_prefix, NULL);\n+\tif (update_data->quiet)\n+\t\tstrvec_push(args, \"--quiet\");\n+\tif (update_data->force)\n+\t\tstrvec_push(args, \"--force\");\n+\tif (update_data->init)\n+\t\tstrvec_push(args, \"--init\");\n+\tif (update_data->remote)\n+\t\tstrvec_push(args, \"--remote\");\n+\tif (update_data->nofetch)\n+\t\tstrvec_push(args, \"--no-fetch\");\n+\tif (update_data->dissociate)\n+\t\tstrvec_push(args, \"--dissociate\");\n+\tif (update_data->progress)\n+\t\tstrvec_push(args, \"--progress\");\n+\tif (update_data->require_init)\n+\t\tstrvec_push(args, \"--require-init\");\n+\tif (update_data->depth)\n+\t\tstrvec_pushf(args, \"--depth=%d\", update_data->depth);\n+\tif (update_data->update_default)\n+\t\tstrvec_pushl(args, \"--update\", update_data->update_default, NULL);\n+\tif (update_data->references.nr) {\n+\t\tstruct string_list_item *item;\n+\t\tfor_each_string_list_item(item, &update_data->references)\n+\t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n+\t}\n+\tif (update_data->recommend_shallow == 0)\n+\t\tstrvec_push(args, \"--no-recommend-shallow\");\n+\telse if (update_data->recommend_shallow == 1)\n+\t\tstrvec_push(args, \"--recommend-shallow\");\n+\tif (update_data->single_branch >= 0)\n+\t\tstrvec_push(args, \"--single-branch\");\n+}\n+\n+static int update_submodule(struct update_data *update_data)\n {\n \tchar *prefixed_path;\n \n@@ -2907,18 +2915,55 @@ static int update_submodule2(struct update_data *update_data)\n \t}\n \n \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n-\t\treturn do_run_update_procedure(update_data);\n+\t\tif (run_update_procedure(update_data))\n+\t\t\treturn 1;\n+\n+\tif (update_data->recursive) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct update_data next = *update_data;\n+\t\tint res;\n+\n+\t\tif (update_data->recursive_prefix)\n+\t\t\tprefixed_path = xstrfmt(\"%s%s/\", update_data->recursive_prefix,\n+\t\t\t\t\t\tupdate_data->sm_path);\n+\t\telse\n+\t\t\tprefixed_path = xstrfmt(\"%s/\", update_data->sm_path);\n+\n+\t\tnext.recursive_prefix = get_submodule_displaypath(prefixed_path,\n+\t\t\t\t\t\t\t\t  update_data->prefix);\n+\t\tnext.prefix = NULL;\n+\t\toidcpy(&next.oid, null_oid());\n+\t\toidcpy(&next.suboid, null_oid());\n+\n+\t\tcp.dir = update_data->sm_path;\n+\t\tcp.git_cmd = 1;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tupdate_data_to_args(&next, &cp.args);\n \n-\treturn 3;\n+\t\t/* die() if child process die()'d */\n+\t\tres = run_command(&cp);\n+\t\tif (!res)\n+\t\t\treturn 0;\n+\t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t    update_data->displaypath);\n+\t\tif (res == 128)\n+\t\t\texit(res);\n+\t\telse if (res)\n+\t\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n }\n \n-static int update_submodules(struct submodule_update_clone *suc)\n+static int update_submodules(struct update_data *update_data)\n {\n-\tint i;\n+\tint i, res = 0;\n+\tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n \n-\trun_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,\n+\tupdate_clone_from_update_data(&suc, update_data);\n+\trun_processes_parallel_tr2(suc.max_jobs, update_clone_get_next_task,\n \t\t\t\t   update_clone_start_failure,\n-\t\t\t\t   update_clone_task_finished, suc, \"submodule\",\n+\t\t\t\t   update_clone_task_finished, &suc, \"submodule\",\n \t\t\t\t   \"parallel/update\");\n \n \t/*\n@@ -2929,50 +2974,69 @@ static int update_submodules(struct submodule_update_clone *suc)\n \t *   checkout involve more straightforward sequential I/O.\n \t * - the listener can avoid doing any work if fetching failed.\n \t */\n-\tif (suc->quickstop)\n-\t\treturn 1;\n+\tif (suc.quickstop) {\n+\t\tres = 1;\n+\t\tgoto cleanup;\n+\t}\n \n-\tfor (i = 0; i < suc->update_clone_nr; i++)\n-\t\tupdate_submodule(&suc->update_clone[i]);\n+\tfor (i = 0; i < suc.update_clone_nr; i++) {\n+\t\tstruct update_clone_data ucd = suc.update_clone[i];\n \n-\treturn 0;\n+\t\toidcpy(&update_data->oid, &ucd.oid);\n+\t\tupdate_data->just_cloned = ucd.just_cloned;\n+\t\tupdate_data->sm_path = ucd.sub->path;\n+\n+\t\tif (update_submodule(update_data))\n+\t\t\tres = 1;\n+\t}\n+\n+cleanup:\n+\tstring_list_clear(&update_data->references, 0);\n+\treturn res;\n }\n \n-static int update_clone(int argc, const char **argv, const char *prefix)\n+static int module_update(int argc, const char **argv, const char *prefix)\n {\n-\tconst char *update = NULL;\n \tstruct pathspec pathspec;\n-\tstruct submodule_update_clone opt = SUBMODULE_UPDATE_CLONE_INIT;\n+\tstruct update_data opt = UPDATE_DATA_INIT;\n \n+\t/* NEEDSWORK: update names and strings */\n \tstruct option module_update_clone_options[] = {\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-\t\tOPT_STRING(0, \"prefix\", &prefix,\n+\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n+\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n+\t\tOPT_BOOL(0, \"recursive\", &opt.recursive,\n+\t\t\t N_(\"traverse submodules recursively\")),\n+\t\tOPT_BOOL('N', \"no-fetch\", &opt.nofetch,\n+\t\t\t N_(\"don't fetch new objects from the remote site\")),\n+\t\tOPT_STRING(0, \"prefix\", &opt.prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree\")),\n \t\tOPT_STRING(0, \"recursive-prefix\", &opt.recursive_prefix,\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree, across nested \"\n \t\t\t      \"submodule boundaries\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n+\t\tOPT_STRING(0, \"update\", &opt.update_default,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n \t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n-\t\t\t   N_(\"reference repository\")),\n+\t\t\t\tN_(\"reference repository\")),\n \t\tOPT_BOOL(0, \"dissociate\", &opt.dissociate,\n-\t\t\t   N_(\"use --reference only while cloning\")),\n-\t\tOPT_STRING(0, \"depth\", &opt.depth, \"<depth>\",\n-\t\t\t   N_(\"create a shallow clone truncated to the \"\n-\t\t\t      \"specified number of revisions\")),\n+\t\t\t N_(\"use --reference only while cloning\")),\n+\t\tOPT_INTEGER(0, \"depth\", &opt.depth,\n+\t\t\t    N_(\"create a shallow clone truncated to the \"\n+\t\t\t       \"specified number of revisions\")),\n \t\tOPT_INTEGER('j', \"jobs\", &opt.max_jobs,\n \t\t\t    N_(\"parallel jobs\")),\n \t\tOPT_BOOL(0, \"recommend-shallow\", &opt.recommend_shallow,\n-\t\t\t    N_(\"whether the initial clone should follow the shallow recommendation\")),\n+\t\t\t N_(\"whether the initial clone should follow the shallow recommendation\")),\n \t\tOPT__QUIET(&opt.quiet, N_(\"don't print cloning progress\")),\n \t\tOPT_BOOL(0, \"progress\", &opt.progress,\n-\t\t\t    N_(\"force cloning progress\")),\n+\t\t\t N_(\"force cloning progress\")),\n \t\tOPT_BOOL(0, \"require-init\", &opt.require_init,\n-\t\t\t   N_(\"disallow cloning into non-empty directory\")),\n+\t\t\t N_(\"disallow cloning into non-empty directory\")),\n \t\tOPT_BOOL(0, \"single-branch\", &opt.single_branch,\n \t\t\t N_(\"clone only one branch, HEAD or --branch\")),\n \t\tOPT_END()\n@@ -2982,16 +3046,18 @@ static int update_clone(int argc, const char **argv, const char *prefix)\n \t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n \t\tNULL\n \t};\n-\topt.prefix = prefix;\n \n \tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n \tgit_config(git_update_clone_config, &opt.max_jobs);\n \n \targc = parse_options(argc, argv, prefix, module_update_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n+\toidcpy(&opt.oid, null_oid());\n+\toidcpy(&opt.suboid, null_oid());\n \n-\tif (update)\n-\t\tif (parse_submodule_update_strategy(update, &opt.update) < 0)\n+\tif (opt.update_default)\n+\t\tif (parse_submodule_update_strategy(opt.update_default,\n+\t\t\t\t\t\t    &opt.update_strategy) < 0)\n \t\t\tdie(_(\"bad value for update parameter\"));\n \n \tif (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0)\n@@ -3413,9 +3479,7 @@ static struct cmd_struct commands[] = {\n \t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, 0},\n \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n-\t{\"update-clone\", update_clone, 0},\n-\t{\"run-update-procedure\", run_update_procedure, 0},\n-\t{\"relative-path\", resolve_relative_path, 0},\n+\t{\"update\", module_update, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 3ccf2388bf..d176469fb1 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -50,6 +50,7 @@ single_branch=\n jobs=\n recommend_shallow=\n \n+# NEEDSWORK this is now unused\n die_if_unmatched ()\n {\n \tif test \"$1\" = \"#unmatched\"\n@@ -347,108 +348,28 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\t{\n-\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper update-clone \\\n+\t# NEEDSWORK --super-prefix isn't actually supported by this\n+\t# command - we just pass the $prefix to --recursive-prefix.\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n \t\t${GIT_QUIET:+--quiet} \\\n-\t\t${progress:+\"--progress\"} \\\n+\t\t${force:+--force} \\\n+\t\t${progress:+--progress} \\\n+\t\t${dissociate:+--dissociate} \\\n+\t\t${remote:+--remote} \\\n+\t\t${recursive:+--recursive} \\\n \t\t${init:+--init} \\\n+\t\t${require_init:+--require-init} \\\n+\t\t${nofetch:+--no-fetch} \\\n \t\t${wt_prefix:+--prefix \"$wt_prefix\"} \\\n \t\t${prefix:+--recursive-prefix \"$prefix\"} \\\n \t\t${update:+--update \"$update\"} \\\n \t\t${reference:+\"$reference\"} \\\n-\t\t${dissociate:+\"--dissociate\"} \\\n-\t\t${depth:+--depth \"$depth\"} \\\n-\t\t${require_init:+--require-init} \\\n+\t\t${depth:+\"$depth\"} \\\n \t\t$single_branch \\\n \t\t$recommend_shallow \\\n \t\t$jobs \\\n \t\t-- \\\n-\t\t\"$@\" || echo \"#unmatched\" $?\n-\t} | {\n-\terr=\n-\twhile read -r quickabort sha1 just_cloned sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$quickabort\" \"$sha1\"\n-\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\n-\t\tif test $just_cloned -eq 0\n-\t\tthen\n-\t\t\tjust_cloned=\n-\t\tfi\n-\n-\t\tout=$(git submodule--helper run-update-procedure \\\n-\t\t\t  ${wt_prefix:+--prefix \"$wt_prefix\"} \\\n-\t\t\t  ${GIT_QUIET:+--quiet} \\\n-\t\t\t  ${force:+--force} \\\n-\t\t\t  ${just_cloned:+--just-cloned} \\\n-\t\t\t  ${nofetch:+--no-fetch} \\\n-\t\t\t  ${depth:+\"$depth\"} \\\n-\t\t\t  ${update:+--update \"$update\"} \\\n-\t\t\t  ${prefix:+--recursive-prefix \"$prefix\"} \\\n-\t\t\t  ${sha1:+--oid \"$sha1\"} \\\n-\t\t\t  ${remote:+--remote} \\\n-\t\t\t  \"--\" \\\n-\t\t\t  \"$sm_path\")\n-\n-\t\t# exit codes for run-update-procedure:\n-\t\t# 0: update was successful, say command output\n-\t\t# 1: update procedure failed, but should not die\n-\t\t# 2 or 128: subcommand died during execution\n-\t\t# 3: no update procedure was run\n-\t\tres=\"$?\"\n-\t\tcase $res in\n-\t\t0)\n-\t\t\tsay \"$out\"\n-\t\t\t;;\n-\t\t1)\n-\t\t\terr=\"${err};fatal: $out\"\n-\t\t\tcontinue\n-\t\t\t;;\n-\t\t2|128)\n-\t\t\tdie_with_status $res \"fatal: $out\"\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=$(git submodule--helper relative-path \"$prefix$sm_path/\" \"$wt_prefix\")\n-\t\t\t\twt_prefix=\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_update\n-\t\t\t)\n-\t\t\tres=$?\n-\t\t\tif test $res -gt 0\n-\t\t\tthen\n-\t\t\t\tdie_msg=\"fatal: $(eval_gettext \"Failed to recurse into submodule path '\\$displaypath'\")\"\n-\t\t\t\tif test $res -ne 2\n-\t\t\t\tthen\n-\t\t\t\t\terr=\"${err};$die_msg\"\n-\t\t\t\t\tcontinue\n-\t\t\t\telse\n-\t\t\t\t\tdie_with_status $res \"$die_msg\"\n-\t\t\t\tfi\n-\t\t\tfi\n-\t\tfi\n-\tdone\n-\n-\tif test -n \"$err\"\n-\tthen\n-\t\tOIFS=$IFS\n-\t\tIFS=';'\n-\t\tfor e in $err\n-\t\tdo\n-\t\t\tif test -n \"$e\"\n-\t\t\tthen\n-\t\t\t\techo >&2 \"$e\"\n-\t\t\tfi\n-\t\tdone\n-\t\tIFS=$OIFS\n-\t\texit 1\n-\tfi\n-\t}\n+\t\t\"$@\"\n }\n \n #\n-- \n2.33.GIT\n\n"},{"id":"448125","messageId":"20220210092833.55360-19-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 18/20] fixup! submodule--helper run-update-procedure: remove --suboid","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:31Z","receivedAt":"2022-02-10T09:29:56Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Signed-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 11 ++++-------\n 1 file changed, 4 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b895e88a64..98d8910930 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2886,14 +2886,11 @@ static int update_submodule(struct update_data *update_data)\n \t\t\t\t\t    update_data->sm_path, update_data->update_default,\n \t\t\t\t\t    &update_data->update_strategy);\n \n-\t/* NEEDSWORK: fix the style issues e.g. braces */\n-\tif (update_data->just_cloned) {\n+\tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\n-\t} else {\n-\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n-\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n-\t\t\t    update_data->displaypath);\n-\t}\n+\telse if (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n+\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\tupdate_data->displaypath);\n \n \tif (update_data->remote) {\n \t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n-- \n2.33.GIT\n\n"},{"id":"448126","messageId":"20220210092833.55360-20-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 19/20] fixup! submodule--helper run-update-procedure: learn --remote","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:32Z","receivedAt":"2022-02-10T09:30:06Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Signed-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 19 -------------------\n 1 file changed, 19 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 98d8910930..5d5302b50b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2516,23 +2516,6 @@ static const char *remote_submodule_branch(const char *path)\n \treturn branch;\n }\n \n-static int resolve_remote_submodule_branch(int argc, const char **argv,\n-\t\tconst char *prefix)\n-{\n-\tconst char *ret;\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (argc != 2)\n-\t\tdie(\"submodule--helper remote-branch takes exactly one arguments, got %d\", argc);\n-\n-\tret = remote_submodule_branch(argv[1]);\n-\tif (!ret)\n-\t\tdie(\"submodule %s doesn't exist\", argv[1]);\n-\n-\tprintf(\"%s\", ret);\n-\tstrbuf_release(&sb);\n-\treturn 0;\n-}\n-\n static int push_check(int argc, const char **argv, const char *prefix)\n {\n \tstruct remote *remote;\n@@ -3484,8 +3467,6 @@ static struct cmd_struct commands[] = {\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, 0},\n \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n-\t/* NEEDSWORK: remote-branch is also obsolete */\n-\t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n \t{\"is-active\", is_active, 0},\n-- \n2.33.GIT\n\n"},{"id":"448127","messageId":"20220210092833.55360-21-chooglen@google.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"[PATCH v7 20/20] fixup! submodule: move core cmd_update() logic to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:28:33Z","receivedAt":"2022-02-10T09:30:09Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Signed-off-by: Glen Choo <chooglen@google.com>\n---\n builtin/submodule--helper.c | 13 +++----------\n git-submodule.sh            | 13 +------------\n 2 files changed, 4 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5d5302b50b..3367997973 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2807,12 +2807,6 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n {\n \tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n-\t/*\n-\t * NEEDSWORK: the equivalent code in git-submodule.sh does not\n-\t * pass --prefix, so this shouldn't either\n-\t*/\n-\tif (update_data->prefix)\n-\t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n \tif (update_data->recursive_prefix)\n \t\tstrvec_pushl(args, \"--recursive-prefix\",\n \t\t\t     update_data->recursive_prefix, NULL);\n@@ -2980,8 +2974,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \n-\t/* NEEDSWORK: update names and strings */\n-\tstruct option module_update_clone_options[] = {\n+\tstruct option module_update_options[] = {\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@@ -3023,14 +3016,14 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t};\n \n \tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper update-clone [--prefix=<path>] [<path>...]\"),\n+\t\tN_(\"git submodule--helper update [--prefix=<path>] [<path>...]\"),\n \t\tNULL\n \t};\n \n \tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n \tgit_config(git_update_clone_config, &opt.max_jobs);\n \n-\targc = parse_options(argc, argv, prefix, module_update_clone_options,\n+\targc = parse_options(argc, argv, prefix, module_update_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \toidcpy(&opt.oid, null_oid());\n \toidcpy(&opt.suboid, null_oid());\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex d176469fb1..89f5cf393e 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -50,15 +50,6 @@ single_branch=\n jobs=\n recommend_shallow=\n \n-# NEEDSWORK this is now unused\n-die_if_unmatched ()\n-{\n-\tif test \"$1\" = \"#unmatched\"\n-\tthen\n-\t\texit ${2:-1}\n-\tfi\n-}\n-\n isnumber()\n {\n \tn=$(($1 + 0)) 2>/dev/null && test \"$n\" = \"$1\"\n@@ -348,9 +339,7 @@ cmd_update()\n \t\tshift\n \tdone\n \n-\t# NEEDSWORK --super-prefix isn't actually supported by this\n-\t# command - we just pass the $prefix to --recursive-prefix.\n-\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper update \\\n \t\t${GIT_QUIET:+--quiet} \\\n \t\t${force:+--force} \\\n \t\t${progress:+--progress} \\\n-- \n2.33.GIT\n\n"},{"id":"448128","messageId":"kl6lwni3dpz6.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"20220210092833.55360-18-chooglen@google.com","subject":"Re: [PATCH v7 17/20] submodule: move core cmd_update() logic to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-10T09:34:53Z","receivedAt":"2022-02-10T09:34:58Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"\nHere is the diff between this tree (+) and that of v5's [1] (-).\n\n[1] https://lore.kernel.org/git/patch-v5-9.9-e8e57606ee9-20220128T125206Z-avarab@gmail.com\n\n----- >8 --------- >8 --------- >8 --------- >8 --------- >8 ----\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 1c28b6f479..b895e88a64 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2003,6 +2003,7 @@ struct update_data {\n \tconst char *recursive_prefix;\n \tconst char *sm_path;\n \tconst char *displaypath;\n+\tconst char *update_default;\n \tstruct object_id oid;\n \tstruct object_id suboid;\n \tstruct submodule_update_strategy update_strategy;\n@@ -2355,15 +2356,8 @@ static int run_update_command(struct update_data *ud, int subforce)\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n \tint must_die_on_failure = 0;\n-\tstruct submodule_update_strategy strategy = SUBMODULE_UPDATE_STRATEGY_INIT;\n \n-\tif (ud->update_strategy.type == SM_UPDATE_UNSPECIFIED || ud->just_cloned)\n-\t\tdetermine_submodule_update_strategy(the_repository, ud->just_cloned,\n-\t\t\t\t\t\t    ud->sm_path, NULL, &strategy);\n-\telse\n-\t\tstrategy = ud->update_strategy;\n-\n-\tswitch (strategy.type) {\n+\tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\tcp.git_cmd = 1;\n \t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n@@ -2386,45 +2380,41 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n \t\tcp.use_shell = 1;\n-\t\tstrvec_push(&cp.args, strategy.command);\n+\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n \t\tmust_die_on_failure = 1;\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&strategy));\n+\t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t}\n \tstrvec_push(&cp.args, oid);\n \n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env_array);\n \tif (run_command(&cp)) {\n-\t\tswitch (strategy.type) {\n+\t\tswitch (ud->update_strategy.type) {\n \t\tcase SM_UPDATE_CHECKOUT:\n \t\t\tdie_message(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n \t\t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n-\t\t\tif (!must_die_on_failure)\n-\t\t\t\tbreak;\n-\t\t\tdie(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\tdie_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n \t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_MERGE:\n-\t\t\tif (!must_die_on_failure)\n-\t\t\t\tbreak;\n-\t\t\tdie(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\tdie_message(_(\"Unable to merge '%s' in submodule path '%s'\"),\n \t\t\t    oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_COMMAND:\n-\t\t\tif (!must_die_on_failure)\n-\t\t\t\tbreak;\n-\t\t\tdie(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n-\t\t\t    strategy.command, oid, ud->displaypath);\n+\t\t\tdie_message(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\t    ud->update_strategy.command, oid, ud->displaypath);\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t\t    submodule_strategy_to_string(&strategy));\n+\t\t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t\t}\n+\t\tif (must_die_on_failure)\n+\t\t\texit(128);\n \n \t\t/* the command failed, but update must continue */\n \t\treturn 1;\n@@ -2433,7 +2423,7 @@ static int run_update_command(struct update_data *ud, int subforce)\n \tif (ud->quiet)\n \t\treturn 0;\n \n-\tswitch (strategy.type) {\n+\tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\tprintf(_(\"Submodule path '%s': checked out '%s'\\n\"),\n \t\t       ud->displaypath, oid);\n@@ -2448,11 +2438,11 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tbreak;\n \tcase SM_UPDATE_COMMAND:\n \t\tprintf(_(\"Submodule path '%s': '%s %s'\\n\"),\n-\t\t       ud->displaypath, strategy.command, oid);\n+\t\t       ud->displaypath, ud->update_strategy.command, oid);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected update strategy type: %s\",\n-\t\t    submodule_strategy_to_string(&strategy));\n+\t\t    submodule_strategy_to_string(&ud->update_strategy));\n \t}\n \n \treturn 0;\n@@ -2832,10 +2822,12 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \n static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n {\n-\tconst char *update = submodule_strategy_to_string(&update_data->update_strategy);\n-\n \tstrvec_pushl(args, \"submodule--helper\", \"update\", \"--recursive\", NULL);\n \tstrvec_pushf(args, \"--jobs=%d\", update_data->max_jobs);\n+\t/*\n+\t * NEEDSWORK: the equivalent code in git-submodule.sh does not\n+\t * pass --prefix, so this shouldn't either\n+\t*/\n \tif (update_data->prefix)\n \t\tstrvec_pushl(args, \"--prefix\", update_data->prefix, NULL);\n \tif (update_data->recursive_prefix)\n@@ -2859,8 +2851,8 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \t\tstrvec_push(args, \"--require-init\");\n \tif (update_data->depth)\n \t\tstrvec_pushf(args, \"--depth=%d\", update_data->depth);\n-\tif (update)\n-\t\tstrvec_pushl(args, \"--update\", update, NULL);\n+\tif (update_data->update_default)\n+\t\tstrvec_pushl(args, \"--update\", update_data->update_default, NULL);\n \tif (update_data->references.nr) {\n \t\tstruct string_list_item *item;\n \t\tfor_each_string_list_item(item, &update_data->references)\n@@ -2890,6 +2882,11 @@ static int update_submodule(struct update_data *update_data)\n \t\t\t\t\t\t\t     update_data->prefix);\n \tfree(prefixed_path);\n \n+\tdetermine_submodule_update_strategy(the_repository, update_data->just_cloned,\n+\t\t\t\t\t    update_data->sm_path, update_data->update_default,\n+\t\t\t\t\t    &update_data->update_strategy);\n+\n+\t/* NEEDSWORK: fix the style issues e.g. braces */\n \tif (update_data->just_cloned) {\n \t\toidcpy(&update_data->suboid, null_oid());\n \t} else {\n@@ -3000,10 +2997,10 @@ static int update_submodules(struct update_data *update_data)\n \n static int module_update(int argc, const char **argv, const char *prefix)\n {\n-\tconst char *update = NULL;\n \tstruct pathspec pathspec;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \n+\t/* NEEDSWORK: update names and strings */\n \tstruct option module_update_clone_options[] = {\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n \t\tOPT_BOOL(0, \"init\", &opt.init,\n@@ -3021,7 +3018,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\t\t   N_(\"path\"),\n \t\t\t   N_(\"path into the working tree, across nested \"\n \t\t\t      \"submodule boundaries\")),\n-\t\tOPT_STRING(0, \"update\", &update,\n+\t\tOPT_STRING(0, \"update\", &opt.update_default,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"rebase, merge, checkout or none\")),\n \t\tOPT_STRING_LIST(0, \"reference\", &opt.references, N_(\"repo\"),\n@@ -3058,8 +3055,8 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \toidcpy(&opt.oid, null_oid());\n \toidcpy(&opt.suboid, null_oid());\n \n-\tif (update)\n-\t\tif (parse_submodule_update_strategy(update,\n+\tif (opt.update_default)\n+\t\tif (parse_submodule_update_strategy(opt.update_default,\n \t\t\t\t\t\t    &opt.update_strategy) < 0)\n \t\t\tdie(_(\"bad value for update parameter\"));\n \n@@ -3490,6 +3487,7 @@ static struct cmd_struct commands[] = {\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"deinit\", module_deinit, 0},\n \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n+\t/* NEEDSWORK: remote-branch is also obsolete */\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex bcd8b92aab..d176469fb1 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -50,6 +50,7 @@ single_branch=\n jobs=\n recommend_shallow=\n \n+# NEEDSWORK this is now unused\n die_if_unmatched ()\n {\n \tif test \"$1\" = \"#unmatched\"\n@@ -347,6 +348,8 @@ cmd_update()\n \t\tshift\n \tdone\n \n+\t# NEEDSWORK --super-prefix isn't actually supported by this\n+\t# command - we just pass the $prefix to --recursive-prefix.\n \tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper update \\\n \t\t${GIT_QUIET:+--quiet} \\\n \t\t${force:+--force} \\\n"},{"id":"448296","messageId":"220212.867da0yxga.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"20220210092833.55360-3-chooglen@google.com","subject":"Re: [PATCH v7 02/20] submodule--helper: refactor get_submodule_displaypath()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-12T14:24:11Z","receivedAt":"2022-02-12T14:24:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 10 2022, Glen Choo wrote:\n\n> From: Atharva Raykar <raykar.ath@gmail.com>\n>\n> We create a function called `do_get_submodule_displaypath()` that\n> generates the display path required by several submodule functions, and\n> takes a custom superprefix parameter, instead of reading it from the\n> environment.\n>\n> We then redefine the existing `get_submodule_displaypath()` function\n> as a call to this new function, where the superprefix is obtained from\n> the environment.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/submodule--helper.c | 12 ++++++++----\n>  1 file changed, 8 insertions(+), 4 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 4c7c1e1432..5efceb9d46 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -261,11 +261,8 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n>  \treturn 0;\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 *do_get_submodule_displaypath(const char *path, const char *prefix, const char *super_prefix)\n\nNit: overly long line (also in my v5, but since we're applying some\nfinal polishing touches...)\n"},{"id":"448297","messageId":"220212.8635koyx4d.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"20220210092833.55360-4-chooglen@google.com","subject":"Re: [PATCH v7 03/20] submodule--helper: allow setting superprefix for init_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-12T14:30:51Z","receivedAt":"2022-02-12T14:32:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 10 2022, Glen Choo wrote:\n\n> From: Atharva Raykar <raykar.ath@gmail.com>\n>\n> We allow callers of the `init_submodule()` function to optionally\n> override the superprefix from the environment.\n>\n> We need to enable this option because in our conversion of the update\n> command that will follow, the '--init' option will be handled through\n> this API. We will need to change the superprefix at that time to ensure\n> the display paths show correctly in the output messages.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/submodule--helper.c | 10 +++++++---\n>  1 file changed, 7 insertions(+), 3 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 5efceb9d46..09cda67c1e 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -606,18 +606,22 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n>  \n>  struct init_cb {\n>  \tconst char *prefix;\n> +\tconst char *superprefix;\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   unsigned int flags)\n> +\t\t\t   const char *superprefix, unsigned int flags)\n>  {\n>  \tconst struct submodule *sub;\n>  \tstruct strbuf sb = STRBUF_INIT;\n>  \tchar *upd = NULL, *url = NULL, *displaypath;\n>  \n> -\tdisplaypath = get_submodule_displaypath(path, prefix);\n> +\t/* try superprefix from the environment, if it is not passed explicitly */\n> +\tif (!superprefix)\n> +\t\tsuperprefix = get_super_prefix();\n> +\tdisplaypath = do_get_submodule_displaypath(path, prefix, superprefix);\n>  \n>  \tsub = submodule_from_path(the_repository, null_oid(), path);\n>  \n> @@ -691,7 +695,7 @@ static void init_submodule(const char *path, const char *prefix,\n>  static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n>  {\n>  \tstruct init_cb *info = cb_data;\n> -\tinit_submodule(list_item->name, info->prefix, info->flags);\n> +\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n>  }\n>  \n>  static int module_init(int argc, const char **argv, const char *prefix)\n\nNote/nit on existing (pre this series) code, I wonder why we ended up\nwith this init_submodule() v.s. init_submodule_cb() indirection,\nv.s. just doing:\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 09cda67c1ea..aa82abeb37a 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -611,9 +611,14 @@ struct init_cb {\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 *superprefix, unsigned int flags)\n+static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n+\tconst char *path = list_item->name;\n+\tstruct init_cb *info = cb_data;\n+\tconst char *prefix = info->prefix;\n+\tconst char *superprefix = info->superprefix ? info->superprefix :\n+\t\tget_super_prefix();\n+\tunsigned int flags = info->flags;\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n@@ -692,12 +697,6 @@ static void init_submodule(const char *path, const char *prefix,\n \tfree(upd);\n }\n \n-static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n-{\n-\tstruct init_cb *info = cb_data;\n-\tinit_submodule(list_item->name, info->prefix, info->superprefix, info->flags);\n-}\n-\n static int module_init(int argc, const char **argv, const char *prefix)\n {\n \tstruct init_cb info = INIT_CB_INIT;\n\nMaybe it's worth it to declare the variables in the argument list\nv.s. the function.\n"},{"id":"448298","messageId":"220212.86y22gxig0.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"20220210092833.55360-5-chooglen@google.com","subject":"Re: [PATCH v7 04/20] submodule--helper: run update using child process struct","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-12T14:33:11Z","receivedAt":"2022-02-12T14:34:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 10 2022, Glen Choo wrote:\n\n> From: Atharva Raykar <raykar.ath@gmail.com>\n>\n> We switch to using the run-command API function that takes a\n> 'struct child process', since we are using a lot of the options. This\n> will also make it simple to switch over to using 'capture_command()'\n> when we start handling the output of the command completely in C.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Shourya Shukla <periperidip@gmail.com>\n> Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/submodule--helper.c | 34 ++++++++++++++++------------------\n>  1 file changed, 16 insertions(+), 18 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 09cda67c1e..db71e6f4ec 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2344,47 +2344,45 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n>  \n>  static int run_update_command(struct update_data *ud, int subforce)\n>  {\n> -\tstruct strvec args = STRVEC_INIT;\n> -\tstruct strvec child_env = STRVEC_INIT;\n> +\tstruct child_process cp = CHILD_PROCESS_INIT;\n>  \tchar *oid = oid_to_hex(&ud->oid);\n>  \tint must_die_on_failure = 0;\n> -\tint git_cmd;\n>  \n>  \tswitch (ud->update_strategy.type) {\n>  \tcase SM_UPDATE_CHECKOUT:\n> -\t\tgit_cmd = 1;\n> -\t\tstrvec_pushl(&args, \"checkout\", \"-q\", NULL);\n> +\t\tcp.git_cmd = 1;\n> +\t\tstrvec_pushl(&cp.args, \"checkout\", \"-q\", NULL);\n>  \t\tif (subforce)\n> -\t\t\tstrvec_push(&args, \"-f\");\n> +\t\t\tstrvec_push(&cp.args, \"-f\");\n>  \t\tbreak;\n>  \tcase SM_UPDATE_REBASE:\n> -\t\tgit_cmd = 1;\n> -\t\tstrvec_push(&args, \"rebase\");\n> +\t\tcp.git_cmd = 1;\n> +\t\tstrvec_push(&cp.args, \"rebase\");\n>  \t\tif (ud->quiet)\n> -\t\t\tstrvec_push(&args, \"--quiet\");\n> +\t\t\tstrvec_push(&cp.args, \"--quiet\");\n>  \t\tmust_die_on_failure = 1;\n>  \t\tbreak;\n>  \tcase SM_UPDATE_MERGE:\n> -\t\tgit_cmd = 1;\n> -\t\tstrvec_push(&args, \"merge\");\n> +\t\tcp.git_cmd = 1;\n> +\t\tstrvec_push(&cp.args, \"merge\");\n>  \t\tif (ud->quiet)\n> -\t\t\tstrvec_push(&args, \"--quiet\");\n> +\t\t\tstrvec_push(&cp.args, \"--quiet\");\n>  \t\tmust_die_on_failure = 1;\n>  \t\tbreak;\n>  \tcase SM_UPDATE_COMMAND:\n> -\t\tgit_cmd = 0;\n> -\t\tstrvec_push(&args, ud->update_strategy.command);\n> +\t\tcp.use_shell = 1;\n> +\t\tstrvec_push(&cp.args, ud->update_strategy.command);\n>  \t\tmust_die_on_failure = 1;\n>  \t\tbreak;\n>  \tdefault:\n>  \t\tBUG(\"unexpected update strategy type: %s\",\n>  \t\t    submodule_strategy_to_string(&ud->update_strategy));\n>  \t}\n> -\tstrvec_push(&args, oid);\n> +\tstrvec_push(&cp.args, oid);\n>  \n> -\tprepare_submodule_repo_env(&child_env);\n> -\tif (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL,\n> -\t\t\t\t     ud->sm_path, child_env.v)) {\n> +\tcp.dir = xstrdup(ud->sm_path);\n> +\tprepare_submodule_repo_env(&cp.env_array);\n> +\tif (run_command(&cp)) {\n>  \t\tswitch (ud->update_strategy.type) {\n>  \t\tcase SM_UPDATE_CHECKOUT:\n>  \t\t\tprintf(_(\"Unable to checkout '%s' in submodule path '%s'\"),\n\nIf this series is re-arranged so that this comes first, this compiles\njust fine & passes all tests.\n\nSo I wonder if we can peel this and perhaps other such easy to review\nprep changes off into its own series, since this one has grown to 20\npatches.\n\nWe could then hopefully fast-track those easy-to-review prep changes,\nwhich would make the \"real\" series to follow smaller and easier to\nreview/grok.\n"},{"id":"448299","messageId":"220212.86tud4xicm.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"20220210092833.55360-10-chooglen@google.com","subject":"Re: [PATCH v7 09/20] submodule--helper: remove update-module-mode","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-12T14:35:12Z","receivedAt":"2022-02-12T14:36:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 10 2022, Glen Choo wrote:\n\n> This is dead code - it has not been used since c51f8f94e5\n> (submodule--helper: run update procedures from C, 2021-08-24).\n>\n> Signed-off-by: Glen Choo <chooglen@google.com>\n> ---\n>  builtin/submodule--helper.c | 24 ------------------------\n>  1 file changed, 24 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 4a0890954e..e0cc1c1b79 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -1965,29 +1965,6 @@ static void determine_submodule_update_strategy(struct repository *r,\n>  \tfree(key);\n>  }\n>  \n> -static int module_update_module_mode(int argc, const char **argv, const char *prefix)\n> -{\n> -\tconst char *path, *update = NULL;\n> -\tint just_cloned;\n> -\tstruct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };\n> -\n> -\tif (argc < 3 || argc > 4)\n> -\t\tdie(\"submodule--helper update-module-clone expects <just-cloned> <path> [<update>]\");\n> -\n> -\tjust_cloned = git_config_int(\"just_cloned\", argv[1]);\n> -\tpath = argv[2];\n> -\n> -\tif (argc == 4)\n> -\t\tupdate = argv[3];\n> -\n> -\tdetermine_submodule_update_strategy(the_repository,\n> -\t\t\t\t\t    just_cloned, path, update,\n> -\t\t\t\t\t    &update_strategy);\n> -\tfputs(submodule_strategy_to_string(&update_strategy), stdout);\n> -\n> -\treturn 0;\n> -}\n> -\n>  struct update_clone_data {\n>  \tconst struct submodule *sub;\n>  \tstruct object_id oid;\n> @@ -3388,7 +3365,6 @@ static struct cmd_struct commands[] = {\n>  \t{\"name\", module_name, 0},\n>  \t{\"clone\", module_clone, 0},\n>  \t{\"add\", module_add, SUPPORT_SUPER_PREFIX},\n> -\t{\"update-module-mode\", module_update_module_mode, 0},\n>  \t{\"update-clone\", update_clone, 0},\n>  \t{\"run-update-procedure\", run_update_procedure, 0},\n>  \t{\"ensure-core-worktree\", ensure_core_worktree, 0},\n\nNice catch!\n\nRe my comment on 04/20 in <220212.86y22gxig0.gmgdl@evledraar.gmail.com>\nat least 04..09/20 could be split into such a \"trivial refactors for\nlater changes\" series, and it would make sense to lead with this (and\nany other deletions of already-dead code).\n"},{"id":"448300","messageId":"220212.86pmnsxi6e.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"20220210092833.55360-13-chooglen@google.com","subject":"Re: [PATCH v7 12/20] submodule--helper run-update-procedure: learn --remote","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-12T14:38:23Z","receivedAt":"2022-02-12T14:39:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 10 2022, Glen Choo wrote:\n\n>  #define UPDATE_DATA_INIT { \\\n>  \t.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \\\n> @@ -2585,6 +2571,8 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)\n>  \t\tOPT_CALLBACK_F(0, \"oid\", &opt.oid, N_(\"sha1\"),\n>  \t\t\t       N_(\"SHA1 expected by superproject\"), PARSE_OPT_NONEG,\n>  \t\t\t       parse_opt_object_id),\n> +\t\tOPT_BOOL(0, \"remote\", &opt.remote,\n> +\t\t\t N_(\"use SHA-1 of submodule's remote tracking branch\")),\n\nFor some things the references to SHA-1 are faithfully copying existing\ntest, but for new things let's use \"object\" instead.\n"},{"id":"448301","messageId":"220212.86leygxi3t.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"20220210092833.55360-16-chooglen@google.com","subject":"Re: [PATCH v7 15/20] submodule--helper: move functions around","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-12T14:41:07Z","receivedAt":"2022-02-12T14:41:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 10 2022, Glen Choo wrote:\n\n> A subsequent commit will change the internals of several functions and\n> arrange them in a more logical manner. Move these functions to their\n> final positions so that the diff is smaller.\n\nShouldn't we do this earlier & avoid the FIXME comment in 10/20? (maybe\na subsequent fixup addresses it, haven't checked...)\n"},{"id":"448302","messageId":"220212.86h794xi0u.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"20220210092833.55360-19-chooglen@google.com","subject":"Re: [PATCH v7 18/20] fixup! submodule--helper run-update-procedure: remove --suboid","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-12T14:41:45Z","receivedAt":"2022-02-12T14:43:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 10 2022, Glen Choo wrote:\n\n> Signed-off-by: Glen Choo <chooglen@google.com>\n> ---\n>  builtin/submodule--helper.c | 11 ++++-------\n>  1 file changed, 4 insertions(+), 7 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index b895e88a64..98d8910930 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2886,14 +2886,11 @@ static int update_submodule(struct update_data *update_data)\n>  \t\t\t\t\t    update_data->sm_path, update_data->update_default,\n>  \t\t\t\t\t    &update_data->update_strategy);\n>  \n> -\t/* NEEDSWORK: fix the style issues e.g. braces */\n> -\tif (update_data->just_cloned) {\n> +\tif (update_data->just_cloned)\n>  \t\toidcpy(&update_data->suboid, null_oid());\n> -\t} else {\n> -\t\tif (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n> -\t\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n> -\t\t\t    update_data->displaypath);\n> -\t}\n> +\telse if (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n> +\t\tdie(_(\"Unable to find current revision in submodule path '%s'\"),\n> +\t\t\tupdate_data->displaypath);\n>  \n>  \tif (update_data->remote) {\n>  \t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n\nThis fixup looks good, let's apply this fix-up to the relevant preceding\ncommit.\n"},{"id":"448303","messageId":"220212.86czjsxi06.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"20220210092833.55360-20-chooglen@google.com","subject":"Re: [PATCH v7 19/20] fixup! submodule--helper run-update-procedure: learn --remote","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-12T14:43:22Z","receivedAt":"2022-02-12T14:43:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 10 2022, Glen Choo wrote:\n\n> Signed-off-by: Glen Choo <chooglen@google.com>\n> ---\n>  builtin/submodule--helper.c | 19 -------------------\n>  1 file changed, 19 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 98d8910930..5d5302b50b 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2516,23 +2516,6 @@ static const char *remote_submodule_branch(const char *path)\n>  \treturn branch;\n>  }\n>  \n> -static int resolve_remote_submodule_branch(int argc, const char **argv,\n> -\t\tconst char *prefix)\n> -{\n> -\tconst char *ret;\n> -\tstruct strbuf sb = STRBUF_INIT;\n> -\tif (argc != 2)\n> -\t\tdie(\"submodule--helper remote-branch takes exactly one arguments, got %d\", argc);\n> -\n> -\tret = remote_submodule_branch(argv[1]);\n> -\tif (!ret)\n> -\t\tdie(\"submodule %s doesn't exist\", argv[1]);\n> -\n> -\tprintf(\"%s\", ret);\n> -\tstrbuf_release(&sb);\n> -\treturn 0;\n> -}\n> -\n>  static int push_check(int argc, const char **argv, const char *prefix)\n>  {\n>  \tstruct remote *remote;\n> @@ -3484,8 +3467,6 @@ static struct cmd_struct commands[] = {\n>  \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n>  \t{\"deinit\", module_deinit, 0},\n>  \t{\"summary\", module_summary, SUPPORT_SUPER_PREFIX},\n> -\t/* NEEDSWORK: remote-branch is also obsolete */\n> -\t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n>  \t{\"push-check\", push_check, 0},\n>  \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n>  \t{\"is-active\", is_active, 0},\n\nDitto good fix-up, should squash this into the relevant commit.\n"},{"id":"448304","messageId":"220212.868rugxhq0.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-12T14:45:00Z","receivedAt":"2022-02-12T14:49:55Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 10 2022, Glen Choo wrote:\n\n> This reroll contains another 'easy' preparatory patch and the fixups I\n> alluded to in v6 [1]. This isn't the split-up I described in the\n> footnote of v6, but it gets the big patch (patch 17) to what I think is\n> a reviewable state.\n>\n> The diff between v7 and v5 is no longer just NEEDSWORK comments, but I\n> think it is easier to reason about. Patch 17 resembles v5 the most (I\n> will include a diff in a reply to that patch); everything after patch 17\n> is fixups (I did not squash them in because they would grow the diff\n> even more).\n>\n> I will also leave a review on patch 17 since the changes were not\n> originally authored by me.\n>\n> [1] https://lore.kernel.org/git/20220208083952.35036-1-chooglen@google.com\n>\n> Changes in v7:\n> - Split the last patch of v6 (the big one) into patches 16-17.\n> - Patch 16 moves logic out of run_update_procedure() (because the\n>   command is going away), removing some noise from patch 17. This makes\n>   the update_strategy parsing easier to reason about, but at the cost of\n>   growing the diff vis-a-vis v5\n> - Patches 18-20 are fixups that address NEEDSWORK comments from earlier\n>   patches. Once maintaining a small diff vis-a-vis v5 stops making\n>   sense, I will squash them in.\n>\n> Atharva Raykar (6):\n>   submodule--helper: get remote names from any repository\n>   submodule--helper: refactor get_submodule_displaypath()\n>   submodule--helper: allow setting superprefix for init_submodule()\n>   submodule--helper: run update using child process struct\n>   builtin/submodule--helper.c: reformat designated initializers\n>   submodule: move core cmd_update() logic to C\n>\n> Glen Choo (11):\n>   submodule--helper: remove update-module-mode\n>   submodule--helper: reorganize code for sh to C conversion\n>   submodule--helper run-update-procedure: remove --suboid\n>   submodule--helper run-update-procedure: learn --remote\n>   submodule--helper: remove ensure-core-worktree\n>   submodule--helper update-clone: learn --init\n>   submodule--helper: move functions around\n>   submodule--helper: reduce logic in run_update_procedure()\n>   fixup! submodule--helper run-update-procedure: remove --suboid\n>   fixup! submodule--helper run-update-procedure: learn --remote\n>   fixup! submodule: move core cmd_update() logic to C\n>\n> Ævar Arnfjörð Bjarmason (3):\n>   builtin/submodule--helper.c: rename option variables to \"opt\"\n>   submodule--helper: don't use bitfield indirection for parse_options()\n>   submodule tests: test for init and update failure output\n\nThanks a lot for picking this up! This split-up is much easier to read\nthan my v5, particularly with the end diff-stat of the \"main\" patch\nbeing:\n\n 2 files changed, 201 insertions(+), 216 deletions(-)\n\nInstead of:\n\n 2 files changed, 356 insertions(+), 388 deletions(-)\n\nI think sending a version of this with the fixups squashed in as a v8\nwould be good, and perhaps addressing some of my comments.\n\nI don't know if my suggested split-up of \"prep fixes\" into another\nseries would be a good thing to pursue overall, perhaps Junio will chime\nin on how he'd be most comfortable in merging this down. I'd think\nsplitting such trivial fixes into their own series be easier to review,\nbut perhaps not.\n\nFor the Signed-off-by question on v6, I think you should add your SOB to\nall the patches you submit. See this in SubmittingPatches:\n    \n    Notice that you can place your own `Signed-off-by` trailer when\n    forwarding somebody else's patch with the above rules for\n    D-C-O.  Indeed you are encouraged to do so.\n\nJust running \"git rebase -i -x 'git commit --amend --no-edit -s'\" should\ndo it.\n    \n"},{"id":"448334","messageId":"xmqqv8xj71mt.fsf@gitster.g","threadId":"56453","inReplyTo":"20220210092833.55360-1-chooglen@google.com","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-02-13T05:54:02Z","receivedAt":"2022-02-13T05:54:10Z","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> This reroll contains another 'easy' preparatory patch and the fixups I\n> alluded to in v6 [1]. This isn't the split-up I described in the\n> footnote of v6, but it gets the big patch (patch 17) to what I think is\n> a reviewable state.\n\nThanks.\n\nThis seems to heavily conflict with \"clone, submodule: pass partial\nclone filters to submodules, 2022-02-04\" by Josh Steadmon\n<690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>\nin both builtins/submodule--helper.c and git-submodule.sh.\n\nIt also removes the code that \"submodule: record superproject gitdir\nduring 'update', 2022-02-03\" by Emily Shaffer\n<20220203215914.683922-5-emilyshaffer@google.com>, so what the other\ntopic ends up adding to the shell script needs to eventually be\nredone in the C code.\n\nI think \"superproject aware\" topic would see a reroll due to a\nslight redesign.  I am not sure how solid the design of the\n\"pass down partial clone filter\" topic is at this moment.\n\nI may try to eject them tentatively and see how well this topic\nplays with the rest of the topics in flight.\n\nThanks.\n\n\n"},{"id":"448335","messageId":"xmqqr18770pc.fsf@gitster.g","threadId":"56453","inReplyTo":"xmqqv8xj71mt.fsf@gitster.g","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-02-13T06:14:07Z","receivedAt":"2022-02-13T06:14:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Glen Choo <chooglen@google.com> writes:\n>\n>> This reroll contains another 'easy' preparatory patch and the fixups I\n>> alluded to in v6 [1]. This isn't the split-up I described in the\n>> footnote of v6, but it gets the big patch (patch 17) to what I think is\n>> a reviewable state.\n>\n> Thanks.\n>\n> This seems to heavily conflict with \"clone, submodule: pass partial\n> clone filters to submodules, 2022-02-04\" by Josh Steadmon\n> <690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>\n> in both builtins/submodule--helper.c and git-submodule.sh.\n>\n> It also removes the code that \"submodule: record superproject gitdir\n> during 'update', 2022-02-03\" by Emily Shaffer\n> <20220203215914.683922-5-emilyshaffer@google.com>, so what the other\n> topic ends up adding to the shell script needs to eventually be\n> redone in the C code.\n>\n> I think \"superproject aware\" topic would see a reroll due to a\n> slight redesign.  I am not sure how solid the design of the\n> \"pass down partial clone filter\" topic is at this moment.\n>\n> I may try to eject them tentatively and see how well this topic\n> plays with the rest of the topics in flight.\n>\n> Thanks.\n\nI can merge this to seen minus the above two topics and get it\ncompile, but it also seems to have some interaction with 961b130d\n(branch: add --recurse-submodules option for branch creation,\n2022-01-28) and makes the t3207, tests added by that other topic,\nfail X-<.\n\n\n\n\n\n\n\n\n"},{"id":"448364","messageId":"kl6la6et76bb.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"xmqqr18770pc.fsf@gitster.g","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-14T16:37:28Z","receivedAt":"2022-02-14T16:37:56Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> This seems to heavily conflict with \"clone, submodule: pass partial\n>> clone filters to submodules, 2022-02-04\" by Josh Steadmon\n>> <690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>\n>> in both builtins/submodule--helper.c and git-submodule.sh.\n>>\n>> It also removes the code that \"submodule: record superproject gitdir\n>> during 'update', 2022-02-03\" by Emily Shaffer\n>> <20220203215914.683922-5-emilyshaffer@google.com>, so what the other\n>> topic ends up adding to the shell script needs to eventually be\n>> redone in the C code.\n>>\n>> I think \"superproject aware\" topic would see a reroll due to a\n>> slight redesign.  I am not sure how solid the design of the\n>> \"pass down partial clone filter\" topic is at this moment.\n\nHm, I haven't looked at where the conflicts are yet, but I'll get to it\nas I'm reviewing the rest of the feedback.\n\nAnd on that note, what do you think of Ævar's suggestion to split off\nthe 'easy to review' and 'obvious' patches into their own preparatory\nseries? I wonder if this would make it harder or easier to manage the\nconflicts.\n\n> I can merge this to seen minus the above two topics and get it\n> compile, but it also seems to have some interaction with 961b130d\n> (branch: add --recurse-submodules option for branch creation,\n> 2022-01-28) and makes the t3207, tests added by that other topic,\n> fail X-<.\n\nOof, that's embarrassing of me, let me take a look at that. There's a\nnontrivial chance that the \"branch --recurse-submodules\" tests caught an\nactual regression.\n"},{"id":"448369","messageId":"220214.86h791xsza.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"kl6la6et76bb.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-14T17:19:53Z","receivedAt":"2022-02-14T17:23:27Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Feb 15 2022, Glen Choo wrote:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>>> This seems to heavily conflict with \"clone, submodule: pass partial\n>>> clone filters to submodules, 2022-02-04\" by Josh Steadmon\n>>> <690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>\n>>> in both builtins/submodule--helper.c and git-submodule.sh.\n>>>\n>>> It also removes the code that \"submodule: record superproject gitdir\n>>> during 'update', 2022-02-03\" by Emily Shaffer\n>>> <20220203215914.683922-5-emilyshaffer@google.com>, so what the other\n>>> topic ends up adding to the shell script needs to eventually be\n>>> redone in the C code.\n>>>\n>>> I think \"superproject aware\" topic would see a reroll due to a\n>>> slight redesign.  I am not sure how solid the design of the\n>>> \"pass down partial clone filter\" topic is at this moment.\n>\n> Hm, I haven't looked at where the conflicts are yet, but I'll get to it\n> as I'm reviewing the rest of the feedback.\n\nTo save you some time, my v4 CL summarizes the semantic conflict between\nthe two:\nhttps://lore.kernel.org/git/cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com/\n\nI.e. Atharva Raykar had working C code to do what an older version of\nthat superproject config series was doing, but the semantics changed in\na later version. It needs some new usage of path.c (or similar) API\nadjusted, but I didn't (and still don't) have time to look into it.\n\n> [...]\n>> I can merge this to seen minus the above two topics and get it\n>> compile, but it also seems to have some interaction with 961b130d\n>> (branch: add --recurse-submodules option for branch creation,\n>> 2022-01-28) and makes the t3207, tests added by that other topic,\n>> fail X-<.\n>\n> Oof, that's embarrassing of me, let me take a look at that. There's a\n> nontrivial chance that the \"branch --recurse-submodules\" tests caught an\n> actual regression.\n\nFWIW one thing I did as an extra sanity check was to run the whole test\nsuite with --tee with/without this series (or rather, my earlier\nversion), and diffing the full test-results output (which you'll need to\nsave in-between the two runs, and IIRC hack t/Makefile to stop removing\nit on successful runs).\n\nThere's a lot of differences in output due to general issues in the test\nsuite output not being reproducable (writing timestamps etc.), but I\ncould not find any issues with the \"git submodule\" output being\ndifferent, of course we may not have tests, or it may be piped to\n/dev/null....\n\nBut I've found it to be a helpful additional validation technique for\nthis series & others where I'm not as confident in the test coverage.\n\n"},{"id":"448372","messageId":"xmqq1r054aiw.fsf@gitster.g","threadId":"56453","inReplyTo":"kl6la6et76bb.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-02-14T17:34:47Z","receivedAt":"2022-02-14T17:34:54Z","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> Hm, I haven't looked at where the conflicts are yet, but I'll get to it\n> as I'm reviewing the rest of the feedback.\n>\n> And on that note, what do you think of Ævar's suggestion to split off\n> the 'easy to review' and 'obvious' patches into their own preparatory\n> series? I wonder if this would make it harder or easier to manage the\n> conflicts.\n\nIt depends on how small an interaction the \"obvious and easy\" part\nhas with topics in flight.  In the best case, if there aren't any\nthe preparatory series may even graduate before the other topics\nthat interfere with the main part of this series becomes ready.\n\nIn a worse case, what the preparatory work to lay more solid\nfoundation wants to do may contradict what some of these topics in\nflight want to do.  Such semantic conflicts need to be resolved\nbefore the main part (and these interfering topics) can move\nforward, and with \"split off\", the core of the contradicting wish\nmay become easier to see and what needs to be resolved may become\nclearer.\n\nSo, I do not think of a way for such a split to make things harder\nfor later.  Of course, the \"easy to review\" and \"obvious\" part has\nto be justifiable on its own, i.e. \"a larger series wants to build\non this foundation and for it to work this part must be done in this\nway\", when the other topics wants to do the part in question\ndifferently, becomes a much weaker justification.  But if it is\ntruly \"obvious\", it is unlikely that the benefit of the change\nbecomes harder to justify.\n\n"},{"id":"448425","messageId":"kl6l35kk79xn.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"xmqq1r054aiw.fsf@gitster.g","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-15T09:31:32Z","receivedAt":"2022-02-15T09:31:51Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Glen Choo <chooglen@google.com> writes:\n>\n>> Hm, I haven't looked at where the conflicts are yet, but I'll get to it\n>> as I'm reviewing the rest of the feedback.\n>>\n>> And on that note, what do you think of Ævar's suggestion to split off\n>> the 'easy to review' and 'obvious' patches into their own preparatory\n>> series? I wonder if this would make it harder or easier to manage the\n>> conflicts.\n>\n> It depends on how small an interaction the \"obvious and easy\" part\n> has with topics in flight.  In the best case, if there aren't any\n> the preparatory series may even graduate before the other topics\n> that interfere with the main part of this series becomes ready.\n>\n> In a worse case, what the preparatory work to lay more solid\n> foundation wants to do may contradict what some of these topics in\n> flight want to do.  Such semantic conflicts need to be resolved\n> before the main part (and these interfering topics) can move\n> forward, and with \"split off\", the core of the contradicting wish\n> may become easier to see and what needs to be resolved may become\n> clearer.\n>\n> So, I do not think of a way for such a split to make things harder\n> for later.  Of course, the \"easy to review\" and \"obvious\" part has\n> to be justifiable on its own, i.e. \"a larger series wants to build\n> on this foundation and for it to work this part must be done in this\n> way\", when the other topics wants to do the part in question\n> differently, becomes a much weaker justification.  But if it is\n> truly \"obvious\", it is unlikely that the benefit of the change\n> becomes harder to justify.\n\nThanks for sharing your thought process. That makes sense, I'll do\nthat :)\n"},{"id":"448426","messageId":"kl6lzgms5v80.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"220214.86h791xsza.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-15T09:34:38Z","receivedAt":"2022-02-15T09:34:44Z","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 Tue, Feb 15 2022, Glen Choo wrote:\n>\n>> Junio C Hamano <gitster@pobox.com> writes:\n>>\n>>>> This seems to heavily conflict with \"clone, submodule: pass partial\n>>>> clone filters to submodules, 2022-02-04\" by Josh Steadmon\n>>>> <690d2316ad518ea4551821b2b3aa652996858475.1644034886.git.steadmon@google.com>\n>>>> in both builtins/submodule--helper.c and git-submodule.sh.\n>>>>\n>>>> It also removes the code that \"submodule: record superproject gitdir\n>>>> during 'update', 2022-02-03\" by Emily Shaffer\n>>>> <20220203215914.683922-5-emilyshaffer@google.com>, so what the other\n>>>> topic ends up adding to the shell script needs to eventually be\n>>>> redone in the C code.\n>>>>\n>>>> I think \"superproject aware\" topic would see a reroll due to a\n>>>> slight redesign.  I am not sure how solid the design of the\n>>>> \"pass down partial clone filter\" topic is at this moment.\n>>\n>> Hm, I haven't looked at where the conflicts are yet, but I'll get to it\n>> as I'm reviewing the rest of the feedback.\n>\n> To save you some time, my v4 CL summarizes the semantic conflict between\n> the two:\n> https://lore.kernel.org/git/cover-v4-0.7-00000000000-20220127T143552Z-avarab@gmail.com/\n>\n> I.e. Atharva Raykar had working C code to do what an older version of\n> that superproject config series was doing, but the semantics changed in\n> a later version. It needs some new usage of path.c (or similar) API\n> adjusted, but I didn't (and still don't) have time to look into it.\n\nAh, thanks for the reminder. That should help.\n\n>>> I can merge this to seen minus the above two topics and get it\n>>> compile, but it also seems to have some interaction with 961b130d\n>>> (branch: add --recurse-submodules option for branch creation,\n>>> 2022-01-28) and makes the t3207, tests added by that other topic,\n>>> fail X-<.\n>>\n>> Oof, that's embarrassing of me, let me take a look at that. There's a\n>> nontrivial chance that the \"branch --recurse-submodules\" tests caught an\n>> actual regression.\n>\n> FWIW one thing I did as an extra sanity check was to run the whole test\n> suite with --tee with/without this series (or rather, my earlier\n> version), and diffing the full test-results output (which you'll need to\n> save in-between the two runs, and IIRC hack t/Makefile to stop removing\n> it on successful runs).\n>\n> There's a lot of differences in output due to general issues in the test\n> suite output not being reproducable (writing timestamps etc.), but I\n> could not find any issues with the \"git submodule\" output being\n> different, of course we may not have tests, or it may be piped to\n> /dev/null....\n>\n> But I've found it to be a helpful additional validation technique for\n> this series & others where I'm not as confident in the test coverage.\n\nThanks for the tip! I hadn't considered trying this, but this makes a\nlot of sense. I can see this being even more useful for this series\nsince it's supposed to be a faithful conversion of sh->c.\n"},{"id":"448427","messageId":"kl6lwnhw5umo.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"kl6la6et76bb.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-15T09:47:27Z","receivedAt":"2022-02-15T09:47:36Z","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> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> I can merge this to seen minus the above two topics and get it\n>> compile, but it also seems to have some interaction with 961b130d\n>> (branch: add --recurse-submodules option for branch creation,\n>> 2022-01-28) and makes the t3207, tests added by that other topic,\n>> fail X-<.\n>\n> Oof, that's embarrassing of me, let me take a look at that. There's a\n> nontrivial chance that the \"branch --recurse-submodules\" tests caught an\n> actual regression.\n\nLooks like this is the case - t3207 caught a regression in how \"git\nsubmodule update\" sets the refspec of nested submodules.\n\nLooks like our concerns about the test suite are well-founded..\n"},{"id":"448660","messageId":"kl6l4k4y59p4.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"220212.868rugxhq0.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-17T05:44:07Z","receivedAt":"2022-02-17T05:44:13Z","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 Thu, Feb 10 2022, Glen Choo wrote:\n>\n>> Atharva Raykar (6):\n>>   submodule--helper: get remote names from any repository\n>>   submodule--helper: refactor get_submodule_displaypath()\n>>   submodule--helper: allow setting superprefix for init_submodule()\n>>   submodule--helper: run update using child process struct\n>>   builtin/submodule--helper.c: reformat designated initializers\n>>   submodule: move core cmd_update() logic to C\n>>\n>> Glen Choo (11):\n>>   submodule--helper: remove update-module-mode\n>>   submodule--helper: reorganize code for sh to C conversion\n>>   submodule--helper run-update-procedure: remove --suboid\n>>   submodule--helper run-update-procedure: learn --remote\n>>   submodule--helper: remove ensure-core-worktree\n>>   submodule--helper update-clone: learn --init\n>>   submodule--helper: move functions around\n>>   submodule--helper: reduce logic in run_update_procedure()\n>>   fixup! submodule--helper run-update-procedure: remove --suboid\n>>   fixup! submodule--helper run-update-procedure: learn --remote\n>>   fixup! submodule: move core cmd_update() logic to C\n>>\n>> Ævar Arnfjörð Bjarmason (3):\n>>   builtin/submodule--helper.c: rename option variables to \"opt\"\n>>   submodule--helper: don't use bitfield indirection for parse_options()\n>>   submodule tests: test for init and update failure output\n>\n> I think sending a version of this with the fixups squashed in as a v8\n> would be good, and perhaps addressing some of my comments.\n>\n> I don't know if my suggested split-up of \"prep fixes\" into another\n> series would be a good thing to pursue overall, perhaps Junio will chime\n> in on how he'd be most comfortable in merging this down. I'd think\n> splitting such trivial fixes into their own series be easier to review,\n> but perhaps not.\n\nCombing through the patches again, I couldn't really convince myself\nthat the patch 4..9 prep fixes make sense as obvious standalone fixes,\nexcept maybe:\n\n- patch 4 submodule--helper: run update using child process struct\n- patch 8 submodule tests: test for init and update failure output\n- patch 9:  087bf43aba submodule--helper: remove update-module-mode\n\nBut, since the 'final' patch (ignoring the fixup!-s) is consuming a huge\nchunk of the work anyway, here's an alternative patch organization with\nthe fixup!-s squashed:\n\n= Move 'easy' and 'obviously correct' code from sh->C\n- patches 8-9   Cleanup and introduce tests\n- patches 1-4   Refactor existing functions, which enables..\n- patches 10-14 Move 'obviously correct' pieces of logic from sh-> C\n\n= Finalize move from sh->C\ni.e. combine \"run-update-procedure\" and \"update-clone\" into \"update\"\n- patches 5,7     Cleanup and prep\n- patches 6,15-16 Shrinking the diff\n- patch 17        Implement \"git submodule--helper update\" \n\nI'll send this if there are no objections :)\n"},{"id":"448672","messageId":"220217.86r181j1g3.gmgdl@evledraar.gmail.com","threadId":"56453","inReplyTo":"kl6l4k4y59p4.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-17T09:17:08Z","receivedAt":"2022-02-17T09:18:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Feb 17 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> On Thu, Feb 10 2022, Glen Choo wrote:\n>>\n>>> Atharva Raykar (6):\n>>>   submodule--helper: get remote names from any repository\n>>>   submodule--helper: refactor get_submodule_displaypath()\n>>>   submodule--helper: allow setting superprefix for init_submodule()\n>>>   submodule--helper: run update using child process struct\n>>>   builtin/submodule--helper.c: reformat designated initializers\n>>>   submodule: move core cmd_update() logic to C\n>>>\n>>> Glen Choo (11):\n>>>   submodule--helper: remove update-module-mode\n>>>   submodule--helper: reorganize code for sh to C conversion\n>>>   submodule--helper run-update-procedure: remove --suboid\n>>>   submodule--helper run-update-procedure: learn --remote\n>>>   submodule--helper: remove ensure-core-worktree\n>>>   submodule--helper update-clone: learn --init\n>>>   submodule--helper: move functions around\n>>>   submodule--helper: reduce logic in run_update_procedure()\n>>>   fixup! submodule--helper run-update-procedure: remove --suboid\n>>>   fixup! submodule--helper run-update-procedure: learn --remote\n>>>   fixup! submodule: move core cmd_update() logic to C\n>>>\n>>> Ævar Arnfjörð Bjarmason (3):\n>>>   builtin/submodule--helper.c: rename option variables to \"opt\"\n>>>   submodule--helper: don't use bitfield indirection for parse_options()\n>>>   submodule tests: test for init and update failure output\n>>\n>> I think sending a version of this with the fixups squashed in as a v8\n>> would be good, and perhaps addressing some of my comments.\n>>\n>> I don't know if my suggested split-up of \"prep fixes\" into another\n>> series would be a good thing to pursue overall, perhaps Junio will chime\n>> in on how he'd be most comfortable in merging this down. I'd think\n>> splitting such trivial fixes into their own series be easier to review,\n>> but perhaps not.\n>\n> Combing through the patches again, I couldn't really convince myself\n> that the patch 4..9 prep fixes make sense as obvious standalone fixes,\n> except maybe:\n>\n> - patch 4 submodule--helper: run update using child process struct\n> - patch 8 submodule tests: test for init and update failure output\n> - patch 9:  087bf43aba submodule--helper: remove update-module-mode\n>\n> But, since the 'final' patch (ignoring the fixup!-s) is consuming a huge\n> chunk of the work anyway, here's an alternative patch organization with\n> the fixup!-s squashed:\n>\n> = Move 'easy' and 'obviously correct' code from sh->C\n> - patches 8-9   Cleanup and introduce tests\n> - patches 1-4   Refactor existing functions, which enables..\n> - patches 10-14 Move 'obviously correct' pieces of logic from sh-> C\n>\n> = Finalize move from sh->C\n> i.e. combine \"run-update-procedure\" and \"update-clone\" into \"update\"\n> - patches 5,7     Cleanup and prep\n> - patches 6,15-16 Shrinking the diff\n> - patch 17        Implement \"git submodule--helper update\" \n>\n> I'll send this if there are no objections :)\n\nYes that sounds good, or rather, I haven't re-looked at that in detail,\nbut I think if you think it makes sense we should go for it.\n\nOr rather, we should really be aiming to produce a patch series that\nmakes sense in its current iteration, as opposed to optimizing for a\ndiff against some ad-hoc re-roll I produced a few versions ago :)\n\nThanks again for working on this & picking this up. It's great to see\nprogress in this area!\n"},{"id":"448713","messageId":"kl6l1r015v3k.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"56453","inReplyTo":"220217.86r181j1g3.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v7 00/20] submodule: convert the rest of 'update' to C","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-02-17T16:14:07Z","receivedAt":"2022-02-17T16:14: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> On Thu, Feb 17 2022, Glen Choo wrote:\n>\n>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>\n>>> On Thu, Feb 10 2022, Glen Choo wrote:\n>>>\n>>>> Atharva Raykar (6):\n>>>>   submodule--helper: get remote names from any repository\n>>>>   submodule--helper: refactor get_submodule_displaypath()\n>>>>   submodule--helper: allow setting superprefix for init_submodule()\n>>>>   submodule--helper: run update using child process struct\n>>>>   builtin/submodule--helper.c: reformat designated initializers\n>>>>   submodule: move core cmd_update() logic to C\n>>>>\n>>>> Glen Choo (11):\n>>>>   submodule--helper: remove update-module-mode\n>>>>   submodule--helper: reorganize code for sh to C conversion\n>>>>   submodule--helper run-update-procedure: remove --suboid\n>>>>   submodule--helper run-update-procedure: learn --remote\n>>>>   submodule--helper: remove ensure-core-worktree\n>>>>   submodule--helper update-clone: learn --init\n>>>>   submodule--helper: move functions around\n>>>>   submodule--helper: reduce logic in run_update_procedure()\n>>>>   fixup! submodule--helper run-update-procedure: remove --suboid\n>>>>   fixup! submodule--helper run-update-procedure: learn --remote\n>>>>   fixup! submodule: move core cmd_update() logic to C\n>>>>\n>>>> Ævar Arnfjörð Bjarmason (3):\n>>>>   builtin/submodule--helper.c: rename option variables to \"opt\"\n>>>>   submodule--helper: don't use bitfield indirection for parse_options()\n>>>>   submodule tests: test for init and update failure output\n>>>\n>>> I think sending a version of this with the fixups squashed in as a v8\n>>> would be good, and perhaps addressing some of my comments.\n>>>\n>>> I don't know if my suggested split-up of \"prep fixes\" into another\n>>> series would be a good thing to pursue overall, perhaps Junio will chime\n>>> in on how he'd be most comfortable in merging this down. I'd think\n>>> splitting such trivial fixes into their own series be easier to review,\n>>> but perhaps not.\n>>\n>> Combing through the patches again, I couldn't really convince myself\n>> that the patch 4..9 prep fixes make sense as obvious standalone fixes,\n>> except maybe:\n>>\n>> - patch 4 submodule--helper: run update using child process struct\n>> - patch 8 submodule tests: test for init and update failure output\n>> - patch 9:  087bf43aba submodule--helper: remove update-module-mode\n>>\n>> But, since the 'final' patch (ignoring the fixup!-s) is consuming a huge\n>> chunk of the work anyway, here's an alternative patch organization with\n>> the fixup!-s squashed:\n>>\n>> = Move 'easy' and 'obviously correct' code from sh->C\n>> - patches 8-9   Cleanup and introduce tests\n>> - patches 1-4   Refactor existing functions, which enables..\n>> - patches 10-14 Move 'obviously correct' pieces of logic from sh-> C\n>>\n>> = Finalize move from sh->C\n>> i.e. combine \"run-update-procedure\" and \"update-clone\" into \"update\"\n>> - patches 5,7     Cleanup and prep\n>> - patches 6,15-16 Shrinking the diff\n>> - patch 17        Implement \"git submodule--helper update\" \n>>\n>> I'll send this if there are no objections :)\n>\n> Yes that sounds good, or rather, I haven't re-looked at that in detail,\n> but I think if you think it makes sense we should go for it.\n>\n> Or rather, we should really be aiming to produce a patch series that\n> makes sense in its current iteration, as opposed to optimizing for a\n> diff against some ad-hoc re-roll I produced a few versions ago :)\n\nAgreed, makes sense.\n\n> Thanks again for working on this & picking this up. It's great to see\n> progress in this area!\n\nThanks to you too for getting the ball rolling and lending me your\nthoughts :)\n"}]}