{"thread":{"id":"58235","subject":"[PATCH 01/20] submodule tests: test usage behavior","startedAt":"2022-07-28T16:17:30Z","lastAt":"2022-09-01T21:00:38Z","messageCount":142,"participants":["Ævar Arnfjörð Bjarmason","Glen Choo","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":20},"messages":[{"id":"460076","messageId":"patch-01.20-84b05bda016-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 01/20] submodule tests: test usage behavior","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:46Z","receivedAt":"2022-07-28T16:17:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Test what exit code and output we emit on \"git submodule -h\", how we\nhandle \"--\" when no subcommand is specified, and how the top-level\n\"--recursive\" option is handled.\n\nFor \"-h\" this doesn't make sense, but let's test for it so that any\nsubsequent eventual behavior change will become clear.\n\nFor \"--\" this follows up on 68cabbfda36 (submodule: document default\nbehavior, 2019-02-15) and tests that when \"status\" isn't supplied we\ndon't support the \"--\" delimiter. There's no intrinsically good reason\nnot to support that. We behave this way due to edge cases in\ngit-submodule.sh's implementation, but as with \"-h\" let's assert our\ncurrent long-standing behavior for now.\n\nFor \"--recursive\" the exclusion of it from the top-level appears to\nhave been an omission in 15fc56a8536 (git submodule foreach: Add\n--recursive to recurse into nested submodules, 2009-08-19), there\ndoesn't seem to be a reason not to support it alongside \"--quiet\" and\n\"--cached\", but let's likewise assert our existing behavior for now.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7400-submodule-basic.sh | 26 ++++++++++++++++++++++++++\n 1 file changed, 26 insertions(+)\n\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex e7cec2e457a..b858871a953 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -14,6 +14,32 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+test_expect_success 'submodule usage: -h' '\n+\tgit submodule -h >out 2>err &&\n+\tgrep \"^usage: git submodule\" out &&\n+\ttest_must_be_empty err\n+'\n+\n+test_expect_success 'submodule usage: --recursive' '\n+\ttest_expect_code 1 git submodule --recursive >out 2>err &&\n+\tgrep \"^usage: git submodule\" err &&\n+\ttest_must_be_empty out\n+'\n+\n+test_expect_success 'submodule usage: status --' '\n+\ttest_expect_code 1 git submodule -- &&\n+\ttest_expect_code 1 git submodule --end-of-options\n+'\n+\n+for opt in '--quiet' '--cached'\n+do\n+\ttest_expect_success \"submodule usage: status $opt\" '\n+\t\tgit submodule $opt &&\n+\t\tgit submodule status $opt &&\n+\t\tgit submodule $opt status\n+\t'\n+done\n+\n test_expect_success 'submodule deinit works on empty repository' '\n \tgit submodule deinit --all\n '\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460077","messageId":"patch-02.20-9671169e348-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 02/20] submodule tests: test for \"add <repository> <abs-path>\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:47Z","receivedAt":"2022-07-28T16:17:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a missing test for \"\"add <repository> <path>\" where \"<path>\" is an\nabsolute path. This tests code added in [1] and later turned into an\n\"else\" branch in clone_submodule() in [2] that's never been tested.\n\nThis needs to be skipped on WINDOWS because all of $PWD, $(pwd) and\nthe \"$(pwd -P)\" we get via \"$submodurl\" would fail in CI with e.g.:\n\n\tfatal: could not create directory 'D:/a/git/git/t/trash\n\tdirectory.t7400-submodule-basic/.git/modules/D:/a/git/git/t/trash\n\tdirectory.t7400-submodule-basic/add-abs'\n\nI.e. we can't handle these sorts of paths in this context on that\nplatform.\n\nI'm not sure where we run into the edges of \"$PWD\" behavior on\nWindows (see [1] for a previous loose end on the topic), but for the\npurposes of this test it's sufficient that we test this on other\nplatforms.\n\n1. ee8838d1577 (submodule: rewrite `module_clone` shell function in C,\n   2015-09-08)\n2. f8eaa0ba98b (submodule--helper, module_clone: always operate on\n   absolute paths, 2016-03-31)\n\n1. https://lore.kernel.org/git/220630.86edz6c75c.gmgdl@evledraar.gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7400-submodule-basic.sh | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex b858871a953..6a77d817a82 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -178,6 +178,11 @@ test_expect_success 'submodule add' '\n \ttest_must_be_empty untracked\n '\n \n+test_expect_success !WINDOWS 'submodule add (absolute path)' '\n+\ttest_when_finished \"git reset --hard\" &&\n+\tgit submodule add \"$submodurl\" \"$submodurl/add-abs\"\n+'\n+\n test_expect_success 'setup parent and one repository' '\n \ttest_create_repo parent &&\n \ttest_commit -C parent one\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460078","messageId":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":null,"subject":"[PATCH 00/20] submodule--helper: add tests, rm dead code, refactor & leak prep","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:45Z","receivedAt":"2022-07-28T16:17:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This new series based on \"master\" splits out the non-leak fixes from\nv3 of the submodule leaks series [1]. Sorry about the churn, but with\ne.g. the thread at [2] the \"leaks\" series was accumulating a lot of\nnon-leaks related fixes, just so that we could get to the point of\nfixing various leaks.\n\nThe immediate reason I split this off was because of the new\n\"remove..helper\" and \"test-tool\" patches here. I.e. some things that\nthe leaks series was changing was test-only code, or code that was\nsimply unused (or we had no business using anymore).\n\nThe [1] series will then be re-rolled on top of this series, which\nwill hopefully make it a lot easier to digest, as it'll now *just*\nfocus on leak fixes.\n\nA passing CI run for this can be found at [3].\n\n1. https://lore.kernel.org/git/cover-v3-00.26-00000000000-20220721T191249Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/220722.86y1wlqmqr.gmgdl@evledraar.gmail.com/\n3. https://github.com/avar/git/tree/avar/submodule--helper-cleanup-and-tests\n\nGlen Choo (2):\n  submodule--helper: add \"const\" to copy of \"update_data\"\n  submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"\n\nÆvar Arnfjörð Bjarmason (18):\n  submodule tests: test usage behavior\n  submodule tests: test for \"add <repository> <abs-path>\"\n  submodule--helper: remove unused \"name\" helper\n  submodule--helper: remove unused \"list\" helper\n  test-tool submodule-config: remove unused \"--url\" handling\n  submodule--helper: move \"is-active\" to a test-tool\n  submodule--helper: move \"check-name\" to a test-tool\n  submodule--helper: move \"resolve-relative-url-test\" to a test-tool\n  submodule--helper style: don't separate declared variables with \\n\\n\n  submodule--helper style: add \\n\\n after variable declarations\n  submodule--helper: replace memset() with { 0 }-initialization\n  submodule--helper: convert a strbuf_detach() to xstrfmt()\n  submodule--helper: stop conflating \"sb\" in clone_submodule()\n  submodule--helper: pass a \"const struct module_clone_data\" to\n    clone_submodule()\n  submodule--helper: rename \"int res\" to \"int ret\"\n  submodule--helper: add skeleton \"goto cleanup\" to update_submodule()\n  submodule--helper: don't exit() on failure, return\n  submodule--helper: fix bad config API usage\n\n Makefile                         |   1 +\n builtin/submodule--helper.c      | 338 ++++++++++++-------------------\n t/helper/test-submodule-config.c |  11 +-\n t/helper/test-submodule.c        | 146 +++++++++++++\n t/helper/test-tool-utils.h       |   9 +\n t/helper/test-tool.c             |   7 +-\n t/helper/test-tool.h             |   1 +\n t/t0060-path-utils.sh            |   2 +-\n t/t7400-submodule-basic.sh       |  56 ++---\n t/t7413-submodule-is-active.sh   |  32 +--\n t/t7450-bad-git-dotfiles.sh      |   2 +-\n 11 files changed, 335 insertions(+), 270 deletions(-)\n create mode 100644 t/helper/test-submodule.c\n create mode 100644 t/helper/test-tool-utils.h\n\nRange-diff:\n -:  ----------- >  1:  84b05bda016 submodule tests: test usage behavior\n -:  ----------- >  2:  9671169e348 submodule tests: test for \"add <repository> <abs-path>\"\n -:  ----------- >  3:  7aa9c14251b submodule--helper: remove unused \"name\" helper\n -:  ----------- >  4:  27df2efe718 submodule--helper: remove unused \"list\" helper\n -:  ----------- >  5:  9fe8deb165a test-tool submodule-config: remove unused \"--url\" handling\n -:  ----------- >  6:  8e4d2b09d56 submodule--helper: move \"is-active\" to a test-tool\n -:  ----------- >  7:  a2f3d812815 submodule--helper: move \"check-name\" to a test-tool\n -:  ----------- >  8:  8188657cdfa submodule--helper: move \"resolve-relative-url-test\" to a test-tool\n -:  ----------- >  9:  79a47f9b94d submodule--helper style: don't separate declared variables with \\n\\n\n -:  ----------- > 10:  5e13080f894 submodule--helper style: add \\n\\n after variable declarations\n 1:  3c7ae3e0222 ! 11:  dc5ac924496 submodule--helper: replace memset() with { 0 }-initialization\n    @@ builtin/submodule--helper.c: static int module_clone(int argc, const char **argv\n      \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n     -\tstruct list_objects_filter_options filter_options;\n     +\tstruct list_objects_filter_options filter_options = { 0 };\n    - \n      \tstruct option module_clone_options[] = {\n      \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n    + \t\t\t   N_(\"path\"),\n     @@ builtin/submodule--helper.c: static int module_clone(int argc, const char **argv, const char *prefix)\n      \t\tNULL\n      \t};\n    @@ builtin/submodule--helper.c: static int module_update(int argc, const char **arg\n     -\tstruct list_objects_filter_options filter_options;\n     +\tstruct list_objects_filter_options filter_options = { 0 };\n      \tint ret;\n    - \n      \tstruct option module_update_options[] = {\n    + \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n     @@ builtin/submodule--helper.c: static int module_update(int argc, const char **argv, const char *prefix)\n      \tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n      \tgit_config(git_update_clone_config, &opt.max_jobs);\n -:  ----------- > 12:  08cc9ce2e24 submodule--helper: convert a strbuf_detach() to xstrfmt()\n 2:  32e4ae7ead5 ! 13:  afe34d8b73b submodule--helper: stop conflating \"sb\" in clone_submodule()\n    @@ Metadata\n      ## Commit message ##\n         submodule--helper: stop conflating \"sb\" in clone_submodule()\n     \n    -    Refactor the three uses of a \"struct strbuf sb\" such that each of them\n    +    Refactor the two uses of a \"struct strbuf sb\" such that each of them\n         exists in its own scope. This makes the control flow clearer.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n    @@ builtin/submodule--helper.c: static void prepare_possible_alternates(const char\n     +\tchar *sm_alternate = NULL, *error_strategy = NULL;\n     +\tstruct child_process cp = CHILD_PROCESS_INIT;\n      \n    - \tif (!is_absolute_path(clone_data->path)) {\n    -+\t\tstruct strbuf sb = STRBUF_INIT;\n    -+\n    - \t\tstrbuf_addf(&sb, \"%s/%s\", get_git_work_tree(), clone_data->path);\n    - \t\tclone_data->path = strbuf_detach(&sb, NULL);\n    - \t} else {\n    + \tif (!is_absolute_path(clone_data->path))\n    + \t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n     @@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data *clone_data)\n      \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n      \t\t\t    clone_data->url, clone_data->path);\n 3:  eee6ca28c6f ! 14:  b364f3200d8 submodule--helper: pass a \"const struct module_clone_data\" to clone_submodule()\n    @@ Commit message\n         clobbering the \"clone_data->path\".\n     \n         We still need to add to the \"reference\" member, which is a \"struct\n    -    string_list\". We could do this by having clone_submodule() create its\n    -    own, and copy the contents over, but let's instead pass it as a\n    -    separate parameter. The main point of doing this is to make it clear\n    -    that e.g. \"clone_data->path\" always comes from the \"argv\", there's no\n    -    ambiguity about whether we can eventually free() the \"struct\n    -    string_list\".\n    +    string_list\". Let's do this by having clone_submodule() create its\n    +    own, and copy the contents over, allowing us to pass it as a\n    +    separate parameter.\n    +\n    +    This new \"struct string_list\" still leaks memory, just as the \"struct\n    +    module_clone_data\" did before. let's not fix that for now, to fix that\n    +    we'll need to add some \"goto cleanup\" to the relevant code. That will\n    +    be done in a follow-up commits, at that point it'll be easier to fix\n    +    the memory leak.\n    +\n    +    The scope of the new \"reference\" variable in add_submodule() could be\n    +    narrowed to the \"else\" block, but as we'll eventually free it with a\n    +    \"goto cleanup\" let's declare it at the start of the function.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    +@@ builtin/submodule--helper.c: struct module_clone_data {\n    + \tconst char *url;\n    + \tconst char *depth;\n    + \tstruct list_objects_filter_options *filter_options;\n    +-\tstruct string_list reference;\n    + \tunsigned int quiet: 1;\n    + \tunsigned int progress: 1;\n    + \tunsigned int dissociate: 1;\n    +@@ builtin/submodule--helper.c: struct module_clone_data {\n    + \tint single_branch;\n    + };\n    + #define MODULE_CLONE_DATA_INIT { \\\n    +-\t.reference = STRING_LIST_INIT_NODUP, \\\n    + \t.single_branch = -1, \\\n    + }\n    + \n     @@ builtin/submodule--helper.c: static char *clone_submodule_sm_gitdir(const char *name)\n      \treturn sm_gitdir;\n      }\n    @@ builtin/submodule--helper.c: static char *clone_submodule_sm_gitdir(const char *\n      \tstruct child_process cp = CHILD_PROCESS_INIT;\n     +\tconst char *clone_data_path;\n      \n    - \tif (!is_absolute_path(clone_data->path)) {\n    - \t\tstruct strbuf sb = STRBUF_INIT;\n    - \n    - \t\tstrbuf_addf(&sb, \"%s/%s\", get_git_work_tree(), clone_data->path);\n    --\t\tclone_data->path = strbuf_detach(&sb, NULL);\n    -+\t\tclone_data_path = strbuf_detach(&sb, NULL);\n    - \t} else {\n    + \tif (!is_absolute_path(clone_data->path))\n    +-\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n    +-\t\t\t\t\t   clone_data->path);\n    ++\t\tclone_data_path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n    ++\t\t\t\t\t  clone_data->path);\n    + \telse\n     -\t\tclone_data->path = xstrdup(clone_data->path);\n    -+\t\tclone_data_path = xstrdup(clone_data_path);\n    - \t}\n    ++\t\tclone_data_path = xstrdup(clone_data->path);\n      \n      \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n    + \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n     @@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data *clone_data)\n      \t\tif (safe_create_leading_directories_const(sm_gitdir) < 0)\n      \t\t\tdie(_(\"could not create directory '%s'\"), sm_gitdir);\n    @@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data\n     -\t\tif (clone_data->reference.nr) {\n     +\t\tif (reference->nr) {\n      \t\t\tstruct string_list_item *item;\n    + \n     -\t\t\tfor_each_string_list_item(item, &clone_data->reference)\n     +\t\t\tfor_each_string_list_item(item, reference)\n      \t\t\t\tstrvec_pushl(&cp.args, \"--reference\",\n    @@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data\n      \n      \t/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */\n      \tgit_config_get_string(\"submodule.alternateLocation\", &sm_alternate);\n    +@@ builtin/submodule--helper.c: static int module_clone(int argc, const char **argv, const char *prefix)\n    + \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n    + \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n    + \tstruct list_objects_filter_options filter_options = { 0 };\n    ++\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n    + \tstruct option module_clone_options[] = {\n    + \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n    + \t\t\t   N_(\"path\"),\n    +@@ builtin/submodule--helper.c: static int module_clone(int argc, const char **argv, const char *prefix)\n    + \t\tOPT_STRING(0, \"url\", &clone_data.url,\n    + \t\t\t   N_(\"string\"),\n    + \t\t\t   N_(\"url where to clone the submodule from\")),\n    +-\t\tOPT_STRING_LIST(0, \"reference\", &clone_data.reference,\n    ++\t\tOPT_STRING_LIST(0, \"reference\", &reference,\n    + \t\t\t   N_(\"repo\"),\n    + \t\t\t   N_(\"reference repository\")),\n    + \t\tOPT_BOOL(0, \"dissociate\", &dissociate,\n     @@ builtin/submodule--helper.c: static int module_clone(int argc, const char **argv, const char *prefix)\n      \t\tusage_with_options(git_submodule_helper_usage,\n      \t\t\t\t   module_clone_options);\n      \n     -\tclone_submodule(&clone_data);\n    -+\tclone_submodule(&clone_data, &clone_data.reference);\n    ++\tclone_submodule(&clone_data, &reference);\n      \tlist_objects_filter_release(&filter_options);\n      \treturn 0;\n      }\n     @@ builtin/submodule--helper.c: static int add_submodule(const struct add_data *add_data)\n    + {\n    + \tchar *submod_gitdir_path;\n    + \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n    ++\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n    + \n    + \t/* perhaps the path already exists and is already a git repo, else clone it */\n    + \tif (is_directory(add_data->sm_path)) {\n    +@@ builtin/submodule--helper.c: static int add_submodule(const struct add_data *add_data)\n    + \t\tfree(submod_gitdir_path);\n    + \t} else {\n    + \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n    ++\n    + \t\tsubmod_gitdir_path = xstrfmt(\".git/modules/%s\", add_data->sm_name);\n    + \n    + \t\tif (is_directory(submod_gitdir_path)) {\n    +@@ builtin/submodule--helper.c: static int add_submodule(const struct add_data *add_data)\n    + \t\tclone_data.quiet = add_data->quiet;\n    + \t\tclone_data.progress = add_data->progress;\n    + \t\tif (add_data->reference_path)\n    +-\t\t\tstring_list_append(&clone_data.reference,\n    ++\t\t\tstring_list_append(&reference,\n    + \t\t\t\t\t   xstrdup(add_data->reference_path));\n    + \t\tclone_data.dissociate = add_data->dissociate;\n      \t\tif (add_data->depth >= 0)\n      \t\t\tclone_data.depth = xstrfmt(\"%d\", add_data->depth);\n      \n     -\t\tif (clone_submodule(&clone_data))\n    -+\t\tif (clone_submodule(&clone_data, &clone_data.reference))\n    ++\t\tif (clone_submodule(&clone_data, &reference))\n      \t\t\treturn -1;\n      \n      \t\tprepare_submodule_repo_env(&cp.env);\n 4:  26f0caf0386 <  -:  ----------- submodule--helper: fix a leak in \"clone_submodule\"\n 5:  75775bf4f6c <  -:  ----------- submodule--helper: fix trivial get_default_remote_submodule() leak\n 6:  7672ef1305f <  -:  ----------- submodule--helper: fix most \"struct pathspec\" memory leaks\n 7:  325aa1521e2 <  -:  ----------- submodule--helper: \"struct pathspec\" memory leak in module_update()\n 8:  424b24961b5 <  -:  ----------- submodule--helper: don't leak {run,capture}_command() cp.dir argument\n 9:  abf5c4754a4 = 15:  e319f4edc54 submodule--helper: add \"const\" to copy of \"update_data\"\n10:  6ab5aabae35 <  -:  ----------- submodule--helper: add and use *_release() functions\n11:  feec1f20bf9 = 16:  68202100d9a submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"\n12:  d368db73de7 <  -:  ----------- submodule--helper: fix \"errmsg_str\" memory leak\n13:  5be941b3d1b <  -:  ----------- submodule--helper: fix \"sm_path\" and other \"module_cb_list\" leaks\n14:  b8560e8c111 <  -:  ----------- submodule--helper: fix a leak with repo_clear()\n15:  abfd61f9f05 <  -:  ----------- submodule--helper: fix a memory leak in get_default_remote_submodule()\n16:  b8df96a9cf0 <  -:  ----------- submodule--helper: fix \"reference\" leak is \"module_clone_data\"\n17:  7811bdbf149 <  -:  ----------- submodule--helper: fix obscure leak in module_add()\n18:  01566d63926 <  -:  ----------- submodule--helper: fix a leak in module_add()\n19:  7ef89abed86 <  -:  ----------- submodule--helper: fix a memory leak in print_status()\n20:  b8d47fc7d70 <  -:  ----------- submodule--helper: free some \"displaypath\" in \"struct update_data\"\n21:  4fb17f0dff1 ! 17:  e8aacb55a18 submodule--helper: rename \"int res\" to \"int ret\"\n    @@ Commit message\n     \n         Rename the \"res\" variable added in b3c5f5cb048 (submodule: move core\n         cmd_update() logic to C, 2022-03-15) to \"ret\", which is the convention\n    -    in the rest of this file. Subsequent commits will change this code to\n    -    a \"goto cleanup\" pattern, let's have the post image look consistent\n    -    with the rest.\n    +    in the rest of this file.\n    +\n    +    Eventual follow-up commits will change this code to a \"goto cleanup\"\n    +    pattern, let's have the post image look consistent with the rest.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n22:  af83925046b ! 18:  41fb22d8549 submodule--helper: add skeleton \"goto cleanup\" to update_submodule()\n    @@ Commit message\n         submodule--helper: add skeleton \"goto cleanup\" to update_submodule()\n     \n         Add a skeleton \"goto cleanup\" pattern to update_submodule(), rather\n    -    than having branches in it \"return\". This is in preparation for doing\n    -    something useful with the \"cleanup\" label, but for now we're using it\n    -    as the equivalent of a \"done\" label.\n    +    than having branches in it \"return\". This is in preparation for\n    +    eventually freeing data with the \"cleanup\" label, but for now we're\n    +    using it as the equivalent of a \"done\" label.\n     \n         The \"exit()\" branch is not handled yet, and neither is the exit() that\n         run_update_procedure() might invoke. That'll be handled in a\n23:  4c60784d281 ! 19:  5a26c9428be submodule--helper: don't exit() on failure, return\n    @@ Commit message\n         to the point where we could avoid calling exit() here.\n     \n         This introduces no functional changes, but makes it easier to both\n    -    call these routines as a library in the future, and to avoid leaking\n    -    memory.\n    +    call these routines as a library in the future, and to eventually\n    +    avoid leaking memory.\n    +\n    +    This and similar control flow in submodule--helper.c could be made\n    +    simpler by properly \"libifying\" it, i.e. to have it consistently\n    +    return -1 on failures, and to early return on any non-success.\n    +\n    +    But let's leave that larger project for now, and (mostly) emulate what\n    +    were doing with the \"exit(128)\" before this change.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n24:  7551af195ad <  -:  ----------- submodule--helper: free rest of \"displaypath\" in \"struct update_data\"\n25:  f650716cd7e = 20:  579560cb9a8 submodule--helper: fix bad config API usage\n26:  581ce0872c0 <  -:  ----------- submodule--helper: fix a configure_added_submodule() leak\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460079","messageId":"patch-03.20-7aa9c14251b-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 03/20] submodule--helper: remove unused \"name\" helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:48Z","receivedAt":"2022-07-28T16:17:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"name\" helper has not been used since e83e3333b57 (submodule: port\nsubmodule subcommand 'summary' from shell to C, 2020-08-13).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.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 fac52ade5e1..ac2553ba9d3 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -771,24 +771,6 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int module_name(int argc, const char **argv, const char *prefix)\n-{\n-\tconst struct submodule *sub;\n-\n-\tif (argc != 2)\n-\t\tusage(_(\"git submodule--helper name <path>\"));\n-\n-\tsub = submodule_from_path(the_repository, null_oid(), argv[1]);\n-\n-\tif (!sub)\n-\t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n-\t\t    argv[1]);\n-\n-\tprintf(\"%s\\n\", sub->name);\n-\n-\treturn 0;\n-}\n-\n struct module_cb {\n \tunsigned int mod_src;\n \tunsigned int mod_dst;\n@@ -3359,7 +3341,6 @@ struct cmd_struct {\n \n static struct cmd_struct commands[] = {\n \t{\"list\", module_list, 0},\n-\t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460080","messageId":"patch-04.20-27df2efe718-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 04/20] submodule--helper: remove unused \"list\" helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:49Z","receivedAt":"2022-07-28T16:17:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the \"submodule--helper list\" sub-command, which hasn't been\nused by git-submodule.sh since 2964d6e5e1e (submodule: port subcommand\n'set-branch' from shell to C, 2020-06-02).\n\nThere was a test added in 2b56bb7a87a (submodule helper list: respect\ncorrect path prefix, 2016-02-24) which relied on it, but the right\nthing to do here is to delete that test as well.\n\nThat test was regression testing the \"list\" subcommand itself. We're\nnot getting anything useful from the \"list | cut -f2\" invocation that\nwe couldn't get from \"foreach 'echo $sm_path'\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 40 -------------------------------------\n t/t7400-submodule-basic.sh  | 25 -----------------------\n 2 files changed, 65 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex ac2553ba9d3..47ed24c6a60 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -266,45 +266,6 @@ static char *get_up_path(const char *path)\n \treturn strbuf_detach(&sb, NULL);\n }\n \n-static int module_list(int argc, const char **argv, const char *prefix)\n-{\n-\tint i;\n-\tstruct pathspec pathspec;\n-\tstruct module_list list = MODULE_LIST_INIT;\n-\n-\tstruct option module_list_options[] = {\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"alternative anchor for relative paths\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper list [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, module_list_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < list.nr; i++) {\n-\t\tconst struct cache_entry *ce = list.entries[i];\n-\n-\t\tif (ce_stage(ce))\n-\t\t\tprintf(\"%06o %s U\\t\", ce->ce_mode,\n-\t\t\t       oid_to_hex(null_oid()));\n-\t\telse\n-\t\t\tprintf(\"%06o %s %d\\t\", ce->ce_mode,\n-\t\t\t       oid_to_hex(&ce->oid), ce_stage(ce));\n-\n-\t\tfprintf(stdout, \"%s\\n\", ce->name);\n-\t}\n-\treturn 0;\n-}\n-\n static void for_each_listed_submodule(const struct module_list *list,\n \t\t\t\t      each_submodule_fn fn, void *cb_data)\n {\n@@ -3340,7 +3301,6 @@ struct cmd_struct {\n };\n \n static struct cmd_struct commands[] = {\n-\t{\"list\", module_list, 0},\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex 6a77d817a82..b50db3f1031 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -1255,31 +1255,6 @@ test_expect_success 'submodule add clone shallow submodule' '\n \t)\n '\n \n-test_expect_success 'submodule helper list is not confused by common prefixes' '\n-\tmkdir -p dir1/b &&\n-\t(\n-\t\tcd dir1/b &&\n-\t\tgit init &&\n-\t\techo hi >testfile2 &&\n-\t\tgit add . &&\n-\t\tgit commit -m \"test1\"\n-\t) &&\n-\tmkdir -p dir2/b &&\n-\t(\n-\t\tcd dir2/b &&\n-\t\tgit init &&\n-\t\techo hello >testfile1 &&\n-\t\tgit add .  &&\n-\t\tgit commit -m \"test2\"\n-\t) &&\n-\tgit submodule add /dir1/b dir1/b &&\n-\tgit submodule add /dir2/b dir2/b &&\n-\tgit commit -m \"first submodule commit\" &&\n-\tgit submodule--helper list dir1/b | cut -f 2 >actual &&\n-\techo \"dir1/b\" >expect &&\n-\ttest_cmp expect actual\n-'\n-\n test_expect_success 'setup superproject with submodules' '\n \tgit init sub1 &&\n \ttest_commit -C sub1 test &&\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460081","messageId":"patch-05.20-9fe8deb165a-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 05/20] test-tool submodule-config: remove unused \"--url\" handling","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:50Z","receivedAt":"2022-07-28T16:17:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"No test has used this \"--url\" parameter since the test code that made\nuse of it was removed in 32bc548329d (submodule-config: remove support\nfor overlaying repository config, 2017-08-03).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/helper/test-submodule-config.c | 11 ++---------\n 1 file changed, 2 insertions(+), 9 deletions(-)\n\ndiff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c\nindex e2692746dfd..22a41c40926 100644\n--- a/t/helper/test-submodule-config.c\n+++ b/t/helper/test-submodule-config.c\n@@ -15,14 +15,11 @@ int cmd__submodule_config(int argc, const char **argv)\n {\n \tconst char **arg = argv;\n \tint my_argc = argc;\n-\tint output_url = 0;\n \tint lookup_name = 0;\n \n \targ++;\n \tmy_argc--;\n \twhile (arg[0] && starts_with(arg[0], \"--\")) {\n-\t\tif (!strcmp(arg[0], \"--url\"))\n-\t\t\toutput_url = 1;\n \t\tif (!strcmp(arg[0], \"--name\"))\n \t\t\tlookup_name = 1;\n \t\targ++;\n@@ -57,12 +54,8 @@ int cmd__submodule_config(int argc, const char **argv)\n \t\tif (!submodule)\n \t\t\tdie_usage(argc, argv, \"Submodule not found.\");\n \n-\t\tif (output_url)\n-\t\t\tprintf(\"Submodule url: '%s' for path '%s'\\n\",\n-\t\t\t\t\tsubmodule->url, submodule->path);\n-\t\telse\n-\t\t\tprintf(\"Submodule name: '%s' for path '%s'\\n\",\n-\t\t\t\t\tsubmodule->name, submodule->path);\n+\t\tprintf(\"Submodule name: '%s' for path '%s'\\n\", submodule->name,\n+\t\t       submodule->path);\n \n \t\targ += 2;\n \t}\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460082","messageId":"patch-06.20-8e4d2b09d56-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 06/20] submodule--helper: move \"is-active\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:51Z","receivedAt":"2022-07-28T16:17:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Create a new \"test-tool submodule\" and move the \"is-active\" subcommand\nover to it. It was added in 5c2bd8b77ae (submodule--helper: add\nis-active subcommand, 2017-03-16), since\na452128a36c (submodule--helper: introduce add-config subcommand,\n2021-08-06) it hasn't been used by git-submodule.sh.\n\nSince we're creating a command dispatch similar to test-tool.c itself\nlet's split out the \"struct test_cmd\" into a new test-tool-utils.h,\nwhich both this new code and test-tool.c itself can use.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile                       |  1 +\n builtin/submodule--helper.c    |  9 ------\n t/helper/test-submodule.c      | 58 ++++++++++++++++++++++++++++++++++\n t/helper/test-tool-utils.h     |  9 ++++++\n t/helper/test-tool.c           |  7 ++--\n t/helper/test-tool.h           |  1 +\n t/t7413-submodule-is-active.sh | 32 +++++++++----------\n 7 files changed, 87 insertions(+), 30 deletions(-)\n create mode 100644 t/helper/test-submodule.c\n create mode 100644 t/helper/test-tool-utils.h\n\ndiff --git a/Makefile b/Makefile\nindex 1624471badc..ad7fbd36885 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -785,6 +785,7 @@ TEST_BUILTINS_OBJS += test-strcmp-offset.o\n TEST_BUILTINS_OBJS += test-string-list.o\n TEST_BUILTINS_OBJS += test-submodule-config.o\n TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o\n+TEST_BUILTINS_OBJS += test-submodule.o\n TEST_BUILTINS_OBJS += test-subprocess.o\n TEST_BUILTINS_OBJS += test-trace2.o\n TEST_BUILTINS_OBJS += test-urlmatch-normalization.o\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 47ed24c6a60..b2fc732b5d8 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2728,14 +2728,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int is_active(int argc, const char **argv, const char *prefix)\n-{\n-\tif (argc != 2)\n-\t\tdie(\"submodule--helper is-active takes exactly 1 argument\");\n-\n-\treturn !is_submodule_active(the_repository, argv[1]);\n-}\n-\n /*\n  * Exit non-zero if any of the submodule names given on the command line is\n  * invalid. If no names are given, filter stdin to print only valid names\n@@ -3313,7 +3305,6 @@ static struct cmd_struct commands[] = {\n \t{\"summary\", module_summary, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n-\t{\"is-active\", is_active, 0},\n \t{\"check-name\", check_name, 0},\n \t{\"config\", module_config, 0},\n \t{\"set-url\", module_set_url, 0},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nnew file mode 100644\nindex 00000000000..494c6558d9f\n--- /dev/null\n+++ b/t/helper/test-submodule.c\n@@ -0,0 +1,58 @@\n+#include \"test-tool.h\"\n+#include \"test-tool-utils.h\"\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+#include \"submodule.h\"\n+\n+#define TEST_TOOL_IS_ACTIVE_USAGE \\\n+\t\"test-tool submodule is-active <name>\"\n+static const char *submodule_is_active_usage[] = {\n+\tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tNULL\n+};\n+\n+static const char *submodule_usage[] = {\n+\tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tNULL\n+};\n+\n+static int cmd__submodule_is_active(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_is_active_usage, 0);\n+\tif (argc != 1)\n+\t\tusage_with_options(submodule_is_active_usage, options);\n+\n+\tsetup_git_directory();\n+\n+\treturn !is_submodule_active(the_repository, argv[0]);\n+}\n+\n+static struct test_cmd cmds[] = {\n+\t{ \"is-active\", cmd__submodule_is_active },\n+};\n+\n+int cmd__submodule(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\tsize_t i;\n+\n+\targc = parse_options(argc, argv, \"test-tools\", options, submodule_usage,\n+\t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n+\tif (argc < 1)\n+\t\tusage_with_options(submodule_usage, options);\n+\n+\tfor (i = 0; i < ARRAY_SIZE(cmds); i++)\n+\t\tif (!strcmp(cmds[i].name, argv[0]))\n+\t\t\treturn cmds[i].fn(argc, argv);\n+\n+\tusage_msg_optf(\"unknown subcommand '%s'\", submodule_usage, options,\n+\t\t       argv[0]);\n+\n+\treturn 0;\n+}\ndiff --git a/t/helper/test-tool-utils.h b/t/helper/test-tool-utils.h\nnew file mode 100644\nindex 00000000000..6a0e5e0074f\n--- /dev/null\n+++ b/t/helper/test-tool-utils.h\n@@ -0,0 +1,9 @@\n+#ifndef TEST_TOOL_UTILS_H\n+#define TEST_TOOL_UTILS_H\n+\n+struct test_cmd {\n+\tconst char *name;\n+\tint (*fn)(int argc, const char **argv);\n+};\n+\n+#endif\ndiff --git a/t/helper/test-tool.c b/t/helper/test-tool.c\nindex 318fdbab0c3..7a6a8b88a91 100644\n--- a/t/helper/test-tool.c\n+++ b/t/helper/test-tool.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"test-tool.h\"\n+#include \"test-tool-utils.h\"\n #include \"trace2.h\"\n #include \"parse-options.h\"\n \n@@ -8,11 +9,6 @@ static const char * const test_tool_usage[] = {\n \tNULL\n };\n \n-struct test_cmd {\n-\tconst char *name;\n-\tint (*fn)(int argc, const char **argv);\n-};\n-\n static struct test_cmd cmds[] = {\n \t{ \"advise\", cmd__advise_if_enabled },\n \t{ \"bitmap\", cmd__bitmap },\n@@ -78,6 +74,7 @@ static struct test_cmd cmds[] = {\n \t{ \"simple-ipc\", cmd__simple_ipc },\n \t{ \"strcmp-offset\", cmd__strcmp_offset },\n \t{ \"string-list\", cmd__string_list },\n+\t{ \"submodule\", cmd__submodule },\n \t{ \"submodule-config\", cmd__submodule_config },\n \t{ \"submodule-nested-repo-config\", cmd__submodule_nested_repo_config },\n \t{ \"subprocess\", cmd__subprocess },\ndiff --git a/t/helper/test-tool.h b/t/helper/test-tool.h\nindex bb799271631..5f4f69dee81 100644\n--- a/t/helper/test-tool.h\n+++ b/t/helper/test-tool.h\n@@ -68,6 +68,7 @@ int cmd__sigchain(int argc, const char **argv);\n int cmd__simple_ipc(int argc, const char **argv);\n int cmd__strcmp_offset(int argc, const char **argv);\n int cmd__string_list(int argc, const char **argv);\n+int cmd__submodule(int argc, const char **argv);\n int cmd__submodule_config(int argc, const char **argv);\n int cmd__submodule_nested_repo_config(int argc, const char **argv);\n int cmd__subprocess(int argc, const char **argv);\ndiff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh\nindex c8e7e983317..9ead083371a 100755\n--- a/t/t7413-submodule-is-active.sh\n+++ b/t/t7413-submodule-is-active.sh\n@@ -1,8 +1,8 @@\n #!/bin/sh\n \n-test_description='Test submodule--helper is-active\n+test_description='Test with test-tool submodule is-active\n \n-This test verifies that `git submodue--helper is-active` correctly identifies\n+This test verifies that `test-tool submodule is-active` correctly identifies\n submodules which are \"active\" and interesting to the user.\n '\n \n@@ -25,13 +25,13 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'is-active works with urls' '\n-\tgit -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2 &&\n+\ttest-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2 &&\n \n \tgit -C super config --unset submodule.sub1.URL &&\n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n \tgit -C super config submodule.sub1.URL ../sub &&\n-\tgit -C super submodule--helper is-active sub1\n+\ttest-tool -C super submodule is-active sub1\n '\n \n test_expect_success 'is-active works with submodule.<name>.active config' '\n@@ -39,11 +39,11 @@ test_expect_success 'is-active works with submodule.<name>.active config' '\n \ttest_when_finished \"git -C super config submodule.sub1.URL ../sub\" &&\n \n \tgit -C super config --bool submodule.sub1.active \"false\" &&\n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n \n \tgit -C super config --bool submodule.sub1.active \"true\" &&\n \tgit -C super config --unset submodule.sub1.URL &&\n-\tgit -C super submodule--helper is-active sub1\n+\ttest-tool -C super submodule is-active sub1\n '\n \n test_expect_success 'is-active works with basic submodule.active config' '\n@@ -53,17 +53,17 @@ test_expect_success 'is-active works with basic submodule.active config' '\n \tgit -C super config --add submodule.active \".\" &&\n \tgit -C super config --unset submodule.sub1.URL &&\n \n-\tgit -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active correctly works with paths that are not submodules' '\n \ttest_when_finished \"git -C super config --unset-all submodule.active\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active not-a-submodule &&\n+\ttest_must_fail test-tool -C super submodule is-active not-a-submodule &&\n \n \tgit -C super config --add submodule.active \".\" &&\n-\ttest_must_fail git -C super submodule--helper is-active not-a-submodule\n+\ttest_must_fail test-tool -C super submodule is-active not-a-submodule\n '\n \n test_expect_success 'is-active works with exclusions in submodule.active config' '\n@@ -72,8 +72,8 @@ test_expect_success 'is-active works with exclusions in submodule.active config'\n \tgit -C super config --add submodule.active \".\" &&\n \tgit -C super config --add submodule.active \":(exclude)sub1\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active with submodule.active and submodule.<name>.active' '\n@@ -85,8 +85,8 @@ test_expect_success 'is-active with submodule.active and submodule.<name>.active\n \tgit -C super config --bool submodule.sub1.active \"false\" &&\n \tgit -C super config --bool submodule.sub2.active \"true\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active, submodule.active and submodule add' '\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460083","messageId":"patch-08.20-8188657cdfa-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 08/20] submodule--helper: move \"resolve-relative-url-test\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:53Z","receivedAt":"2022-07-28T16:17:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As its name suggests the \"resolve-relative-url-test\" has never been\nused outside of the test suite, see 63e95beb085 (submodule: port\nresolve_relative_url from shell to C, 2016-04-15) for its original\naddition.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 23 --------------------\n t/helper/test-submodule.c   | 42 +++++++++++++++++++++++++++++++++++++\n t/t0060-path-utils.sh       |  2 +-\n 3 files changed, 43 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 06307886080..246457ec2e9 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -96,28 +96,6 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n \treturn resolved_url;\n }\n \n-static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remoteurl, *res;\n-\tconst char *up_path, *url;\n-\n-\tif (argc != 4)\n-\t\tdie(\"resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>\");\n-\n-\tup_path = argv[1];\n-\tremoteurl = xstrdup(argv[2]);\n-\turl = argv[3];\n-\n-\tif (!strcmp(up_path, \"(null)\"))\n-\t\tup_path = NULL;\n-\n-\tres = relative_url(remoteurl, url, up_path);\n-\tputs(res);\n-\tfree(res);\n-\tfree(remoteurl);\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 {\n@@ -3273,7 +3251,6 @@ static struct cmd_struct commands[] = {\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n-\t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, 0},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nindex 9f0eb440192..e0e0c53d386 100644\n--- a/t/helper/test-submodule.c\n+++ b/t/helper/test-submodule.c\n@@ -2,6 +2,7 @@\n #include \"test-tool-utils.h\"\n #include \"cache.h\"\n #include \"parse-options.h\"\n+#include \"remote.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n \n@@ -19,9 +20,17 @@ static const char *submodule_is_active_usage[] = {\n \tNULL\n };\n \n+#define TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE \\\n+\t\"test-tool submodule resolve-relative-url <up_path> <remoteurl> <url>\"\n+static const char *submodule_resolve_relative_url_usage[] = {\n+\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n+\tNULL,\n+};\n+\n static const char *submodule_usage[] = {\n \tTEST_TOOL_CHECK_NAME_USAGE,\n \tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n \tNULL\n };\n \n@@ -76,9 +85,42 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n \treturn !is_submodule_active(the_repository, argv[0]);\n }\n \n+static int resolve_relative_url(int argc, const char **argv)\n+{\n+\tchar *remoteurl, *res;\n+\tconst char *up_path, *url;\n+\n+\tup_path = argv[0];\n+\tremoteurl = xstrdup(argv[1]);\n+\turl = argv[2];\n+\n+\tif (!strcmp(up_path, \"(null)\"))\n+\t\tup_path = NULL;\n+\n+\tres = relative_url(remoteurl, url, up_path);\n+\tputs(res);\n+\tfree(res);\n+\tfree(remoteurl);\n+\treturn 0;\n+}\n+\n+static int cmd__submodule_resolve_relative_url(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_resolve_relative_url_usage, 0);\n+\tif (argc != 3)\n+\t\tusage_with_options(submodule_resolve_relative_url_usage, options);\n+\n+\treturn resolve_relative_url(argc, argv);\n+}\n+\n static struct test_cmd cmds[] = {\n \t{ \"check-name\", cmd__submodule_check_name },\n \t{ \"is-active\", cmd__submodule_is_active },\n+\t{ \"resolve-relative-url\", cmd__submodule_resolve_relative_url},\n };\n \n int cmd__submodule(int argc, const char **argv)\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 1f2007e62b7..68e29c904a6 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -22,7 +22,7 @@ relative_path() {\n \n test_submodule_relative_url() {\n \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n-\t\tactual=\\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&\n+\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n \t\ttest \\\"\\$actual\\\" = '$4'\n \t\"\n }\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460084","messageId":"patch-07.20-a2f3d812815-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 07/20] submodule--helper: move \"check-name\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:52Z","receivedAt":"2022-07-28T16:17:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the \"check-name\" helper to a test-tool, since\na6226fd772b (submodule--helper: convert the bulk of cmd_add() to C,\n2021-08-10) it has only been used by this test, not git-submodule.sh.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 24 -------------------\n t/helper/test-submodule.c   | 46 +++++++++++++++++++++++++++++++++++++\n t/t7450-bad-git-dotfiles.sh |  2 +-\n 3 files changed, 47 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b2fc732b5d8..06307886080 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2728,29 +2728,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-/*\n- * Exit non-zero if any of the submodule names given on the command line is\n- * invalid. If no names are given, filter stdin to print only valid names\n- * (which is primarily intended for testing).\n- */\n-static int check_name(int argc, const char **argv, const char *prefix)\n-{\n-\tif (argc > 1) {\n-\t\twhile (*++argv) {\n-\t\t\tif (check_submodule_name(*argv) < 0)\n-\t\t\t\treturn 1;\n-\t\t}\n-\t} else {\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n-\t\t\tif (!check_submodule_name(buf.buf))\n-\t\t\t\tprintf(\"%s\\n\", buf.buf);\n-\t\t}\n-\t\tstrbuf_release(&buf);\n-\t}\n-\treturn 0;\n-}\n-\n static int module_config(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -3305,7 +3282,6 @@ static struct cmd_struct commands[] = {\n \t{\"summary\", module_summary, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n-\t{\"check-name\", check_name, 0},\n \t{\"config\", module_config, 0},\n \t{\"set-url\", module_set_url, 0},\n \t{\"set-branch\", module_set_branch, 0},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nindex 494c6558d9f..9f0eb440192 100644\n--- a/t/helper/test-submodule.c\n+++ b/t/helper/test-submodule.c\n@@ -2,8 +2,16 @@\n #include \"test-tool-utils.h\"\n #include \"cache.h\"\n #include \"parse-options.h\"\n+#include \"submodule-config.h\"\n #include \"submodule.h\"\n \n+#define TEST_TOOL_CHECK_NAME_USAGE \\\n+\t\"test-tool submodule check-name <name>\"\n+static const char *submodule_check_name_usage[] = {\n+\tTEST_TOOL_CHECK_NAME_USAGE,\n+\tNULL\n+};\n+\n #define TEST_TOOL_IS_ACTIVE_USAGE \\\n \t\"test-tool submodule is-active <name>\"\n static const char *submodule_is_active_usage[] = {\n@@ -12,10 +20,47 @@ static const char *submodule_is_active_usage[] = {\n };\n \n static const char *submodule_usage[] = {\n+\tTEST_TOOL_CHECK_NAME_USAGE,\n \tTEST_TOOL_IS_ACTIVE_USAGE,\n \tNULL\n };\n \n+/*\n+ * Exit non-zero if any of the submodule names given on the command line is\n+ * invalid. If no names are given, filter stdin to print only valid names\n+ * (which is primarily intended for testing).\n+ */\n+static int check_name(int argc, const char **argv)\n+{\n+\tif (argc > 1) {\n+\t\twhile (*++argv) {\n+\t\t\tif (check_submodule_name(*argv) < 0)\n+\t\t\t\treturn 1;\n+\t\t}\n+\t} else {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n+\t\t\tif (!check_submodule_name(buf.buf))\n+\t\t\t\tprintf(\"%s\\n\", buf.buf);\n+\t\t}\n+\t\tstrbuf_release(&buf);\n+\t}\n+\treturn 0;\n+}\n+\n+static int cmd__submodule_check_name(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_check_name_usage, 0);\n+\tif (argc)\n+\t\tusage_with_options(submodule_check_name_usage, options);\n+\n+\treturn check_name(argc, argv);\n+}\n+\n static int cmd__submodule_is_active(int argc, const char **argv)\n {\n \tstruct option options[] = {\n@@ -32,6 +77,7 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n }\n \n static struct test_cmd cmds[] = {\n+\t{ \"check-name\", cmd__submodule_check_name },\n \t{ \"is-active\", cmd__submodule_is_active },\n };\n \ndiff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh\nindex 41706c1c9ff..2c24f120da3 100755\n--- a/t/t7450-bad-git-dotfiles.sh\n+++ b/t/t7450-bad-git-dotfiles.sh\n@@ -21,7 +21,7 @@ test_expect_success 'check names' '\n \tvalid/with/paths\n \tEOF\n \n-\tgit submodule--helper check-name >actual <<-\\EOF &&\n+\ttest-tool submodule check-name >actual <<-\\EOF &&\n \tvalid\n \tvalid/with/paths\n \n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460085","messageId":"patch-09.20-79a47f9b94d-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 09/20] submodule--helper style: don't separate declared variables with \\n\\n","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:54Z","receivedAt":"2022-07-28T16:18:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The usual style in the codebase is to separate declared variables with\na single newline, not two, let's adjust this code to conform to\nthat. This makes the eventual addition of various \"int ret\" variables\nmore consistent.\n\nIn doing this the comment added in 2964d6e5e1e (submodule: port\nsubcommand 'set-branch' from shell to C, 2020-06-02) might become\nambiguous to some, although it should be clear what it's referring to,\nlet's move it above the 'OPT_NOOP_NOARG('q', \"quiet\")' to make that\nclearer.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 33 +++++----------------------------\n 1 file changed, 5 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 246457ec2e9..53b9e14767d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -368,14 +368,12 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tstruct foreach_cb info = FOREACH_CB_INIT;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n-\n \tstruct option module_foreach_options[] = {\n \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n \t\t\t N_(\"recurse into nested submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule foreach [--quiet] [--recursive] [--] <command>\"),\n \t\tNULL\n@@ -504,12 +502,10 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\n \tstruct option module_init_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for initializing a submodule\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule init [<options>] [<path>]\"),\n \t\tNULL\n@@ -682,14 +678,12 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\n \tstruct option module_status_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule status [--quiet] [--cached] [--recursive] [<path>...]\"),\n \t\tNULL\n@@ -1082,7 +1076,6 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \tenum diff_cmd diff_cmd = DIFF_INDEX;\n \tstruct object_id head_oid;\n \tint ret;\n-\n \tstruct option module_summary_options[] = {\n \t\tOPT_BOOL(0, \"cached\", &cached,\n \t\t\t N_(\"use the commit stored in the index instead of the submodule HEAD\")),\n@@ -1094,7 +1087,6 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \t\t\t     N_(\"limit the summary size\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule summary [<options>] [<commit>] [--] [<path>]\"),\n \t\tNULL\n@@ -1251,14 +1243,12 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n \tint recursive = 0;\n-\n \tstruct option module_sync_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n \t\tOPT_BOOL(0, \"recursive\", &recursive,\n \t\t\tN_(\"recurse into nested submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule sync [--quiet] [--recursive] [<path>]\"),\n \t\tNULL\n@@ -1390,14 +1380,12 @@ static int module_deinit(int argc, const char **argv, const char *prefix)\n \tint quiet = 0;\n \tint force = 0;\n \tint all = 0;\n-\n \tstruct option module_deinit_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT__FORCE(&force, N_(\"remove submodule working trees even if they contain local changes\"), 0),\n \t\tOPT_BOOL(0, \"all\", &all, N_(\"unregister all submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]\"),\n \t\tNULL\n@@ -1666,7 +1654,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options;\n-\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1698,7 +1685,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tOPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule--helper clone [--prefix=<path>] [--quiet] \"\n \t\t   \"[--reference <repository>] [--name <name>] [--depth <depth>] \"\n@@ -2486,7 +2472,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options;\n \tint ret;\n-\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@@ -2530,7 +2515,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\tOPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule [--quiet] update\"\n \t\t\" [--init [--filter=<filter-spec>]] [--remote]\"\n@@ -2679,7 +2663,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tunsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;\n-\n \tstruct option embed_gitdir_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n@@ -2688,7 +2671,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \t\t\tABSORB_GITDIR_RECURSE_SUBMODULES),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule absorbgitdirs [<options>] [<path>...]\"),\n \t\tNULL\n@@ -2712,7 +2694,6 @@ static int module_config(int argc, const char **argv, const char *prefix)\n \t\tCHECK_WRITEABLE = 1,\n \t\tDO_UNSET = 2\n \t} command = 0;\n-\n \tstruct option module_config_options[] = {\n \t\tOPT_CMDMODE(0, \"check-writeable\", &command,\n \t\t\t    N_(\"check if it is safe to write to the .gitmodules file\"),\n@@ -2758,7 +2739,6 @@ static int module_set_url(int argc, const char **argv, const char *prefix)\n \tconst char *newurl;\n \tconst char *path;\n \tchar *config_name;\n-\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for setting url of a submodule\")),\n \t\tOPT_END()\n@@ -2789,13 +2769,13 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \tconst char *opt_branch = NULL;\n \tconst char *path;\n \tchar *config_name;\n-\n-\t/*\n-\t * We accept the `quiet` option for uniformity across subcommands,\n-\t * though there is nothing to make less verbose in this subcommand.\n-\t */\n \tstruct option options[] = {\n+\t\t/*\n+\t\t * We accept the `quiet` option for uniformity across subcommands,\n+\t\t * though there is nothing to make less verbose in this subcommand.\n+\t\t */\n \t\tOPT_NOOP_NOARG('q', \"quiet\"),\n+\n \t\tOPT_BOOL('d', \"default\", &opt_default,\n \t\t\tN_(\"set the default tracking branch to master\")),\n \t\tOPT_STRING('b', \"branch\", &opt_branch, N_(\"branch\"),\n@@ -2830,7 +2810,6 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)\n {\n \tenum branch_track track;\n \tint quiet = 0, force = 0, reflog = 0, dry_run = 0;\n-\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"print only error messages\")),\n \t\tOPT__FORCE(&force, N_(\"force creation\"), 0),\n@@ -3129,7 +3108,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \tint force = 0, quiet = 0, progress = 0, dissociate = 0;\n \tstruct add_data add_data = ADD_DATA_INIT;\n \tchar *to_free = NULL;\n-\n \tstruct option options[] = {\n \t\tOPT_STRING('b', \"branch\", &add_data.branch, N_(\"branch\"),\n \t\t\t   N_(\"branch of repository to add as submodule\")),\n@@ -3146,7 +3124,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \t\tOPT_INTEGER(0, \"depth\", &add_data.depth, N_(\"depth for shallow clones\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule add [<options>] [--] <repository> [<path>]\"),\n \t\tNULL\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460086","messageId":"patch-10.20-5e13080f894-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 10/20] submodule--helper style: add \\n\\n after variable declarations","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:55Z","receivedAt":"2022-07-28T16:18:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Since the preceding commit fixed style issues with \\n\\n among the\ndeclared variables let's fix the minor stylistic issues with those\nvariables not being consistently followed by a \\n\\n.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 25 +++++++++++++++++++++++--\n 1 file changed, 23 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 53b9e14767d..15bf89910f4 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -167,6 +167,7 @@ static int module_list_compute(int argc, const char **argv,\n {\n \tint i, result = 0;\n \tchar *ps_matched = NULL;\n+\n \tparse_pathspec(pathspec, 0,\n \t\t       PATHSPEC_PREFER_FULL,\n \t\t       prefix, argv);\n@@ -248,6 +249,7 @@ static void for_each_listed_submodule(const struct module_list *list,\n \t\t\t\t      each_submodule_fn fn, void *cb_data)\n {\n \tint i;\n+\n \tfor (i = 0; i < list->nr; i++)\n \t\tfn(list->entries[i], cb_data);\n }\n@@ -267,7 +269,6 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tstruct foreach_cb *info = cb_data;\n \tconst char *path = list_item->name;\n \tconst struct object_id *ce_oid = &list_item->oid;\n-\n \tconst struct submodule *sub;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *displaypath;\n@@ -456,6 +457,7 @@ static void init_submodule(const char *path, const char *prefix,\n \t\tif (starts_with_dot_dot_slash(url) ||\n \t\t    starts_with_dot_slash(url)) {\n \t\t\tchar *oldurl = url;\n+\n \t\t\turl = resolve_relative_url(oldurl, NULL, 0);\n \t\t\tfree(oldurl);\n \t\t}\n@@ -493,6 +495,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+\n \tinit_submodule(list_item->name, info->prefix, info->flags);\n }\n \n@@ -562,6 +565,7 @@ static int handle_submodule_head_ref(const char *refname,\n \t\t\t\t     void *cb_data)\n {\n \tstruct object_id *output = cb_data;\n+\n \tif (oid)\n \t\toidcpy(output, oid);\n \n@@ -668,6 +672,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,\n \t\t\t\tvoid *cb_data)\n {\n \tstruct status_cb *info = cb_data;\n+\n \tstatus_submodule(list_item->name, &list_item->oid, list_item->ce_flags,\n \t\t\t info->prefix, info->flags);\n }\n@@ -820,6 +825,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n \tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n \t\t\tstruct ref_store *refs = get_submodule_ref_store(p->sm_path);\n+\n \t\t\tif (refs)\n \t\t\t\trefs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);\n \t\t} else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {\n@@ -1158,6 +1164,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tif (starts_with_dot_dot_slash(sub->url) ||\n \t\t    starts_with_dot_slash(sub->url)) {\n \t\t\tchar *up_path = get_up_path(path);\n+\n \t\t\tsub_origin_url = resolve_relative_url(sub->url, up_path, 1);\n \t\t\tsuper_config_url = resolve_relative_url(sub->url, NULL, 1);\n \t\t\tfree(up_path);\n@@ -1233,6 +1240,7 @@ static void sync_submodule(const char *path, const char *prefix,\n static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct sync_cb *info = cb_data;\n+\n \tsync_submodule(list_item->name, info->prefix, info->flags);\n }\n \n@@ -1312,6 +1320,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \n \t\tif (!(flags & OPT_FORCE)) {\n \t\t\tstruct child_process cp_rm = CHILD_PROCESS_INIT;\n+\n \t\t\tcp_rm.git_cmd = 1;\n \t\t\tstrvec_pushl(&cp_rm.args, \"rm\", \"-qn\",\n \t\t\t\t     path, NULL);\n@@ -1348,6 +1357,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \t/* remove the .git/config entries (unless the user already did it) */\n \tif (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {\n \t\tchar *sub_key = xstrfmt(\"submodule.%s\", sub->name);\n+\n \t\t/*\n \t\t * remove the whole section so we have a clean state when\n \t\t * the user later decides to init this submodule again\n@@ -1585,6 +1595,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tstrvec_pushl(&cp.args, \"--depth\", clone_data->depth, NULL);\n \t\tif (clone_data->reference.nr) {\n \t\t\tstruct string_list_item *item;\n+\n \t\t\tfor_each_string_list_item(item, &clone_data->reference)\n \t\t\t\tstrvec_pushl(&cp.args, \"--reference\",\n \t\t\t\t\t     item->string, NULL);\n@@ -1935,6 +1946,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tstrvec_pushl(&child->args, \"--url\", url, NULL);\n \tif (suc->update_data->references.nr) {\n \t\tstruct string_list_item *item;\n+\n \t\tfor_each_string_list_item(item, &suc->update_data->references)\n \t\t\tstrvec_pushl(&child->args, \"--reference\", item->string, NULL);\n \t}\n@@ -1967,6 +1979,7 @@ static int update_clone_get_next_task(struct child_process *child,\n \t\tce = suc->update_data->list.entries[suc->current];\n \t\tif (prepare_to_clone_next_submodule(ce, child, suc, err)) {\n \t\t\tint *p = xmalloc(sizeof(*p));\n+\n \t\t\t*p = suc->current;\n \t\t\t*idx_task_cb = p;\n \t\t\tsuc->current++;\n@@ -1982,6 +1995,7 @@ static int update_clone_get_next_task(struct child_process *child,\n \tindex = suc->current - suc->update_data->list.nr;\n \tif (index < suc->failed_clones_nr) {\n \t\tint *p;\n+\n \t\tce = suc->failed_clones[index];\n \t\tif (!prepare_to_clone_next_submodule(ce, child, suc, err)) {\n \t\t\tsuc->current ++;\n@@ -2005,6 +2019,7 @@ static int update_clone_start_failure(struct strbuf *err,\n \t\t\t\t      void *idx_task_cb)\n {\n \tstruct submodule_update_clone *suc = suc_cb;\n+\n \tsuc->quickstop = 1;\n \treturn 1;\n }\n@@ -2016,9 +2031,9 @@ static int update_clone_task_finished(int result,\n {\n \tconst struct cache_entry *ce;\n \tstruct submodule_update_clone *suc = suc_cb;\n-\n \tint *idxP = idx_task_cb;\n \tint idx = *idxP;\n+\n \tfree(idxP);\n \n \tif (!result)\n@@ -2051,6 +2066,7 @@ static int git_update_clone_config(const char *var, const char *value,\n \t\t\t\t   void *cb)\n {\n \tint *max_jobs = cb;\n+\n \tif (!strcmp(var, \"submodule.fetchjobs\"))\n \t\t*max_jobs = parse_submodule_fetchjobs(var, value);\n \treturn 0;\n@@ -2091,6 +2107,7 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \tif (oid) {\n \t\tchar *hex = oid_to_hex(oid);\n \t\tchar *remote = get_default_remote();\n+\n \t\tstrvec_pushl(&cp.args, remote, hex, NULL);\n \t\tfree(remote);\n \t}\n@@ -2340,6 +2357,7 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \n \tif (update_data->references.nr) {\n \t\tstruct string_list_item *item;\n+\n \t\tfor_each_string_list_item(item, &update_data->references)\n \t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n \t}\n@@ -2872,8 +2890,10 @@ static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)\n \tif (!capture_command(&cp_remote, &sb_remote_out, 0)) {\n \t\tchar *next_line;\n \t\tchar *line = sb_remote_out.buf;\n+\n \t\twhile ((next_line = strchr(line, '\\n')) != NULL) {\n \t\t\tsize_t len = next_line - line;\n+\n \t\t\tif (strip_suffix_mem(line, &len, \" (fetch)\"))\n \t\t\t\tstrbuf_addf(msg, \"  %.*s\\n\", (int)len, line);\n \t\t\tline = next_line + 1;\n@@ -3180,6 +3200,7 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \t\tint exit_code = -1;\n \t\tstruct strbuf sb = STRBUF_INIT;\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n \t\tcp.git_cmd = 1;\n \t\tcp.no_stdout = 1;\n \t\tstrvec_pushl(&cp.args, \"add\", \"--dry-run\", \"--ignore-missing\",\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460087","messageId":"patch-11.20-dc5ac924496-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 11/20] submodule--helper: replace memset() with { 0 }-initialization","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:56Z","receivedAt":"2022-07-28T16:18:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use the less verbose { 0 }-initialization syntax rather than memset()\nin builtin/submodule--helper.c, this doesn't make a difference in\nterms of behavior, but as we're about to modify adjacent code makes\nthis more consistent, and lets us avoid worrying about when the\nmemset() happens v.s. a \"goto cleanup\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 6 ++----\n 1 file changed, 2 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 15bf89910f4..60165a848a2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1664,7 +1664,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n {\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n-\tstruct list_objects_filter_options filter_options;\n+\tstruct list_objects_filter_options filter_options = { 0 };\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1704,7 +1704,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tNULL\n \t};\n \n-\tmemset(&filter_options, 0, sizeof(filter_options));\n \targc = parse_options(argc, argv, prefix, module_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n@@ -2488,7 +2487,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n {\n \tstruct pathspec pathspec;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n-\tstruct list_objects_filter_options filter_options;\n+\tstruct list_objects_filter_options filter_options = { 0 };\n \tint ret;\n \tstruct option module_update_options[] = {\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n@@ -2546,7 +2545,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n \tgit_config(git_update_clone_config, &opt.max_jobs);\n \n-\tmemset(&filter_options, 0, sizeof(filter_options));\n \targc = parse_options(argc, argv, prefix, module_update_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460088","messageId":"patch-12.20-08cc9ce2e24-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 12/20] submodule--helper: convert a strbuf_detach() to xstrfmt()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:57Z","receivedAt":"2022-07-28T16:18:49Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Convert a case where we had no reason to use a \"struct strbuf\" to use\nan xstrfmt(). This code was added along with other uses of \"struct\nstrbuf\" in this function in ee8838d1577 (submodule: rewrite\n`module_clone` shell function in C, 2015-09-08).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 60165a848a2..f74957444e1 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1568,12 +1568,11 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \tsm_gitdir = absolute_pathdup(sb.buf);\n \tstrbuf_reset(&sb);\n \n-\tif (!is_absolute_path(clone_data->path)) {\n-\t\tstrbuf_addf(&sb, \"%s/%s\", get_git_work_tree(), clone_data->path);\n-\t\tclone_data->path = strbuf_detach(&sb, NULL);\n-\t} else {\n+\tif (!is_absolute_path(clone_data->path))\n+\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n+\t\t\t\t\t   clone_data->path);\n+\telse\n \t\tclone_data->path = xstrdup(clone_data->path);\n-\t}\n \n \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460089","messageId":"patch-13.20-afe34d8b73b-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 13/20] submodule--helper: stop conflating \"sb\" in clone_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:58Z","receivedAt":"2022-07-28T16:18:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor the two uses of a \"struct strbuf sb\" such that each of them\nexists in its own scope. This makes the control flow clearer.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 25 +++++++++++++++++--------\n 1 file changed, 17 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex f74957444e1..6cedcc5b239 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1557,16 +1557,24 @@ static void prepare_possible_alternates(const char *sm_name,\n \tfree(error_strategy);\n }\n \n-static int clone_submodule(struct module_clone_data *clone_data)\n+static char *clone_submodule_sm_gitdir(const char *name)\n {\n-\tchar *p, *sm_gitdir;\n-\tchar *sm_alternate = NULL, *error_strategy = NULL;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tchar *sm_gitdir;\n \n-\tsubmodule_name_to_gitdir(&sb, the_repository, clone_data->name);\n+\tsubmodule_name_to_gitdir(&sb, the_repository, name);\n \tsm_gitdir = absolute_pathdup(sb.buf);\n-\tstrbuf_reset(&sb);\n+\tstrbuf_release(&sb);\n+\n+\treturn sm_gitdir;\n+}\n+\n+static int clone_submodule(struct module_clone_data *clone_data)\n+{\n+\tchar *p;\n+\tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n+\tchar *sm_alternate = NULL, *error_strategy = NULL;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \n \tif (!is_absolute_path(clone_data->path))\n \t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n@@ -1624,6 +1632,8 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n \t\t\t    clone_data->url, clone_data->path);\n \t} else {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n \t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n \t\t    !is_empty_dir(clone_data->path))\n \t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n@@ -1631,7 +1641,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n \t\tstrbuf_addf(&sb, \"%s/index\", sm_gitdir);\n \t\tunlink_or_warn(sb.buf);\n-\t\tstrbuf_reset(&sb);\n+\t\tstrbuf_release(&sb);\n \t}\n \n \tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n@@ -1653,7 +1663,6 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \tfree(sm_alternate);\n \tfree(error_strategy);\n \n-\tstrbuf_release(&sb);\n \tfree(sm_gitdir);\n \tfree(p);\n \treturn 0;\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460090","messageId":"patch-14.20-b364f3200d8-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 14/20] submodule--helper: pass a \"const struct module_clone_data\" to clone_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:16:59Z","receivedAt":"2022-07-28T16:18:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add \"const\" to the \"struct module_clone_data\" that we pass to\nclone_submodule(), which makes the ownership clear, and stops us from\nclobbering the \"clone_data->path\".\n\nWe still need to add to the \"reference\" member, which is a \"struct\nstring_list\". Let's do this by having clone_submodule() create its\nown, and copy the contents over, allowing us to pass it as a\nseparate parameter.\n\nThis new \"struct string_list\" still leaks memory, just as the \"struct\nmodule_clone_data\" did before. let's not fix that for now, to fix that\nwe'll need to add some \"goto cleanup\" to the relevant code. That will\nbe done in a follow-up commits, at that point it'll be easier to fix\nthe memory leak.\n\nThe scope of the new \"reference\" variable in add_submodule() could be\nnarrowed to the \"else\" block, but as we'll eventually free it with a\n\"goto cleanup\" let's declare it at the start of the function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 49 ++++++++++++++++++++-----------------\n 1 file changed, 26 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 6cedcc5b239..e235acce985 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1434,7 +1434,6 @@ struct module_clone_data {\n \tconst char *url;\n \tconst char *depth;\n \tstruct list_objects_filter_options *filter_options;\n-\tstruct string_list reference;\n \tunsigned int quiet: 1;\n \tunsigned int progress: 1;\n \tunsigned int dissociate: 1;\n@@ -1442,7 +1441,6 @@ struct module_clone_data {\n \tint single_branch;\n };\n #define MODULE_CLONE_DATA_INIT { \\\n-\t.reference = STRING_LIST_INIT_NODUP, \\\n \t.single_branch = -1, \\\n }\n \n@@ -1569,18 +1567,20 @@ static char *clone_submodule_sm_gitdir(const char *name)\n \treturn sm_gitdir;\n }\n \n-static int clone_submodule(struct module_clone_data *clone_data)\n+static int clone_submodule(const struct module_clone_data *clone_data,\n+\t\t\t   struct string_list *reference)\n {\n \tchar *p;\n \tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n \tchar *sm_alternate = NULL, *error_strategy = NULL;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tconst char *clone_data_path;\n \n \tif (!is_absolute_path(clone_data->path))\n-\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n-\t\t\t\t\t   clone_data->path);\n+\t\tclone_data_path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n+\t\t\t\t\t  clone_data->path);\n \telse\n-\t\tclone_data->path = xstrdup(clone_data->path);\n+\t\tclone_data_path = xstrdup(clone_data->path);\n \n \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n@@ -1590,7 +1590,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\tif (safe_create_leading_directories_const(sm_gitdir) < 0)\n \t\t\tdie(_(\"could not create directory '%s'\"), sm_gitdir);\n \n-\t\tprepare_possible_alternates(clone_data->name, &clone_data->reference);\n+\t\tprepare_possible_alternates(clone_data->name, reference);\n \n \t\tstrvec_push(&cp.args, \"clone\");\n \t\tstrvec_push(&cp.args, \"--no-checkout\");\n@@ -1600,10 +1600,10 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tstrvec_push(&cp.args, \"--progress\");\n \t\tif (clone_data->depth && *(clone_data->depth))\n \t\t\tstrvec_pushl(&cp.args, \"--depth\", clone_data->depth, NULL);\n-\t\tif (clone_data->reference.nr) {\n+\t\tif (reference->nr) {\n \t\t\tstruct string_list_item *item;\n \n-\t\t\tfor_each_string_list_item(item, &clone_data->reference)\n+\t\t\tfor_each_string_list_item(item, reference)\n \t\t\t\tstrvec_pushl(&cp.args, \"--reference\",\n \t\t\t\t\t     item->string, NULL);\n \t\t}\n@@ -1622,7 +1622,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \n \t\tstrvec_push(&cp.args, \"--\");\n \t\tstrvec_push(&cp.args, clone_data->url);\n-\t\tstrvec_push(&cp.args, clone_data->path);\n+\t\tstrvec_push(&cp.args, clone_data_path);\n \n \t\tcp.git_cmd = 1;\n \t\tprepare_submodule_repo_env(&cp.env);\n@@ -1630,25 +1630,25 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \n \t\tif(run_command(&cp))\n \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n-\t\t\t    clone_data->url, clone_data->path);\n+\t\t\t    clone_data->url, clone_data_path);\n \t} else {\n \t\tstruct strbuf sb = STRBUF_INIT;\n \n-\t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n-\t\t    !is_empty_dir(clone_data->path))\n-\t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n-\t\tif (safe_create_leading_directories_const(clone_data->path) < 0)\n-\t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n+\t\tif (clone_data->require_init && !access(clone_data_path, X_OK) &&\n+\t\t    !is_empty_dir(clone_data_path))\n+\t\t\tdie(_(\"directory not empty: '%s'\"), clone_data_path);\n+\t\tif (safe_create_leading_directories_const(clone_data_path) < 0)\n+\t\t\tdie(_(\"could not create directory '%s'\"), clone_data_path);\n \t\tstrbuf_addf(&sb, \"%s/index\", sm_gitdir);\n \t\tunlink_or_warn(sb.buf);\n \t\tstrbuf_release(&sb);\n \t}\n \n-\tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n+\tconnect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);\n \n-\tp = git_pathdup_submodule(clone_data->path, \"config\");\n+\tp = git_pathdup_submodule(clone_data_path, \"config\");\n \tif (!p)\n-\t\tdie(_(\"could not get submodule directory for '%s'\"), clone_data->path);\n+\t\tdie(_(\"could not get submodule directory for '%s'\"), clone_data_path);\n \n \t/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */\n \tgit_config_get_string(\"submodule.alternateLocation\", &sm_alternate);\n@@ -1673,6 +1673,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options = { 0 };\n+\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1686,7 +1687,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING(0, \"url\", &clone_data.url,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"url where to clone the submodule from\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &clone_data.reference,\n+\t\tOPT_STRING_LIST(0, \"reference\", &reference,\n \t\t\t   N_(\"repo\"),\n \t\t\t   N_(\"reference repository\")),\n \t\tOPT_BOOL(0, \"dissociate\", &dissociate,\n@@ -1725,7 +1726,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_submodule_helper_usage,\n \t\t\t\t   module_clone_options);\n \n-\tclone_submodule(&clone_data);\n+\tclone_submodule(&clone_data, &reference);\n \tlist_objects_filter_release(&filter_options);\n \treturn 0;\n }\n@@ -2913,6 +2914,7 @@ static int add_submodule(const struct add_data *add_data)\n {\n \tchar *submod_gitdir_path;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n+\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n \n \t/* perhaps the path already exists and is already a git repo, else clone it */\n \tif (is_directory(add_data->sm_path)) {\n@@ -2929,6 +2931,7 @@ static int add_submodule(const struct add_data *add_data)\n \t\tfree(submod_gitdir_path);\n \t} else {\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n \t\tsubmod_gitdir_path = xstrfmt(\".git/modules/%s\", add_data->sm_name);\n \n \t\tif (is_directory(submod_gitdir_path)) {\n@@ -2968,13 +2971,13 @@ static int add_submodule(const struct add_data *add_data)\n \t\tclone_data.quiet = add_data->quiet;\n \t\tclone_data.progress = add_data->progress;\n \t\tif (add_data->reference_path)\n-\t\t\tstring_list_append(&clone_data.reference,\n+\t\t\tstring_list_append(&reference,\n \t\t\t\t\t   xstrdup(add_data->reference_path));\n \t\tclone_data.dissociate = add_data->dissociate;\n \t\tif (add_data->depth >= 0)\n \t\t\tclone_data.depth = xstrfmt(\"%d\", add_data->depth);\n \n-\t\tif (clone_submodule(&clone_data))\n+\t\tif (clone_submodule(&clone_data, &reference))\n \t\t\treturn -1;\n \n \t\tprepare_submodule_repo_env(&cp.env);\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460091","messageId":"patch-15.20-e319f4edc54-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 15/20] submodule--helper: add \"const\" to copy of \"update_data\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:17:00Z","receivedAt":"2022-07-28T16:18:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nAdd a \"const\" to the copy of \"struct update_data\" that's tracked by\nthe \"struct submodule_update_clone\", as it neither owns nor modifies\nit.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e235acce985..fe92c9858ce 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1777,7 +1777,7 @@ struct submodule_update_clone {\n \tint current;\n \n \t/* configuration parameters which are passed on to the children */\n-\tstruct update_data *update_data;\n+\tconst struct update_data *update_data;\n \n \t/* to be consumed by update_submodule() */\n \tstruct update_clone_data *update_clone;\n@@ -1862,7 +1862,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tconst char *update_string;\n \tenum submodule_update_type update_type;\n \tchar *key;\n-\tstruct update_data *ud = suc->update_data;\n+\tconst struct update_data *ud = suc->update_data;\n \tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460092","messageId":"patch-16.20-68202100d9a-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 16/20] submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:17:01Z","receivedAt":"2022-07-28T16:18:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nRefactor code added in e83e3333b57 (submodule: port submodule\nsubcommand 'summary' from shell to C, 2020-08-13) so that \"errmsg\" and\n\"errmsg_str\" are folded into one. The distinction between the empty\nstring and NULL is something that's tested for by\ne.g. \"t/t7401-submodule-summary.sh\".\n\nThis is in preparation for fixing a memory leak the \"struct strbuf\" in\nthe pre-image.\n\nLet's also pass a \"const char *\" to print_submodule_summary(), as it\nshould not be modifying the \"errmsg\".\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 14 ++++++--------\n 1 file changed, 6 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex fe92c9858ce..f451704af79 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -761,7 +761,7 @@ static char *verify_submodule_committish(const char *sm_path,\n \treturn strbuf_detach(&result, NULL);\n }\n \n-static void print_submodule_summary(struct summary_cb *info, char *errmsg,\n+static void print_submodule_summary(struct summary_cb *info, const char *errmsg,\n \t\t\t\t    int total_commits, const char *displaypath,\n \t\t\t\t    const char *src_abbrev, const char *dst_abbrev,\n \t\t\t\t    struct module_cb *p)\n@@ -819,7 +819,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n {\n \tchar *displaypath, *src_abbrev = NULL, *dst_abbrev;\n \tint missing_src = 0, missing_dst = 0;\n-\tchar *errmsg = NULL;\n+\tstruct strbuf errmsg = STRBUF_INIT;\n \tint total_commits = -1;\n \n \tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n@@ -920,23 +920,21 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t\t * submodule, i.e., deleted or changed to blob\n \t\t */\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n-\t\t\tstruct strbuf errmsg_str = STRBUF_INIT;\n \t\t\tif (missing_src && missing_dst) {\n-\t\t\t\tstrbuf_addf(&errmsg_str, \"  Warn: %s doesn't contain commits %s and %s\\n\",\n+\t\t\t\tstrbuf_addf(&errmsg, \"  Warn: %s doesn't contain commits %s and %s\\n\",\n \t\t\t\t\t    displaypath, oid_to_hex(&p->oid_src),\n \t\t\t\t\t    oid_to_hex(&p->oid_dst));\n \t\t\t} else {\n-\t\t\t\tstrbuf_addf(&errmsg_str, \"  Warn: %s doesn't contain commit %s\\n\",\n+\t\t\t\tstrbuf_addf(&errmsg, \"  Warn: %s doesn't contain commit %s\\n\",\n \t\t\t\t\t    displaypath, missing_src ?\n \t\t\t\t\t    oid_to_hex(&p->oid_src) :\n \t\t\t\t\t    oid_to_hex(&p->oid_dst));\n \t\t\t}\n-\t\t\terrmsg = strbuf_detach(&errmsg_str, NULL);\n \t\t}\n \t}\n \n-\tprint_submodule_summary(info, errmsg, total_commits,\n-\t\t\t\tdisplaypath, src_abbrev,\n+\tprint_submodule_summary(info, errmsg.len ? errmsg.buf : NULL,\n+\t\t\t\ttotal_commits, displaypath, src_abbrev,\n \t\t\t\tdst_abbrev, p);\n \n \tfree(displaypath);\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460093","messageId":"patch-17.20-e8aacb55a18-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 17/20] submodule--helper: rename \"int res\" to \"int ret\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:17:02Z","receivedAt":"2022-07-28T16:19:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Rename the \"res\" variable added in b3c5f5cb048 (submodule: move core\ncmd_update() logic to C, 2022-03-15) to \"ret\", which is the convention\nin the rest of this file.\n\nEventual follow-up commits will change this code to a \"goto cleanup\"\npattern, let's have the post image look consistent with the rest.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex f451704af79..349fe7f269c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2424,7 +2424,7 @@ static int update_submodule(struct update_data *update_data)\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+\t\tint ret;\n \n \t\tnext.prefix = NULL;\n \t\toidcpy(&next.oid, null_oid());\n@@ -2436,14 +2436,14 @@ static int update_submodule(struct update_data *update_data)\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\tret = run_command(&cp);\n+\t\tif (!ret)\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\tif (ret == 128)\n+\t\t\texit(ret);\n+\t\telse if (ret)\n \t\t\treturn 1;\n \t}\n \n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460094","messageId":"patch-18.20-41fb22d8549-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 18/20] submodule--helper: add skeleton \"goto cleanup\" to update_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:17:03Z","receivedAt":"2022-07-28T16:19:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a skeleton \"goto cleanup\" pattern to update_submodule(), rather\nthan having branches in it \"return\". This is in preparation for\neventually freeing data with the \"cleanup\" label, but for now we're\nusing it as the equivalent of a \"done\" label.\n\nThe \"exit()\" branch is not handled yet, and neither is the exit() that\nrun_update_procedure() might invoke. That'll be handled in a\nsubsequent commit.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 22 ++++++++++++++--------\n 1 file changed, 14 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 349fe7f269c..68aa10a26cd 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2383,6 +2383,8 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \n static int update_submodule(struct update_data *update_data)\n {\n+\tint ret = 1;\n+\n \tensure_core_worktree(update_data->sm_path);\n \n \tupdate_data->displaypath = get_submodule_displaypath(\n@@ -2417,14 +2419,14 @@ static int update_submodule(struct update_data *update_data)\n \t\tfree(remote_ref);\n \t}\n \n-\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\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+\t\t\tgoto cleanup;\n+\t}\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 ret;\n \n \t\tnext.prefix = NULL;\n \t\toidcpy(&next.oid, null_oid());\n@@ -2438,16 +2440,20 @@ static int update_submodule(struct update_data *update_data)\n \t\t/* die() if child process die()'d */\n \t\tret = run_command(&cp);\n \t\tif (!ret)\n-\t\t\treturn 0;\n+\t\t\tgoto cleanup;\n \t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n \t\t\t    update_data->displaypath);\n-\t\tif (ret == 128)\n+\t\tif (ret == 128) {\n \t\t\texit(ret);\n-\t\telse if (ret)\n-\t\t\treturn 1;\n+\t\t} else if (ret) {\n+\t\t\tret = 1;\n+\t\t\tgoto cleanup;\n+\t\t}\n \t}\n \n-\treturn 0;\n+\tret = 0;\n+cleanup:\n+\treturn ret;\n }\n \n static int update_submodules(struct update_data *update_data)\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460095","messageId":"patch-19.20-5a26c9428be-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 19/20] submodule--helper: don't exit() on failure, return","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:17:04Z","receivedAt":"2022-07-28T16:19:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code downstream of module_update() to short-circuit and return\nto the top-level on failure, rather than calling exit().\n\nTo do so we need to diligently check whether we \"must_die_on_failure\",\nwhich is a pattern started in c51f8f94e5b (submodule--helper: run\nupdate procedures from C, 2021-08-24), but which hadn't been completed\nto the point where we could avoid calling exit() here.\n\nThis introduces no functional changes, but makes it easier to both\ncall these routines as a library in the future, and to eventually\navoid leaking memory.\n\nThis and similar control flow in submodule--helper.c could be made\nsimpler by properly \"libifying\" it, i.e. to have it consistently\nreturn -1 on failures, and to early return on any non-success.\n\nBut let's leave that larger project for now, and (mostly) emulate what\nwere doing with the \"exit(128)\" before this change.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 36 ++++++++++++++++++++++++++----------\n 1 file changed, 26 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 68aa10a26cd..d3f22f03766 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2121,7 +2121,8 @@ 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,\n+\t\t\t      int *must_die_on_failurep)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n@@ -2183,8 +2184,10 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tif (must_die_on_failure)\n-\t\t\texit(128);\n+\t\tif (must_die_on_failure) {\n+\t\t\t*must_die_on_failurep = 1;\n+\t\t\treturn 128;\n+\t\t}\n \n \t\t/* the command failed, but update must continue */\n \t\treturn 1;\n@@ -2218,7 +2221,8 @@ static int run_update_command(struct update_data *ud, int subforce)\n \treturn 0;\n }\n \n-static int run_update_procedure(struct update_data *ud)\n+static int run_update_procedure(struct update_data *ud,\n+\t\t\t\tint *must_die_on_failure)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2245,7 +2249,7 @@ static int 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, must_die_on_failure);\n }\n \n static const char *remote_submodule_branch(const char *path)\n@@ -2381,7 +2385,8 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \t\t\t\t    \"--no-single-branch\");\n }\n \n-static int update_submodule(struct update_data *update_data)\n+static int update_submodule(struct update_data *update_data,\n+\t\t\t    int *must_die_on_failure)\n {\n \tint ret = 1;\n \n@@ -2420,8 +2425,13 @@ 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 (run_update_procedure(update_data))\n+\t\tret = run_update_procedure(update_data, must_die_on_failure);\n+\t\tif (ret && *must_die_on_failure) {\n+\t\t\tgoto cleanup;\n+\t\t} else if (ret) {\n+\t\t\tret = 1;\n \t\t\tgoto cleanup;\n+\t\t}\n \t}\n \n \tif (update_data->recursive) {\n@@ -2444,7 +2454,8 @@ static int update_submodule(struct update_data *update_data)\n \t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n \t\t\t    update_data->displaypath);\n \t\tif (ret == 128) {\n-\t\t\texit(ret);\n+\t\t\t*must_die_on_failure = 1;\n+\t\t\tgoto cleanup;\n \t\t} else if (ret) {\n \t\t\tret = 1;\n \t\t\tgoto cleanup;\n@@ -2482,13 +2493,18 @@ static int update_submodules(struct update_data *update_data)\n \n \tfor (i = 0; i < suc.update_clone_nr; i++) {\n \t\tstruct update_clone_data ucd = suc.update_clone[i];\n+\t\tint code;\n+\t\tint must_die_on_failure = 0;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n+\t\tif (code)\n+\t\t\tres = code;\n+\t\tif (must_die_on_failure)\n+\t\t\tgoto cleanup;\n \t}\n \n cleanup:\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460096","messageId":"patch-20.20-579560cb9a8-20220728T161116Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH 20/20] submodule--helper: fix bad config API usage","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-28T16:17:05Z","receivedAt":"2022-07-28T16:19:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix bad config API usage added in a452128a36c (submodule--helper:\nintroduce add-config subcommand, 2021-08-06). After\ngit_config_get_string() returns successfully we know the \"char **dest\"\nwill be non-NULL.\n\nA coccinelle patch that transforms this turns up a couple of other\nsuch issues, one in fetch-pack.c, and another in upload-pack.c:\n\n\t@@\n\tidentifier F =~ \"^(repo|git)_config_get_string(_tmp)?$\";\n\tidentifier V;\n\t@@\n\t  !F(..., &V)\n\t- && (V)\n\nBut let's focus narrowly on submodule--helper for now, we can fix\nthose some other time.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex d3f22f03766..22c79353bb0 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -3083,7 +3083,7 @@ static void configure_added_submodule(struct add_data *add_data)\n \t * is_submodule_active(), since that function needs to find\n \t * out the value of \"submodule.active\" again anyway.\n \t */\n-\tif (!git_config_get_string(\"submodule.active\", &val) && val) {\n+\tif (!git_config_get_string(\"submodule.active\", &val)) {\n \t\t/*\n \t\t * If the submodule being added isn't already covered by the\n \t\t * current configured pathspec, set the submodule's active flag\n-- \n2.37.1.1167.g38fda70d8c4\n\n"},{"id":"460235","messageId":"kl6l4jyzsv6o.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-13.20-afe34d8b73b-20220728T161116Z-avarab@gmail.com","subject":"Re: [PATCH 13/20] submodule--helper: stop conflating \"sb\" in clone_submodule()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-07-29T17:08:47Z","receivedAt":"2022-07-29T17:08:53Z","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> Refactor the two uses of a \"struct strbuf sb\" such that each of them\n> exists in its own scope. This makes the control flow clearer.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 25 +++++++++++++++++--------\n>  1 file changed, 17 insertions(+), 8 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index f74957444e1..6cedcc5b239 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -1557,16 +1557,24 @@ static void prepare_possible_alternates(const char *sm_name,\n>  \tfree(error_strategy);\n>  }\n>  \n> -static int clone_submodule(struct module_clone_data *clone_data)\n> +static char *clone_submodule_sm_gitdir(const char *name)\n>  {\n> -\tchar *p, *sm_gitdir;\n> -\tchar *sm_alternate = NULL, *error_strategy = NULL;\n>  \tstruct strbuf sb = STRBUF_INIT;\n> -\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\tchar *sm_gitdir;\n>  \n> -\tsubmodule_name_to_gitdir(&sb, the_repository, clone_data->name);\n> +\tsubmodule_name_to_gitdir(&sb, the_repository, name);\n>  \tsm_gitdir = absolute_pathdup(sb.buf);\n> -\tstrbuf_reset(&sb);\n> +\tstrbuf_release(&sb);\n> +\n> +\treturn sm_gitdir;\n> +}\n> +\n> +static int clone_submodule(struct module_clone_data *clone_data)\n> +{\n> +\tchar *p;\n> +\tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n> +\tchar *sm_alternate = NULL, *error_strategy = NULL;\n> +\tstruct child_process cp = CHILD_PROCESS_INIT;\n>  \n>  \tif (!is_absolute_path(clone_data->path))\n>  \t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n> @@ -1624,6 +1632,8 @@ static int clone_submodule(struct module_clone_data *clone_data)\n>  \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n>  \t\t\t    clone_data->url, clone_data->path);\n>  \t} else {\n> +\t\tstruct strbuf sb = STRBUF_INIT;\n> +\n>  \t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n>  \t\t    !is_empty_dir(clone_data->path))\n>  \t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n> @@ -1631,7 +1641,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n>  \t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n>  \t\tstrbuf_addf(&sb, \"%s/index\", sm_gitdir);\n>  \t\tunlink_or_warn(sb.buf);\n> -\t\tstrbuf_reset(&sb);\n> +\t\tstrbuf_release(&sb);\n>  \t}\n\nAs Junio mentioned in\nhttps://lore.kernel.org/git/xmqqlesmf9or.fsf@gitster.g, we could also\nreplace this with xstrfmt(). I think that gets rid of all of the\nusers of \"sb\", so I doubt we'll even need this patch once we\nmake that change :)\n\n>  \n>  \tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n> @@ -1653,7 +1663,6 @@ static int clone_submodule(struct module_clone_data *clone_data)\n>  \tfree(sm_alternate);\n>  \tfree(error_strategy);\n>  \n> -\tstrbuf_release(&sb);\n>  \tfree(sm_gitdir);\n>  \tfree(p);\n>  \treturn 0;\n> -- \n> 2.37.1.1167.g38fda70d8c4\n"},{"id":"460268","messageId":"kl6l1qu3slv0.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-01.20-84b05bda016-20220728T161116Z-avarab@gmail.com","subject":"Re: [PATCH 01/20] submodule tests: test usage behavior","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-07-29T20:30:11Z","receivedAt":"2022-07-29T20:30:23Z","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> Test what exit code and output we emit on \"git submodule -h\", how we\n> handle \"--\" when no subcommand is specified, and how the top-level\n> \"--recursive\" option is handled.\n>\n> For \"-h\" this doesn't make sense, but let's test for it so that any\n> subsequent eventual behavior change will become clear.\n\nAs a smoke test, this makes sense.\n\n>\n> For \"--\" this follows up on 68cabbfda36 (submodule: document default\n> behavior, 2019-02-15) and tests that when \"status\" isn't supplied we\n> don't support the \"--\" delimiter. There's no intrinsically good reason\n> not to support that. We behave this way due to edge cases in\n> git-submodule.sh's implementation, but as with \"-h\" let's assert our\n> current long-standing behavior for now.\n\nBy this, do you mean that git-submodule.sh inserts \"--\" when it invokes\n\"git submodule--helper\"? That also seems ok.\n\n>\n> For \"--recursive\" the exclusion of it from the top-level appears to\n> have been an omission in 15fc56a8536 (git submodule foreach: Add\n> --recursive to recurse into nested submodules, 2009-08-19), there\n> doesn't seem to be a reason not to support it alongside \"--quiet\" and\n> \"--cached\", but let's likewise assert our existing behavior for now.\n\nI'm not sure about this one. \"--recursive\" isn't a top level option, and\n15fc56a8536 doesn't seem to suggest that it was meant to be one (but I\ndid realize that git-submodule.txt documents all of the options to all\nsubcommands, which is very confusing.)\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t7400-submodule-basic.sh | 26 ++++++++++++++++++++++++++\n>  1 file changed, 26 insertions(+)\n>\n> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\n> index e7cec2e457a..b858871a953 100755\n> --- a/t/t7400-submodule-basic.sh\n> +++ b/t/t7400-submodule-basic.sh\n> @@ -14,6 +14,32 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n>  \n>  . ./test-lib.sh\n>  \n> +test_expect_success 'submodule usage: -h' '\n> +\tgit submodule -h >out 2>err &&\n> +\tgrep \"^usage: git submodule\" out &&\n> +\ttest_must_be_empty err\n> +'\n> +\n> +test_expect_success 'submodule usage: --recursive' '\n> +\ttest_expect_code 1 git submodule --recursive >out 2>err &&\n> +\tgrep \"^usage: git submodule\" err &&\n> +\ttest_must_be_empty out\n> +'\n> +\n> +test_expect_success 'submodule usage: status --' '\n> +\ttest_expect_code 1 git submodule -- &&\n> +\ttest_expect_code 1 git submodule --end-of-options\n> +'\n> +\n> +for opt in '--quiet' '--cached'\n> +do\n> +\ttest_expect_success \"submodule usage: status $opt\" '\n> +\t\tgit submodule $opt &&\n> +\t\tgit submodule status $opt &&\n> +\t\tgit submodule $opt status\n> +\t'\n> +done\n> +\n>  test_expect_success 'submodule deinit works on empty repository' '\n>  \tgit submodule deinit --all\n>  '\n> -- \n> 2.37.1.1167.g38fda70d8c4\n"},{"id":"460277","messageId":"kl6ly1wbr4h7.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-04.20-27df2efe718-20220728T161116Z-avarab@gmail.com","subject":"Re: [PATCH 04/20] submodule--helper: remove unused \"list\" helper","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-07-29T21:31:00Z","receivedAt":"2022-07-29T21:31:14Z","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> Remove the \"submodule--helper list\" sub-command, which hasn't been\n> used by git-submodule.sh since 2964d6e5e1e (submodule: port subcommand\n> 'set-branch' from shell to C, 2020-06-02).\n>\n> There was a test added in 2b56bb7a87a (submodule helper list: respect\n> correct path prefix, 2016-02-24) which relied on it, but the right\n> thing to do here is to delete that test as well.\n>\n> That test was regression testing the \"list\" subcommand itself. We're\n> not getting anything useful from the \"list | cut -f2\" invocation that\n> we couldn't get from \"foreach 'echo $sm_path'\".\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 40 -------------------------------------\n>  t/t7400-submodule-basic.sh  | 25 -----------------------\n>  2 files changed, 65 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index ac2553ba9d3..47ed24c6a60 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -266,45 +266,6 @@ static char *get_up_path(const char *path)\n>  \treturn strbuf_detach(&sb, NULL);\n>  }\n>  \n> -static int module_list(int argc, const char **argv, const char *prefix)\n> -{\n> -\tint i;\n> -\tstruct pathspec pathspec;\n> -\tstruct module_list list = MODULE_LIST_INIT;\n> -\n> -\tstruct option module_list_options[] = {\n> -\t\tOPT_STRING(0, \"prefix\", &prefix,\n> -\t\t\t   N_(\"path\"),\n> -\t\t\t   N_(\"alternative anchor for relative paths\")),\n> -\t\tOPT_END()\n> -\t};\n> -\n> -\tconst char *const git_submodule_helper_usage[] = {\n> -\t\tN_(\"git submodule--helper list [--prefix=<path>] [<path>...]\"),\n> -\t\tNULL\n> -\t};\n> -\n> -\targc = parse_options(argc, argv, prefix, module_list_options,\n> -\t\t\t     git_submodule_helper_usage, 0);\n> -\n> -\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n> -\t\treturn 1;\n> -\n> -\tfor (i = 0; i < list.nr; i++) {\n> -\t\tconst struct cache_entry *ce = list.entries[i];\n> -\n> -\t\tif (ce_stage(ce))\n> -\t\t\tprintf(\"%06o %s U\\t\", ce->ce_mode,\n> -\t\t\t       oid_to_hex(null_oid()));\n> -\t\telse\n> -\t\t\tprintf(\"%06o %s %d\\t\", ce->ce_mode,\n> -\t\t\t       oid_to_hex(&ce->oid), ce_stage(ce));\n> -\n> -\t\tfprintf(stdout, \"%s\\n\", ce->name);\n> -\t}\n> -\treturn 0;\n> -}\n> -\n\nHooray for nuking dead code! Thanks :)\n\nI'm happy that we're taking a sh -> C path that's catching little things\nlike this.\n\n>  static void for_each_listed_submodule(const struct module_list *list,\n>  \t\t\t\t      each_submodule_fn fn, void *cb_data)\n>  {\n> @@ -3340,7 +3301,6 @@ struct cmd_struct {\n>  };\n>  \n>  static struct cmd_struct commands[] = {\n> -\t{\"list\", module_list, 0},\n>  \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n>  \t{\"add\", module_add, 0},\n>  \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\n> index 6a77d817a82..b50db3f1031 100755\n> --- a/t/t7400-submodule-basic.sh\n> +++ b/t/t7400-submodule-basic.sh\n> @@ -1255,31 +1255,6 @@ test_expect_success 'submodule add clone shallow submodule' '\n>  \t)\n>  '\n>  \n> -test_expect_success 'submodule helper list is not confused by common prefixes' '\n> -\tmkdir -p dir1/b &&\n> -\t(\n> -\t\tcd dir1/b &&\n> -\t\tgit init &&\n> -\t\techo hi >testfile2 &&\n> -\t\tgit add . &&\n> -\t\tgit commit -m \"test1\"\n> -\t) &&\n> -\tmkdir -p dir2/b &&\n> -\t(\n> -\t\tcd dir2/b &&\n> -\t\tgit init &&\n> -\t\techo hello >testfile1 &&\n> -\t\tgit add .  &&\n> -\t\tgit commit -m \"test2\"\n> -\t) &&\n> -\tgit submodule add /dir1/b dir1/b &&\n> -\tgit submodule add /dir2/b dir2/b &&\n> -\tgit commit -m \"first submodule commit\" &&\n> -\tgit submodule--helper list dir1/b | cut -f 2 >actual &&\n> -\techo \"dir1/b\" >expect &&\n> -\ttest_cmp expect actual\n> -'\n> -\n>  test_expect_success 'setup superproject with submodules' '\n>  \tgit init sub1 &&\n>  \ttest_commit -C sub1 test &&\n> -- \n> 2.37.1.1167.g38fda70d8c4\n"},{"id":"460279","messageId":"kl6lv8rfr3tc.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-06.20-8e4d2b09d56-20220728T161116Z-avarab@gmail.com","subject":"Re: [PATCH 06/20] submodule--helper: move \"is-active\" to a test-tool","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-07-29T21:45:19Z","receivedAt":"2022-07-29T21:45:25Z","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> Create a new \"test-tool submodule\" and move the \"is-active\" subcommand\n> over to it. It was added in 5c2bd8b77ae (submodule--helper: add\n> is-active subcommand, 2017-03-16), since\n> a452128a36c (submodule--helper: introduce add-config subcommand,\n> 2021-08-06) it hasn't been used by git-submodule.sh.\n>\n> Since we're creating a command dispatch similar to test-tool.c itself\n> let's split out the \"struct test_cmd\" into a new test-tool-utils.h,\n> which both this new code and test-tool.c itself can use.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  Makefile                       |  1 +\n>  builtin/submodule--helper.c    |  9 ------\n>  t/helper/test-submodule.c      | 58 ++++++++++++++++++++++++++++++++++\n>  t/helper/test-tool-utils.h     |  9 ++++++\n>  t/helper/test-tool.c           |  7 ++--\n>  t/helper/test-tool.h           |  1 +\n>  t/t7413-submodule-is-active.sh | 32 +++++++++----------\n>  7 files changed, 87 insertions(+), 30 deletions(-)\n>  create mode 100644 t/helper/test-submodule.c\n>  create mode 100644 t/helper/test-tool-utils.h\n>\n> diff --git a/Makefile b/Makefile\n> index 1624471badc..ad7fbd36885 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -785,6 +785,7 @@ TEST_BUILTINS_OBJS += test-strcmp-offset.o\n>  TEST_BUILTINS_OBJS += test-string-list.o\n>  TEST_BUILTINS_OBJS += test-submodule-config.o\n>  TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o\n> +TEST_BUILTINS_OBJS += test-submodule.o\n>  TEST_BUILTINS_OBJS += test-subprocess.o\n>  TEST_BUILTINS_OBJS += test-trace2.o\n>  TEST_BUILTINS_OBJS += test-urlmatch-normalization.o\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 47ed24c6a60..b2fc732b5d8 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2728,14 +2728,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n>  \treturn 0;\n>  }\n>  \n> -static int is_active(int argc, const char **argv, const char *prefix)\n> -{\n> -\tif (argc != 2)\n> -\t\tdie(\"submodule--helper is-active takes exactly 1 argument\");\n> -\n> -\treturn !is_submodule_active(the_repository, argv[1]);\n> -}\n> -\n>  /*\n>   * Exit non-zero if any of the submodule names given on the command line is\n>   * invalid. If no names are given, filter stdin to print only valid names\n> @@ -3313,7 +3305,6 @@ static struct cmd_struct commands[] = {\n>  \t{\"summary\", module_summary, 0},\n>  \t{\"push-check\", push_check, 0},\n>  \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n> -\t{\"is-active\", is_active, 0},\n>  \t{\"check-name\", check_name, 0},\n>  \t{\"config\", module_config, 0},\n>  \t{\"set-url\", module_set_url, 0},\n> diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\n> new file mode 100644\n> index 00000000000..494c6558d9f\n> --- /dev/null\n> +++ b/t/helper/test-submodule.c\n> @@ -0,0 +1,58 @@\n> +#include \"test-tool.h\"\n> +#include \"test-tool-utils.h\"\n> +#include \"cache.h\"\n> +#include \"parse-options.h\"\n> +#include \"submodule.h\"\n> +\n> +#define TEST_TOOL_IS_ACTIVE_USAGE \\\n> +\t\"test-tool submodule is-active <name>\"\n> +static const char *submodule_is_active_usage[] = {\n> +\tTEST_TOOL_IS_ACTIVE_USAGE,\n> +\tNULL\n> +};\n> +\n> +static const char *submodule_usage[] = {\n> +\tTEST_TOOL_IS_ACTIVE_USAGE,\n> +\tNULL\n> +};\n> +\n> +static int cmd__submodule_is_active(int argc, const char **argv)\n> +{\n> +\tstruct option options[] = {\n> +\t\tOPT_END()\n> +\t};\n> +\targc = parse_options(argc, argv, \"test-tools\", options,\n> +\t\t\t     submodule_is_active_usage, 0);\n> +\tif (argc != 1)\n> +\t\tusage_with_options(submodule_is_active_usage, options);\n> +\n> +\tsetup_git_directory();\n> +\n> +\treturn !is_submodule_active(the_repository, argv[0]);\n> +}\n> +\n> +static struct test_cmd cmds[] = {\n> +\t{ \"is-active\", cmd__submodule_is_active },\n> +};\n> +\n> +int cmd__submodule(int argc, const char **argv)\n> +{\n> +\tstruct option options[] = {\n> +\t\tOPT_END()\n> +\t};\n> +\tsize_t i;\n> +\n> +\targc = parse_options(argc, argv, \"test-tools\", options, submodule_usage,\n> +\t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n> +\tif (argc < 1)\n> +\t\tusage_with_options(submodule_usage, options);\n> +\n> +\tfor (i = 0; i < ARRAY_SIZE(cmds); i++)\n> +\t\tif (!strcmp(cmds[i].name, argv[0]))\n> +\t\t\treturn cmds[i].fn(argc, argv);\n> +\n> +\tusage_msg_optf(\"unknown subcommand '%s'\", submodule_usage, options,\n> +\t\t       argv[0]);\n> +\n> +\treturn 0;\n> +}\n> diff --git a/t/helper/test-tool-utils.h b/t/helper/test-tool-utils.h\n> new file mode 100644\n> index 00000000000..6a0e5e0074f\n> --- /dev/null\n> +++ b/t/helper/test-tool-utils.h\n> @@ -0,0 +1,9 @@\n> +#ifndef TEST_TOOL_UTILS_H\n> +#define TEST_TOOL_UTILS_H\n> +\n> +struct test_cmd {\n> +\tconst char *name;\n> +\tint (*fn)(int argc, const char **argv);\n> +};\n> +\n> +#endif\n> diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c\n> index 318fdbab0c3..7a6a8b88a91 100644\n> --- a/t/helper/test-tool.c\n> +++ b/t/helper/test-tool.c\n> @@ -1,5 +1,6 @@\n>  #include \"git-compat-util.h\"\n>  #include \"test-tool.h\"\n> +#include \"test-tool-utils.h\"\n>  #include \"trace2.h\"\n>  #include \"parse-options.h\"\n>  \n> @@ -8,11 +9,6 @@ static const char * const test_tool_usage[] = {\n>  \tNULL\n>  };\n>  \n> -struct test_cmd {\n> -\tconst char *name;\n> -\tint (*fn)(int argc, const char **argv);\n> -};\n> -\n>  static struct test_cmd cmds[] = {\n>  \t{ \"advise\", cmd__advise_if_enabled },\n>  \t{ \"bitmap\", cmd__bitmap },\n> @@ -78,6 +74,7 @@ static struct test_cmd cmds[] = {\n>  \t{ \"simple-ipc\", cmd__simple_ipc },\n>  \t{ \"strcmp-offset\", cmd__strcmp_offset },\n>  \t{ \"string-list\", cmd__string_list },\n> +\t{ \"submodule\", cmd__submodule },\n>  \t{ \"submodule-config\", cmd__submodule_config },\n>  \t{ \"submodule-nested-repo-config\", cmd__submodule_nested_repo_config },\n>  \t{ \"subprocess\", cmd__subprocess },\n> diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h\n> index bb799271631..5f4f69dee81 100644\n> --- a/t/helper/test-tool.h\n> +++ b/t/helper/test-tool.h\n> @@ -68,6 +68,7 @@ int cmd__sigchain(int argc, const char **argv);\n>  int cmd__simple_ipc(int argc, const char **argv);\n>  int cmd__strcmp_offset(int argc, const char **argv);\n>  int cmd__string_list(int argc, const char **argv);\n> +int cmd__submodule(int argc, const char **argv);\n>  int cmd__submodule_config(int argc, const char **argv);\n>  int cmd__submodule_nested_repo_config(int argc, const char **argv);\n>  int cmd__subprocess(int argc, const char **argv);\n\nI'm underqualified to comment on structure of test-tool, so I won't\ncomment on that, but it makes sense to convert code that is only used in\ntests into test helpers.\n\nThat said, don't we only use \"git submodule--helper is-active\" inside\nthe tests for \"git submodule--helper is-active\"? If so, I'd think the\nright thing to do is to just get rid of the code altogether.\n\nThe exception IMO, is if we think that we want a kind of \"unit test\"\nthat checks our logic for determining if a submodule is active. I don't\nreally think that's necessary, but if so, we probably want to update the\ndescription of t7413 to describe that intent.\n\n> diff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh\n> index c8e7e983317..9ead083371a 100755\n> --- a/t/t7413-submodule-is-active.sh\n> +++ b/t/t7413-submodule-is-active.sh\n> @@ -1,8 +1,8 @@\n>  #!/bin/sh\n>  \n> -test_description='Test submodule--helper is-active\n> +test_description='Test with test-tool submodule is-active\n>  \n> -This test verifies that `git submodue--helper is-active` correctly identifies\n> +This test verifies that `test-tool submodule is-active` correctly identifies\n>  submodules which are \"active\" and interesting to the user.\n>  '\n>  \n> @@ -25,13 +25,13 @@ test_expect_success 'setup' '\n>  '\n>  \n>  test_expect_success 'is-active works with urls' '\n> -\tgit -C super submodule--helper is-active sub1 &&\n> -\tgit -C super submodule--helper is-active sub2 &&\n> +\ttest-tool -C super submodule is-active sub1 &&\n> +\ttest-tool -C super submodule is-active sub2 &&\n>  \n>  \tgit -C super config --unset submodule.sub1.URL &&\n> -\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n> +\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n>  \tgit -C super config submodule.sub1.URL ../sub &&\n> -\tgit -C super submodule--helper is-active sub1\n> +\ttest-tool -C super submodule is-active sub1\n>  '\n>  \n>  test_expect_success 'is-active works with submodule.<name>.active config' '\n> @@ -39,11 +39,11 @@ test_expect_success 'is-active works with submodule.<name>.active config' '\n>  \ttest_when_finished \"git -C super config submodule.sub1.URL ../sub\" &&\n>  \n>  \tgit -C super config --bool submodule.sub1.active \"false\" &&\n> -\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n> +\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n>  \n>  \tgit -C super config --bool submodule.sub1.active \"true\" &&\n>  \tgit -C super config --unset submodule.sub1.URL &&\n> -\tgit -C super submodule--helper is-active sub1\n> +\ttest-tool -C super submodule is-active sub1\n>  '\n>  \n>  test_expect_success 'is-active works with basic submodule.active config' '\n> @@ -53,17 +53,17 @@ test_expect_success 'is-active works with basic submodule.active config' '\n>  \tgit -C super config --add submodule.active \".\" &&\n>  \tgit -C super config --unset submodule.sub1.URL &&\n>  \n> -\tgit -C super submodule--helper is-active sub1 &&\n> -\tgit -C super submodule--helper is-active sub2\n> +\ttest-tool -C super submodule is-active sub1 &&\n> +\ttest-tool -C super submodule is-active sub2\n>  '\n>  \n>  test_expect_success 'is-active correctly works with paths that are not submodules' '\n>  \ttest_when_finished \"git -C super config --unset-all submodule.active\" &&\n>  \n> -\ttest_must_fail git -C super submodule--helper is-active not-a-submodule &&\n> +\ttest_must_fail test-tool -C super submodule is-active not-a-submodule &&\n>  \n>  \tgit -C super config --add submodule.active \".\" &&\n> -\ttest_must_fail git -C super submodule--helper is-active not-a-submodule\n> +\ttest_must_fail test-tool -C super submodule is-active not-a-submodule\n>  '\n>  \n>  test_expect_success 'is-active works with exclusions in submodule.active config' '\n> @@ -72,8 +72,8 @@ test_expect_success 'is-active works with exclusions in submodule.active config'\n>  \tgit -C super config --add submodule.active \".\" &&\n>  \tgit -C super config --add submodule.active \":(exclude)sub1\" &&\n>  \n> -\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n> -\tgit -C super submodule--helper is-active sub2\n> +\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n> +\ttest-tool -C super submodule is-active sub2\n>  '\n>  \n>  test_expect_success 'is-active with submodule.active and submodule.<name>.active' '\n> @@ -85,8 +85,8 @@ test_expect_success 'is-active with submodule.active and submodule.<name>.active\n>  \tgit -C super config --bool submodule.sub1.active \"false\" &&\n>  \tgit -C super config --bool submodule.sub2.active \"true\" &&\n>  \n> -\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n> -\tgit -C super submodule--helper is-active sub2\n> +\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n> +\ttest-tool -C super submodule is-active sub2\n>  '\n>  \n>  test_expect_success 'is-active, submodule.active and submodule add' '\n> -- \n> 2.37.1.1167.g38fda70d8c4\n"},{"id":"460280","messageId":"kl6lsfmjr3d3.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-07.20-a2f3d812815-20220728T161116Z-avarab@gmail.com","subject":"Re: [PATCH 07/20] submodule--helper: move \"check-name\" to a test-tool","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-07-29T21:55:04Z","receivedAt":"2022-07-29T21:55:12Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Move the \"check-name\" helper to a test-tool, since\n> a6226fd772b (submodule--helper: convert the bulk of cmd_add() to C,\n> 2021-08-10) it has only been used by this test, not git-submodule.sh.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 24 -------------------\n>  t/helper/test-submodule.c   | 46 +++++++++++++++++++++++++++++++++++++\n>  t/t7450-bad-git-dotfiles.sh |  2 +-\n>  3 files changed, 47 insertions(+), 25 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index b2fc732b5d8..06307886080 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2728,29 +2728,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n>  \treturn 0;\n>  }\n>  \n> -/*\n> - * Exit non-zero if any of the submodule names given on the command line is\n> - * invalid. If no names are given, filter stdin to print only valid names\n> - * (which is primarily intended for testing).\n> - */\n> -static int check_name(int argc, const char **argv, const char *prefix)\n> -{\n> -\tif (argc > 1) {\n> -\t\twhile (*++argv) {\n> -\t\t\tif (check_submodule_name(*argv) < 0)\n> -\t\t\t\treturn 1;\n> -\t\t}\n> -\t} else {\n> -\t\tstruct strbuf buf = STRBUF_INIT;\n> -\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n> -\t\t\tif (!check_submodule_name(buf.buf))\n> -\t\t\t\tprintf(\"%s\\n\", buf.buf);\n> -\t\t}\n> -\t\tstrbuf_release(&buf);\n> -\t}\n> -\treturn 0;\n> -}\n> -\n>  static int module_config(int argc, const char **argv, const char *prefix)\n>  {\n>  \tenum {\n> @@ -3305,7 +3282,6 @@ static struct cmd_struct commands[] = {\n>  \t{\"summary\", module_summary, 0},\n>  \t{\"push-check\", push_check, 0},\n>  \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n> -\t{\"check-name\", check_name, 0},\n>  \t{\"config\", module_config, 0},\n>  \t{\"set-url\", module_set_url, 0},\n>  \t{\"set-branch\", module_set_branch, 0},\n> diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\n> index 494c6558d9f..9f0eb440192 100644\n> --- a/t/helper/test-submodule.c\n> +++ b/t/helper/test-submodule.c\n> @@ -2,8 +2,16 @@\n>  #include \"test-tool-utils.h\"\n>  #include \"cache.h\"\n>  #include \"parse-options.h\"\n> +#include \"submodule-config.h\"\n>  #include \"submodule.h\"\n>  \n> +#define TEST_TOOL_CHECK_NAME_USAGE \\\n> +\t\"test-tool submodule check-name <name>\"\n> +static const char *submodule_check_name_usage[] = {\n> +\tTEST_TOOL_CHECK_NAME_USAGE,\n> +\tNULL\n> +};\n> +\n>  #define TEST_TOOL_IS_ACTIVE_USAGE \\\n>  \t\"test-tool submodule is-active <name>\"\n>  static const char *submodule_is_active_usage[] = {\n> @@ -12,10 +20,47 @@ static const char *submodule_is_active_usage[] = {\n>  };\n>  \n>  static const char *submodule_usage[] = {\n> +\tTEST_TOOL_CHECK_NAME_USAGE,\n>  \tTEST_TOOL_IS_ACTIVE_USAGE,\n>  \tNULL\n>  };\n>  \n> +/*\n> + * Exit non-zero if any of the submodule names given on the command line is\n> + * invalid. If no names are given, filter stdin to print only valid names\n> + * (which is primarily intended for testing).\n> + */\n> +static int check_name(int argc, const char **argv)\n> +{\n> +\tif (argc > 1) {\n> +\t\twhile (*++argv) {\n> +\t\t\tif (check_submodule_name(*argv) < 0)\n> +\t\t\t\treturn 1;\n> +\t\t}\n> +\t} else {\n> +\t\tstruct strbuf buf = STRBUF_INIT;\n> +\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n> +\t\t\tif (!check_submodule_name(buf.buf))\n> +\t\t\t\tprintf(\"%s\\n\", buf.buf);\n> +\t\t}\n> +\t\tstrbuf_release(&buf);\n> +\t}\n> +\treturn 0;\n> +}\n> +\n> +static int cmd__submodule_check_name(int argc, const char **argv)\n> +{\n> +\tstruct option options[] = {\n> +\t\tOPT_END()\n> +\t};\n> +\targc = parse_options(argc, argv, \"test-tools\", options,\n> +\t\t\t     submodule_check_name_usage, 0);\n> +\tif (argc)\n> +\t\tusage_with_options(submodule_check_name_usage, options);\n> +\n> +\treturn check_name(argc, argv);\n> +}\n> +\n>  static int cmd__submodule_is_active(int argc, const char **argv)\n>  {\n>  \tstruct option options[] = {\n> @@ -32,6 +77,7 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n>  }\n>  \n>  static struct test_cmd cmds[] = {\n> +\t{ \"check-name\", cmd__submodule_check_name },\n>  \t{ \"is-active\", cmd__submodule_is_active },\n>  };\n>  \n> diff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh\n> index 41706c1c9ff..2c24f120da3 100755\n> --- a/t/t7450-bad-git-dotfiles.sh\n> +++ b/t/t7450-bad-git-dotfiles.sh\n> @@ -21,7 +21,7 @@ test_expect_success 'check names' '\n>  \tvalid/with/paths\n>  \tEOF\n>  \n> -\tgit submodule--helper check-name >actual <<-\\EOF &&\n> +\ttest-tool submodule check-name >actual <<-\\EOF &&\n>  \tvalid\n>  \tvalid/with/paths\n\nSimilar to the previous patch, the only tests that use this are\nverifying the behavior of \"check-name\" itself. But I think it makes\nsense to keep this one since this seems to have always been intended to\nbe a sort of \"unit test\"; it was introduced in 0383bbb901\n(submodule-config: verify submodule names as paths, 2018-04-30), and the\ncommit message indicates that this test protects us against certain\nvulnerabilities from maliciously-crafted submodule names.\n\n>  \n> -- \n> 2.37.1.1167.g38fda70d8c4\n"},{"id":"460281","messageId":"kl6lpmhnr37n.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-08.20-8188657cdfa-20220728T161116Z-avarab@gmail.com","subject":"Re: [PATCH 08/20] submodule--helper: move \"resolve-relative-url-test\" to a test-tool","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-07-29T21:58:20Z","receivedAt":"2022-07-29T21:58:27Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> As its name suggests the \"resolve-relative-url-test\" has never been\n> used outside of the test suite, see 63e95beb085 (submodule: port\n> resolve_relative_url from shell to C, 2016-04-15) for its original\n> addition.\n\n[...]\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>\n> diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\n> index 1f2007e62b7..68e29c904a6 100755\n> --- a/t/t0060-path-utils.sh\n> +++ b/t/t0060-path-utils.sh\n> @@ -22,7 +22,7 @@ relative_path() {\n>  \n>  test_submodule_relative_url() {\n>  \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n> -\t\tactual=\\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&\n> +\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n>  \t\ttest \\\"\\$actual\\\" = '$4'\n>  \t\"\n>  }\n\nIt seems like this was only ever intended as a regression test when\nporting resolve_relative_url from sh -> C. Unless we see a good reason\nto \"unit test\" resolve_relative_url, I'm ok to drop this test too.\n\n> -- \n> 2.37.1.1167.g38fda70d8c4\n"},{"id":"460286","messageId":"kl6lmtcrr2ov.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-14.20-b364f3200d8-20220728T161116Z-avarab@gmail.com","subject":"Re: [PATCH 14/20] submodule--helper: pass a \"const struct module_clone_data\" to clone_submodule()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-07-29T22:09:36Z","receivedAt":"2022-07-29T22:09:41Z","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> Add \"const\" to the \"struct module_clone_data\" that we pass to\n> clone_submodule(), which makes the ownership clear, and stops us from\n> clobbering the \"clone_data->path\".\n>\n> We still need to add to the \"reference\" member, which is a \"struct\n> string_list\". Let's do this by having clone_submodule() create its\n> own, and copy the contents over, allowing us to pass it as a\n> separate parameter.\n\nI can't help but think that this would be easier to review as part of\nthe leaks series since:\n\n- Outside of leaks, I don't think we really care about ownership (though\n  please please correct me if I'm off base).\n\n- The ownership of \"reference\" is still quite messy (downstream code\n  might append to it, but its members are sometimes free()-able and\n  sometimes not), so it's hard to visualize what we're getting out of\n  this change without seeing the corresponding leak fix.\n\nand...\n\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 6cedcc5b239..e235acce985 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -1569,18 +1567,20 @@ static char *clone_submodule_sm_gitdir(const char *name)\n>  \treturn sm_gitdir;\n>  }\n>  \n> -static int clone_submodule(struct module_clone_data *clone_data)\n> +static int clone_submodule(const struct module_clone_data *clone_data,\n> +\t\t\t   struct string_list *reference)\n>  {\n>  \tchar *p;\n>  \tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n>  \tchar *sm_alternate = NULL, *error_strategy = NULL;\n>  \tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\tconst char *clone_data_path;\n>  \n>  \tif (!is_absolute_path(clone_data->path))\n> -\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n> -\t\t\t\t\t   clone_data->path);\n> +\t\tclone_data_path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n> +\t\t\t\t\t  clone_data->path);\n\n- (this is pretty minor) It feels weird to see that we're intentionally\n  leaking clone_data_path at its inception. We aren't introducing any\n  new leaks, but moving this to the leaks series makes it clearer that\n  we eventually do the right thing.\n"},{"id":"460288","messageId":"kl6lilnfr22i.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-19.20-5a26c9428be-20220728T161116Z-avarab@gmail.com","subject":"Re: [PATCH 19/20] submodule--helper: don't exit() on failure, return","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-07-29T22:23:01Z","receivedAt":"2022-07-29T22:23:07Z","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> Change code downstream of module_update() to short-circuit and return\n> to the top-level on failure, rather than calling exit().\n>\n> To do so we need to diligently check whether we \"must_die_on_failure\",\n> which is a pattern started in c51f8f94e5b (submodule--helper: run\n> update procedures from C, 2021-08-24), but which hadn't been completed\n> to the point where we could avoid calling exit() here.\n>\n> This introduces no functional changes, but makes it easier to both\n> call these routines as a library in the future, and to eventually\n> avoid leaking memory.\n>\n> This and similar control flow in submodule--helper.c could be made\n> simpler by properly \"libifying\" it, i.e. to have it consistently\n> return -1 on failures, and to early return on any non-success.\n>\n> But let's leave that larger project for now, and (mostly) emulate what\n> were doing with the \"exit(128)\" before this change.\n\nThanks! This is a lot clearer. I'm still kind of iffy on this change\nthough. On the one hand, we know for sure that we're doing the right\nthing because we have tests for \"git submodule update --recursive\". But\non the other, we return 128 from so deep inside the call chain that I\ndon't think it's easy for a casual reader to convince themselves that\nthis is indeed the same.\n\nIf the \"libification\" isn't too hard, I'd strongly prefer to have that\nnow, but since we already have tests in place, I don't feel strongly\nenough to block this patch.\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 36 ++++++++++++++++++++++++++----------\n>  1 file changed, 26 insertions(+), 10 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 68aa10a26cd..d3f22f03766 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2121,7 +2121,8 @@ 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,\n> +\t\t\t      int *must_die_on_failurep)\n>  {\n>  \tstruct child_process cp = CHILD_PROCESS_INIT;\n>  \tchar *oid = oid_to_hex(&ud->oid);\n> @@ -2183,8 +2184,10 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tif (must_die_on_failure)\n> -\t\t\texit(128);\n> +\t\tif (must_die_on_failure) {\n> +\t\t\t*must_die_on_failurep = 1;\n> +\t\t\treturn 128;\n> +\t\t}\n>  \n>  \t\t/* the command failed, but update must continue */\n>  \t\treturn 1;\n> @@ -2218,7 +2221,8 @@ static int run_update_command(struct update_data *ud, int subforce)\n>  \treturn 0;\n>  }\n>  \n> -static int run_update_procedure(struct update_data *ud)\n> +static int run_update_procedure(struct update_data *ud,\n> +\t\t\t\tint *must_die_on_failure)\n>  {\n>  \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n>  \n> @@ -2245,7 +2249,7 @@ static int 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, must_die_on_failure);\n>  }\n>  \n>  static const char *remote_submodule_branch(const char *path)\n> @@ -2381,7 +2385,8 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n>  \t\t\t\t    \"--no-single-branch\");\n>  }\n>  \n> -static int update_submodule(struct update_data *update_data)\n> +static int update_submodule(struct update_data *update_data,\n> +\t\t\t    int *must_die_on_failure)\n>  {\n>  \tint ret = 1;\n>  \n> @@ -2420,8 +2425,13 @@ 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 (run_update_procedure(update_data))\n> +\t\tret = run_update_procedure(update_data, must_die_on_failure);\n> +\t\tif (ret && *must_die_on_failure) {\n> +\t\t\tgoto cleanup;\n> +\t\t} else if (ret) {\n> +\t\t\tret = 1;\n>  \t\t\tgoto cleanup;\n> +\t\t}\n>  \t}\n>  \n>  \tif (update_data->recursive) {\n> @@ -2444,7 +2454,8 @@ static int update_submodule(struct update_data *update_data)\n>  \t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n>  \t\t\t    update_data->displaypath);\n>  \t\tif (ret == 128) {\n> -\t\t\texit(ret);\n> +\t\t\t*must_die_on_failure = 1;\n> +\t\t\tgoto cleanup;\n>  \t\t} else if (ret) {\n>  \t\t\tret = 1;\n>  \t\t\tgoto cleanup;\n> @@ -2482,13 +2493,18 @@ static int update_submodules(struct update_data *update_data)\n>  \n>  \tfor (i = 0; i < suc.update_clone_nr; i++) {\n>  \t\tstruct update_clone_data ucd = suc.update_clone[i];\n> +\t\tint code;\n> +\t\tint must_die_on_failure = 0;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n> +\t\tif (code)\n> +\t\t\tres = code;\n> +\t\tif (must_die_on_failure)\n> +\t\t\tgoto cleanup;\n>  \t}\n>  \n>  cleanup:\n> -- \n> 2.37.1.1167.g38fda70d8c4\n"},{"id":"460289","messageId":"kl6lfsijr0q7.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"Re: [PATCH 00/20] submodule--helper: add tests, rm dead code, refactor & leak prep","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-07-29T22:52:00Z","receivedAt":"2022-07-29T22:52:05Z","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> This new series based on \"master\" splits out the non-leak fixes from\n> v3 of the submodule leaks series [1]. Sorry about the churn, but with\n> e.g. the thread at [2] the \"leaks\" series was accumulating a lot of\n> non-leaks related fixes, just so that we could get to the point of\n> fixing various leaks.\n>\n> The immediate reason I split this off was because of the new\n> \"remove..helper\" and \"test-tool\" patches here. I.e. some things that\n> the leaks series was changing was test-only code, or code that was\n> simply unused (or we had no business using anymore).\n>\n> The [1] series will then be re-rolled on top of this series, which\n> will hopefully make it a lot easier to digest, as it'll now *just*\n> focus on leak fixes.\n\n\nThanks! I was worried about the churn at first, but most of these\npatches are just the ones we already reviewed in previous versions, and\nthe leaks series looks a lot easier to review.\n\nI left the bigger comments in-thread. Some themes I saw in the patches:\n\n>   submodule tests: test usage behavior\n>   submodule tests: test for \"add <repository> <abs-path>\"\n\nI assume these tests are meant for catching regressions?\n\n>   submodule--helper: remove unused \"name\" helper\n>   submodule--helper: remove unused \"list\" helper\n\nHooray for rm-ing dead code!\n\n>   test-tool submodule-config: remove unused \"--url\" handling\n>   submodule--helper: move \"is-active\" to a test-tool\n>   submodule--helper: move \"check-name\" to a test-tool\n>   submodule--helper: move \"resolve-relative-url-test\" to a test-tool\n\nEach of these commands are only used in _their own_ tests as opposed to\nbe used in tests for _other_ commands (or, to borrow the language of\ngarbage collection, the only references we have are weak references ;)),\nwhich makes me think that we could:\n\na) be more ruthless in considering these dead code\nb) be more explicit in calling them \"unit tests\"\nc) (somewhere down the line) absorb them into the rest of the test suite\ninstead of creating a special testing escape hatch.\n\n>   submodule--helper: add \"const\" to copy of \"update_data\"\n>   submodule--helper: pass a \"const struct module_clone_data\" to\n>     clone_submodule()\n\nI suspect these changes to ownership make more sense in the leaks\nseries. For the former patch, it would explain why we don't have to\nplug leaks in \"update_data\". For latter, the ownership rules are still a\nbit confusing (for historical reasons, not anything you introduced), so\nthe leak fix might help explain why the new ownership is better than\nwhat we had before.\n\n>   submodule--helper: stop conflating \"sb\" in clone_submodule()\n>   submodule--helper: add skeleton \"goto cleanup\" to update_submodule()\n>   submodule--helper: don't exit() on failure, return\n\nIMO this refactoring doesn't really stand on its own unless we also take\nthe leaks fixes. Might be nice to move these to that series, but I don't\nfeel strongly about it.\n\n>   submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"\n>   submodule--helper style: don't separate declared variables with \\n\\n\n>   submodule--helper style: add \\n\\n after variable declarations\n>   submodule--helper: rename \"int res\" to \"int ret\"\n>   submodule--helper: replace memset() with { 0 }-initialization\n>   submodule--helper: convert a strbuf_detach() to xstrfmt()\n>   submodule--helper: fix bad config API usage\n\nStyle and API fixes that make sense on their own :)\n\nSince we now have an extra topic for cleanup, I wonder what you think\nabout incorporating [1], i.e. refactor out init_submodules() to be\ncalled from module_update(). It's a bit big, but it would make [2]\nobsolete.\n\n[1] https://lore.kernel.org/git/kl6lbktitf6e.fsf@chooglen-macbookpro.roam.corp.google.com\n[2] https://lore.kernel.org/git/patch-v4-04.17-683d327752f-20220728T162442Z-avarab@gmail.com\n"},{"id":"460356","messageId":"220801.86v8rcgfxz.gmgdl@evledraar.gmail.com","threadId":"58235","inReplyTo":"kl6lmtcrr2ov.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH 14/20] submodule--helper: pass a \"const struct module_clone_data\" to clone_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-01T15:05:49Z","receivedAt":"2022-08-01T15:07:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Jul 29 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> Add \"const\" to the \"struct module_clone_data\" that we pass to\n>> clone_submodule(), which makes the ownership clear, and stops us from\n>> clobbering the \"clone_data->path\".\n>>\n>> We still need to add to the \"reference\" member, which is a \"struct\n>> string_list\". Let's do this by having clone_submodule() create its\n>> own, and copy the contents over, allowing us to pass it as a\n>> separate parameter.\n>\n> I can't help but think that this would be easier to review as part of\n> the leaks series since:\n>\n> - Outside of leaks, I don't think we really care about ownership (though\n>   please please correct me if I'm off base).\n>\n> - The ownership of \"reference\" is still quite messy (downstream code\n>   might append to it, but its members are sometimes free()-able and\n>   sometimes not), so it's hard to visualize what we're getting out of\n>   this change without seeing the corresponding leak fix.\n\nI'll amend the commit message. I'll leave this in this series, as\nstarting to split \"is this really just for the leak fix?\" out of this\nwill generally lead to the slippery slope of bundling most of this up\nagain.\n\nI think the addition of \"const\" helps things along independently of\nthat.\n\n>> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n>> index 6cedcc5b239..e235acce985 100644\n>> --- a/builtin/submodule--helper.c\n>> +++ b/builtin/submodule--helper.c\n>> @@ -1569,18 +1567,20 @@ static char *clone_submodule_sm_gitdir(const char *name)\n>>  \treturn sm_gitdir;\n>>  }\n>>  \n>> -static int clone_submodule(struct module_clone_data *clone_data)\n>> +static int clone_submodule(const struct module_clone_data *clone_data,\n>> +\t\t\t   struct string_list *reference)\n>>  {\n>>  \tchar *p;\n>>  \tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n>>  \tchar *sm_alternate = NULL, *error_strategy = NULL;\n>>  \tstruct child_process cp = CHILD_PROCESS_INIT;\n>> +\tconst char *clone_data_path;\n>>  \n>>  \tif (!is_absolute_path(clone_data->path))\n>> -\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n>> -\t\t\t\t\t   clone_data->path);\n>> +\t\tclone_data_path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n>> +\t\t\t\t\t  clone_data->path);\n>\n> - (this is pretty minor) It feels weird to see that we're intentionally\n>   leaking clone_data_path at its inception. We aren't introducing any\n>   new leaks, but moving this to the leaks series makes it clearer that\n>   we eventually do the right thing.\n\nHere we're just preserving the status quo, memory leaks aren't really\ntied to variable scope (except as a reporting convenience in some\ntools). We're leaking in the same way before & after this. I think it's\nbetter to fix the leak in the follow-up series to separate the concerns\nhere.\n"},{"id":"460448","messageId":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH v2 00/28] submodule--helper: add tests, rm dead code, refactor & leak prep","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:44Z","receivedAt":"2022-08-02T15:46:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series is a \"prep\" series for the meaty leak fixes for\nsubmodule--helper, see [1] (which will be re-rolled on top of this\nv2).\n\nChange since v1:\n\n * This hopefully addresses all of Glen's comments on v1.\n\n * The \"libification\" of \"update\" suggested in [2] is (almost)\n   complete here. See 27/28 for the \"almost\". This is why the series\n   grew from 20 to 28 patches.\n\n   There's a lot of incremental \"showing work\" here.\n\n * The \"goto cleanup\" in update_submodule() change is gone, it's\n   needed for the current v4 of the follow-up, but I'll submit a\n   re-roll which solves that problem in a cleaner way.\n\n   For this series it means we can end up with just a \"return\n   die_message(...)\" rather than \"ret = die_message(...); goto\n   cleanup\" in that code, which is a lot less verbose.\n\n * Various other small changes, see the range-diff below.\n\nA CI run for this & branch is at [3].\n\n1. https://lore.kernel.org/git/cover-v4-00.17-00000000000-20220728T162442Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/kl6lilnfr22i.fsf@chooglen-macbookpro.roam.corp.google.com/\n3. https://github.com/avar/git/tree/avar/submodule--helper-cleanup-and-tests-2\n\nGlen Choo (2):\n  submodule--helper: add \"const\" to copy of \"update_data\"\n  submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"\n\nÆvar Arnfjörð Bjarmason (26):\n  submodule tests: test usage behavior\n  submodule tests: test for \"add <repository> <abs-path>\"\n  submodule--helper: remove unused \"name\" helper\n  submodule--helper: remove unused \"list\" helper\n  test-tool submodule-config: remove unused \"--url\" handling\n  submodule--helper: move \"is-active\" to a test-tool\n  submodule--helper: move \"check-name\" to a test-tool\n  submodule--helper: move \"resolve-relative-url-test\" to a test-tool\n  submodule--helper style: don't separate declared variables with \\n\\n\n  submodule--helper style: add \\n\\n after variable declarations\n  submodule--helper: replace memset() with { 0 }-initialization\n  submodule--helper: use xstrfmt() in clone_submodule()\n  submodule--helper: move \"sb\" in clone_submodule() to its own scope\n  submodule--helper: pass a \"const struct module_clone_data\" to\n    clone_submodule()\n  submodule--helper: don't redundantly check \"else if (res)\"\n  submodule--helper: rename \"int res\" to \"int ret\"\n  submodule--helper: return \"ret\", not \"1\" from update_submodule()\n  submodule--helper: add missing braces to \"else\" arm\n  submodule--helper: don't call submodule_strategy_to_string() in BUG()\n  submodule--helper: move submodule_strategy_to_string() to only user\n  submodule--helper: use \"code\" in run_update_command()\n  submodule--helper: don't exit() on failure, return\n  submodule--helper: libify determine_submodule_update_strategy()\n  submodule--helper: libify \"must_die_on_failure\" code paths\n  submodule--helper: libify \"must_die_on_failure\" code paths (for die)\n  submodule--helper: fix bad config API usage\n\n Makefile                         |   1 +\n builtin/submodule--helper.c      | 451 +++++++++++++------------------\n submodule.c                      |  21 --\n submodule.h                      |   1 -\n t/helper/test-submodule-config.c |  11 +-\n t/helper/test-submodule.c        | 146 ++++++++++\n t/helper/test-tool-utils.h       |   9 +\n t/helper/test-tool.c             |   7 +-\n t/helper/test-tool.h             |   1 +\n t/t0060-path-utils.sh            |   2 +-\n t/t7400-submodule-basic.sh       |  56 ++--\n t/t7406-submodule-update.sh      |   2 +-\n t/t7413-submodule-is-active.sh   |  35 +--\n t/t7450-bad-git-dotfiles.sh      |   2 +-\n 14 files changed, 403 insertions(+), 342 deletions(-)\n create mode 100644 t/helper/test-submodule.c\n create mode 100644 t/helper/test-tool-utils.h\n\nRange-diff against v1:\n 1:  84b05bda016 !  1:  daa5d3f9962 submodule tests: test usage behavior\n    @@ Commit message\n         subsequent eventual behavior change will become clear.\n     \n         For \"--\" this follows up on 68cabbfda36 (submodule: document default\n    -    behavior, 2019-02-15) and tests that when \"status\" isn't supplied we\n    -    don't support the \"--\" delimiter. There's no intrinsically good reason\n    -    not to support that. We behave this way due to edge cases in\n    +    behavior, 2019-02-15) and tests that \"status\" doesn't don't support\n    +    the \"--\" delimiter. There's no intrinsically good reason not to\n    +    support that. We behave this way due to edge cases in\n         git-submodule.sh's implementation, but as with \"-h\" let's assert our\n         current long-standing behavior for now.\n     \n 2:  9671169e348 =  2:  9d920326df3 submodule tests: test for \"add <repository> <abs-path>\"\n 3:  7aa9c14251b =  3:  d981db49fa1 submodule--helper: remove unused \"name\" helper\n 4:  27df2efe718 =  4:  6f78f9c9274 submodule--helper: remove unused \"list\" helper\n 5:  9fe8deb165a =  5:  43902201701 test-tool submodule-config: remove unused \"--url\" handling\n 6:  8e4d2b09d56 !  6:  e2a8bb0a28e submodule--helper: move \"is-active\" to a test-tool\n    @@ t/t7413-submodule-is-active.sh\n     -This test verifies that `git submodue--helper is-active` correctly identifies\n     +This test verifies that `test-tool submodule is-active` correctly identifies\n      submodules which are \"active\" and interesting to the user.\n    ++\n    ++This is a unit test of the submodule.c is_submodule_active() function,\n    ++which is also indirectly tested elsewhere.\n      '\n      \n    + . ./test-lib.sh\n     @@ t/t7413-submodule-is-active.sh: test_expect_success 'setup' '\n      '\n      \n 7:  a2f3d812815 !  7:  b209532eb17 submodule--helper: move \"check-name\" to a test-tool\n    @@ Commit message\n         a6226fd772b (submodule--helper: convert the bulk of cmd_add() to C,\n         2021-08-10) it has only been used by this test, not git-submodule.sh.\n     \n    +    As noted with its introduction in 0383bbb9015 (submodule-config:\n    +    verify submodule names as paths, 2018-04-30) the intent of\n    +    t7450-bad-git-dotfiles.sh has always been to unit test the\n    +    check_submodule_name() function.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n 8:  8188657cdfa !  8:  de49f31dab0 submodule--helper: move \"resolve-relative-url-test\" to a test-tool\n    @@ Commit message\n         resolve_relative_url from shell to C, 2016-04-15) for its original\n         addition.\n     \n    +    Perhaps it would make sense to drop this code entirely, as we feel\n    +    that we've got enough indirect test coverage, but let's leave that\n    +    question to a possible follow-up change. For now let's keep the test\n    +    coverage this gives us.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n 9:  79a47f9b94d =  9:  b0238f699ce submodule--helper style: don't separate declared variables with \\n\\n\n10:  5e13080f894 = 10:  5f5e68a868b submodule--helper style: add \\n\\n after variable declarations\n11:  dc5ac924496 = 11:  72dcf19e1c4 submodule--helper: replace memset() with { 0 }-initialization\n12:  08cc9ce2e24 ! 12:  e5e267dccd5 submodule--helper: convert a strbuf_detach() to xstrfmt()\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    submodule--helper: convert a strbuf_detach() to xstrfmt()\n    +    submodule--helper: use xstrfmt() in clone_submodule()\n     \n    -    Convert a case where we had no reason to use a \"struct strbuf\" to use\n    -    an xstrfmt(). This code was added along with other uses of \"struct\n    +    Use xstrfmt() in clone_submodule() instead of a \"struct strbuf\" in two\n    +    cases where we weren't getting anything out of using the \"struct\n    +    strbuf\".\n    +\n    +    This changes code that was was added along with other uses of \"struct\n         strbuf\" in this function in ee8838d1577 (submodule: rewrite\n         `module_clone` shell function in C, 2015-09-08).\n     \n    @@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data\n      \n      \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n      \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n    +@@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data *clone_data)\n    + \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n    + \t\t\t    clone_data->url, clone_data->path);\n    + \t} else {\n    ++\t\tchar *path;\n    ++\n    + \t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n    + \t\t    !is_empty_dir(clone_data->path))\n    + \t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n    + \t\tif (safe_create_leading_directories_const(clone_data->path) < 0)\n    + \t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n    +-\t\tstrbuf_addf(&sb, \"%s/index\", sm_gitdir);\n    +-\t\tunlink_or_warn(sb.buf);\n    +-\t\tstrbuf_reset(&sb);\n    ++\t\tpath = xstrfmt(\"%s/index\", sm_gitdir);\n    ++\t\tunlink_or_warn(path);\n    ++\t\tfree(path);\n    + \t}\n    + \n    + \tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n13:  afe34d8b73b ! 13:  91558745e2e submodule--helper: stop conflating \"sb\" in clone_submodule()\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    submodule--helper: stop conflating \"sb\" in clone_submodule()\n    +    submodule--helper: move \"sb\" in clone_submodule() to its own scope\n     \n    -    Refactor the two uses of a \"struct strbuf sb\" such that each of them\n    -    exists in its own scope. This makes the control flow clearer.\n    +    Refactor the only remaining use of a \"struct strbuf sb\" in\n    +    clone_submodule() to live in its own scope. This makes the code\n    +    clearer by limiting its lifetime.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ builtin/submodule--helper.c: static void prepare_possible_alternates(const char\n      \n      \tif (!is_absolute_path(clone_data->path))\n      \t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n    -@@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data *clone_data)\n    - \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n    - \t\t\t    clone_data->url, clone_data->path);\n    - \t} else {\n    -+\t\tstruct strbuf sb = STRBUF_INIT;\n    -+\n    - \t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n    - \t\t    !is_empty_dir(clone_data->path))\n    - \t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n    -@@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data *clone_data)\n    - \t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n    - \t\tstrbuf_addf(&sb, \"%s/index\", sm_gitdir);\n    - \t\tunlink_or_warn(sb.buf);\n    --\t\tstrbuf_reset(&sb);\n    -+\t\tstrbuf_release(&sb);\n    - \t}\n    - \n    - \tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n     @@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data *clone_data)\n      \tfree(sm_alternate);\n      \tfree(error_strategy);\n14:  b364f3200d8 ! 14:  866b8397a59 submodule--helper: pass a \"const struct module_clone_data\" to clone_submodule()\n    @@ Commit message\n         This new \"struct string_list\" still leaks memory, just as the \"struct\n         module_clone_data\" did before. let's not fix that for now, to fix that\n         we'll need to add some \"goto cleanup\" to the relevant code. That will\n    -    be done in a follow-up commits, at that point it'll be easier to fix\n    -    the memory leak.\n    +    eventually be done in follow-up commits, this change makes it easier\n    +    to fix the memory leak.\n     \n         The scope of the new \"reference\" variable in add_submodule() could be\n         narrowed to the \"else\" block, but as we'll eventually free it with a\n    @@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data\n     -\t\t\t    clone_data->url, clone_data->path);\n     +\t\t\t    clone_data->url, clone_data_path);\n      \t} else {\n    - \t\tstruct strbuf sb = STRBUF_INIT;\n    + \t\tchar *path;\n      \n     -\t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n     -\t\t    !is_empty_dir(clone_data->path))\n    @@ builtin/submodule--helper.c: static int clone_submodule(struct module_clone_data\n     +\t\t\tdie(_(\"directory not empty: '%s'\"), clone_data_path);\n     +\t\tif (safe_create_leading_directories_const(clone_data_path) < 0)\n     +\t\t\tdie(_(\"could not create directory '%s'\"), clone_data_path);\n    - \t\tstrbuf_addf(&sb, \"%s/index\", sm_gitdir);\n    - \t\tunlink_or_warn(sb.buf);\n    - \t\tstrbuf_release(&sb);\n    + \t\tpath = xstrfmt(\"%s/index\", sm_gitdir);\n    + \t\tunlink_or_warn(path);\n    + \t\tfree(path);\n      \t}\n      \n     -\tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n15:  e319f4edc54 = 15:  1ff380ec7b5 submodule--helper: add \"const\" to copy of \"update_data\"\n16:  68202100d9a = 16:  d3a7e646adc submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"\n -:  ----------- > 17:  23eb07176d9 submodule--helper: don't redundantly check \"else if (res)\"\n17:  e8aacb55a18 ! 18:  78f74df6d5e submodule--helper: rename \"int res\" to \"int ret\"\n    @@ Commit message\n         cmd_update() logic to C, 2022-03-15) to \"ret\", which is the convention\n         in the rest of this file.\n     \n    -    Eventual follow-up commits will change this code to a \"goto cleanup\"\n    -    pattern, let's have the post image look consistent with the rest.\n    +    Eventual follow-up commits will change the code in update_submodule()\n    +    to a \"goto cleanup\" pattern, let's have the post image look consistent\n    +    with the rest. For update_submodules() let's also use a \"ret\" for\n    +    consistency, that use was also added in b3c5f5cb048. We'll be\n    +    modifying that codepath in subsequent commits.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *upd\n      \t\t\t    update_data->displaypath);\n     -\t\tif (res == 128)\n     -\t\t\texit(res);\n    --\t\telse if (res)\n     +\t\tif (ret == 128)\n     +\t\t\texit(ret);\n    -+\t\telse if (ret)\n    - \t\t\treturn 1;\n    + \t\treturn 1;\n      \t}\n      \n    +@@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data)\n    + \n    + static int update_submodules(struct update_data *update_data)\n    + {\n    +-\tint i, res = 0;\n    ++\tint i, ret = 0;\n    + \tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n    + \n    + \tsuc.update_data = update_data;\n    +@@ builtin/submodule--helper.c: static int update_submodules(struct update_data *update_data)\n    + \t * - the listener can avoid doing any work if fetching failed.\n    + \t */\n    + \tif (suc.quickstop) {\n    +-\t\tres = 1;\n    ++\t\tret = 1;\n    + \t\tgoto cleanup;\n    + \t}\n    + \n    +@@ builtin/submodule--helper.c: static int update_submodules(struct update_data *update_data)\n    + \t\tupdate_data->sm_path = ucd.sub->path;\n    + \n    + \t\tif (update_submodule(update_data))\n    +-\t\t\tres = 1;\n    ++\t\t\tret = 1;\n    + \t}\n    + \n    + cleanup:\n    + \tstring_list_clear(&update_data->references, 0);\n    +-\treturn res;\n    ++\treturn ret;\n    + }\n    + \n    + static int module_update(int argc, const char **argv, const char *prefix)\n18:  41fb22d8549 <  -:  ----------- submodule--helper: add skeleton \"goto cleanup\" to update_submodule()\n -:  ----------- > 19:  f0258e37ebe submodule--helper: return \"ret\", not \"1\" from update_submodule()\n -:  ----------- > 20:  70f030cca4e submodule--helper: add missing braces to \"else\" arm\n -:  ----------- > 21:  bce1a014a2f submodule--helper: don't call submodule_strategy_to_string() in BUG()\n -:  ----------- > 22:  98c3e562c82 submodule--helper: move submodule_strategy_to_string() to only user\n -:  ----------- > 23:  db2d2fb5a21 submodule--helper: use \"code\" in run_update_command()\n19:  5a26c9428be ! 24:  d33260487bd submodule--helper: don't exit() on failure, return\n    @@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_pa\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,\n    -+\t\t\t      int *must_die_on_failurep)\n    ++\t\t\t      int *must_die_on_failure)\n      {\n      \tstruct child_process cp = CHILD_PROCESS_INIT;\n      \tchar *oid = oid_to_hex(&ud->oid);\n     @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\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\tif (must_die_on_failure)\n    --\t\t\texit(128);\n    -+\t\tif (must_die_on_failure) {\n    -+\t\t\t*must_die_on_failurep = 1;\n    -+\t\t\treturn 128;\n    -+\t\t}\n    - \n    - \t\t/* the command failed, but update must continue */\n    - \t\treturn 1;\n    + \n    + \t\tif (ret == 128)\n    +-\t\t\texit(ret);\n    ++\t\t\t*must_die_on_failure = 1;\n    + \t\treturn ret;\n    + \t}\n    + \n     @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n      \treturn 0;\n      }\n    @@ builtin/submodule--helper.c: static void update_data_to_args(struct update_data\n     +static int update_submodule(struct update_data *update_data,\n     +\t\t\t    int *must_die_on_failure)\n      {\n    - \tint ret = 1;\n    + \tensure_core_worktree(update_data->sm_path);\n      \n     @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data)\n    + \t\tfree(remote_ref);\n      \t}\n      \n    - \tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force) {\n    +-\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)\n     -\t\tif (run_update_procedure(update_data))\n    ++\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force) {\n    ++\t\tint ret;\n    ++\n     +\t\tret = run_update_procedure(update_data, must_die_on_failure);\n    -+\t\tif (ret && *must_die_on_failure) {\n    -+\t\t\tgoto cleanup;\n    -+\t\t} else if (ret) {\n    -+\t\t\tret = 1;\n    - \t\t\tgoto cleanup;\n    -+\t\t}\n    - \t}\n    ++\t\tif (*must_die_on_failure)\n    ++\t\t\treturn ret;\n    ++\t\tif (ret)\n    + \t\t\treturn 1;\n    ++\t}\n      \n      \tif (update_data->recursive) {\n    + \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n     @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data)\n      \t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n      \t\t\t    update_data->displaypath);\n    - \t\tif (ret == 128) {\n    + \t\tif (ret == 128)\n     -\t\t\texit(ret);\n     +\t\t\t*must_die_on_failure = 1;\n    -+\t\t\tgoto cleanup;\n    - \t\t} else if (ret) {\n    - \t\t\tret = 1;\n    - \t\t\tgoto cleanup;\n    + \t\treturn ret;\n    + \t}\n    + \n     @@ builtin/submodule--helper.c: static int update_submodules(struct update_data *update_data)\n      \n      \tfor (i = 0; i < suc.update_clone_nr; i++) {\n      \t\tstruct update_clone_data ucd = suc.update_clone[i];\n    -+\t\tint code;\n     +\t\tint must_die_on_failure = 0;\n    ++\t\tint code;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n     +\t\tif (code)\n    -+\t\t\tres = code;\n    ++\t\t\tret = code;\n     +\t\tif (must_die_on_failure)\n     +\t\t\tgoto cleanup;\n    ++\t\telse if (code)\n    + \t\t\tret = 1;\n      \t}\n      \n    - cleanup:\n -:  ----------- > 25:  9981a75d7e8 submodule--helper: libify determine_submodule_update_strategy()\n -:  ----------- > 26:  b48705c6cc0 submodule--helper: libify \"must_die_on_failure\" code paths\n -:  ----------- > 27:  93cd1ccde54 submodule--helper: libify \"must_die_on_failure\" code paths (for die)\n20:  579560cb9a8 = 28:  6160a1ab250 submodule--helper: fix bad config API usage\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460447","messageId":"patch-v2-02.28-9d920326df3-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 02/28] submodule tests: test for \"add <repository> <abs-path>\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:46Z","receivedAt":"2022-08-02T15:46:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a missing test for \"\"add <repository> <path>\" where \"<path>\" is an\nabsolute path. This tests code added in [1] and later turned into an\n\"else\" branch in clone_submodule() in [2] that's never been tested.\n\nThis needs to be skipped on WINDOWS because all of $PWD, $(pwd) and\nthe \"$(pwd -P)\" we get via \"$submodurl\" would fail in CI with e.g.:\n\n\tfatal: could not create directory 'D:/a/git/git/t/trash\n\tdirectory.t7400-submodule-basic/.git/modules/D:/a/git/git/t/trash\n\tdirectory.t7400-submodule-basic/add-abs'\n\nI.e. we can't handle these sorts of paths in this context on that\nplatform.\n\nI'm not sure where we run into the edges of \"$PWD\" behavior on\nWindows (see [1] for a previous loose end on the topic), but for the\npurposes of this test it's sufficient that we test this on other\nplatforms.\n\n1. ee8838d1577 (submodule: rewrite `module_clone` shell function in C,\n   2015-09-08)\n2. f8eaa0ba98b (submodule--helper, module_clone: always operate on\n   absolute paths, 2016-03-31)\n\n1. https://lore.kernel.org/git/220630.86edz6c75c.gmgdl@evledraar.gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7400-submodule-basic.sh | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex b858871a953..6a77d817a82 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -178,6 +178,11 @@ test_expect_success 'submodule add' '\n \ttest_must_be_empty untracked\n '\n \n+test_expect_success !WINDOWS 'submodule add (absolute path)' '\n+\ttest_when_finished \"git reset --hard\" &&\n+\tgit submodule add \"$submodurl\" \"$submodurl/add-abs\"\n+'\n+\n test_expect_success 'setup parent and one repository' '\n \ttest_create_repo parent &&\n \ttest_commit -C parent one\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460449","messageId":"patch-v2-01.28-daa5d3f9962-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 01/28] submodule tests: test usage behavior","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:45Z","receivedAt":"2022-08-02T15:46:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Test what exit code and output we emit on \"git submodule -h\", how we\nhandle \"--\" when no subcommand is specified, and how the top-level\n\"--recursive\" option is handled.\n\nFor \"-h\" this doesn't make sense, but let's test for it so that any\nsubsequent eventual behavior change will become clear.\n\nFor \"--\" this follows up on 68cabbfda36 (submodule: document default\nbehavior, 2019-02-15) and tests that \"status\" doesn't don't support\nthe \"--\" delimiter. There's no intrinsically good reason not to\nsupport that. We behave this way due to edge cases in\ngit-submodule.sh's implementation, but as with \"-h\" let's assert our\ncurrent long-standing behavior for now.\n\nFor \"--recursive\" the exclusion of it from the top-level appears to\nhave been an omission in 15fc56a8536 (git submodule foreach: Add\n--recursive to recurse into nested submodules, 2009-08-19), there\ndoesn't seem to be a reason not to support it alongside \"--quiet\" and\n\"--cached\", but let's likewise assert our existing behavior for now.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7400-submodule-basic.sh | 26 ++++++++++++++++++++++++++\n 1 file changed, 26 insertions(+)\n\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex e7cec2e457a..b858871a953 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -14,6 +14,32 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+test_expect_success 'submodule usage: -h' '\n+\tgit submodule -h >out 2>err &&\n+\tgrep \"^usage: git submodule\" out &&\n+\ttest_must_be_empty err\n+'\n+\n+test_expect_success 'submodule usage: --recursive' '\n+\ttest_expect_code 1 git submodule --recursive >out 2>err &&\n+\tgrep \"^usage: git submodule\" err &&\n+\ttest_must_be_empty out\n+'\n+\n+test_expect_success 'submodule usage: status --' '\n+\ttest_expect_code 1 git submodule -- &&\n+\ttest_expect_code 1 git submodule --end-of-options\n+'\n+\n+for opt in '--quiet' '--cached'\n+do\n+\ttest_expect_success \"submodule usage: status $opt\" '\n+\t\tgit submodule $opt &&\n+\t\tgit submodule status $opt &&\n+\t\tgit submodule $opt status\n+\t'\n+done\n+\n test_expect_success 'submodule deinit works on empty repository' '\n \tgit submodule deinit --all\n '\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460450","messageId":"patch-v2-03.28-d981db49fa1-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 03/28] submodule--helper: remove unused \"name\" helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:47Z","receivedAt":"2022-08-02T15:46:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"name\" helper has not been used since e83e3333b57 (submodule: port\nsubmodule subcommand 'summary' from shell to C, 2020-08-13).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.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 fac52ade5e1..ac2553ba9d3 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -771,24 +771,6 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int module_name(int argc, const char **argv, const char *prefix)\n-{\n-\tconst struct submodule *sub;\n-\n-\tif (argc != 2)\n-\t\tusage(_(\"git submodule--helper name <path>\"));\n-\n-\tsub = submodule_from_path(the_repository, null_oid(), argv[1]);\n-\n-\tif (!sub)\n-\t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n-\t\t    argv[1]);\n-\n-\tprintf(\"%s\\n\", sub->name);\n-\n-\treturn 0;\n-}\n-\n struct module_cb {\n \tunsigned int mod_src;\n \tunsigned int mod_dst;\n@@ -3359,7 +3341,6 @@ struct cmd_struct {\n \n static struct cmd_struct commands[] = {\n \t{\"list\", module_list, 0},\n-\t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460451","messageId":"patch-v2-05.28-43902201701-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 05/28] test-tool submodule-config: remove unused \"--url\" handling","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:49Z","receivedAt":"2022-08-02T15:46:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"No test has used this \"--url\" parameter since the test code that made\nuse of it was removed in 32bc548329d (submodule-config: remove support\nfor overlaying repository config, 2017-08-03).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/helper/test-submodule-config.c | 11 ++---------\n 1 file changed, 2 insertions(+), 9 deletions(-)\n\ndiff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c\nindex e2692746dfd..22a41c40926 100644\n--- a/t/helper/test-submodule-config.c\n+++ b/t/helper/test-submodule-config.c\n@@ -15,14 +15,11 @@ int cmd__submodule_config(int argc, const char **argv)\n {\n \tconst char **arg = argv;\n \tint my_argc = argc;\n-\tint output_url = 0;\n \tint lookup_name = 0;\n \n \targ++;\n \tmy_argc--;\n \twhile (arg[0] && starts_with(arg[0], \"--\")) {\n-\t\tif (!strcmp(arg[0], \"--url\"))\n-\t\t\toutput_url = 1;\n \t\tif (!strcmp(arg[0], \"--name\"))\n \t\t\tlookup_name = 1;\n \t\targ++;\n@@ -57,12 +54,8 @@ int cmd__submodule_config(int argc, const char **argv)\n \t\tif (!submodule)\n \t\t\tdie_usage(argc, argv, \"Submodule not found.\");\n \n-\t\tif (output_url)\n-\t\t\tprintf(\"Submodule url: '%s' for path '%s'\\n\",\n-\t\t\t\t\tsubmodule->url, submodule->path);\n-\t\telse\n-\t\t\tprintf(\"Submodule name: '%s' for path '%s'\\n\",\n-\t\t\t\t\tsubmodule->name, submodule->path);\n+\t\tprintf(\"Submodule name: '%s' for path '%s'\\n\", submodule->name,\n+\t\t       submodule->path);\n \n \t\targ += 2;\n \t}\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460452","messageId":"patch-v2-04.28-6f78f9c9274-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 04/28] submodule--helper: remove unused \"list\" helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:48Z","receivedAt":"2022-08-02T15:46:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the \"submodule--helper list\" sub-command, which hasn't been\nused by git-submodule.sh since 2964d6e5e1e (submodule: port subcommand\n'set-branch' from shell to C, 2020-06-02).\n\nThere was a test added in 2b56bb7a87a (submodule helper list: respect\ncorrect path prefix, 2016-02-24) which relied on it, but the right\nthing to do here is to delete that test as well.\n\nThat test was regression testing the \"list\" subcommand itself. We're\nnot getting anything useful from the \"list | cut -f2\" invocation that\nwe couldn't get from \"foreach 'echo $sm_path'\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 40 -------------------------------------\n t/t7400-submodule-basic.sh  | 25 -----------------------\n 2 files changed, 65 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex ac2553ba9d3..47ed24c6a60 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -266,45 +266,6 @@ static char *get_up_path(const char *path)\n \treturn strbuf_detach(&sb, NULL);\n }\n \n-static int module_list(int argc, const char **argv, const char *prefix)\n-{\n-\tint i;\n-\tstruct pathspec pathspec;\n-\tstruct module_list list = MODULE_LIST_INIT;\n-\n-\tstruct option module_list_options[] = {\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"alternative anchor for relative paths\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper list [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, module_list_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < list.nr; i++) {\n-\t\tconst struct cache_entry *ce = list.entries[i];\n-\n-\t\tif (ce_stage(ce))\n-\t\t\tprintf(\"%06o %s U\\t\", ce->ce_mode,\n-\t\t\t       oid_to_hex(null_oid()));\n-\t\telse\n-\t\t\tprintf(\"%06o %s %d\\t\", ce->ce_mode,\n-\t\t\t       oid_to_hex(&ce->oid), ce_stage(ce));\n-\n-\t\tfprintf(stdout, \"%s\\n\", ce->name);\n-\t}\n-\treturn 0;\n-}\n-\n static void for_each_listed_submodule(const struct module_list *list,\n \t\t\t\t      each_submodule_fn fn, void *cb_data)\n {\n@@ -3340,7 +3301,6 @@ struct cmd_struct {\n };\n \n static struct cmd_struct commands[] = {\n-\t{\"list\", module_list, 0},\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex 6a77d817a82..b50db3f1031 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -1255,31 +1255,6 @@ test_expect_success 'submodule add clone shallow submodule' '\n \t)\n '\n \n-test_expect_success 'submodule helper list is not confused by common prefixes' '\n-\tmkdir -p dir1/b &&\n-\t(\n-\t\tcd dir1/b &&\n-\t\tgit init &&\n-\t\techo hi >testfile2 &&\n-\t\tgit add . &&\n-\t\tgit commit -m \"test1\"\n-\t) &&\n-\tmkdir -p dir2/b &&\n-\t(\n-\t\tcd dir2/b &&\n-\t\tgit init &&\n-\t\techo hello >testfile1 &&\n-\t\tgit add .  &&\n-\t\tgit commit -m \"test2\"\n-\t) &&\n-\tgit submodule add /dir1/b dir1/b &&\n-\tgit submodule add /dir2/b dir2/b &&\n-\tgit commit -m \"first submodule commit\" &&\n-\tgit submodule--helper list dir1/b | cut -f 2 >actual &&\n-\techo \"dir1/b\" >expect &&\n-\ttest_cmp expect actual\n-'\n-\n test_expect_success 'setup superproject with submodules' '\n \tgit init sub1 &&\n \ttest_commit -C sub1 test &&\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460453","messageId":"patch-v2-06.28-e2a8bb0a28e-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 06/28] submodule--helper: move \"is-active\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:50Z","receivedAt":"2022-08-02T15:46:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Create a new \"test-tool submodule\" and move the \"is-active\" subcommand\nover to it. It was added in 5c2bd8b77ae (submodule--helper: add\nis-active subcommand, 2017-03-16), since\na452128a36c (submodule--helper: introduce add-config subcommand,\n2021-08-06) it hasn't been used by git-submodule.sh.\n\nSince we're creating a command dispatch similar to test-tool.c itself\nlet's split out the \"struct test_cmd\" into a new test-tool-utils.h,\nwhich both this new code and test-tool.c itself can use.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile                       |  1 +\n builtin/submodule--helper.c    |  9 ------\n t/helper/test-submodule.c      | 58 ++++++++++++++++++++++++++++++++++\n t/helper/test-tool-utils.h     |  9 ++++++\n t/helper/test-tool.c           |  7 ++--\n t/helper/test-tool.h           |  1 +\n t/t7413-submodule-is-active.sh | 35 ++++++++++----------\n 7 files changed, 90 insertions(+), 30 deletions(-)\n create mode 100644 t/helper/test-submodule.c\n create mode 100644 t/helper/test-tool-utils.h\n\ndiff --git a/Makefile b/Makefile\nindex 1624471badc..ad7fbd36885 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -785,6 +785,7 @@ TEST_BUILTINS_OBJS += test-strcmp-offset.o\n TEST_BUILTINS_OBJS += test-string-list.o\n TEST_BUILTINS_OBJS += test-submodule-config.o\n TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o\n+TEST_BUILTINS_OBJS += test-submodule.o\n TEST_BUILTINS_OBJS += test-subprocess.o\n TEST_BUILTINS_OBJS += test-trace2.o\n TEST_BUILTINS_OBJS += test-urlmatch-normalization.o\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 47ed24c6a60..b2fc732b5d8 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2728,14 +2728,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int is_active(int argc, const char **argv, const char *prefix)\n-{\n-\tif (argc != 2)\n-\t\tdie(\"submodule--helper is-active takes exactly 1 argument\");\n-\n-\treturn !is_submodule_active(the_repository, argv[1]);\n-}\n-\n /*\n  * Exit non-zero if any of the submodule names given on the command line is\n  * invalid. If no names are given, filter stdin to print only valid names\n@@ -3313,7 +3305,6 @@ static struct cmd_struct commands[] = {\n \t{\"summary\", module_summary, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n-\t{\"is-active\", is_active, 0},\n \t{\"check-name\", check_name, 0},\n \t{\"config\", module_config, 0},\n \t{\"set-url\", module_set_url, 0},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nnew file mode 100644\nindex 00000000000..494c6558d9f\n--- /dev/null\n+++ b/t/helper/test-submodule.c\n@@ -0,0 +1,58 @@\n+#include \"test-tool.h\"\n+#include \"test-tool-utils.h\"\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+#include \"submodule.h\"\n+\n+#define TEST_TOOL_IS_ACTIVE_USAGE \\\n+\t\"test-tool submodule is-active <name>\"\n+static const char *submodule_is_active_usage[] = {\n+\tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tNULL\n+};\n+\n+static const char *submodule_usage[] = {\n+\tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tNULL\n+};\n+\n+static int cmd__submodule_is_active(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_is_active_usage, 0);\n+\tif (argc != 1)\n+\t\tusage_with_options(submodule_is_active_usage, options);\n+\n+\tsetup_git_directory();\n+\n+\treturn !is_submodule_active(the_repository, argv[0]);\n+}\n+\n+static struct test_cmd cmds[] = {\n+\t{ \"is-active\", cmd__submodule_is_active },\n+};\n+\n+int cmd__submodule(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\tsize_t i;\n+\n+\targc = parse_options(argc, argv, \"test-tools\", options, submodule_usage,\n+\t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n+\tif (argc < 1)\n+\t\tusage_with_options(submodule_usage, options);\n+\n+\tfor (i = 0; i < ARRAY_SIZE(cmds); i++)\n+\t\tif (!strcmp(cmds[i].name, argv[0]))\n+\t\t\treturn cmds[i].fn(argc, argv);\n+\n+\tusage_msg_optf(\"unknown subcommand '%s'\", submodule_usage, options,\n+\t\t       argv[0]);\n+\n+\treturn 0;\n+}\ndiff --git a/t/helper/test-tool-utils.h b/t/helper/test-tool-utils.h\nnew file mode 100644\nindex 00000000000..6a0e5e0074f\n--- /dev/null\n+++ b/t/helper/test-tool-utils.h\n@@ -0,0 +1,9 @@\n+#ifndef TEST_TOOL_UTILS_H\n+#define TEST_TOOL_UTILS_H\n+\n+struct test_cmd {\n+\tconst char *name;\n+\tint (*fn)(int argc, const char **argv);\n+};\n+\n+#endif\ndiff --git a/t/helper/test-tool.c b/t/helper/test-tool.c\nindex 318fdbab0c3..7a6a8b88a91 100644\n--- a/t/helper/test-tool.c\n+++ b/t/helper/test-tool.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"test-tool.h\"\n+#include \"test-tool-utils.h\"\n #include \"trace2.h\"\n #include \"parse-options.h\"\n \n@@ -8,11 +9,6 @@ static const char * const test_tool_usage[] = {\n \tNULL\n };\n \n-struct test_cmd {\n-\tconst char *name;\n-\tint (*fn)(int argc, const char **argv);\n-};\n-\n static struct test_cmd cmds[] = {\n \t{ \"advise\", cmd__advise_if_enabled },\n \t{ \"bitmap\", cmd__bitmap },\n@@ -78,6 +74,7 @@ static struct test_cmd cmds[] = {\n \t{ \"simple-ipc\", cmd__simple_ipc },\n \t{ \"strcmp-offset\", cmd__strcmp_offset },\n \t{ \"string-list\", cmd__string_list },\n+\t{ \"submodule\", cmd__submodule },\n \t{ \"submodule-config\", cmd__submodule_config },\n \t{ \"submodule-nested-repo-config\", cmd__submodule_nested_repo_config },\n \t{ \"subprocess\", cmd__subprocess },\ndiff --git a/t/helper/test-tool.h b/t/helper/test-tool.h\nindex bb799271631..5f4f69dee81 100644\n--- a/t/helper/test-tool.h\n+++ b/t/helper/test-tool.h\n@@ -68,6 +68,7 @@ int cmd__sigchain(int argc, const char **argv);\n int cmd__simple_ipc(int argc, const char **argv);\n int cmd__strcmp_offset(int argc, const char **argv);\n int cmd__string_list(int argc, const char **argv);\n+int cmd__submodule(int argc, const char **argv);\n int cmd__submodule_config(int argc, const char **argv);\n int cmd__submodule_nested_repo_config(int argc, const char **argv);\n int cmd__subprocess(int argc, const char **argv);\ndiff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh\nindex c8e7e983317..ede6f02dbd5 100755\n--- a/t/t7413-submodule-is-active.sh\n+++ b/t/t7413-submodule-is-active.sh\n@@ -1,9 +1,12 @@\n #!/bin/sh\n \n-test_description='Test submodule--helper is-active\n+test_description='Test with test-tool submodule is-active\n \n-This test verifies that `git submodue--helper is-active` correctly identifies\n+This test verifies that `test-tool submodule is-active` correctly identifies\n submodules which are \"active\" and interesting to the user.\n+\n+This is a unit test of the submodule.c is_submodule_active() function,\n+which is also indirectly tested elsewhere.\n '\n \n . ./test-lib.sh\n@@ -25,13 +28,13 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'is-active works with urls' '\n-\tgit -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2 &&\n+\ttest-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2 &&\n \n \tgit -C super config --unset submodule.sub1.URL &&\n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n \tgit -C super config submodule.sub1.URL ../sub &&\n-\tgit -C super submodule--helper is-active sub1\n+\ttest-tool -C super submodule is-active sub1\n '\n \n test_expect_success 'is-active works with submodule.<name>.active config' '\n@@ -39,11 +42,11 @@ test_expect_success 'is-active works with submodule.<name>.active config' '\n \ttest_when_finished \"git -C super config submodule.sub1.URL ../sub\" &&\n \n \tgit -C super config --bool submodule.sub1.active \"false\" &&\n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n \n \tgit -C super config --bool submodule.sub1.active \"true\" &&\n \tgit -C super config --unset submodule.sub1.URL &&\n-\tgit -C super submodule--helper is-active sub1\n+\ttest-tool -C super submodule is-active sub1\n '\n \n test_expect_success 'is-active works with basic submodule.active config' '\n@@ -53,17 +56,17 @@ test_expect_success 'is-active works with basic submodule.active config' '\n \tgit -C super config --add submodule.active \".\" &&\n \tgit -C super config --unset submodule.sub1.URL &&\n \n-\tgit -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active correctly works with paths that are not submodules' '\n \ttest_when_finished \"git -C super config --unset-all submodule.active\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active not-a-submodule &&\n+\ttest_must_fail test-tool -C super submodule is-active not-a-submodule &&\n \n \tgit -C super config --add submodule.active \".\" &&\n-\ttest_must_fail git -C super submodule--helper is-active not-a-submodule\n+\ttest_must_fail test-tool -C super submodule is-active not-a-submodule\n '\n \n test_expect_success 'is-active works with exclusions in submodule.active config' '\n@@ -72,8 +75,8 @@ test_expect_success 'is-active works with exclusions in submodule.active config'\n \tgit -C super config --add submodule.active \".\" &&\n \tgit -C super config --add submodule.active \":(exclude)sub1\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active with submodule.active and submodule.<name>.active' '\n@@ -85,8 +88,8 @@ test_expect_success 'is-active with submodule.active and submodule.<name>.active\n \tgit -C super config --bool submodule.sub1.active \"false\" &&\n \tgit -C super config --bool submodule.sub2.active \"true\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active, submodule.active and submodule add' '\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460455","messageId":"patch-v2-07.28-b209532eb17-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 07/28] submodule--helper: move \"check-name\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:51Z","receivedAt":"2022-08-02T15:46:44Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the \"check-name\" helper to a test-tool, since\na6226fd772b (submodule--helper: convert the bulk of cmd_add() to C,\n2021-08-10) it has only been used by this test, not git-submodule.sh.\n\nAs noted with its introduction in 0383bbb9015 (submodule-config:\nverify submodule names as paths, 2018-04-30) the intent of\nt7450-bad-git-dotfiles.sh has always been to unit test the\ncheck_submodule_name() function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 24 -------------------\n t/helper/test-submodule.c   | 46 +++++++++++++++++++++++++++++++++++++\n t/t7450-bad-git-dotfiles.sh |  2 +-\n 3 files changed, 47 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b2fc732b5d8..06307886080 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2728,29 +2728,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-/*\n- * Exit non-zero if any of the submodule names given on the command line is\n- * invalid. If no names are given, filter stdin to print only valid names\n- * (which is primarily intended for testing).\n- */\n-static int check_name(int argc, const char **argv, const char *prefix)\n-{\n-\tif (argc > 1) {\n-\t\twhile (*++argv) {\n-\t\t\tif (check_submodule_name(*argv) < 0)\n-\t\t\t\treturn 1;\n-\t\t}\n-\t} else {\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n-\t\t\tif (!check_submodule_name(buf.buf))\n-\t\t\t\tprintf(\"%s\\n\", buf.buf);\n-\t\t}\n-\t\tstrbuf_release(&buf);\n-\t}\n-\treturn 0;\n-}\n-\n static int module_config(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -3305,7 +3282,6 @@ static struct cmd_struct commands[] = {\n \t{\"summary\", module_summary, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n-\t{\"check-name\", check_name, 0},\n \t{\"config\", module_config, 0},\n \t{\"set-url\", module_set_url, 0},\n \t{\"set-branch\", module_set_branch, 0},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nindex 494c6558d9f..9f0eb440192 100644\n--- a/t/helper/test-submodule.c\n+++ b/t/helper/test-submodule.c\n@@ -2,8 +2,16 @@\n #include \"test-tool-utils.h\"\n #include \"cache.h\"\n #include \"parse-options.h\"\n+#include \"submodule-config.h\"\n #include \"submodule.h\"\n \n+#define TEST_TOOL_CHECK_NAME_USAGE \\\n+\t\"test-tool submodule check-name <name>\"\n+static const char *submodule_check_name_usage[] = {\n+\tTEST_TOOL_CHECK_NAME_USAGE,\n+\tNULL\n+};\n+\n #define TEST_TOOL_IS_ACTIVE_USAGE \\\n \t\"test-tool submodule is-active <name>\"\n static const char *submodule_is_active_usage[] = {\n@@ -12,10 +20,47 @@ static const char *submodule_is_active_usage[] = {\n };\n \n static const char *submodule_usage[] = {\n+\tTEST_TOOL_CHECK_NAME_USAGE,\n \tTEST_TOOL_IS_ACTIVE_USAGE,\n \tNULL\n };\n \n+/*\n+ * Exit non-zero if any of the submodule names given on the command line is\n+ * invalid. If no names are given, filter stdin to print only valid names\n+ * (which is primarily intended for testing).\n+ */\n+static int check_name(int argc, const char **argv)\n+{\n+\tif (argc > 1) {\n+\t\twhile (*++argv) {\n+\t\t\tif (check_submodule_name(*argv) < 0)\n+\t\t\t\treturn 1;\n+\t\t}\n+\t} else {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n+\t\t\tif (!check_submodule_name(buf.buf))\n+\t\t\t\tprintf(\"%s\\n\", buf.buf);\n+\t\t}\n+\t\tstrbuf_release(&buf);\n+\t}\n+\treturn 0;\n+}\n+\n+static int cmd__submodule_check_name(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_check_name_usage, 0);\n+\tif (argc)\n+\t\tusage_with_options(submodule_check_name_usage, options);\n+\n+\treturn check_name(argc, argv);\n+}\n+\n static int cmd__submodule_is_active(int argc, const char **argv)\n {\n \tstruct option options[] = {\n@@ -32,6 +77,7 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n }\n \n static struct test_cmd cmds[] = {\n+\t{ \"check-name\", cmd__submodule_check_name },\n \t{ \"is-active\", cmd__submodule_is_active },\n };\n \ndiff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh\nindex 41706c1c9ff..2c24f120da3 100755\n--- a/t/t7450-bad-git-dotfiles.sh\n+++ b/t/t7450-bad-git-dotfiles.sh\n@@ -21,7 +21,7 @@ test_expect_success 'check names' '\n \tvalid/with/paths\n \tEOF\n \n-\tgit submodule--helper check-name >actual <<-\\EOF &&\n+\ttest-tool submodule check-name >actual <<-\\EOF &&\n \tvalid\n \tvalid/with/paths\n \n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460454","messageId":"patch-v2-08.28-de49f31dab0-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 08/28] submodule--helper: move \"resolve-relative-url-test\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:52Z","receivedAt":"2022-08-02T15:46:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As its name suggests the \"resolve-relative-url-test\" has never been\nused outside of the test suite, see 63e95beb085 (submodule: port\nresolve_relative_url from shell to C, 2016-04-15) for its original\naddition.\n\nPerhaps it would make sense to drop this code entirely, as we feel\nthat we've got enough indirect test coverage, but let's leave that\nquestion to a possible follow-up change. For now let's keep the test\ncoverage this gives us.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 23 --------------------\n t/helper/test-submodule.c   | 42 +++++++++++++++++++++++++++++++++++++\n t/t0060-path-utils.sh       |  2 +-\n 3 files changed, 43 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 06307886080..246457ec2e9 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -96,28 +96,6 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n \treturn resolved_url;\n }\n \n-static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remoteurl, *res;\n-\tconst char *up_path, *url;\n-\n-\tif (argc != 4)\n-\t\tdie(\"resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>\");\n-\n-\tup_path = argv[1];\n-\tremoteurl = xstrdup(argv[2]);\n-\turl = argv[3];\n-\n-\tif (!strcmp(up_path, \"(null)\"))\n-\t\tup_path = NULL;\n-\n-\tres = relative_url(remoteurl, url, up_path);\n-\tputs(res);\n-\tfree(res);\n-\tfree(remoteurl);\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 {\n@@ -3273,7 +3251,6 @@ static struct cmd_struct commands[] = {\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n-\t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, 0},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nindex 9f0eb440192..e0e0c53d386 100644\n--- a/t/helper/test-submodule.c\n+++ b/t/helper/test-submodule.c\n@@ -2,6 +2,7 @@\n #include \"test-tool-utils.h\"\n #include \"cache.h\"\n #include \"parse-options.h\"\n+#include \"remote.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n \n@@ -19,9 +20,17 @@ static const char *submodule_is_active_usage[] = {\n \tNULL\n };\n \n+#define TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE \\\n+\t\"test-tool submodule resolve-relative-url <up_path> <remoteurl> <url>\"\n+static const char *submodule_resolve_relative_url_usage[] = {\n+\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n+\tNULL,\n+};\n+\n static const char *submodule_usage[] = {\n \tTEST_TOOL_CHECK_NAME_USAGE,\n \tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n \tNULL\n };\n \n@@ -76,9 +85,42 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n \treturn !is_submodule_active(the_repository, argv[0]);\n }\n \n+static int resolve_relative_url(int argc, const char **argv)\n+{\n+\tchar *remoteurl, *res;\n+\tconst char *up_path, *url;\n+\n+\tup_path = argv[0];\n+\tremoteurl = xstrdup(argv[1]);\n+\turl = argv[2];\n+\n+\tif (!strcmp(up_path, \"(null)\"))\n+\t\tup_path = NULL;\n+\n+\tres = relative_url(remoteurl, url, up_path);\n+\tputs(res);\n+\tfree(res);\n+\tfree(remoteurl);\n+\treturn 0;\n+}\n+\n+static int cmd__submodule_resolve_relative_url(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_resolve_relative_url_usage, 0);\n+\tif (argc != 3)\n+\t\tusage_with_options(submodule_resolve_relative_url_usage, options);\n+\n+\treturn resolve_relative_url(argc, argv);\n+}\n+\n static struct test_cmd cmds[] = {\n \t{ \"check-name\", cmd__submodule_check_name },\n \t{ \"is-active\", cmd__submodule_is_active },\n+\t{ \"resolve-relative-url\", cmd__submodule_resolve_relative_url},\n };\n \n int cmd__submodule(int argc, const char **argv)\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 1f2007e62b7..68e29c904a6 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -22,7 +22,7 @@ relative_path() {\n \n test_submodule_relative_url() {\n \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n-\t\tactual=\\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&\n+\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n \t\ttest \\\"\\$actual\\\" = '$4'\n \t\"\n }\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460456","messageId":"patch-v2-11.28-72dcf19e1c4-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 11/28] submodule--helper: replace memset() with { 0 }-initialization","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:55Z","receivedAt":"2022-08-02T15:46:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use the less verbose { 0 }-initialization syntax rather than memset()\nin builtin/submodule--helper.c, this doesn't make a difference in\nterms of behavior, but as we're about to modify adjacent code makes\nthis more consistent, and lets us avoid worrying about when the\nmemset() happens v.s. a \"goto cleanup\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 6 ++----\n 1 file changed, 2 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 15bf89910f4..60165a848a2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1664,7 +1664,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n {\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n-\tstruct list_objects_filter_options filter_options;\n+\tstruct list_objects_filter_options filter_options = { 0 };\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1704,7 +1704,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tNULL\n \t};\n \n-\tmemset(&filter_options, 0, sizeof(filter_options));\n \targc = parse_options(argc, argv, prefix, module_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n@@ -2488,7 +2487,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n {\n \tstruct pathspec pathspec;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n-\tstruct list_objects_filter_options filter_options;\n+\tstruct list_objects_filter_options filter_options = { 0 };\n \tint ret;\n \tstruct option module_update_options[] = {\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n@@ -2546,7 +2545,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n \tgit_config(git_update_clone_config, &opt.max_jobs);\n \n-\tmemset(&filter_options, 0, sizeof(filter_options));\n \targc = parse_options(argc, argv, prefix, module_update_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460457","messageId":"patch-v2-10.28-5f5e68a868b-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 10/28] submodule--helper style: add \\n\\n after variable declarations","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:54Z","receivedAt":"2022-08-02T15:46:55Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Since the preceding commit fixed style issues with \\n\\n among the\ndeclared variables let's fix the minor stylistic issues with those\nvariables not being consistently followed by a \\n\\n.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 25 +++++++++++++++++++++++--\n 1 file changed, 23 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 53b9e14767d..15bf89910f4 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -167,6 +167,7 @@ static int module_list_compute(int argc, const char **argv,\n {\n \tint i, result = 0;\n \tchar *ps_matched = NULL;\n+\n \tparse_pathspec(pathspec, 0,\n \t\t       PATHSPEC_PREFER_FULL,\n \t\t       prefix, argv);\n@@ -248,6 +249,7 @@ static void for_each_listed_submodule(const struct module_list *list,\n \t\t\t\t      each_submodule_fn fn, void *cb_data)\n {\n \tint i;\n+\n \tfor (i = 0; i < list->nr; i++)\n \t\tfn(list->entries[i], cb_data);\n }\n@@ -267,7 +269,6 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tstruct foreach_cb *info = cb_data;\n \tconst char *path = list_item->name;\n \tconst struct object_id *ce_oid = &list_item->oid;\n-\n \tconst struct submodule *sub;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *displaypath;\n@@ -456,6 +457,7 @@ static void init_submodule(const char *path, const char *prefix,\n \t\tif (starts_with_dot_dot_slash(url) ||\n \t\t    starts_with_dot_slash(url)) {\n \t\t\tchar *oldurl = url;\n+\n \t\t\turl = resolve_relative_url(oldurl, NULL, 0);\n \t\t\tfree(oldurl);\n \t\t}\n@@ -493,6 +495,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+\n \tinit_submodule(list_item->name, info->prefix, info->flags);\n }\n \n@@ -562,6 +565,7 @@ static int handle_submodule_head_ref(const char *refname,\n \t\t\t\t     void *cb_data)\n {\n \tstruct object_id *output = cb_data;\n+\n \tif (oid)\n \t\toidcpy(output, oid);\n \n@@ -668,6 +672,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,\n \t\t\t\tvoid *cb_data)\n {\n \tstruct status_cb *info = cb_data;\n+\n \tstatus_submodule(list_item->name, &list_item->oid, list_item->ce_flags,\n \t\t\t info->prefix, info->flags);\n }\n@@ -820,6 +825,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n \tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n \t\t\tstruct ref_store *refs = get_submodule_ref_store(p->sm_path);\n+\n \t\t\tif (refs)\n \t\t\t\trefs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);\n \t\t} else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {\n@@ -1158,6 +1164,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tif (starts_with_dot_dot_slash(sub->url) ||\n \t\t    starts_with_dot_slash(sub->url)) {\n \t\t\tchar *up_path = get_up_path(path);\n+\n \t\t\tsub_origin_url = resolve_relative_url(sub->url, up_path, 1);\n \t\t\tsuper_config_url = resolve_relative_url(sub->url, NULL, 1);\n \t\t\tfree(up_path);\n@@ -1233,6 +1240,7 @@ static void sync_submodule(const char *path, const char *prefix,\n static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct sync_cb *info = cb_data;\n+\n \tsync_submodule(list_item->name, info->prefix, info->flags);\n }\n \n@@ -1312,6 +1320,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \n \t\tif (!(flags & OPT_FORCE)) {\n \t\t\tstruct child_process cp_rm = CHILD_PROCESS_INIT;\n+\n \t\t\tcp_rm.git_cmd = 1;\n \t\t\tstrvec_pushl(&cp_rm.args, \"rm\", \"-qn\",\n \t\t\t\t     path, NULL);\n@@ -1348,6 +1357,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \t/* remove the .git/config entries (unless the user already did it) */\n \tif (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {\n \t\tchar *sub_key = xstrfmt(\"submodule.%s\", sub->name);\n+\n \t\t/*\n \t\t * remove the whole section so we have a clean state when\n \t\t * the user later decides to init this submodule again\n@@ -1585,6 +1595,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tstrvec_pushl(&cp.args, \"--depth\", clone_data->depth, NULL);\n \t\tif (clone_data->reference.nr) {\n \t\t\tstruct string_list_item *item;\n+\n \t\t\tfor_each_string_list_item(item, &clone_data->reference)\n \t\t\t\tstrvec_pushl(&cp.args, \"--reference\",\n \t\t\t\t\t     item->string, NULL);\n@@ -1935,6 +1946,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tstrvec_pushl(&child->args, \"--url\", url, NULL);\n \tif (suc->update_data->references.nr) {\n \t\tstruct string_list_item *item;\n+\n \t\tfor_each_string_list_item(item, &suc->update_data->references)\n \t\t\tstrvec_pushl(&child->args, \"--reference\", item->string, NULL);\n \t}\n@@ -1967,6 +1979,7 @@ static int update_clone_get_next_task(struct child_process *child,\n \t\tce = suc->update_data->list.entries[suc->current];\n \t\tif (prepare_to_clone_next_submodule(ce, child, suc, err)) {\n \t\t\tint *p = xmalloc(sizeof(*p));\n+\n \t\t\t*p = suc->current;\n \t\t\t*idx_task_cb = p;\n \t\t\tsuc->current++;\n@@ -1982,6 +1995,7 @@ static int update_clone_get_next_task(struct child_process *child,\n \tindex = suc->current - suc->update_data->list.nr;\n \tif (index < suc->failed_clones_nr) {\n \t\tint *p;\n+\n \t\tce = suc->failed_clones[index];\n \t\tif (!prepare_to_clone_next_submodule(ce, child, suc, err)) {\n \t\t\tsuc->current ++;\n@@ -2005,6 +2019,7 @@ static int update_clone_start_failure(struct strbuf *err,\n \t\t\t\t      void *idx_task_cb)\n {\n \tstruct submodule_update_clone *suc = suc_cb;\n+\n \tsuc->quickstop = 1;\n \treturn 1;\n }\n@@ -2016,9 +2031,9 @@ static int update_clone_task_finished(int result,\n {\n \tconst struct cache_entry *ce;\n \tstruct submodule_update_clone *suc = suc_cb;\n-\n \tint *idxP = idx_task_cb;\n \tint idx = *idxP;\n+\n \tfree(idxP);\n \n \tif (!result)\n@@ -2051,6 +2066,7 @@ static int git_update_clone_config(const char *var, const char *value,\n \t\t\t\t   void *cb)\n {\n \tint *max_jobs = cb;\n+\n \tif (!strcmp(var, \"submodule.fetchjobs\"))\n \t\t*max_jobs = parse_submodule_fetchjobs(var, value);\n \treturn 0;\n@@ -2091,6 +2107,7 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \tif (oid) {\n \t\tchar *hex = oid_to_hex(oid);\n \t\tchar *remote = get_default_remote();\n+\n \t\tstrvec_pushl(&cp.args, remote, hex, NULL);\n \t\tfree(remote);\n \t}\n@@ -2340,6 +2357,7 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \n \tif (update_data->references.nr) {\n \t\tstruct string_list_item *item;\n+\n \t\tfor_each_string_list_item(item, &update_data->references)\n \t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n \t}\n@@ -2872,8 +2890,10 @@ static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)\n \tif (!capture_command(&cp_remote, &sb_remote_out, 0)) {\n \t\tchar *next_line;\n \t\tchar *line = sb_remote_out.buf;\n+\n \t\twhile ((next_line = strchr(line, '\\n')) != NULL) {\n \t\t\tsize_t len = next_line - line;\n+\n \t\t\tif (strip_suffix_mem(line, &len, \" (fetch)\"))\n \t\t\t\tstrbuf_addf(msg, \"  %.*s\\n\", (int)len, line);\n \t\t\tline = next_line + 1;\n@@ -3180,6 +3200,7 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \t\tint exit_code = -1;\n \t\tstruct strbuf sb = STRBUF_INIT;\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n \t\tcp.git_cmd = 1;\n \t\tcp.no_stdout = 1;\n \t\tstrvec_pushl(&cp.args, \"add\", \"--dry-run\", \"--ignore-missing\",\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460458","messageId":"patch-v2-09.28-b0238f699ce-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 09/28] submodule--helper style: don't separate declared variables with \\n\\n","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:53Z","receivedAt":"2022-08-02T15:46:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The usual style in the codebase is to separate declared variables with\na single newline, not two, let's adjust this code to conform to\nthat. This makes the eventual addition of various \"int ret\" variables\nmore consistent.\n\nIn doing this the comment added in 2964d6e5e1e (submodule: port\nsubcommand 'set-branch' from shell to C, 2020-06-02) might become\nambiguous to some, although it should be clear what it's referring to,\nlet's move it above the 'OPT_NOOP_NOARG('q', \"quiet\")' to make that\nclearer.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 33 +++++----------------------------\n 1 file changed, 5 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 246457ec2e9..53b9e14767d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -368,14 +368,12 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tstruct foreach_cb info = FOREACH_CB_INIT;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n-\n \tstruct option module_foreach_options[] = {\n \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n \t\t\t N_(\"recurse into nested submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule foreach [--quiet] [--recursive] [--] <command>\"),\n \t\tNULL\n@@ -504,12 +502,10 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\n \tstruct option module_init_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for initializing a submodule\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule init [<options>] [<path>]\"),\n \t\tNULL\n@@ -682,14 +678,12 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\n \tstruct option module_status_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule status [--quiet] [--cached] [--recursive] [<path>...]\"),\n \t\tNULL\n@@ -1082,7 +1076,6 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \tenum diff_cmd diff_cmd = DIFF_INDEX;\n \tstruct object_id head_oid;\n \tint ret;\n-\n \tstruct option module_summary_options[] = {\n \t\tOPT_BOOL(0, \"cached\", &cached,\n \t\t\t N_(\"use the commit stored in the index instead of the submodule HEAD\")),\n@@ -1094,7 +1087,6 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \t\t\t     N_(\"limit the summary size\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule summary [<options>] [<commit>] [--] [<path>]\"),\n \t\tNULL\n@@ -1251,14 +1243,12 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n \tint recursive = 0;\n-\n \tstruct option module_sync_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n \t\tOPT_BOOL(0, \"recursive\", &recursive,\n \t\t\tN_(\"recurse into nested submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule sync [--quiet] [--recursive] [<path>]\"),\n \t\tNULL\n@@ -1390,14 +1380,12 @@ static int module_deinit(int argc, const char **argv, const char *prefix)\n \tint quiet = 0;\n \tint force = 0;\n \tint all = 0;\n-\n \tstruct option module_deinit_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT__FORCE(&force, N_(\"remove submodule working trees even if they contain local changes\"), 0),\n \t\tOPT_BOOL(0, \"all\", &all, N_(\"unregister all submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]\"),\n \t\tNULL\n@@ -1666,7 +1654,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options;\n-\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1698,7 +1685,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tOPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule--helper clone [--prefix=<path>] [--quiet] \"\n \t\t   \"[--reference <repository>] [--name <name>] [--depth <depth>] \"\n@@ -2486,7 +2472,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options;\n \tint ret;\n-\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@@ -2530,7 +2515,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\tOPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule [--quiet] update\"\n \t\t\" [--init [--filter=<filter-spec>]] [--remote]\"\n@@ -2679,7 +2663,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tunsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;\n-\n \tstruct option embed_gitdir_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n@@ -2688,7 +2671,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \t\t\tABSORB_GITDIR_RECURSE_SUBMODULES),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule absorbgitdirs [<options>] [<path>...]\"),\n \t\tNULL\n@@ -2712,7 +2694,6 @@ static int module_config(int argc, const char **argv, const char *prefix)\n \t\tCHECK_WRITEABLE = 1,\n \t\tDO_UNSET = 2\n \t} command = 0;\n-\n \tstruct option module_config_options[] = {\n \t\tOPT_CMDMODE(0, \"check-writeable\", &command,\n \t\t\t    N_(\"check if it is safe to write to the .gitmodules file\"),\n@@ -2758,7 +2739,6 @@ static int module_set_url(int argc, const char **argv, const char *prefix)\n \tconst char *newurl;\n \tconst char *path;\n \tchar *config_name;\n-\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for setting url of a submodule\")),\n \t\tOPT_END()\n@@ -2789,13 +2769,13 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \tconst char *opt_branch = NULL;\n \tconst char *path;\n \tchar *config_name;\n-\n-\t/*\n-\t * We accept the `quiet` option for uniformity across subcommands,\n-\t * though there is nothing to make less verbose in this subcommand.\n-\t */\n \tstruct option options[] = {\n+\t\t/*\n+\t\t * We accept the `quiet` option for uniformity across subcommands,\n+\t\t * though there is nothing to make less verbose in this subcommand.\n+\t\t */\n \t\tOPT_NOOP_NOARG('q', \"quiet\"),\n+\n \t\tOPT_BOOL('d', \"default\", &opt_default,\n \t\t\tN_(\"set the default tracking branch to master\")),\n \t\tOPT_STRING('b', \"branch\", &opt_branch, N_(\"branch\"),\n@@ -2830,7 +2810,6 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)\n {\n \tenum branch_track track;\n \tint quiet = 0, force = 0, reflog = 0, dry_run = 0;\n-\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"print only error messages\")),\n \t\tOPT__FORCE(&force, N_(\"force creation\"), 0),\n@@ -3129,7 +3108,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \tint force = 0, quiet = 0, progress = 0, dissociate = 0;\n \tstruct add_data add_data = ADD_DATA_INIT;\n \tchar *to_free = NULL;\n-\n \tstruct option options[] = {\n \t\tOPT_STRING('b', \"branch\", &add_data.branch, N_(\"branch\"),\n \t\t\t   N_(\"branch of repository to add as submodule\")),\n@@ -3146,7 +3124,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \t\tOPT_INTEGER(0, \"depth\", &add_data.depth, N_(\"depth for shallow clones\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule add [<options>] [--] <repository> [<path>]\"),\n \t\tNULL\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460459","messageId":"patch-v2-13.28-91558745e2e-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 13/28] submodule--helper: move \"sb\" in clone_submodule() to its own scope","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:57Z","receivedAt":"2022-08-02T15:47:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor the only remaining use of a \"struct strbuf sb\" in\nclone_submodule() to live in its own scope. This makes the code\nclearer by limiting its lifetime.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 21 ++++++++++++++-------\n 1 file changed, 14 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 63008970f1c..fe32abd45e6 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1557,16 +1557,24 @@ static void prepare_possible_alternates(const char *sm_name,\n \tfree(error_strategy);\n }\n \n-static int clone_submodule(struct module_clone_data *clone_data)\n+static char *clone_submodule_sm_gitdir(const char *name)\n {\n-\tchar *p, *sm_gitdir;\n-\tchar *sm_alternate = NULL, *error_strategy = NULL;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tchar *sm_gitdir;\n \n-\tsubmodule_name_to_gitdir(&sb, the_repository, clone_data->name);\n+\tsubmodule_name_to_gitdir(&sb, the_repository, name);\n \tsm_gitdir = absolute_pathdup(sb.buf);\n-\tstrbuf_reset(&sb);\n+\tstrbuf_release(&sb);\n+\n+\treturn sm_gitdir;\n+}\n+\n+static int clone_submodule(struct module_clone_data *clone_data)\n+{\n+\tchar *p;\n+\tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n+\tchar *sm_alternate = NULL, *error_strategy = NULL;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \n \tif (!is_absolute_path(clone_data->path))\n \t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n@@ -1655,7 +1663,6 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \tfree(sm_alternate);\n \tfree(error_strategy);\n \n-\tstrbuf_release(&sb);\n \tfree(sm_gitdir);\n \tfree(p);\n \treturn 0;\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460460","messageId":"patch-v2-12.28-e5e267dccd5-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 12/28] submodule--helper: use xstrfmt() in clone_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:56Z","receivedAt":"2022-08-02T15:47:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use xstrfmt() in clone_submodule() instead of a \"struct strbuf\" in two\ncases where we weren't getting anything out of using the \"struct\nstrbuf\".\n\nThis changes code that was was added along with other uses of \"struct\nstrbuf\" in this function in ee8838d1577 (submodule: rewrite\n`module_clone` shell function in C, 2015-09-08).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 17 +++++++++--------\n 1 file changed, 9 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 60165a848a2..63008970f1c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1568,12 +1568,11 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \tsm_gitdir = absolute_pathdup(sb.buf);\n \tstrbuf_reset(&sb);\n \n-\tif (!is_absolute_path(clone_data->path)) {\n-\t\tstrbuf_addf(&sb, \"%s/%s\", get_git_work_tree(), clone_data->path);\n-\t\tclone_data->path = strbuf_detach(&sb, NULL);\n-\t} else {\n+\tif (!is_absolute_path(clone_data->path))\n+\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n+\t\t\t\t\t   clone_data->path);\n+\telse\n \t\tclone_data->path = xstrdup(clone_data->path);\n-\t}\n \n \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n@@ -1625,14 +1624,16 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n \t\t\t    clone_data->url, clone_data->path);\n \t} else {\n+\t\tchar *path;\n+\n \t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n \t\t    !is_empty_dir(clone_data->path))\n \t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n \t\tif (safe_create_leading_directories_const(clone_data->path) < 0)\n \t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n-\t\tstrbuf_addf(&sb, \"%s/index\", sm_gitdir);\n-\t\tunlink_or_warn(sb.buf);\n-\t\tstrbuf_reset(&sb);\n+\t\tpath = xstrfmt(\"%s/index\", sm_gitdir);\n+\t\tunlink_or_warn(path);\n+\t\tfree(path);\n \t}\n \n \tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460461","messageId":"patch-v2-15.28-1ff380ec7b5-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 15/28] submodule--helper: add \"const\" to copy of \"update_data\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:59Z","receivedAt":"2022-08-02T15:47:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nAdd a \"const\" to the copy of \"struct update_data\" that's tracked by\nthe \"struct submodule_update_clone\", as it neither owns nor modifies\nit.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 6b4ee8a31bb..1391316cde2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1777,7 +1777,7 @@ struct submodule_update_clone {\n \tint current;\n \n \t/* configuration parameters which are passed on to the children */\n-\tstruct update_data *update_data;\n+\tconst struct update_data *update_data;\n \n \t/* to be consumed by update_submodule() */\n \tstruct update_clone_data *update_clone;\n@@ -1862,7 +1862,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tconst char *update_string;\n \tenum submodule_update_type update_type;\n \tchar *key;\n-\tstruct update_data *ud = suc->update_data;\n+\tconst struct update_data *ud = suc->update_data;\n \tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460462","messageId":"patch-v2-14.28-866b8397a59-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 14/28] submodule--helper: pass a \"const struct module_clone_data\" to clone_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:45:58Z","receivedAt":"2022-08-02T15:47:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add \"const\" to the \"struct module_clone_data\" that we pass to\nclone_submodule(), which makes the ownership clear, and stops us from\nclobbering the \"clone_data->path\".\n\nWe still need to add to the \"reference\" member, which is a \"struct\nstring_list\". Let's do this by having clone_submodule() create its\nown, and copy the contents over, allowing us to pass it as a\nseparate parameter.\n\nThis new \"struct string_list\" still leaks memory, just as the \"struct\nmodule_clone_data\" did before. let's not fix that for now, to fix that\nwe'll need to add some \"goto cleanup\" to the relevant code. That will\neventually be done in follow-up commits, this change makes it easier\nto fix the memory leak.\n\nThe scope of the new \"reference\" variable in add_submodule() could be\nnarrowed to the \"else\" block, but as we'll eventually free it with a\n\"goto cleanup\" let's declare it at the start of the function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 49 ++++++++++++++++++++-----------------\n 1 file changed, 26 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex fe32abd45e6..6b4ee8a31bb 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1434,7 +1434,6 @@ struct module_clone_data {\n \tconst char *url;\n \tconst char *depth;\n \tstruct list_objects_filter_options *filter_options;\n-\tstruct string_list reference;\n \tunsigned int quiet: 1;\n \tunsigned int progress: 1;\n \tunsigned int dissociate: 1;\n@@ -1442,7 +1441,6 @@ struct module_clone_data {\n \tint single_branch;\n };\n #define MODULE_CLONE_DATA_INIT { \\\n-\t.reference = STRING_LIST_INIT_NODUP, \\\n \t.single_branch = -1, \\\n }\n \n@@ -1569,18 +1567,20 @@ static char *clone_submodule_sm_gitdir(const char *name)\n \treturn sm_gitdir;\n }\n \n-static int clone_submodule(struct module_clone_data *clone_data)\n+static int clone_submodule(const struct module_clone_data *clone_data,\n+\t\t\t   struct string_list *reference)\n {\n \tchar *p;\n \tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n \tchar *sm_alternate = NULL, *error_strategy = NULL;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tconst char *clone_data_path;\n \n \tif (!is_absolute_path(clone_data->path))\n-\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n-\t\t\t\t\t   clone_data->path);\n+\t\tclone_data_path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n+\t\t\t\t\t  clone_data->path);\n \telse\n-\t\tclone_data->path = xstrdup(clone_data->path);\n+\t\tclone_data_path = xstrdup(clone_data->path);\n \n \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n@@ -1590,7 +1590,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\tif (safe_create_leading_directories_const(sm_gitdir) < 0)\n \t\t\tdie(_(\"could not create directory '%s'\"), sm_gitdir);\n \n-\t\tprepare_possible_alternates(clone_data->name, &clone_data->reference);\n+\t\tprepare_possible_alternates(clone_data->name, reference);\n \n \t\tstrvec_push(&cp.args, \"clone\");\n \t\tstrvec_push(&cp.args, \"--no-checkout\");\n@@ -1600,10 +1600,10 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tstrvec_push(&cp.args, \"--progress\");\n \t\tif (clone_data->depth && *(clone_data->depth))\n \t\t\tstrvec_pushl(&cp.args, \"--depth\", clone_data->depth, NULL);\n-\t\tif (clone_data->reference.nr) {\n+\t\tif (reference->nr) {\n \t\t\tstruct string_list_item *item;\n \n-\t\t\tfor_each_string_list_item(item, &clone_data->reference)\n+\t\t\tfor_each_string_list_item(item, reference)\n \t\t\t\tstrvec_pushl(&cp.args, \"--reference\",\n \t\t\t\t\t     item->string, NULL);\n \t\t}\n@@ -1622,7 +1622,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \n \t\tstrvec_push(&cp.args, \"--\");\n \t\tstrvec_push(&cp.args, clone_data->url);\n-\t\tstrvec_push(&cp.args, clone_data->path);\n+\t\tstrvec_push(&cp.args, clone_data_path);\n \n \t\tcp.git_cmd = 1;\n \t\tprepare_submodule_repo_env(&cp.env);\n@@ -1630,25 +1630,25 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \n \t\tif(run_command(&cp))\n \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n-\t\t\t    clone_data->url, clone_data->path);\n+\t\t\t    clone_data->url, clone_data_path);\n \t} else {\n \t\tchar *path;\n \n-\t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n-\t\t    !is_empty_dir(clone_data->path))\n-\t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n-\t\tif (safe_create_leading_directories_const(clone_data->path) < 0)\n-\t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n+\t\tif (clone_data->require_init && !access(clone_data_path, X_OK) &&\n+\t\t    !is_empty_dir(clone_data_path))\n+\t\t\tdie(_(\"directory not empty: '%s'\"), clone_data_path);\n+\t\tif (safe_create_leading_directories_const(clone_data_path) < 0)\n+\t\t\tdie(_(\"could not create directory '%s'\"), clone_data_path);\n \t\tpath = xstrfmt(\"%s/index\", sm_gitdir);\n \t\tunlink_or_warn(path);\n \t\tfree(path);\n \t}\n \n-\tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n+\tconnect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);\n \n-\tp = git_pathdup_submodule(clone_data->path, \"config\");\n+\tp = git_pathdup_submodule(clone_data_path, \"config\");\n \tif (!p)\n-\t\tdie(_(\"could not get submodule directory for '%s'\"), clone_data->path);\n+\t\tdie(_(\"could not get submodule directory for '%s'\"), clone_data_path);\n \n \t/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */\n \tgit_config_get_string(\"submodule.alternateLocation\", &sm_alternate);\n@@ -1673,6 +1673,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options = { 0 };\n+\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1686,7 +1687,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING(0, \"url\", &clone_data.url,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"url where to clone the submodule from\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &clone_data.reference,\n+\t\tOPT_STRING_LIST(0, \"reference\", &reference,\n \t\t\t   N_(\"repo\"),\n \t\t\t   N_(\"reference repository\")),\n \t\tOPT_BOOL(0, \"dissociate\", &dissociate,\n@@ -1725,7 +1726,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_submodule_helper_usage,\n \t\t\t\t   module_clone_options);\n \n-\tclone_submodule(&clone_data);\n+\tclone_submodule(&clone_data, &reference);\n \tlist_objects_filter_release(&filter_options);\n \treturn 0;\n }\n@@ -2913,6 +2914,7 @@ static int add_submodule(const struct add_data *add_data)\n {\n \tchar *submod_gitdir_path;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n+\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n \n \t/* perhaps the path already exists and is already a git repo, else clone it */\n \tif (is_directory(add_data->sm_path)) {\n@@ -2929,6 +2931,7 @@ static int add_submodule(const struct add_data *add_data)\n \t\tfree(submod_gitdir_path);\n \t} else {\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n \t\tsubmod_gitdir_path = xstrfmt(\".git/modules/%s\", add_data->sm_name);\n \n \t\tif (is_directory(submod_gitdir_path)) {\n@@ -2968,13 +2971,13 @@ static int add_submodule(const struct add_data *add_data)\n \t\tclone_data.quiet = add_data->quiet;\n \t\tclone_data.progress = add_data->progress;\n \t\tif (add_data->reference_path)\n-\t\t\tstring_list_append(&clone_data.reference,\n+\t\t\tstring_list_append(&reference,\n \t\t\t\t\t   xstrdup(add_data->reference_path));\n \t\tclone_data.dissociate = add_data->dissociate;\n \t\tif (add_data->depth >= 0)\n \t\t\tclone_data.depth = xstrfmt(\"%d\", add_data->depth);\n \n-\t\tif (clone_submodule(&clone_data))\n+\t\tif (clone_submodule(&clone_data, &reference))\n \t\t\treturn -1;\n \n \t\tprepare_submodule_repo_env(&cp.env);\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460463","messageId":"patch-v2-17.28-23eb07176d9-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 17/28] submodule--helper: don't redundantly check \"else if (res)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:01Z","receivedAt":"2022-08-02T15:47:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"res\" variable must be true at this point in update_submodule(),\nas just a few lines above this we've unconditionally:\n\n\tif (!res)\n\t\treturn 0;\n\nSo we don't need to guard the \"return 1\" with an \"else if (res)\", we\nan return unconditionally at this point. See b3c5f5cb048 (submodule:\nmove core cmd_update() logic to C, 2022-03-15) for the initial\nintroduction of this code, this check of \"res\" has always been\nredundant.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5ea308273f4..1a19723f596 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2443,8 +2443,7 @@ static int update_submodule(struct update_data *update_data)\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\treturn 1;\n \t}\n \n \treturn 0;\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460464","messageId":"patch-v2-16.28-d3a7e646adc-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 16/28] submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:00Z","receivedAt":"2022-08-02T15:47:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nRefactor code added in e83e3333b57 (submodule: port submodule\nsubcommand 'summary' from shell to C, 2020-08-13) so that \"errmsg\" and\n\"errmsg_str\" are folded into one. The distinction between the empty\nstring and NULL is something that's tested for by\ne.g. \"t/t7401-submodule-summary.sh\".\n\nThis is in preparation for fixing a memory leak the \"struct strbuf\" in\nthe pre-image.\n\nLet's also pass a \"const char *\" to print_submodule_summary(), as it\nshould not be modifying the \"errmsg\".\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 14 ++++++--------\n 1 file changed, 6 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 1391316cde2..5ea308273f4 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -761,7 +761,7 @@ static char *verify_submodule_committish(const char *sm_path,\n \treturn strbuf_detach(&result, NULL);\n }\n \n-static void print_submodule_summary(struct summary_cb *info, char *errmsg,\n+static void print_submodule_summary(struct summary_cb *info, const char *errmsg,\n \t\t\t\t    int total_commits, const char *displaypath,\n \t\t\t\t    const char *src_abbrev, const char *dst_abbrev,\n \t\t\t\t    struct module_cb *p)\n@@ -819,7 +819,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n {\n \tchar *displaypath, *src_abbrev = NULL, *dst_abbrev;\n \tint missing_src = 0, missing_dst = 0;\n-\tchar *errmsg = NULL;\n+\tstruct strbuf errmsg = STRBUF_INIT;\n \tint total_commits = -1;\n \n \tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n@@ -920,23 +920,21 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t\t * submodule, i.e., deleted or changed to blob\n \t\t */\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n-\t\t\tstruct strbuf errmsg_str = STRBUF_INIT;\n \t\t\tif (missing_src && missing_dst) {\n-\t\t\t\tstrbuf_addf(&errmsg_str, \"  Warn: %s doesn't contain commits %s and %s\\n\",\n+\t\t\t\tstrbuf_addf(&errmsg, \"  Warn: %s doesn't contain commits %s and %s\\n\",\n \t\t\t\t\t    displaypath, oid_to_hex(&p->oid_src),\n \t\t\t\t\t    oid_to_hex(&p->oid_dst));\n \t\t\t} else {\n-\t\t\t\tstrbuf_addf(&errmsg_str, \"  Warn: %s doesn't contain commit %s\\n\",\n+\t\t\t\tstrbuf_addf(&errmsg, \"  Warn: %s doesn't contain commit %s\\n\",\n \t\t\t\t\t    displaypath, missing_src ?\n \t\t\t\t\t    oid_to_hex(&p->oid_src) :\n \t\t\t\t\t    oid_to_hex(&p->oid_dst));\n \t\t\t}\n-\t\t\terrmsg = strbuf_detach(&errmsg_str, NULL);\n \t\t}\n \t}\n \n-\tprint_submodule_summary(info, errmsg, total_commits,\n-\t\t\t\tdisplaypath, src_abbrev,\n+\tprint_submodule_summary(info, errmsg.len ? errmsg.buf : NULL,\n+\t\t\t\ttotal_commits, displaypath, src_abbrev,\n \t\t\t\tdst_abbrev, p);\n \n \tfree(displaypath);\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460465","messageId":"patch-v2-18.28-78f74df6d5e-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 18/28] submodule--helper: rename \"int res\" to \"int ret\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:02Z","receivedAt":"2022-08-02T15:47:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Rename the \"res\" variable added in b3c5f5cb048 (submodule: move core\ncmd_update() logic to C, 2022-03-15) to \"ret\", which is the convention\nin the rest of this file.\n\nEventual follow-up commits will change the code in update_submodule()\nto a \"goto cleanup\" pattern, let's have the post image look consistent\nwith the rest. For update_submodules() let's also use a \"ret\" for\nconsistency, that use was also added in b3c5f5cb048. We'll be\nmodifying that codepath in subsequent commits.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 1a19723f596..29f3e1dd8c8 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2424,7 +2424,7 @@ static int update_submodule(struct update_data *update_data)\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+\t\tint ret;\n \n \t\tnext.prefix = NULL;\n \t\toidcpy(&next.oid, null_oid());\n@@ -2436,13 +2436,13 @@ static int update_submodule(struct update_data *update_data)\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\tret = run_command(&cp);\n+\t\tif (!ret)\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\tif (ret == 128)\n+\t\t\texit(ret);\n \t\treturn 1;\n \t}\n \n@@ -2451,7 +2451,7 @@ static int update_submodule(struct update_data *update_data)\n \n static int update_submodules(struct update_data *update_data)\n {\n-\tint i, res = 0;\n+\tint i, ret = 0;\n \tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n \n \tsuc.update_data = update_data;\n@@ -2469,7 +2469,7 @@ static int update_submodules(struct update_data *update_data)\n \t * - the listener can avoid doing any work if fetching failed.\n \t */\n \tif (suc.quickstop) {\n-\t\tres = 1;\n+\t\tret = 1;\n \t\tgoto cleanup;\n \t}\n \n@@ -2481,12 +2481,12 @@ static int update_submodules(struct update_data *update_data)\n \t\tupdate_data->sm_path = ucd.sub->path;\n \n \t\tif (update_submodule(update_data))\n-\t\t\tres = 1;\n+\t\t\tret = 1;\n \t}\n \n cleanup:\n \tstring_list_clear(&update_data->references, 0);\n-\treturn res;\n+\treturn ret;\n }\n \n static int module_update(int argc, const char **argv, const char *prefix)\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460466","messageId":"patch-v2-19.28-f0258e37ebe-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 19/28] submodule--helper: return \"ret\", not \"1\" from update_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:03Z","receivedAt":"2022-08-02T15:47:36Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend the update_submodule() function to return the failing \"ret\" on\nerror, instead of overriding it with \"1\".\n\nThis code was added in b3c5f5cb048 (submodule: move core cmd_update()\nlogic to C, 2022-03-15), and this change ends up not making a\ndifference as this function is only called in update_submodules(). If\nwe return non-zero here we'll always in turn return \"1\" in\nmodule_update().\n\nBut if we didn't do that and returned any other non-zero exit code in\nupdate_submodules() we'd fail the test that's being amended\nhere. We're still testing the status quo here.\n\nThis change makes subsequent refactoring of update_submodule() easier,\nas we'll no longer need to worry about clobbering the \"ret\" we get\nfrom the run_command().\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 2 +-\n t/t7406-submodule-update.sh | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 29f3e1dd8c8..0fb780a724c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2443,7 +2443,7 @@ static int update_submodule(struct update_data *update_data)\n \t\t\t    update_data->displaypath);\n \t\tif (ret == 128)\n \t\t\texit(ret);\n-\t\treturn 1;\n+\t\treturn ret;\n \t}\n \n \treturn 0;\ndiff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh\nindex 6cc07460dd2..c5f5dbe55e0 100755\n--- a/t/t7406-submodule-update.sh\n+++ b/t/t7406-submodule-update.sh\n@@ -769,7 +769,7 @@ test_expect_success 'submodule update continues after recursive checkout error'\n \t   echo \"\" > file\n \t  )\n \t ) &&\n-\t test_must_fail git submodule update --recursive &&\n+\t test_expect_code 1 git submodule update --recursive &&\n \t (cd submodule2 &&\n \t  git rev-parse --verify HEAD >../actual\n \t ) &&\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460467","messageId":"patch-v2-20.28-70f030cca4e-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 20/28] submodule--helper: add missing braces to \"else\" arm","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:04Z","receivedAt":"2022-08-02T15:47:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add missing braces to an \"else\" arm in init_submodule(), this\nstylistic change makes this code conform to the CodingGuidelines, and\nmakes a subsequent commit smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 0fb780a724c..955deb375ee 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -480,8 +480,9 @@ static void init_submodule(const char *path, const char *prefix,\n \t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n \t\t\t\tsub->name);\n \t\t\tupd = xstrdup(\"none\");\n-\t\t} else\n+\t\t} else {\n \t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n+\t\t}\n \n \t\tif (git_config_set_gently(sb.buf, upd))\n \t\t\tdie(_(\"Failed to register update mode for submodule path '%s'\"), displaypath);\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460468","messageId":"patch-v2-21.28-bce1a014a2f-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 21/28] submodule--helper: don't call submodule_strategy_to_string() in BUG()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:05Z","receivedAt":"2022-08-02T15:47:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Don't call submodule_strategy_to_string() in a BUG() message. These\ncalls added in c51f8f94e5b (submodule--helper: run update procedures\nfrom C, 2021-08-24) don't need the extra information\nsubmodule_strategy_to_string() gives us, as we'll never reach the\nSM_UPDATE_COMMAND case here.\n\nThat case is the only one where we'd get any information beyond the\nstraightforward number-to-string mapping.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 955deb375ee..b49528e1ba9 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2155,8 +2155,8 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n+\t\t    ud->update_strategy.type);\n \t}\n \tstrvec_push(&cp.args, oid);\n \n@@ -2181,8 +2181,8 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n+\t\t\t    ud->update_strategy.type);\n \t\t}\n \t\tif (must_die_on_failure)\n \t\t\texit(128);\n@@ -2212,8 +2212,8 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n+\t\t    ud->update_strategy.type);\n \t}\n \n \treturn 0;\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460469","messageId":"patch-v2-22.28-98c3e562c82-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 22/28] submodule--helper: move submodule_strategy_to_string() to only user","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:06Z","receivedAt":"2022-08-02T15:47:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the submodule_strategy_to_string() function added in\n3604242f080 (submodule: port init from shell to C, 2016-04-15) to its\nonly user.\n\nThis function would return NULL on SM_UPDATE_UNSPECIFIED, so it wasn't\nsafe to xstrdup() its return value in the general case, or to use it\nin a sprintf() format as the code removed in the preceding commit did.\n\nBut its callers would never call it with either SM_UPDATE_UNSPECIFIED\nor SM_UPDATE_COMMAND. Let's move it to a \"static\" helper, and have its\nfunctionality reflect how it's used, and BUG() out on the rest.\n\nBy doing this we can also stop needlessly xstrdup()-ing and free()-ing\nthe memory for the config we're setting. We can instead always use\nconstant strings. We can also use the *_tmp() variant of\ngit_config_get_string().\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 29 ++++++++++++++++++++++++-----\n submodule.c                 | 21 ---------------------\n submodule.h                 |  1 -\n 3 files changed, 24 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b49528e1ba9..d787c0fead4 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -413,12 +413,32 @@ struct init_cb {\n };\n #define INIT_CB_INIT { 0 }\n \n+static const char *submodule_strategy_to_string(enum submodule_update_type type)\n+{\n+\tswitch (type) {\n+\tcase SM_UPDATE_CHECKOUT:\n+\t\treturn \"checkout\";\n+\tcase SM_UPDATE_MERGE:\n+\t\treturn \"merge\";\n+\tcase SM_UPDATE_REBASE:\n+\t\treturn \"rebase\";\n+\tcase SM_UPDATE_NONE:\n+\t\treturn \"none\";\n+\tcase SM_UPDATE_UNSPECIFIED:\n+\tcase SM_UPDATE_COMMAND:\n+\t\tBUG(\"init_submodule() should handle type %d\", type);\n+\tdefault:\n+\t\tBUG(\"unexpected update strategy type: %d\", type);\n+\t}\n+}\n+\n static void init_submodule(const char *path, const char *prefix,\n \t\t\t   unsigned int flags)\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tchar *upd = NULL, *url = NULL, *displaypath;\n+\tconst char *upd;\n+\tchar *url = NULL, *displaypath;\n \n \tdisplaypath = get_submodule_displaypath(path, prefix);\n \n@@ -474,14 +494,14 @@ static void init_submodule(const char *path, const char *prefix,\n \n \t/* Copy \"update\" setting when it is not set yet */\n \tstrbuf_addf(&sb, \"submodule.%s.update\", sub->name);\n-\tif (git_config_get_string(sb.buf, &upd) &&\n+\tif (git_config_get_string_tmp(sb.buf, &upd) &&\n \t    sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n \t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND) {\n \t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n \t\t\t\tsub->name);\n-\t\t\tupd = xstrdup(\"none\");\n+\t\t\tupd = \"none\";\n \t\t} else {\n-\t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n+\t\t\tupd = submodule_strategy_to_string(sub->update_strategy.type);\n \t\t}\n \n \t\tif (git_config_set_gently(sb.buf, upd))\n@@ -490,7 +510,6 @@ static void init_submodule(const char *path, const char *prefix,\n \tstrbuf_release(&sb);\n \tfree(displaypath);\n \tfree(url);\n-\tfree(upd);\n }\n \n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\ndiff --git a/submodule.c b/submodule.c\nindex 3fa5db3ecdf..e297d94d17f 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -415,27 +415,6 @@ int parse_submodule_update_strategy(const char *value,\n \treturn 0;\n }\n \n-const char *submodule_strategy_to_string(const struct submodule_update_strategy *s)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tswitch (s->type) {\n-\tcase SM_UPDATE_CHECKOUT:\n-\t\treturn \"checkout\";\n-\tcase SM_UPDATE_MERGE:\n-\t\treturn \"merge\";\n-\tcase SM_UPDATE_REBASE:\n-\t\treturn \"rebase\";\n-\tcase SM_UPDATE_NONE:\n-\t\treturn \"none\";\n-\tcase SM_UPDATE_UNSPECIFIED:\n-\t\treturn NULL;\n-\tcase SM_UPDATE_COMMAND:\n-\t\tstrbuf_addf(&sb, \"!%s\", s->command);\n-\t\treturn strbuf_detach(&sb, NULL);\n-\t}\n-\treturn NULL;\n-}\n-\n void handle_ignore_submodules_arg(struct diff_options *diffopt,\n \t\t\t\t  const char *arg)\n {\ndiff --git a/submodule.h b/submodule.h\nindex bfaa9da1868..949f67b8031 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -72,7 +72,6 @@ void die_path_inside_submodule(struct index_state *istate,\n enum submodule_update_type parse_submodule_update_type(const char *value);\n int parse_submodule_update_strategy(const char *value,\n \t\t\t\t    struct submodule_update_strategy *dst);\n-const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);\n void handle_ignore_submodules_arg(struct diff_options *, const char *);\n void show_submodule_diff_summary(struct diff_options *o, const char *path,\n \t\t\t    struct object_id *one, struct object_id *two,\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460470","messageId":"patch-v2-24.28-d33260487bd-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 24/28] submodule--helper: don't exit() on failure, return","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:08Z","receivedAt":"2022-08-02T15:47:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code downstream of module_update() to short-circuit and return\nto the top-level on failure, rather than calling exit().\n\nTo do so we need to diligently check whether we \"must_die_on_failure\",\nwhich is a pattern started in c51f8f94e5b (submodule--helper: run\nupdate procedures from C, 2021-08-24), but which hadn't been completed\nto the point where we could avoid calling exit() here.\n\nThis introduces no functional changes, but makes it easier to both\ncall these routines as a library in the future, and to eventually\navoid leaking memory.\n\nThis and similar control flow in submodule--helper.c could be made\nsimpler by properly \"libifying\" it, i.e. to have it consistently\nreturn -1 on failures, and to early return on any non-success.\n\nBut let's leave that larger project for now, and (mostly) emulate what\nwere doing with the \"exit(128)\" before this change.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 34 +++++++++++++++++++++++++---------\n 1 file changed, 25 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex bac45e2bab7..8d83f1f99d2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2141,7 +2141,8 @@ 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,\n+\t\t\t      int *must_die_on_failure)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n@@ -2205,7 +2206,7 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\t}\n \n \t\tif (ret == 128)\n-\t\t\texit(ret);\n+\t\t\t*must_die_on_failure = 1;\n \t\treturn ret;\n \t}\n \n@@ -2237,7 +2238,8 @@ static int run_update_command(struct update_data *ud, int subforce)\n \treturn 0;\n }\n \n-static int run_update_procedure(struct update_data *ud)\n+static int run_update_procedure(struct update_data *ud,\n+\t\t\t\tint *must_die_on_failure)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2264,7 +2266,7 @@ static int 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, must_die_on_failure);\n }\n \n static const char *remote_submodule_branch(const char *path)\n@@ -2400,7 +2402,8 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \t\t\t\t    \"--no-single-branch\");\n }\n \n-static int update_submodule(struct update_data *update_data)\n+static int update_submodule(struct update_data *update_data,\n+\t\t\t    int *must_die_on_failure)\n {\n \tensure_core_worktree(update_data->sm_path);\n \n@@ -2436,9 +2439,15 @@ static int update_submodule(struct update_data *update_data)\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+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force) {\n+\t\tint ret;\n+\n+\t\tret = run_update_procedure(update_data, must_die_on_failure);\n+\t\tif (*must_die_on_failure)\n+\t\t\treturn ret;\n+\t\tif (ret)\n \t\t\treturn 1;\n+\t}\n \n \tif (update_data->recursive) {\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2461,7 +2470,7 @@ static int update_submodule(struct update_data *update_data)\n \t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n \t\t\t    update_data->displaypath);\n \t\tif (ret == 128)\n-\t\t\texit(ret);\n+\t\t\t*must_die_on_failure = 1;\n \t\treturn ret;\n \t}\n \n@@ -2494,12 +2503,19 @@ static int update_submodules(struct update_data *update_data)\n \n \tfor (i = 0; i < suc.update_clone_nr; i++) {\n \t\tstruct update_clone_data ucd = suc.update_clone[i];\n+\t\tint must_die_on_failure = 0;\n+\t\tint code;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n+\t\tif (code)\n+\t\t\tret = code;\n+\t\tif (must_die_on_failure)\n+\t\t\tgoto cleanup;\n+\t\telse if (code)\n \t\t\tret = 1;\n \t}\n \n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460471","messageId":"patch-v2-25.28-9981a75d7e8-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 25/28] submodule--helper: libify determine_submodule_update_strategy()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:09Z","receivedAt":"2022-08-02T15:47:55Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Libify the determine_submodule_update_strategy() by having it invoke\ndie_message() rather than die(), and returning the code die_message()\nreturns on failure.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 39 ++++++++++++++++++++++++-------------\n 1 file changed, 25 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 8d83f1f99d2..2b78fa7573f 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1749,24 +1749,27 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void determine_submodule_update_strategy(struct repository *r,\n-\t\t\t\t\t\tint just_cloned,\n-\t\t\t\t\t\tconst char *path,\n-\t\t\t\t\t\tenum submodule_update_type update,\n-\t\t\t\t\t\tstruct submodule_update_strategy *out)\n+static int determine_submodule_update_strategy(struct repository *r,\n+\t\t\t\t\t       int just_cloned,\n+\t\t\t\t\t       const char *path,\n+\t\t\t\t\t       enum submodule_update_type update,\n+\t\t\t\t\t       struct submodule_update_strategy *out)\n {\n \tconst struct submodule *sub = submodule_from_path(r, null_oid(), path);\n \tchar *key;\n \tconst char *val;\n+\tint ret;\n \n \tkey = xstrfmt(\"submodule.%s.update\", sub->name);\n \n \tif (update) {\n \t\tout->type = update;\n \t} else if (!repo_config_get_string_tmp(r, key, &val)) {\n-\t\tif (parse_submodule_update_strategy(val, out) < 0)\n-\t\t\tdie(_(\"Invalid update mode '%s' configured for submodule path '%s'\"),\n-\t\t\t\tval, path);\n+\t\tif (parse_submodule_update_strategy(val, out) < 0) {\n+\t\t\tret = die_message(_(\"Invalid update mode '%s' configured for submodule path '%s'\"),\n+\t\t\t\t\t  val, path);\n+\t\t\tgoto cleanup;\n+\t\t}\n \t} else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n \t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND)\n \t\t\tBUG(\"how did we read update = !command from .gitmodules?\");\n@@ -1781,7 +1784,10 @@ static void determine_submodule_update_strategy(struct repository *r,\n \t     out->type == SM_UPDATE_NONE))\n \t\tout->type = SM_UPDATE_CHECKOUT;\n \n+\tret = 0;\n+cleanup:\n \tfree(key);\n+\treturn ret;\n }\n \n struct update_clone_data {\n@@ -2405,14 +2411,22 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n static int update_submodule(struct update_data *update_data,\n \t\t\t    int *must_die_on_failure)\n {\n+\tint ret;\n+\n \tensure_core_worktree(update_data->sm_path);\n \n \tupdate_data->displaypath = get_submodule_displaypath(\n \t\tupdate_data->sm_path, update_data->prefix);\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+\tret = determine_submodule_update_strategy(the_repository,\n+\t\t\t\t\t\t  update_data->just_cloned,\n+\t\t\t\t\t\t  update_data->sm_path,\n+\t\t\t\t\t\t  update_data->update_default,\n+\t\t\t\t\t\t  &update_data->update_strategy);\n+\tif (ret) {\n+\t\t*must_die_on_failure = 1;\n+\t\treturn ret;\n+\t}\n \n \tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\n@@ -2440,8 +2454,6 @@ 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\tint ret;\n-\n \t\tret = run_update_procedure(update_data, must_die_on_failure);\n \t\tif (*must_die_on_failure)\n \t\t\treturn ret;\n@@ -2452,7 +2464,6 @@ static int update_submodule(struct update_data *update_data,\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 ret;\n \n \t\tnext.prefix = NULL;\n \t\toidcpy(&next.oid, null_oid());\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460472","messageId":"patch-v2-23.28-db2d2fb5a21-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 23/28] submodule--helper: use \"code\" in run_update_command()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:07Z","receivedAt":"2022-08-02T15:47:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Apply some DRY principles in run_update_command() and don't have two\n\"switch\" statements over \"ud->update_strategy.type\" determine the same\nthing.\n\nFirst we were setting \"must_die_on_failure = 1\" in all cases except\n\"SM_UPDATE_CHECKOUT\" (and we'd BUG(...) out on the rest). This code\nwas added in c51f8f94e5b (submodule--helper: run update procedures\nfrom C, 2021-08-24).\n\nThen we'd duplicate same \"switch\" logic when we were using the\n\"must_die_on_failure\" variable.\n\nLet's instead have the \"case\" branches in that inner \"switch\"\ndetermine whether or not the \"update must continue\" by picking an exit\ncode.\n\nThis also mostly avoids hardcoding the \"128\" exit code, instead we can\nmake use of the return value of the die_message() function, which\nwe've been calling here since 55b3f12cb54 (submodule update: use\ndie_message(), 2022-03-15). We're still hardcoding it to determine if\nwe \"exit()\", but subsequent commit(s) will address that.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 27 +++++++++++++--------------\n 1 file changed, 13 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex d787c0fead4..bac45e2bab7 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2145,7 +2145,6 @@ static int run_update_command(struct update_data *ud, int subforce)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n-\tint must_die_on_failure = 0;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n@@ -2159,19 +2158,16 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->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\tcp.git_cmd = 1;\n \t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->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\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: %d\",\n@@ -2182,32 +2178,35 @@ static int run_update_command(struct update_data *ud, int subforce)\n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env);\n \tif (run_command(&cp)) {\n+\t\tint ret;\n+\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\t/* the command failed, but update must continue */\n+\t\t\tret = 1;\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n-\t\t\tdie_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t    oid, ud->displaypath);\n+\t\t\tret = die_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t\t\t  oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_MERGE:\n-\t\t\tdie_message(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t    oid, ud->displaypath);\n+\t\t\tret = die_message(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t\t\t  oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_COMMAND:\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\tret = die_message(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\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: %d\",\n \t\t\t    ud->update_strategy.type);\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+\t\tif (ret == 128)\n+\t\t\texit(ret);\n+\t\treturn ret;\n \t}\n \n \tif (ud->quiet)\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460473","messageId":"patch-v2-27.28-93cd1ccde54-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 27/28] submodule--helper: libify \"must_die_on_failure\" code paths (for die)","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:11Z","receivedAt":"2022-08-02T15:47:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Continue the libification of codepaths that previously relied on\n\"must_die_on_failure\". In these cases we've always been early aborting\nby calling die(), but as we know that these codpaths will properly\nhandle return codes of 128 to mean an early abort let's have them use\ndie_message() instead.\n\nThis still isn't a complete migration away from die() for these\ncodepaths, in particular this code in update_submodule() will still call die() in some cases:\n\n\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n\nBut as that code is used by other callers than the \"update\" code let's\nleave converting it for now.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 33 ++++++++++++++++++---------------\n 1 file changed, 18 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 79a11992d1c..4f7ece6fb05 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2263,9 +2263,9 @@ static int run_update_procedure(struct update_data *ud)\n \t\t */\n \t\tif (!is_tip_reachable(ud->sm_path, &ud->oid) &&\n \t\t    fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, &ud->oid))\n-\t\t\tdie(_(\"Fetched in submodule path '%s', but it did not \"\n-\t\t\t      \"contain %s. Direct fetching of that commit failed.\"),\n-\t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n+\t\t\treturn die_message(_(\"Fetched in submodule path '%s', but it did not \"\n+\t\t\t\t\t     \"contain %s. Direct fetching of that commit failed.\"),\n+\t\t\t\t\t   ud->displaypath, oid_to_hex(&ud->oid));\n \t}\n \n \treturn run_update_command(ud, subforce);\n@@ -2309,13 +2309,14 @@ static const char *remote_submodule_branch(const char *path)\n \treturn branch;\n }\n \n-static void ensure_core_worktree(const char *path)\n+static int ensure_core_worktree(const char *path)\n {\n \tconst char *cw;\n \tstruct repository subrepo;\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+\t\treturn die_message(_(\"could not get a repository handle for submodule '%s'\"),\n+\t\t\t\t   path);\n \n \tif (!repo_config_get_string_tmp(&subrepo, \"core.worktree\", &cw)) {\n \t\tchar *cfg_file, *abs_path;\n@@ -2333,6 +2334,8 @@ static void ensure_core_worktree(const char *path)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n+\n+\treturn 0;\n }\n \n static const char *submodule_update_type_to_label(enum submodule_update_type type)\n@@ -2408,7 +2411,9 @@ static int update_submodule(struct update_data *update_data)\n {\n \tint ret;\n \n-\tensure_core_worktree(update_data->sm_path);\n+\tret = ensure_core_worktree(update_data->sm_path);\n+\tif (ret)\n+\t\treturn ret;\n \n \tupdate_data->displaypath = get_submodule_displaypath(\n \t\tupdate_data->sm_path, update_data->prefix);\n@@ -2418,16 +2423,14 @@ static int update_submodule(struct update_data *update_data)\n \t\t\t\t\t\t  update_data->sm_path,\n \t\t\t\t\t\t  update_data->update_default,\n \t\t\t\t\t\t  &update_data->update_strategy);\n-\tif (ret) {\n-\t\t*must_die_on_failure = 1;\n+\tif (ret)\n \t\treturn ret;\n-\t}\n \n \tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\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+\t\treturn die_message(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t\t   update_data->displaypath);\n \n \tif (update_data->remote) {\n \t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n@@ -2437,13 +2440,13 @@ static int update_submodule(struct update_data *update_data)\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\t\treturn die_message(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\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+\t\t\treturn die_message(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t\t\t   remote_ref, update_data->sm_path);\n \n \t\tfree(remote_ref);\n \t}\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460474","messageId":"patch-v2-26.28-b48705c6cc0-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 26/28] submodule--helper: libify \"must_die_on_failure\" code paths","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:10Z","receivedAt":"2022-08-02T15:48:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In preceding commits the codepaths around update_submodules() were\nchanged from using exit() or die() to ferrying up a\n\"must_die_on_failure\" in the cases where we'd exit(), and in most\ncases where we'd die().\n\nWe needed to do this this to ensure that we'd early exit or otherwise\nabort the update_submodules() processing before it was completed.\n\nNow that those preceding changes have shown that we've converted those\npaths, we can remove the remaining \"ret == 128\" special-cases, leaving\nthe only such special-case in update_submodules(). I.e. we now know\nafter having gone through the various codepaths that we were only\nreturning 128 if we meant to early abort.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 33 +++++++++++----------------------\n 1 file changed, 11 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 2b78fa7573f..79a11992d1c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2147,8 +2147,7 @@ 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-\t\t\t      int *must_die_on_failure)\n+static int run_update_command(struct update_data *ud, int subforce)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n@@ -2211,8 +2210,6 @@ static int run_update_command(struct update_data *ud, int subforce,\n \t\t\t    ud->update_strategy.type);\n \t\t}\n \n-\t\tif (ret == 128)\n-\t\t\t*must_die_on_failure = 1;\n \t\treturn ret;\n \t}\n \n@@ -2244,8 +2241,7 @@ static int run_update_command(struct update_data *ud, int subforce,\n \treturn 0;\n }\n \n-static int run_update_procedure(struct update_data *ud,\n-\t\t\t\tint *must_die_on_failure)\n+static int run_update_procedure(struct update_data *ud)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2272,7 +2268,7 @@ static int 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, must_die_on_failure);\n+\treturn run_update_command(ud, subforce);\n }\n \n static const char *remote_submodule_branch(const char *path)\n@@ -2408,8 +2404,7 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \t\t\t\t    \"--no-single-branch\");\n }\n \n-static int update_submodule(struct update_data *update_data,\n-\t\t\t    int *must_die_on_failure)\n+static int update_submodule(struct update_data *update_data)\n {\n \tint ret;\n \n@@ -2454,11 +2449,9 @@ 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\tret = run_update_procedure(update_data, must_die_on_failure);\n-\t\tif (*must_die_on_failure)\n-\t\t\treturn ret;\n+\t\tret = run_update_procedure(update_data);\n \t\tif (ret)\n-\t\t\treturn 1;\n+\t\t\treturn ret;\n \t}\n \n \tif (update_data->recursive) {\n@@ -2476,12 +2469,9 @@ static int update_submodule(struct update_data *update_data,\n \n \t\t/* die() if child process die()'d */\n \t\tret = run_command(&cp);\n-\t\tif (!ret)\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 (ret == 128)\n-\t\t\t*must_die_on_failure = 1;\n+\t\tif (ret)\n+\t\t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t\t    update_data->displaypath);\n \t\treturn ret;\n \t}\n \n@@ -2514,17 +2504,16 @@ static int update_submodules(struct update_data *update_data)\n \n \tfor (i = 0; i < suc.update_clone_nr; i++) {\n \t\tstruct update_clone_data ucd = suc.update_clone[i];\n-\t\tint must_die_on_failure = 0;\n \t\tint code;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n+\t\tcode = update_submodule(update_data);\n \t\tif (code)\n \t\t\tret = code;\n-\t\tif (must_die_on_failure)\n+\t\tif (code == 128)\n \t\t\tgoto cleanup;\n \t\telse if (code)\n \t\t\tret = 1;\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460475","messageId":"patch-v2-28.28-6160a1ab250-20220802T154036Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v2-00.28-00000000000-20220802T154036Z-avarab@gmail.com","subject":"[PATCH v2 28/28] submodule--helper: fix bad config API usage","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-02T15:46:12Z","receivedAt":"2022-08-02T15:48:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix bad config API usage added in a452128a36c (submodule--helper:\nintroduce add-config subcommand, 2021-08-06). After\ngit_config_get_string() returns successfully we know the \"char **dest\"\nwill be non-NULL.\n\nA coccinelle patch that transforms this turns up a couple of other\nsuch issues, one in fetch-pack.c, and another in upload-pack.c:\n\n\t@@\n\tidentifier F =~ \"^(repo|git)_config_get_string(_tmp)?$\";\n\tidentifier V;\n\t@@\n\t  !F(..., &V)\n\t- && (V)\n\nBut let's focus narrowly on submodule--helper for now, we can fix\nthose some other time.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4f7ece6fb05..5bc9cc41369 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -3098,7 +3098,7 @@ static void configure_added_submodule(struct add_data *add_data)\n \t * is_submodule_active(), since that function needs to find\n \t * out the value of \"submodule.active\" again anyway.\n \t */\n-\tif (!git_config_get_string(\"submodule.active\", &val) && val) {\n+\tif (!git_config_get_string(\"submodule.active\", &val)) {\n \t\t/*\n \t\t * If the submodule being added isn't already covered by the\n \t\t * current configured pathspec, set the submodule's active flag\n-- \n2.37.1.1233.ge8b09efaedc\n\n"},{"id":"460516","messageId":"kl6ltu6uth1t.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v2-01.28-daa5d3f9962-20220802T154036Z-avarab@gmail.com","subject":"Re: [PATCH v2 01/28] submodule tests: test usage behavior","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-02T22:30:06Z","receivedAt":"2022-08-02T22:31:35Z","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> Test what exit code and output we emit on \"git submodule -h\", how we\n> handle \"--\" when no subcommand is specified, and how the top-level\n> \"--recursive\" option is handled.\n>\n> For \"-h\" this doesn't make sense, but let's test for it so that any\n> subsequent eventual behavior change will become clear.\n>\n> For \"--\" this follows up on 68cabbfda36 (submodule: document default\n> behavior, 2019-02-15) and tests that \"status\" doesn't don't support\n\ns/doesn't don't/doesn't/ I assume ;)\n\n> the \"--\" delimiter. There's no intrinsically good reason not to\n> support that. We behave this way due to edge cases in\n> git-submodule.sh's implementation, but as with \"-h\" let's assert our\n> current long-standing behavior for now.\n>\n> For \"--recursive\" the exclusion of it from the top-level appears to\n> have been an omission in 15fc56a8536 (git submodule foreach: Add\n> --recursive to recurse into nested submodules, 2009-08-19), there\n> doesn't seem to be a reason not to support it alongside \"--quiet\" and\n> \"--cached\", but let's likewise assert our existing behavior for now.\n\nI think my original comment isn't directly addressed here:\n\n  I'm not sure about this one. \"--recursive\" isn't a top level option, and\n  15fc56a8536 doesn't seem to suggest that it was meant to be one (but I\n  did realize that git-submodule.txt documents all of the options to all\n  subcommands, which is very confusing.)\n\nBut maybe I'm mistaken and it's somewhere. Do we know whether\n\"--recursive\" was always intended to be top-level?\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t7400-submodule-basic.sh | 26 ++++++++++++++++++++++++++\n>  1 file changed, 26 insertions(+)\n>\n> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\n> index e7cec2e457a..b858871a953 100755\n> --- a/t/t7400-submodule-basic.sh\n> +++ b/t/t7400-submodule-basic.sh\n> @@ -14,6 +14,32 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n>  \n>  . ./test-lib.sh\n>  \n> +test_expect_success 'submodule usage: -h' '\n> +\tgit submodule -h >out 2>err &&\n> +\tgrep \"^usage: git submodule\" out &&\n> +\ttest_must_be_empty err\n> +'\n> +\n> +test_expect_success 'submodule usage: --recursive' '\n> +\ttest_expect_code 1 git submodule --recursive >out 2>err &&\n> +\tgrep \"^usage: git submodule\" err &&\n> +\ttest_must_be_empty out\n> +'\n> +\n> +test_expect_success 'submodule usage: status --' '\n> +\ttest_expect_code 1 git submodule -- &&\n> +\ttest_expect_code 1 git submodule --end-of-options\n> +'\n> +\n> +for opt in '--quiet' '--cached'\n> +do\n> +\ttest_expect_success \"submodule usage: status $opt\" '\n> +\t\tgit submodule $opt &&\n> +\t\tgit submodule status $opt &&\n> +\t\tgit submodule $opt status\n> +\t'\n> +done\n> +\n>  test_expect_success 'submodule deinit works on empty repository' '\n>  \tgit submodule deinit --all\n>  '\n\nThe changes themselves look good :)\n\n> -- \n> 2.37.1.1233.ge8b09efaedc\n"},{"id":"460517","messageId":"kl6lr11ytgy5.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v2-08.28-de49f31dab0-20220802T154036Z-avarab@gmail.com","subject":"Re: [PATCH v2 08/28] submodule--helper: move \"resolve-relative-url-test\" to a test-tool","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-02T22:32:18Z","receivedAt":"2022-08-02T22:32:25Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> As its name suggests the \"resolve-relative-url-test\" has never been\n> used outside of the test suite, see 63e95beb085 (submodule: port\n> resolve_relative_url from shell to C, 2016-04-15) for its original\n> addition.\n>\n> Perhaps it would make sense to drop this code entirely, as we feel\n> that we've got enough indirect test coverage, but let's leave that\n> question to a possible follow-up change. For now let's keep the test\n> coverage this gives us.\n\nAgree with this and the other related messages that describe the intent\nbehind the test code. Thanks!\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 23 --------------------\n>  t/helper/test-submodule.c   | 42 +++++++++++++++++++++++++++++++++++++\n>  t/t0060-path-utils.sh       |  2 +-\n>  3 files changed, 43 insertions(+), 24 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 06307886080..246457ec2e9 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -96,28 +96,6 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n>  \treturn resolved_url;\n>  }\n>  \n> -static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)\n> -{\n> -\tchar *remoteurl, *res;\n> -\tconst char *up_path, *url;\n> -\n> -\tif (argc != 4)\n> -\t\tdie(\"resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>\");\n> -\n> -\tup_path = argv[1];\n> -\tremoteurl = xstrdup(argv[2]);\n> -\turl = argv[3];\n> -\n> -\tif (!strcmp(up_path, \"(null)\"))\n> -\t\tup_path = NULL;\n> -\n> -\tres = relative_url(remoteurl, url, up_path);\n> -\tputs(res);\n> -\tfree(res);\n> -\tfree(remoteurl);\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>  {\n> @@ -3273,7 +3251,6 @@ static struct cmd_struct commands[] = {\n>  \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n>  \t{\"add\", module_add, 0},\n>  \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n> -\t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n>  \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n>  \t{\"init\", module_init, 0},\n>  \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n> diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\n> index 9f0eb440192..e0e0c53d386 100644\n> --- a/t/helper/test-submodule.c\n> +++ b/t/helper/test-submodule.c\n> @@ -2,6 +2,7 @@\n>  #include \"test-tool-utils.h\"\n>  #include \"cache.h\"\n>  #include \"parse-options.h\"\n> +#include \"remote.h\"\n>  #include \"submodule-config.h\"\n>  #include \"submodule.h\"\n>  \n> @@ -19,9 +20,17 @@ static const char *submodule_is_active_usage[] = {\n>  \tNULL\n>  };\n>  \n> +#define TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE \\\n> +\t\"test-tool submodule resolve-relative-url <up_path> <remoteurl> <url>\"\n> +static const char *submodule_resolve_relative_url_usage[] = {\n> +\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n> +\tNULL,\n> +};\n> +\n>  static const char *submodule_usage[] = {\n>  \tTEST_TOOL_CHECK_NAME_USAGE,\n>  \tTEST_TOOL_IS_ACTIVE_USAGE,\n> +\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n>  \tNULL\n>  };\n>  \n> @@ -76,9 +85,42 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n>  \treturn !is_submodule_active(the_repository, argv[0]);\n>  }\n>  \n> +static int resolve_relative_url(int argc, const char **argv)\n> +{\n> +\tchar *remoteurl, *res;\n> +\tconst char *up_path, *url;\n> +\n> +\tup_path = argv[0];\n> +\tremoteurl = xstrdup(argv[1]);\n> +\turl = argv[2];\n> +\n> +\tif (!strcmp(up_path, \"(null)\"))\n> +\t\tup_path = NULL;\n> +\n> +\tres = relative_url(remoteurl, url, up_path);\n> +\tputs(res);\n> +\tfree(res);\n> +\tfree(remoteurl);\n> +\treturn 0;\n> +}\n> +\n> +static int cmd__submodule_resolve_relative_url(int argc, const char **argv)\n> +{\n> +\tstruct option options[] = {\n> +\t\tOPT_END()\n> +\t};\n> +\targc = parse_options(argc, argv, \"test-tools\", options,\n> +\t\t\t     submodule_resolve_relative_url_usage, 0);\n> +\tif (argc != 3)\n> +\t\tusage_with_options(submodule_resolve_relative_url_usage, options);\n> +\n> +\treturn resolve_relative_url(argc, argv);\n> +}\n> +\n>  static struct test_cmd cmds[] = {\n>  \t{ \"check-name\", cmd__submodule_check_name },\n>  \t{ \"is-active\", cmd__submodule_is_active },\n> +\t{ \"resolve-relative-url\", cmd__submodule_resolve_relative_url},\n>  };\n>  \n>  int cmd__submodule(int argc, const char **argv)\n> diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\n> index 1f2007e62b7..68e29c904a6 100755\n> --- a/t/t0060-path-utils.sh\n> +++ b/t/t0060-path-utils.sh\n> @@ -22,7 +22,7 @@ relative_path() {\n>  \n>  test_submodule_relative_url() {\n>  \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n> -\t\tactual=\\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&\n> +\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n>  \t\ttest \\\"\\$actual\\\" = '$4'\n>  \t\"\n>  }\n> -- \n> 2.37.1.1233.ge8b09efaedc\n"},{"id":"460522","messageId":"kl6lo7x2tfa2.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v2-21.28-bce1a014a2f-20220802T154036Z-avarab@gmail.com","subject":"Re: [PATCH v2 21/28] submodule--helper: don't call submodule_strategy_to_string() in BUG()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-02T23:08:21Z","receivedAt":"2022-08-02T23:08:54Z","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> Don't call submodule_strategy_to_string() in a BUG() message. These\n> calls added in c51f8f94e5b (submodule--helper: run update procedures\n> from C, 2021-08-24) don't need the extra information\n> submodule_strategy_to_string() gives us, as we'll never reach the\n> SM_UPDATE_COMMAND case here.\n>\n> That case is the only one where we'd get any information beyond the\n> straightforward number-to-string mapping.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 12 ++++++------\n>  1 file changed, 6 insertions(+), 6 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 955deb375ee..b49528e1ba9 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2155,8 +2155,8 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n> +\t\t    ud->update_strategy.type);\n>  \t}\n\nAt first I worried that we would be losing readability by printing the\nraw int value instead of a string, but then I remembered that we\nprobably wouldn't print anything sensible for an unknown value anyway :x\n\nWhat makes this change obviously good is that we're switching on\nud->update_strategy.type, so it makes the most sense to print that value\n(instead of ud->update_strategy). Unfortunately we can't see that from\nthe context lines though.\n\n>  \tstrvec_push(&cp.args, oid);\n>  \n> @@ -2181,8 +2181,8 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n> +\t\t\t    ud->update_strategy.type);\n>  \t\t}\n>  \t\tif (must_die_on_failure)\n>  \t\t\texit(128);\n> @@ -2212,8 +2212,8 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n> +\t\t    ud->update_strategy.type);\n>  \t}\n>  \n>  \treturn 0;\n> -- \n> 2.37.1.1233.ge8b09efaedc\n"},{"id":"460523","messageId":"kl6lles6te9q.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v2-22.28-98c3e562c82-20220802T154036Z-avarab@gmail.com","subject":"Re: [PATCH v2 22/28] submodule--helper: move submodule_strategy_to_string() to only user","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-02T23:30:09Z","receivedAt":"2022-08-02T23:30:18Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Move the submodule_strategy_to_string() function added in\n> 3604242f080 (submodule: port init from shell to C, 2016-04-15) to its\n> only user.\n>\n> This function would return NULL on SM_UPDATE_UNSPECIFIED, so it wasn't\n> safe to xstrdup() its return value in the general case, or to use it\n> in a sprintf() format as the code removed in the preceding commit did.\n>\n> But its callers would never call it with either SM_UPDATE_UNSPECIFIED\n> or SM_UPDATE_COMMAND. Let's move it to a \"static\" helper, and have its\n> functionality reflect how it's used, and BUG() out on the rest.\n>\n> By doing this we can also stop needlessly xstrdup()-ing and free()-ing\n> the memory for the config we're setting. We can instead always use\n> constant strings. We can also use the *_tmp() variant of\n> git_config_get_string().\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 29 ++++++++++++++++++++++++-----\n>  submodule.c                 | 21 ---------------------\n>  submodule.h                 |  1 -\n>  3 files changed, 24 insertions(+), 27 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index b49528e1ba9..d787c0fead4 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -413,12 +413,32 @@ struct init_cb {\n>  };\n>  #define INIT_CB_INIT { 0 }\n>  \n> +static const char *submodule_strategy_to_string(enum submodule_update_type type)\n> +{\n> +\tswitch (type) {\n> +\tcase SM_UPDATE_CHECKOUT:\n> +\t\treturn \"checkout\";\n> +\tcase SM_UPDATE_MERGE:\n> +\t\treturn \"merge\";\n> +\tcase SM_UPDATE_REBASE:\n> +\t\treturn \"rebase\";\n> +\tcase SM_UPDATE_NONE:\n> +\t\treturn \"none\";\n> +\tcase SM_UPDATE_UNSPECIFIED:\n> +\tcase SM_UPDATE_COMMAND:\n> +\t\tBUG(\"init_submodule() should handle type %d\", type);\n> +\tdefault:\n> +\t\tBUG(\"unexpected update strategy type: %d\", type);\n> +\t}\n> +}\n> +\n\nThis function is meant to convert from an update strategy back to the\nstring that the user actually provided in their gitconfig.\n\nThe change in behavior makes this function BUG() out on types that\naren't \"magic\" tokens, i.e. \"UNSPECIFIED\" (which is obviously not\nexpressible) and \"COMMAND\" (which allows users to specify an arbitrary\ncommand using \"!\", like \"!cat\"). It shouldn't be difficult to teach\ncallers to handle \"COMMAND\", so this seems like an ok change, though I\nthink we should probably amend the function name to\nsubmodule_update_type_to_string() and change the UNSPECIFIED and COMMAND\narms to something like BUG(\"type %d has no corresponding string\").\n\nI'm not so convinced that this function should be static, though. I\nthink it's more natural for submodule_update_type_to_string() to have\nthe same visibility as enum submodule_update_type. Today, we only have\none other caller who uses this enum, and it doesn't even need this\n_to_string() fn (fsck.c calls parse_submodule_update_type() and doesn't\nneed _to_string() because it has the raw config values). But it feels a\nbit inevitable that this will get moved back to submodule.h.\n\n>  static void init_submodule(const char *path, const char *prefix,\n>  \t\t\t   unsigned int flags)\n>  {\n>  \tconst struct submodule *sub;\n>  \tstruct strbuf sb = STRBUF_INIT;\n> -\tchar *upd = NULL, *url = NULL, *displaypath;\n> +\tconst char *upd;\n> +\tchar *url = NULL, *displaypath;\n>  \n>  \tdisplaypath = get_submodule_displaypath(path, prefix);\n>  \n> @@ -474,14 +494,14 @@ static void init_submodule(const char *path, const char *prefix,\n>  \n>  \t/* Copy \"update\" setting when it is not set yet */\n>  \tstrbuf_addf(&sb, \"submodule.%s.update\", sub->name);\n> -\tif (git_config_get_string(sb.buf, &upd) &&\n> +\tif (git_config_get_string_tmp(sb.buf, &upd) &&\n>  \t    sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n>  \t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND) {\n>  \t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n>  \t\t\t\tsub->name);\n> -\t\t\tupd = xstrdup(\"none\");\n> +\t\t\tupd = \"none\";\n>  \t\t} else {\n> -\t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n> +\t\t\tupd = submodule_strategy_to_string(sub->update_strategy.type);\n>  \t\t}\n>  \n>  \t\tif (git_config_set_gently(sb.buf, upd))\n> @@ -490,7 +510,6 @@ static void init_submodule(const char *path, const char *prefix,\n>  \tstrbuf_release(&sb);\n>  \tfree(displaypath);\n>  \tfree(url);\n> -\tfree(upd);\n>  }\n>  \n>  static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n> diff --git a/submodule.c b/submodule.c\n> index 3fa5db3ecdf..e297d94d17f 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -415,27 +415,6 @@ int parse_submodule_update_strategy(const char *value,\n>  \treturn 0;\n>  }\n>  \n> -const char *submodule_strategy_to_string(const struct submodule_update_strategy *s)\n> -{\n> -\tstruct strbuf sb = STRBUF_INIT;\n> -\tswitch (s->type) {\n> -\tcase SM_UPDATE_CHECKOUT:\n> -\t\treturn \"checkout\";\n> -\tcase SM_UPDATE_MERGE:\n> -\t\treturn \"merge\";\n> -\tcase SM_UPDATE_REBASE:\n> -\t\treturn \"rebase\";\n> -\tcase SM_UPDATE_NONE:\n> -\t\treturn \"none\";\n> -\tcase SM_UPDATE_UNSPECIFIED:\n> -\t\treturn NULL;\n> -\tcase SM_UPDATE_COMMAND:\n> -\t\tstrbuf_addf(&sb, \"!%s\", s->command);\n> -\t\treturn strbuf_detach(&sb, NULL);\n> -\t}\n> -\treturn NULL;\n> -}\n> -\n\nThe rest of the changes look good. An alternative would be to _always_\nreturn a non-const char * (e.g. return xstrdup(\"none\")) and expect the\ncaller to free it, but that feels like bending over backwards to\naccomodate xstrfmt(\"!%s\").\n\n>  void handle_ignore_submodules_arg(struct diff_options *diffopt,\n>  \t\t\t\t  const char *arg)\n>  {\n> diff --git a/submodule.h b/submodule.h\n> index bfaa9da1868..949f67b8031 100644\n> --- a/submodule.h\n> +++ b/submodule.h\n> @@ -72,7 +72,6 @@ void die_path_inside_submodule(struct index_state *istate,\n>  enum submodule_update_type parse_submodule_update_type(const char *value);\n>  int parse_submodule_update_strategy(const char *value,\n>  \t\t\t\t    struct submodule_update_strategy *dst);\n> -const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);\n>  void handle_ignore_submodules_arg(struct diff_options *, const char *);\n>  void show_submodule_diff_summary(struct diff_options *o, const char *path,\n>  \t\t\t    struct object_id *one, struct object_id *two,\n> -- \n> 2.37.1.1233.ge8b09efaedc\n"},{"id":"460526","messageId":"kl6lilnat0a2.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v2-27.28-93cd1ccde54-20220802T154036Z-avarab@gmail.com","subject":"Re: [PATCH v2 27/28] submodule--helper: libify \"must_die_on_failure\" code paths (for die)","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-03T04:32:21Z","receivedAt":"2022-08-03T04:32:33Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"\nPatches 19-20 and 22-27 are pretty much \"show your work\" for the same\nlibification, so I'll comment on them together.\n\nÆvar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Continue the libification of codepaths that previously relied on\n> \"must_die_on_failure\". In these cases we've always been early aborting\n> by calling die(), but as we know that these codpaths will properly\n> handle return codes of 128 to mean an early abort let's have them use\n> die_message() instead.\n>\n> This still isn't a complete migration away from die() for these\n> codepaths, in particular this code in update_submodule() will still call die() in some cases:\n>\n> \tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n> \tconst char *branch = remote_submodule_branch(update_data->sm_path);\n>\n> But as that code is used by other callers than the \"update\" code let's\n> leave converting it for now.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 33 ++++++++++++++++++---------------\n>  1 file changed, 18 insertions(+), 15 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 79a11992d1c..4f7ece6fb05 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2263,9 +2263,9 @@ static int run_update_procedure(struct update_data *ud)\n>  \t\t */\n>  \t\tif (!is_tip_reachable(ud->sm_path, &ud->oid) &&\n>  \t\t    fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, &ud->oid))\n> -\t\t\tdie(_(\"Fetched in submodule path '%s', but it did not \"\n> -\t\t\t      \"contain %s. Direct fetching of that commit failed.\"),\n> -\t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n> +\t\t\treturn die_message(_(\"Fetched in submodule path '%s', but it did not \"\n> +\t\t\t\t\t     \"contain %s. Direct fetching of that commit failed.\"),\n> +\t\t\t\t\t   ud->displaypath, oid_to_hex(&ud->oid));\n\nTwo things I really like about these changes:\n\n- The intermediate return values are opaque, and we always return on\n  error. As a result, the code looks quite uniform (instead of e.g.\n  mixing return and exit()).\n- The \"return die_message()\" pattern is pretty elegant and it's used\n  often enough that there's no doubt that it's pretty clear that\n  intermediate functions can and will return 128 to signify that we want\n  the process to die.\n\nSo these look great to me :)\n\n>  \t}\n>  \n>  \treturn run_update_command(ud, subforce);\n> @@ -2309,13 +2309,14 @@ static const char *remote_submodule_branch(const char *path)\n>  \treturn branch;\n>  }\n>  \n> -static void ensure_core_worktree(const char *path)\n> +static int ensure_core_worktree(const char *path)\n>  {\n>  \tconst char *cw;\n>  \tstruct repository subrepo;\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> +\t\treturn die_message(_(\"could not get a repository handle for submodule '%s'\"),\n> +\t\t\t\t   path);\n>  \n>  \tif (!repo_config_get_string_tmp(&subrepo, \"core.worktree\", &cw)) {\n>  \t\tchar *cfg_file, *abs_path;\n> @@ -2333,6 +2334,8 @@ static void ensure_core_worktree(const char *path)\n>  \t\tfree(abs_path);\n>  \t\tstrbuf_release(&sb);\n>  \t}\n> +\n> +\treturn 0;\n>  }\n>  \n>  static const char *submodule_update_type_to_label(enum submodule_update_type type)\n> @@ -2408,7 +2411,9 @@ static int update_submodule(struct update_data *update_data)\n>  {\n>  \tint ret;\n>  \n> -\tensure_core_worktree(update_data->sm_path);\n> +\tret = ensure_core_worktree(update_data->sm_path);\n> +\tif (ret)\n> +\t\treturn ret;\n>  \n>  \tupdate_data->displaypath = get_submodule_displaypath(\n>  \t\tupdate_data->sm_path, update_data->prefix);\n> @@ -2418,16 +2423,14 @@ static int update_submodule(struct update_data *update_data)\n>  \t\t\t\t\t\t  update_data->sm_path,\n>  \t\t\t\t\t\t  update_data->update_default,\n>  \t\t\t\t\t\t  &update_data->update_strategy);\n> -\tif (ret) {\n> -\t\t*must_die_on_failure = 1;\n> +\tif (ret)\n>  \t\treturn ret;\n> -\t}\n>  \n>  \tif (update_data->just_cloned)\n>  \t\toidcpy(&update_data->suboid, null_oid());\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> +\t\treturn die_message(_(\"Unable to find current revision in submodule path '%s'\"),\n> +\t\t\t\t   update_data->displaypath);\n>  \n>  \tif (update_data->remote) {\n>  \t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n> @@ -2437,13 +2440,13 @@ static int update_submodule(struct update_data *update_data)\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\t\treturn die_message(_(\"Unable to fetch in submodule path '%s'\"),\n> +\t\t\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> +\t\t\treturn die_message(_(\"Unable to find %s revision in submodule path '%s'\"),\n> +\t\t\t\t\t   remote_ref, update_data->sm_path);\n>  \n>  \t\tfree(remote_ref);\n>  \t}\n> -- \n> 2.37.1.1233.ge8b09efaedc\n"},{"id":"460527","messageId":"kl6lfsiet02b.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v2-26.28-b48705c6cc0-20220802T154036Z-avarab@gmail.com","subject":"Re: [PATCH v2 26/28] submodule--helper: libify \"must_die_on_failure\" code paths","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-03T04:37:00Z","receivedAt":"2022-08-03T04:37:06Z","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> In preceding commits the codepaths around update_submodules() were\n> changed from using exit() or die() to ferrying up a\n> \"must_die_on_failure\" in the cases where we'd exit(), and in most\n> cases where we'd die().\n>\n> We needed to do this this to ensure that we'd early exit or otherwise\n> abort the update_submodules() processing before it was completed.\n>\n> Now that those preceding changes have shown that we've converted those\n> paths, we can remove the remaining \"ret == 128\" special-cases, leaving\n> the only such special-case in update_submodules(). I.e. we now know\n> after having gone through the various codepaths that we were only\n> returning 128 if we meant to early abort.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 33 +++++++++++----------------------\n>  1 file changed, 11 insertions(+), 22 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 2b78fa7573f..79a11992d1c 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2147,8 +2147,7 @@ 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> -\t\t\t      int *must_die_on_failure)\n> +static int run_update_command(struct update_data *ud, int subforce)\n>  {\n>  \tstruct child_process cp = CHILD_PROCESS_INIT;\n>  \tchar *oid = oid_to_hex(&ud->oid);\n> @@ -2211,8 +2210,6 @@ static int run_update_command(struct update_data *ud, int subforce,\n>  \t\t\t    ud->update_strategy.type);\n>  \t\t}\n>  \n> -\t\tif (ret == 128)\n> -\t\t\t*must_die_on_failure = 1;\n>  \t\treturn ret;\n>  \t}\n>  \n> @@ -2244,8 +2241,7 @@ static int run_update_command(struct update_data *ud, int subforce,\n>  \treturn 0;\n>  }\n>  \n> -static int run_update_procedure(struct update_data *ud,\n> -\t\t\t\tint *must_die_on_failure)\n> +static int run_update_procedure(struct update_data *ud)\n>  {\n>  \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n>  \n> @@ -2272,7 +2268,7 @@ static int 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, must_die_on_failure);\n> +\treturn run_update_command(ud, subforce);\n>  }\n>  \n>  static const char *remote_submodule_branch(const char *path)\n> @@ -2408,8 +2404,7 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n>  \t\t\t\t    \"--no-single-branch\");\n>  }\n>  \n> -static int update_submodule(struct update_data *update_data,\n> -\t\t\t    int *must_die_on_failure)\n> +static int update_submodule(struct update_data *update_data)\n>  {\n>  \tint ret;\n>  \n> @@ -2454,11 +2449,9 @@ 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\tret = run_update_procedure(update_data, must_die_on_failure);\n> -\t\tif (*must_die_on_failure)\n> -\t\t\treturn ret;\n> +\t\tret = run_update_procedure(update_data);\n>  \t\tif (ret)\n> -\t\t\treturn 1;\n> +\t\t\treturn ret;\n>  \t}\n>  \n>  \tif (update_data->recursive) {\n> @@ -2476,12 +2469,9 @@ static int update_submodule(struct update_data *update_data,\n>  \n>  \t\t/* die() if child process die()'d */\n>  \t\tret = run_command(&cp);\n> -\t\tif (!ret)\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 (ret == 128)\n> -\t\t\t*must_die_on_failure = 1;\n> +\t\tif (ret)\n> +\t\t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n> +\t\t\t\t    update_data->displaypath);\n>  \t\treturn ret;\n>  \t}\n>  \n> @@ -2514,17 +2504,16 @@ static int update_submodules(struct update_data *update_data)\n>  \n>  \tfor (i = 0; i < suc.update_clone_nr; i++) {\n>  \t\tstruct update_clone_data ucd = suc.update_clone[i];\n> -\t\tint must_die_on_failure = 0;\n>  \t\tint code;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n> +\t\tcode = update_submodule(update_data);\n>  \t\tif (code)\n>  \t\t\tret = code;\n> -\t\tif (must_die_on_failure)\n> +\t\tif (code == 128)\n>  \t\t\tgoto cleanup;\n>  \t\telse if (code)\n>  \t\t\tret = 1;\n\nThis hunk makes sense in the context of this patch, but\n\n\t\tif (code)\n\t\t\tret = code;\n\t\tif (code == 128)\n\t\t\tgoto cleanup;\n\t\telse if (code)\n\t\t\tret = 1;\n\nreads a bit awkwardly. Maybe we could drop \"code\" altogether and just\nhave:\n\n\t\tif (ret == 128)\n\t\t\tgoto cleanup;\n\t\telse if (ret)\n\t\t\tret = 1;\n\nBut I don't feel strongly either way.\n\n> -- \n> 2.37.1.1233.ge8b09efaedc\n"},{"id":"460544","messageId":"220803.86h72tfpcc.gmgdl@evledraar.gmail.com","threadId":"58235","inReplyTo":"kl6lles6te9q.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v2 22/28] submodule--helper: move submodule_strategy_to_string() to only user","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-03T13:06:01Z","receivedAt":"2022-08-03T13:08:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Aug 02 2022, Glen Choo wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> Move the submodule_strategy_to_string() function added in\n>> 3604242f080 (submodule: port init from shell to C, 2016-04-15) to its\n>> only user.\n>>\n>> This function would return NULL on SM_UPDATE_UNSPECIFIED, so it wasn't\n>> safe to xstrdup() its return value in the general case, or to use it\n>> in a sprintf() format as the code removed in the preceding commit did.\n>>\n>> But its callers would never call it with either SM_UPDATE_UNSPECIFIED\n>> or SM_UPDATE_COMMAND. Let's move it to a \"static\" helper, and have its\n>> functionality reflect how it's used, and BUG() out on the rest.\n>>\n>> By doing this we can also stop needlessly xstrdup()-ing and free()-ing\n>> the memory for the config we're setting. We can instead always use\n>> constant strings. We can also use the *_tmp() variant of\n>> git_config_get_string().\n>>\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> ---\n>>  builtin/submodule--helper.c | 29 ++++++++++++++++++++++++-----\n>>  submodule.c                 | 21 ---------------------\n>>  submodule.h                 |  1 -\n>>  3 files changed, 24 insertions(+), 27 deletions(-)\n>>\n>> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n>> index b49528e1ba9..d787c0fead4 100644\n>> --- a/builtin/submodule--helper.c\n>> +++ b/builtin/submodule--helper.c\n>> @@ -413,12 +413,32 @@ struct init_cb {\n>>  };\n>>  #define INIT_CB_INIT { 0 }\n>>  \n>> +static const char *submodule_strategy_to_string(enum submodule_update_type type)\n>> +{\n>> +\tswitch (type) {\n>> +\tcase SM_UPDATE_CHECKOUT:\n>> +\t\treturn \"checkout\";\n>> +\tcase SM_UPDATE_MERGE:\n>> +\t\treturn \"merge\";\n>> +\tcase SM_UPDATE_REBASE:\n>> +\t\treturn \"rebase\";\n>> +\tcase SM_UPDATE_NONE:\n>> +\t\treturn \"none\";\n>> +\tcase SM_UPDATE_UNSPECIFIED:\n>> +\tcase SM_UPDATE_COMMAND:\n>> +\t\tBUG(\"init_submodule() should handle type %d\", type);\n>> +\tdefault:\n>> +\t\tBUG(\"unexpected update strategy type: %d\", type);\n>> +\t}\n>> +}\n>> +\n>\n> This function is meant to convert from an update strategy back to the\n> string that the user actually provided in their gitconfig.\n>\n> The change in behavior makes this function BUG() out on types that\n> aren't \"magic\" tokens, i.e. \"UNSPECIFIED\" (which is obviously not\n> expressible) and \"COMMAND\" (which allows users to specify an arbitrary\n> command using \"!\", like \"!cat\"). It shouldn't be difficult to teach\n> callers to handle \"COMMAND\", so this seems like an ok change, though I\n> think we should probably amend the function name to\n> submodule_update_type_to_string() and change the UNSPECIFIED and COMMAND\n> arms to something like BUG(\"type %d has no corresponding string\").\n\nMakes sense, will rename it.\n\n> I'm not so convinced that this function should be static, though. I\n> think it's more natural for submodule_update_type_to_string() to have\n> the same visibility as enum submodule_update_type. Today, we only have\n> one other caller who uses this enum, and it doesn't even need this\n> _to_string() fn (fsck.c calls parse_submodule_update_type() and doesn't\n> need _to_string() because it has the raw config values). But it feels a\n> bit inevitable that this will get moved back to submodule.h.\n\nI'll re-roll & leave it in submodule.[ch].\n"},{"id":"461686","messageId":"patch-v3-01.32-77586985ab3-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 01/32] submodule tests: test usage behavior","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:10Z","receivedAt":"2022-08-21T13:58:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Test what exit code and output we emit on \"git submodule -h\", how we\nhandle \"--\" when no subcommand is specified, and how the top-level\n\"--recursive\" option is handled.\n\nFor \"-h\" this doesn't make sense, but let's test for it so that any\nsubsequent eventual behavior change will become clear.\n\nFor \"--\" this follows up on 68cabbfda36 (submodule: document default\nbehavior, 2019-02-15) and tests that \"status\" doesn't support\nthe \"--\" delimiter. There's no intrinsically good reason not to\nsupport that. We behave this way due to edge cases in\ngit-submodule.sh's implementation, but as with \"-h\" let's assert our\ncurrent long-standing behavior for now.\n\nFor \"--recursive\" the exclusion of it from the top-level appears to\nhave been an omission in 15fc56a8536 (git submodule foreach: Add\n--recursive to recurse into nested submodules, 2009-08-19), there\ndoesn't seem to be a reason not to support it alongside \"--quiet\" and\n\"--cached\", but let's likewise assert our existing behavior for now.\n\nI.e. as long as \"status\" is optional it would make sense to support\nall of its options when it's omitted, but we only do that with\n\"--quiet\" and \"--cached\", and curiously omit \"--recursive\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7400-submodule-basic.sh | 26 ++++++++++++++++++++++++++\n 1 file changed, 26 insertions(+)\n\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex e7cec2e457a..b858871a953 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -14,6 +14,32 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+test_expect_success 'submodule usage: -h' '\n+\tgit submodule -h >out 2>err &&\n+\tgrep \"^usage: git submodule\" out &&\n+\ttest_must_be_empty err\n+'\n+\n+test_expect_success 'submodule usage: --recursive' '\n+\ttest_expect_code 1 git submodule --recursive >out 2>err &&\n+\tgrep \"^usage: git submodule\" err &&\n+\ttest_must_be_empty out\n+'\n+\n+test_expect_success 'submodule usage: status --' '\n+\ttest_expect_code 1 git submodule -- &&\n+\ttest_expect_code 1 git submodule --end-of-options\n+'\n+\n+for opt in '--quiet' '--cached'\n+do\n+\ttest_expect_success \"submodule usage: status $opt\" '\n+\t\tgit submodule $opt &&\n+\t\tgit submodule status $opt &&\n+\t\tgit submodule $opt status\n+\t'\n+done\n+\n test_expect_success 'submodule deinit works on empty repository' '\n \tgit submodule deinit --all\n '\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461687","messageId":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-00.20-00000000000-20220728T161116Z-avarab@gmail.com","subject":"[PATCH v3 00/32] submodule--helper: add tests, rm dead code, refactor & leak prep","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:09Z","receivedAt":"2022-08-21T13:58:36Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series is a \"prep\" series for the meaty leak fixes for\nsubmodule--helper, see [1] (which will be re-rolled on top of this\nv3). The v6 re-roll will be at [2].\n\nChanges since v2:\n\n * Clarified 1/* commit message.\n * 22/*: keep the \"to string\" API function in submodule.[ch], as\n   suggested by Glen.\n * 24/*: Minor change to existing comment obsoleted by the code change.\n * 26-31/*: Do the full libification suggested by Glen, instead of\n   leaving it for later. As a result we don't need to pass up the\n   \"must_die_on_failure\", and some parts of the soon-to-be-rerolled\n   \"leak\" series[1] will be better as a result.\n\n1. https://lore.kernel.org/git/cover-v5-00.17-00000000000-20220802T155002Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/cover-v6-00.17-00000000000-20220821T130415Z-avarab@gmail.com\n\nGlen Choo (2):\n  submodule--helper: add \"const\" to copy of \"update_data\"\n  submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"\n\nÆvar Arnfjörð Bjarmason (30):\n  submodule tests: test usage behavior\n  submodule tests: test for \"add <repository> <abs-path>\"\n  submodule--helper: remove unused \"name\" helper\n  submodule--helper: remove unused \"list\" helper\n  test-tool submodule-config: remove unused \"--url\" handling\n  submodule--helper: move \"is-active\" to a test-tool\n  submodule--helper: move \"check-name\" to a test-tool\n  submodule--helper: move \"resolve-relative-url-test\" to a test-tool\n  submodule--helper style: don't separate declared variables with \\n\\n\n  submodule--helper style: add \\n\\n after variable declarations\n  submodule--helper: replace memset() with { 0 }-initialization\n  submodule--helper: use xstrfmt() in clone_submodule()\n  submodule--helper: move \"sb\" in clone_submodule() to its own scope\n  submodule--helper: add \"const\" to passed \"module_clone_data\"\n  submodule--helper: don't redundantly check \"else if (res)\"\n  submodule--helper: rename \"int res\" to \"int ret\"\n  submodule--helper: return \"ret\", not \"1\" from update_submodule()\n  submodule--helper: add missing braces to \"else\" arm\n  submodule--helper: don't call submodule_strategy_to_string() in BUG()\n  submodule API: don't handle SM_..{UNSPECIFIED,COMMAND} in to_string()\n  submodule--helper: use \"code\" in run_update_command()\n  submodule--helper: don't exit() on failure, return\n  submodule--helper: libify determine_submodule_update_strategy()\n  submodule--helper: libify \"must_die_on_failure\" code paths\n  submodule--helper update: don't override 'checkout' exit code\n  submodule--helper: libify \"must_die_on_failure\" code paths (for die)\n  submodule--helper: check repo{_submodule,}_init() return values\n  submodule--helper: libify more \"die\" paths for module_update()\n  submodule--helper: libify even more \"die\" paths for module_update()\n  submodule--helper: fix bad config API usage\n\n Makefile                         |   1 +\n builtin/submodule--helper.c      | 534 ++++++++++++++-----------------\n git-compat-util.h                |   3 +\n repository.h                     |   3 +\n submodule.c                      |  12 +-\n submodule.h                      |   2 +-\n t/helper/test-submodule-config.c |  11 +-\n t/helper/test-submodule.c        | 146 +++++++++\n t/helper/test-tool-utils.h       |   9 +\n t/helper/test-tool.c             |   7 +-\n t/helper/test-tool.h             |   1 +\n t/t0060-path-utils.sh            |   2 +-\n t/t7400-submodule-basic.sh       |  56 ++--\n t/t7406-submodule-update.sh      |   2 +-\n t/t7413-submodule-is-active.sh   |  35 +-\n t/t7450-bad-git-dotfiles.sh      |   2 +-\n 16 files changed, 460 insertions(+), 366 deletions(-)\n create mode 100644 t/helper/test-submodule.c\n create mode 100644 t/helper/test-tool-utils.h\n\nRange-diff against v2:\n 1:  daa5d3f9962 !  1:  77586985ab3 submodule tests: test usage behavior\n    @@ Commit message\n         subsequent eventual behavior change will become clear.\n     \n         For \"--\" this follows up on 68cabbfda36 (submodule: document default\n    -    behavior, 2019-02-15) and tests that \"status\" doesn't don't support\n    +    behavior, 2019-02-15) and tests that \"status\" doesn't support\n         the \"--\" delimiter. There's no intrinsically good reason not to\n         support that. We behave this way due to edge cases in\n         git-submodule.sh's implementation, but as with \"-h\" let's assert our\n    @@ Commit message\n         doesn't seem to be a reason not to support it alongside \"--quiet\" and\n         \"--cached\", but let's likewise assert our existing behavior for now.\n     \n    +    I.e. as long as \"status\" is optional it would make sense to support\n    +    all of its options when it's omitted, but we only do that with\n    +    \"--quiet\" and \"--cached\", and curiously omit \"--recursive\".\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## t/t7400-submodule-basic.sh ##\n 2:  9d920326df3 =  2:  7425f0025da submodule tests: test for \"add <repository> <abs-path>\"\n 3:  d981db49fa1 =  3:  1be48c0b22f submodule--helper: remove unused \"name\" helper\n 4:  6f78f9c9274 =  4:  10189ba3da7 submodule--helper: remove unused \"list\" helper\n 5:  43902201701 =  5:  ef66dfcd45f test-tool submodule-config: remove unused \"--url\" handling\n 6:  e2a8bb0a28e =  6:  4727fbb4b64 submodule--helper: move \"is-active\" to a test-tool\n 7:  b209532eb17 =  7:  9c644460b1d submodule--helper: move \"check-name\" to a test-tool\n 8:  de49f31dab0 =  8:  03c8383b8e7 submodule--helper: move \"resolve-relative-url-test\" to a test-tool\n 9:  b0238f699ce =  9:  b1eaa6a796b submodule--helper style: don't separate declared variables with \\n\\n\n10:  5f5e68a868b = 10:  fd7fbe08536 submodule--helper style: add \\n\\n after variable declarations\n11:  72dcf19e1c4 = 11:  356f07db436 submodule--helper: replace memset() with { 0 }-initialization\n12:  e5e267dccd5 = 12:  241ac5c7eee submodule--helper: use xstrfmt() in clone_submodule()\n13:  91558745e2e = 13:  f2f412f50c1 submodule--helper: move \"sb\" in clone_submodule() to its own scope\n14:  866b8397a59 ! 14:  ad7848067a9 submodule--helper: pass a \"const struct module_clone_data\" to clone_submodule()\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    submodule--helper: pass a \"const struct module_clone_data\" to clone_submodule()\n    +    submodule--helper: add \"const\" to passed \"module_clone_data\"\n     \n         Add \"const\" to the \"struct module_clone_data\" that we pass to\n         clone_submodule(), which makes the ownership clear, and stops us from\n15:  1ff380ec7b5 = 15:  ab283479b92 submodule--helper: add \"const\" to copy of \"update_data\"\n16:  d3a7e646adc = 16:  ab0fd2c60f0 submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"\n17:  23eb07176d9 = 17:  fa2417c7a17 submodule--helper: don't redundantly check \"else if (res)\"\n18:  78f74df6d5e = 18:  be1ffbf2e26 submodule--helper: rename \"int res\" to \"int ret\"\n19:  f0258e37ebe = 19:  92e17c37839 submodule--helper: return \"ret\", not \"1\" from update_submodule()\n20:  70f030cca4e = 20:  55e3ea5f9dd submodule--helper: add missing braces to \"else\" arm\n21:  bce1a014a2f = 21:  2bb45302392 submodule--helper: don't call submodule_strategy_to_string() in BUG()\n22:  98c3e562c82 ! 22:  0131c197427 submodule--helper: move submodule_strategy_to_string() to only user\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    submodule--helper: move submodule_strategy_to_string() to only user\n    +    submodule API: don't handle SM_..{UNSPECIFIED,COMMAND} in to_string()\n     \n    -    Move the submodule_strategy_to_string() function added in\n    -    3604242f080 (submodule: port init from shell to C, 2016-04-15) to its\n    -    only user.\n    +    Change the submodule_strategy_to_string() function added in\n    +    3604242f080 (submodule: port init from shell to C, 2016-04-15) to\n    +    really return a \"const char *\". In the \"SM_UPDATE_COMMAND\" case it\n    +    would return a strbuf_detach().\n     \n    -    This function would return NULL on SM_UPDATE_UNSPECIFIED, so it wasn't\n    -    safe to xstrdup() its return value in the general case, or to use it\n    -    in a sprintf() format as the code removed in the preceding commit did.\n    +    Furthermore, this function would return NULL on SM_UPDATE_UNSPECIFIED,\n    +    so it wasn't safe to xstrdup() its return value in the general case,\n    +    or to use it in a sprintf() format as the code removed in the\n    +    preceding commit did.\n     \n         But its callers would never call it with either SM_UPDATE_UNSPECIFIED\n    -    or SM_UPDATE_COMMAND. Let's move it to a \"static\" helper, and have its\n    -    functionality reflect how it's used, and BUG() out on the rest.\n    +    or SM_UPDATE_COMMAND. Let's have its behavior reflect how its only\n    +    user expects it to behave, and BUG() out on the rest.\n     \n         By doing this we can also stop needlessly xstrdup()-ing and free()-ing\n         the memory for the config we're setting. We can instead always use\n         constant strings. We can also use the *_tmp() variant of\n         git_config_get_string().\n     \n    +    Let's also rename this submodule_strategy_to_string() function to\n    +    submodule_update_type_to_string(). Now that it's only tasked with\n    +    returning a string version of the \"enum submodule_update_type type\".\n    +    Before it would look at the \"command\" field in \"struct\n    +    submodule_update_strategy\".\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: struct init_cb {\n    - };\n    - #define INIT_CB_INIT { 0 }\n    - \n    -+static const char *submodule_strategy_to_string(enum submodule_update_type type)\n    -+{\n    -+\tswitch (type) {\n    -+\tcase SM_UPDATE_CHECKOUT:\n    -+\t\treturn \"checkout\";\n    -+\tcase SM_UPDATE_MERGE:\n    -+\t\treturn \"merge\";\n    -+\tcase SM_UPDATE_REBASE:\n    -+\t\treturn \"rebase\";\n    -+\tcase SM_UPDATE_NONE:\n    -+\t\treturn \"none\";\n    -+\tcase SM_UPDATE_UNSPECIFIED:\n    -+\tcase SM_UPDATE_COMMAND:\n    -+\t\tBUG(\"init_submodule() should handle type %d\", type);\n    -+\tdefault:\n    -+\t\tBUG(\"unexpected update strategy type: %d\", type);\n    -+\t}\n    -+}\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 void init_submodule(const char *path, const char *prefix,\n      {\n      \tconst struct submodule *sub;\n      \tstruct strbuf sb = STRBUF_INIT;\n    @@ builtin/submodule--helper.c: static void init_submodule(const char *path, const\n     +\t\t\tupd = \"none\";\n      \t\t} else {\n     -\t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n    -+\t\t\tupd = submodule_strategy_to_string(sub->update_strategy.type);\n    ++\t\t\tupd = submodule_update_type_to_string(sub->update_strategy.type);\n      \t\t}\n      \n      \t\tif (git_config_set_gently(sb.buf, upd))\n    @@ submodule.c: int parse_submodule_update_strategy(const char *value,\n      }\n      \n     -const char *submodule_strategy_to_string(const struct submodule_update_strategy *s)\n    --{\n    ++const char *submodule_update_type_to_string(enum submodule_update_type type)\n    + {\n     -\tstruct strbuf sb = STRBUF_INIT;\n     -\tswitch (s->type) {\n    --\tcase SM_UPDATE_CHECKOUT:\n    --\t\treturn \"checkout\";\n    --\tcase SM_UPDATE_MERGE:\n    --\t\treturn \"merge\";\n    --\tcase SM_UPDATE_REBASE:\n    --\t\treturn \"rebase\";\n    --\tcase SM_UPDATE_NONE:\n    --\t\treturn \"none\";\n    --\tcase SM_UPDATE_UNSPECIFIED:\n    ++\tswitch (type) {\n    + \tcase SM_UPDATE_CHECKOUT:\n    + \t\treturn \"checkout\";\n    + \tcase SM_UPDATE_MERGE:\n    +@@ submodule.c: const char *submodule_strategy_to_string(const struct submodule_update_strategy\n    + \tcase SM_UPDATE_NONE:\n    + \t\treturn \"none\";\n    + \tcase SM_UPDATE_UNSPECIFIED:\n     -\t\treturn NULL;\n    --\tcase SM_UPDATE_COMMAND:\n    + \tcase SM_UPDATE_COMMAND:\n     -\t\tstrbuf_addf(&sb, \"!%s\", s->command);\n     -\t\treturn strbuf_detach(&sb, NULL);\n    --\t}\n    ++\t\tBUG(\"init_submodule() should handle type %d\", type);\n    ++\tdefault:\n    ++\t\tBUG(\"unexpected update strategy type: %d\", type);\n    + \t}\n     -\treturn NULL;\n    --}\n    --\n    + }\n    + \n      void handle_ignore_submodules_arg(struct diff_options *diffopt,\n    - \t\t\t\t  const char *arg)\n    - {\n     \n      ## submodule.h ##\n     @@ submodule.h: void die_path_inside_submodule(struct index_state *istate,\n    @@ submodule.h: void die_path_inside_submodule(struct index_state *istate,\n      int parse_submodule_update_strategy(const char *value,\n      \t\t\t\t    struct submodule_update_strategy *dst);\n     -const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);\n    ++const char *submodule_update_type_to_string(enum submodule_update_type type);\n      void handle_ignore_submodules_arg(struct diff_options *, const char *);\n      void show_submodule_diff_summary(struct diff_options *o, const char *path,\n      \t\t\t    struct object_id *one, struct object_id *two,\n23:  db2d2fb5a21 = 23:  6cac6cb2fa6 submodule--helper: use \"code\" in run_update_command()\n24:  d33260487bd ! 24:  6d56f671c7a submodule--helper: don't exit() on failure, return\n    @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *upd\n      \tif (update_data->recursive) {\n      \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n     @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data)\n    + \t\tprepare_submodule_repo_env(&cp.env);\n    + \t\tupdate_data_to_args(&next, &cp.args);\n    + \n    +-\t\t/* die() if child process die()'d */\n    + \t\tret = run_command(&cp);\n    + \t\tif (!ret)\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 (ret == 128)\n25:  9981a75d7e8 = 25:  dfd5c8bcd61 submodule--helper: libify determine_submodule_update_strategy()\n26:  b48705c6cc0 ! 26:  da1a07afd25 submodule--helper: libify \"must_die_on_failure\" code paths\n    @@ Commit message\n         after having gone through the various codepaths that we were only\n         returning 128 if we meant to early abort.\n     \n    +    In update_submodules() we'll for now set any non-zero non-128 exit\n    +    codes to \"1\", but will start ferrying up the exit code as-is in a\n    +    subsequent commit.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    @@ builtin/submodule--helper.c: static void update_data_to_args(struct update_data\n      {\n      \tint ret;\n      \n    +@@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data,\n    + \t\t\t\t\t\t  update_data->sm_path,\n    + \t\t\t\t\t\t  update_data->update_default,\n    + \t\t\t\t\t\t  &update_data->update_strategy);\n    +-\tif (ret) {\n    +-\t\t*must_die_on_failure = 1;\n    ++\tif (ret)\n    + \t\treturn ret;\n    +-\t}\n    + \n    + \tif (update_data->just_cloned)\n    + \t\toidcpy(&update_data->suboid, null_oid());\n     @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data,\n      \t}\n      \n    @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *upd\n      \n      \tif (update_data->recursive) {\n     @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data,\n    + \t\tupdate_data_to_args(&next, &cp.args);\n      \n    - \t\t/* die() if child process die()'d */\n      \t\tret = run_command(&cp);\n     -\t\tif (!ret)\n     -\t\t\treturn 0;\n    @@ builtin/submodule--helper.c: static int update_submodules(struct update_data *up\n      \t\tupdate_data->sm_path = ucd.sub->path;\n      \n     -\t\tcode = update_submodule(update_data, &must_die_on_failure);\n    -+\t\tcode = update_submodule(update_data);\n    - \t\tif (code)\n    - \t\t\tret = code;\n    +-\t\tif (code)\n    +-\t\t\tret = code;\n     -\t\tif (must_die_on_failure)\n    -+\t\tif (code == 128)\n    ++\t\tcode = update_submodule(update_data);\n    ++\t\tif (!code)\n    ++\t\t\tcontinue;\n    ++\t\tret = code;\n    ++\t\tif (ret == 128)\n      \t\t\tgoto cleanup;\n    - \t\telse if (code)\n    - \t\t\tret = 1;\n    +-\t\telse if (code)\n    +-\t\t\tret = 1;\n    ++\t\tret = 1;\n    + \t}\n    + \n    + cleanup:\n -:  ----------- > 27:  2795a3738c8 submodule--helper update: don't override 'checkout' exit code\n27:  93cd1ccde54 ! 28:  6d9bccb34c3 submodule--helper: libify \"must_die_on_failure\" code paths (for die)\n    @@ Commit message\n                 const char *branch = remote_submodule_branch(update_data->sm_path);\n     \n         But as that code is used by other callers than the \"update\" code let's\n    -    leave converting it for now.\n    +    leave converting it for a subsequent commit.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *upd\n      \tupdate_data->displaypath = get_submodule_displaypath(\n      \t\tupdate_data->sm_path, update_data->prefix);\n     @@ builtin/submodule--helper.c: static int update_submodule(struct update_data *update_data)\n    - \t\t\t\t\t\t  update_data->sm_path,\n    - \t\t\t\t\t\t  update_data->update_default,\n    - \t\t\t\t\t\t  &update_data->update_strategy);\n    --\tif (ret) {\n    --\t\t*must_die_on_failure = 1;\n    -+\tif (ret)\n    - \t\treturn ret;\n    --\t}\n    - \n      \tif (update_data->just_cloned)\n      \t\toidcpy(&update_data->suboid, null_oid());\n      \telse if (resolve_gitlink_ref(update_data->sm_path, \"HEAD\", &update_data->suboid))\n -:  ----------- > 29:  d4b55f07a30 submodule--helper: check repo{_submodule,}_init() return values\n -:  ----------- > 30:  15c2490a978 submodule--helper: libify more \"die\" paths for module_update()\n -:  ----------- > 31:  1694ccfe882 submodule--helper: libify even more \"die\" paths for module_update()\n28:  6160a1ab250 = 32:  d133402462f submodule--helper: fix bad config API usage\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461688","messageId":"patch-v3-02.32-7425f0025da-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 02/32] submodule tests: test for \"add <repository> <abs-path>\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:11Z","receivedAt":"2022-08-21T13:58:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a missing test for \"\"add <repository> <path>\" where \"<path>\" is an\nabsolute path. This tests code added in [1] and later turned into an\n\"else\" branch in clone_submodule() in [2] that's never been tested.\n\nThis needs to be skipped on WINDOWS because all of $PWD, $(pwd) and\nthe \"$(pwd -P)\" we get via \"$submodurl\" would fail in CI with e.g.:\n\n\tfatal: could not create directory 'D:/a/git/git/t/trash\n\tdirectory.t7400-submodule-basic/.git/modules/D:/a/git/git/t/trash\n\tdirectory.t7400-submodule-basic/add-abs'\n\nI.e. we can't handle these sorts of paths in this context on that\nplatform.\n\nI'm not sure where we run into the edges of \"$PWD\" behavior on\nWindows (see [1] for a previous loose end on the topic), but for the\npurposes of this test it's sufficient that we test this on other\nplatforms.\n\n1. ee8838d1577 (submodule: rewrite `module_clone` shell function in C,\n   2015-09-08)\n2. f8eaa0ba98b (submodule--helper, module_clone: always operate on\n   absolute paths, 2016-03-31)\n\n1. https://lore.kernel.org/git/220630.86edz6c75c.gmgdl@evledraar.gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7400-submodule-basic.sh | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex b858871a953..6a77d817a82 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -178,6 +178,11 @@ test_expect_success 'submodule add' '\n \ttest_must_be_empty untracked\n '\n \n+test_expect_success !WINDOWS 'submodule add (absolute path)' '\n+\ttest_when_finished \"git reset --hard\" &&\n+\tgit submodule add \"$submodurl\" \"$submodurl/add-abs\"\n+'\n+\n test_expect_success 'setup parent and one repository' '\n \ttest_create_repo parent &&\n \ttest_commit -C parent one\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461689","messageId":"patch-v3-03.32-1be48c0b22f-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 03/32] submodule--helper: remove unused \"name\" helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:12Z","receivedAt":"2022-08-21T13:58:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"name\" helper has not been used since e83e3333b57 (submodule: port\nsubmodule subcommand 'summary' from shell to C, 2020-08-13).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.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 b63f420ecef..fc4d2779da6 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -771,24 +771,6 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int module_name(int argc, const char **argv, const char *prefix)\n-{\n-\tconst struct submodule *sub;\n-\n-\tif (argc != 2)\n-\t\tusage(_(\"git submodule--helper name <path>\"));\n-\n-\tsub = submodule_from_path(the_repository, null_oid(), argv[1]);\n-\n-\tif (!sub)\n-\t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n-\t\t    argv[1]);\n-\n-\tprintf(\"%s\\n\", sub->name);\n-\n-\treturn 0;\n-}\n-\n struct module_cb {\n \tunsigned int mod_src;\n \tunsigned int mod_dst;\n@@ -3362,7 +3344,6 @@ struct cmd_struct {\n \n static struct cmd_struct commands[] = {\n \t{\"list\", module_list, 0},\n-\t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461690","messageId":"patch-v3-04.32-10189ba3da7-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 04/32] submodule--helper: remove unused \"list\" helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:13Z","receivedAt":"2022-08-21T13:58:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the \"submodule--helper list\" sub-command, which hasn't been\nused by git-submodule.sh since 2964d6e5e1e (submodule: port subcommand\n'set-branch' from shell to C, 2020-06-02).\n\nThere was a test added in 2b56bb7a87a (submodule helper list: respect\ncorrect path prefix, 2016-02-24) which relied on it, but the right\nthing to do here is to delete that test as well.\n\nThat test was regression testing the \"list\" subcommand itself. We're\nnot getting anything useful from the \"list | cut -f2\" invocation that\nwe couldn't get from \"foreach 'echo $sm_path'\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 40 -------------------------------------\n t/t7400-submodule-basic.sh  | 25 -----------------------\n 2 files changed, 65 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex fc4d2779da6..24a305151d1 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -266,45 +266,6 @@ static char *get_up_path(const char *path)\n \treturn strbuf_detach(&sb, NULL);\n }\n \n-static int module_list(int argc, const char **argv, const char *prefix)\n-{\n-\tint i;\n-\tstruct pathspec pathspec;\n-\tstruct module_list list = MODULE_LIST_INIT;\n-\n-\tstruct option module_list_options[] = {\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"alternative anchor for relative paths\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper list [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, module_list_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < list.nr; i++) {\n-\t\tconst struct cache_entry *ce = list.entries[i];\n-\n-\t\tif (ce_stage(ce))\n-\t\t\tprintf(\"%06o %s U\\t\", ce->ce_mode,\n-\t\t\t       oid_to_hex(null_oid()));\n-\t\telse\n-\t\t\tprintf(\"%06o %s %d\\t\", ce->ce_mode,\n-\t\t\t       oid_to_hex(&ce->oid), ce_stage(ce));\n-\n-\t\tfprintf(stdout, \"%s\\n\", ce->name);\n-\t}\n-\treturn 0;\n-}\n-\n static void for_each_listed_submodule(const struct module_list *list,\n \t\t\t\t      each_submodule_fn fn, void *cb_data)\n {\n@@ -3343,7 +3304,6 @@ struct cmd_struct {\n };\n \n static struct cmd_struct commands[] = {\n-\t{\"list\", module_list, 0},\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex 6a77d817a82..b50db3f1031 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -1255,31 +1255,6 @@ test_expect_success 'submodule add clone shallow submodule' '\n \t)\n '\n \n-test_expect_success 'submodule helper list is not confused by common prefixes' '\n-\tmkdir -p dir1/b &&\n-\t(\n-\t\tcd dir1/b &&\n-\t\tgit init &&\n-\t\techo hi >testfile2 &&\n-\t\tgit add . &&\n-\t\tgit commit -m \"test1\"\n-\t) &&\n-\tmkdir -p dir2/b &&\n-\t(\n-\t\tcd dir2/b &&\n-\t\tgit init &&\n-\t\techo hello >testfile1 &&\n-\t\tgit add .  &&\n-\t\tgit commit -m \"test2\"\n-\t) &&\n-\tgit submodule add /dir1/b dir1/b &&\n-\tgit submodule add /dir2/b dir2/b &&\n-\tgit commit -m \"first submodule commit\" &&\n-\tgit submodule--helper list dir1/b | cut -f 2 >actual &&\n-\techo \"dir1/b\" >expect &&\n-\ttest_cmp expect actual\n-'\n-\n test_expect_success 'setup superproject with submodules' '\n \tgit init sub1 &&\n \ttest_commit -C sub1 test &&\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461691","messageId":"patch-v3-05.32-ef66dfcd45f-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 05/32] test-tool submodule-config: remove unused \"--url\" handling","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:14Z","receivedAt":"2022-08-21T13:58:44Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"No test has used this \"--url\" parameter since the test code that made\nuse of it was removed in 32bc548329d (submodule-config: remove support\nfor overlaying repository config, 2017-08-03).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/helper/test-submodule-config.c | 11 ++---------\n 1 file changed, 2 insertions(+), 9 deletions(-)\n\ndiff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c\nindex e2692746dfd..22a41c40926 100644\n--- a/t/helper/test-submodule-config.c\n+++ b/t/helper/test-submodule-config.c\n@@ -15,14 +15,11 @@ int cmd__submodule_config(int argc, const char **argv)\n {\n \tconst char **arg = argv;\n \tint my_argc = argc;\n-\tint output_url = 0;\n \tint lookup_name = 0;\n \n \targ++;\n \tmy_argc--;\n \twhile (arg[0] && starts_with(arg[0], \"--\")) {\n-\t\tif (!strcmp(arg[0], \"--url\"))\n-\t\t\toutput_url = 1;\n \t\tif (!strcmp(arg[0], \"--name\"))\n \t\t\tlookup_name = 1;\n \t\targ++;\n@@ -57,12 +54,8 @@ int cmd__submodule_config(int argc, const char **argv)\n \t\tif (!submodule)\n \t\t\tdie_usage(argc, argv, \"Submodule not found.\");\n \n-\t\tif (output_url)\n-\t\t\tprintf(\"Submodule url: '%s' for path '%s'\\n\",\n-\t\t\t\t\tsubmodule->url, submodule->path);\n-\t\telse\n-\t\t\tprintf(\"Submodule name: '%s' for path '%s'\\n\",\n-\t\t\t\t\tsubmodule->name, submodule->path);\n+\t\tprintf(\"Submodule name: '%s' for path '%s'\\n\", submodule->name,\n+\t\t       submodule->path);\n \n \t\targ += 2;\n \t}\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461692","messageId":"patch-v3-06.32-4727fbb4b64-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 06/32] submodule--helper: move \"is-active\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:15Z","receivedAt":"2022-08-21T13:58:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Create a new \"test-tool submodule\" and move the \"is-active\" subcommand\nover to it. It was added in 5c2bd8b77ae (submodule--helper: add\nis-active subcommand, 2017-03-16), since\na452128a36c (submodule--helper: introduce add-config subcommand,\n2021-08-06) it hasn't been used by git-submodule.sh.\n\nSince we're creating a command dispatch similar to test-tool.c itself\nlet's split out the \"struct test_cmd\" into a new test-tool-utils.h,\nwhich both this new code and test-tool.c itself can use.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile                       |  1 +\n builtin/submodule--helper.c    |  9 ------\n t/helper/test-submodule.c      | 58 ++++++++++++++++++++++++++++++++++\n t/helper/test-tool-utils.h     |  9 ++++++\n t/helper/test-tool.c           |  7 ++--\n t/helper/test-tool.h           |  1 +\n t/t7413-submodule-is-active.sh | 35 ++++++++++----------\n 7 files changed, 90 insertions(+), 30 deletions(-)\n create mode 100644 t/helper/test-submodule.c\n create mode 100644 t/helper/test-tool-utils.h\n\ndiff --git a/Makefile b/Makefile\nindex e8adeb09f1c..b6acd560e75 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -785,6 +785,7 @@ TEST_BUILTINS_OBJS += test-strcmp-offset.o\n TEST_BUILTINS_OBJS += test-string-list.o\n TEST_BUILTINS_OBJS += test-submodule-config.o\n TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o\n+TEST_BUILTINS_OBJS += test-submodule.o\n TEST_BUILTINS_OBJS += test-subprocess.o\n TEST_BUILTINS_OBJS += test-trace2.o\n TEST_BUILTINS_OBJS += test-urlmatch-normalization.o\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 24a305151d1..e10c3ac7550 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2731,14 +2731,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int is_active(int argc, const char **argv, const char *prefix)\n-{\n-\tif (argc != 2)\n-\t\tdie(\"submodule--helper is-active takes exactly 1 argument\");\n-\n-\treturn !is_submodule_active(the_repository, argv[1]);\n-}\n-\n /*\n  * Exit non-zero if any of the submodule names given on the command line is\n  * invalid. If no names are given, filter stdin to print only valid names\n@@ -3316,7 +3308,6 @@ static struct cmd_struct commands[] = {\n \t{\"summary\", module_summary, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n-\t{\"is-active\", is_active, 0},\n \t{\"check-name\", check_name, 0},\n \t{\"config\", module_config, 0},\n \t{\"set-url\", module_set_url, 0},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nnew file mode 100644\nindex 00000000000..494c6558d9f\n--- /dev/null\n+++ b/t/helper/test-submodule.c\n@@ -0,0 +1,58 @@\n+#include \"test-tool.h\"\n+#include \"test-tool-utils.h\"\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+#include \"submodule.h\"\n+\n+#define TEST_TOOL_IS_ACTIVE_USAGE \\\n+\t\"test-tool submodule is-active <name>\"\n+static const char *submodule_is_active_usage[] = {\n+\tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tNULL\n+};\n+\n+static const char *submodule_usage[] = {\n+\tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tNULL\n+};\n+\n+static int cmd__submodule_is_active(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_is_active_usage, 0);\n+\tif (argc != 1)\n+\t\tusage_with_options(submodule_is_active_usage, options);\n+\n+\tsetup_git_directory();\n+\n+\treturn !is_submodule_active(the_repository, argv[0]);\n+}\n+\n+static struct test_cmd cmds[] = {\n+\t{ \"is-active\", cmd__submodule_is_active },\n+};\n+\n+int cmd__submodule(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\tsize_t i;\n+\n+\targc = parse_options(argc, argv, \"test-tools\", options, submodule_usage,\n+\t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n+\tif (argc < 1)\n+\t\tusage_with_options(submodule_usage, options);\n+\n+\tfor (i = 0; i < ARRAY_SIZE(cmds); i++)\n+\t\tif (!strcmp(cmds[i].name, argv[0]))\n+\t\t\treturn cmds[i].fn(argc, argv);\n+\n+\tusage_msg_optf(\"unknown subcommand '%s'\", submodule_usage, options,\n+\t\t       argv[0]);\n+\n+\treturn 0;\n+}\ndiff --git a/t/helper/test-tool-utils.h b/t/helper/test-tool-utils.h\nnew file mode 100644\nindex 00000000000..6a0e5e0074f\n--- /dev/null\n+++ b/t/helper/test-tool-utils.h\n@@ -0,0 +1,9 @@\n+#ifndef TEST_TOOL_UTILS_H\n+#define TEST_TOOL_UTILS_H\n+\n+struct test_cmd {\n+\tconst char *name;\n+\tint (*fn)(int argc, const char **argv);\n+};\n+\n+#endif\ndiff --git a/t/helper/test-tool.c b/t/helper/test-tool.c\nindex 318fdbab0c3..7a6a8b88a91 100644\n--- a/t/helper/test-tool.c\n+++ b/t/helper/test-tool.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"test-tool.h\"\n+#include \"test-tool-utils.h\"\n #include \"trace2.h\"\n #include \"parse-options.h\"\n \n@@ -8,11 +9,6 @@ static const char * const test_tool_usage[] = {\n \tNULL\n };\n \n-struct test_cmd {\n-\tconst char *name;\n-\tint (*fn)(int argc, const char **argv);\n-};\n-\n static struct test_cmd cmds[] = {\n \t{ \"advise\", cmd__advise_if_enabled },\n \t{ \"bitmap\", cmd__bitmap },\n@@ -78,6 +74,7 @@ static struct test_cmd cmds[] = {\n \t{ \"simple-ipc\", cmd__simple_ipc },\n \t{ \"strcmp-offset\", cmd__strcmp_offset },\n \t{ \"string-list\", cmd__string_list },\n+\t{ \"submodule\", cmd__submodule },\n \t{ \"submodule-config\", cmd__submodule_config },\n \t{ \"submodule-nested-repo-config\", cmd__submodule_nested_repo_config },\n \t{ \"subprocess\", cmd__subprocess },\ndiff --git a/t/helper/test-tool.h b/t/helper/test-tool.h\nindex bb799271631..5f4f69dee81 100644\n--- a/t/helper/test-tool.h\n+++ b/t/helper/test-tool.h\n@@ -68,6 +68,7 @@ int cmd__sigchain(int argc, const char **argv);\n int cmd__simple_ipc(int argc, const char **argv);\n int cmd__strcmp_offset(int argc, const char **argv);\n int cmd__string_list(int argc, const char **argv);\n+int cmd__submodule(int argc, const char **argv);\n int cmd__submodule_config(int argc, const char **argv);\n int cmd__submodule_nested_repo_config(int argc, const char **argv);\n int cmd__subprocess(int argc, const char **argv);\ndiff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh\nindex c8e7e983317..ede6f02dbd5 100755\n--- a/t/t7413-submodule-is-active.sh\n+++ b/t/t7413-submodule-is-active.sh\n@@ -1,9 +1,12 @@\n #!/bin/sh\n \n-test_description='Test submodule--helper is-active\n+test_description='Test with test-tool submodule is-active\n \n-This test verifies that `git submodue--helper is-active` correctly identifies\n+This test verifies that `test-tool submodule is-active` correctly identifies\n submodules which are \"active\" and interesting to the user.\n+\n+This is a unit test of the submodule.c is_submodule_active() function,\n+which is also indirectly tested elsewhere.\n '\n \n . ./test-lib.sh\n@@ -25,13 +28,13 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'is-active works with urls' '\n-\tgit -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2 &&\n+\ttest-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2 &&\n \n \tgit -C super config --unset submodule.sub1.URL &&\n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n \tgit -C super config submodule.sub1.URL ../sub &&\n-\tgit -C super submodule--helper is-active sub1\n+\ttest-tool -C super submodule is-active sub1\n '\n \n test_expect_success 'is-active works with submodule.<name>.active config' '\n@@ -39,11 +42,11 @@ test_expect_success 'is-active works with submodule.<name>.active config' '\n \ttest_when_finished \"git -C super config submodule.sub1.URL ../sub\" &&\n \n \tgit -C super config --bool submodule.sub1.active \"false\" &&\n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n \n \tgit -C super config --bool submodule.sub1.active \"true\" &&\n \tgit -C super config --unset submodule.sub1.URL &&\n-\tgit -C super submodule--helper is-active sub1\n+\ttest-tool -C super submodule is-active sub1\n '\n \n test_expect_success 'is-active works with basic submodule.active config' '\n@@ -53,17 +56,17 @@ test_expect_success 'is-active works with basic submodule.active config' '\n \tgit -C super config --add submodule.active \".\" &&\n \tgit -C super config --unset submodule.sub1.URL &&\n \n-\tgit -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active correctly works with paths that are not submodules' '\n \ttest_when_finished \"git -C super config --unset-all submodule.active\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active not-a-submodule &&\n+\ttest_must_fail test-tool -C super submodule is-active not-a-submodule &&\n \n \tgit -C super config --add submodule.active \".\" &&\n-\ttest_must_fail git -C super submodule--helper is-active not-a-submodule\n+\ttest_must_fail test-tool -C super submodule is-active not-a-submodule\n '\n \n test_expect_success 'is-active works with exclusions in submodule.active config' '\n@@ -72,8 +75,8 @@ test_expect_success 'is-active works with exclusions in submodule.active config'\n \tgit -C super config --add submodule.active \".\" &&\n \tgit -C super config --add submodule.active \":(exclude)sub1\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active with submodule.active and submodule.<name>.active' '\n@@ -85,8 +88,8 @@ test_expect_success 'is-active with submodule.active and submodule.<name>.active\n \tgit -C super config --bool submodule.sub1.active \"false\" &&\n \tgit -C super config --bool submodule.sub2.active \"true\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active, submodule.active and submodule add' '\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461693","messageId":"patch-v3-07.32-9c644460b1d-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 07/32] submodule--helper: move \"check-name\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:16Z","receivedAt":"2022-08-21T13:58:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the \"check-name\" helper to a test-tool, since\na6226fd772b (submodule--helper: convert the bulk of cmd_add() to C,\n2021-08-10) it has only been used by this test, not git-submodule.sh.\n\nAs noted with its introduction in 0383bbb9015 (submodule-config:\nverify submodule names as paths, 2018-04-30) the intent of\nt7450-bad-git-dotfiles.sh has always been to unit test the\ncheck_submodule_name() function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 24 -------------------\n t/helper/test-submodule.c   | 46 +++++++++++++++++++++++++++++++++++++\n t/t7450-bad-git-dotfiles.sh |  2 +-\n 3 files changed, 47 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e10c3ac7550..e8458567976 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2731,29 +2731,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-/*\n- * Exit non-zero if any of the submodule names given on the command line is\n- * invalid. If no names are given, filter stdin to print only valid names\n- * (which is primarily intended for testing).\n- */\n-static int check_name(int argc, const char **argv, const char *prefix)\n-{\n-\tif (argc > 1) {\n-\t\twhile (*++argv) {\n-\t\t\tif (check_submodule_name(*argv) < 0)\n-\t\t\t\treturn 1;\n-\t\t}\n-\t} else {\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n-\t\t\tif (!check_submodule_name(buf.buf))\n-\t\t\t\tprintf(\"%s\\n\", buf.buf);\n-\t\t}\n-\t\tstrbuf_release(&buf);\n-\t}\n-\treturn 0;\n-}\n-\n static int module_config(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -3308,7 +3285,6 @@ static struct cmd_struct commands[] = {\n \t{\"summary\", module_summary, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n-\t{\"check-name\", check_name, 0},\n \t{\"config\", module_config, 0},\n \t{\"set-url\", module_set_url, 0},\n \t{\"set-branch\", module_set_branch, 0},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nindex 494c6558d9f..9f0eb440192 100644\n--- a/t/helper/test-submodule.c\n+++ b/t/helper/test-submodule.c\n@@ -2,8 +2,16 @@\n #include \"test-tool-utils.h\"\n #include \"cache.h\"\n #include \"parse-options.h\"\n+#include \"submodule-config.h\"\n #include \"submodule.h\"\n \n+#define TEST_TOOL_CHECK_NAME_USAGE \\\n+\t\"test-tool submodule check-name <name>\"\n+static const char *submodule_check_name_usage[] = {\n+\tTEST_TOOL_CHECK_NAME_USAGE,\n+\tNULL\n+};\n+\n #define TEST_TOOL_IS_ACTIVE_USAGE \\\n \t\"test-tool submodule is-active <name>\"\n static const char *submodule_is_active_usage[] = {\n@@ -12,10 +20,47 @@ static const char *submodule_is_active_usage[] = {\n };\n \n static const char *submodule_usage[] = {\n+\tTEST_TOOL_CHECK_NAME_USAGE,\n \tTEST_TOOL_IS_ACTIVE_USAGE,\n \tNULL\n };\n \n+/*\n+ * Exit non-zero if any of the submodule names given on the command line is\n+ * invalid. If no names are given, filter stdin to print only valid names\n+ * (which is primarily intended for testing).\n+ */\n+static int check_name(int argc, const char **argv)\n+{\n+\tif (argc > 1) {\n+\t\twhile (*++argv) {\n+\t\t\tif (check_submodule_name(*argv) < 0)\n+\t\t\t\treturn 1;\n+\t\t}\n+\t} else {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n+\t\t\tif (!check_submodule_name(buf.buf))\n+\t\t\t\tprintf(\"%s\\n\", buf.buf);\n+\t\t}\n+\t\tstrbuf_release(&buf);\n+\t}\n+\treturn 0;\n+}\n+\n+static int cmd__submodule_check_name(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_check_name_usage, 0);\n+\tif (argc)\n+\t\tusage_with_options(submodule_check_name_usage, options);\n+\n+\treturn check_name(argc, argv);\n+}\n+\n static int cmd__submodule_is_active(int argc, const char **argv)\n {\n \tstruct option options[] = {\n@@ -32,6 +77,7 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n }\n \n static struct test_cmd cmds[] = {\n+\t{ \"check-name\", cmd__submodule_check_name },\n \t{ \"is-active\", cmd__submodule_is_active },\n };\n \ndiff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh\nindex 41706c1c9ff..2c24f120da3 100755\n--- a/t/t7450-bad-git-dotfiles.sh\n+++ b/t/t7450-bad-git-dotfiles.sh\n@@ -21,7 +21,7 @@ test_expect_success 'check names' '\n \tvalid/with/paths\n \tEOF\n \n-\tgit submodule--helper check-name >actual <<-\\EOF &&\n+\ttest-tool submodule check-name >actual <<-\\EOF &&\n \tvalid\n \tvalid/with/paths\n \n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461694","messageId":"patch-v3-08.32-03c8383b8e7-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 08/32] submodule--helper: move \"resolve-relative-url-test\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:17Z","receivedAt":"2022-08-21T13:58:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As its name suggests the \"resolve-relative-url-test\" has never been\nused outside of the test suite, see 63e95beb085 (submodule: port\nresolve_relative_url from shell to C, 2016-04-15) for its original\naddition.\n\nPerhaps it would make sense to drop this code entirely, as we feel\nthat we've got enough indirect test coverage, but let's leave that\nquestion to a possible follow-up change. For now let's keep the test\ncoverage this gives us.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 23 --------------------\n t/helper/test-submodule.c   | 42 +++++++++++++++++++++++++++++++++++++\n t/t0060-path-utils.sh       |  2 +-\n 3 files changed, 43 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e8458567976..7e2986902dd 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -96,28 +96,6 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n \treturn resolved_url;\n }\n \n-static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remoteurl, *res;\n-\tconst char *up_path, *url;\n-\n-\tif (argc != 4)\n-\t\tdie(\"resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>\");\n-\n-\tup_path = argv[1];\n-\tremoteurl = xstrdup(argv[2]);\n-\turl = argv[3];\n-\n-\tif (!strcmp(up_path, \"(null)\"))\n-\t\tup_path = NULL;\n-\n-\tres = relative_url(remoteurl, url, up_path);\n-\tputs(res);\n-\tfree(res);\n-\tfree(remoteurl);\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 {\n@@ -3276,7 +3254,6 @@ static struct cmd_struct commands[] = {\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n-\t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, 0},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nindex 9f0eb440192..e0e0c53d386 100644\n--- a/t/helper/test-submodule.c\n+++ b/t/helper/test-submodule.c\n@@ -2,6 +2,7 @@\n #include \"test-tool-utils.h\"\n #include \"cache.h\"\n #include \"parse-options.h\"\n+#include \"remote.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n \n@@ -19,9 +20,17 @@ static const char *submodule_is_active_usage[] = {\n \tNULL\n };\n \n+#define TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE \\\n+\t\"test-tool submodule resolve-relative-url <up_path> <remoteurl> <url>\"\n+static const char *submodule_resolve_relative_url_usage[] = {\n+\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n+\tNULL,\n+};\n+\n static const char *submodule_usage[] = {\n \tTEST_TOOL_CHECK_NAME_USAGE,\n \tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n \tNULL\n };\n \n@@ -76,9 +85,42 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n \treturn !is_submodule_active(the_repository, argv[0]);\n }\n \n+static int resolve_relative_url(int argc, const char **argv)\n+{\n+\tchar *remoteurl, *res;\n+\tconst char *up_path, *url;\n+\n+\tup_path = argv[0];\n+\tremoteurl = xstrdup(argv[1]);\n+\turl = argv[2];\n+\n+\tif (!strcmp(up_path, \"(null)\"))\n+\t\tup_path = NULL;\n+\n+\tres = relative_url(remoteurl, url, up_path);\n+\tputs(res);\n+\tfree(res);\n+\tfree(remoteurl);\n+\treturn 0;\n+}\n+\n+static int cmd__submodule_resolve_relative_url(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_resolve_relative_url_usage, 0);\n+\tif (argc != 3)\n+\t\tusage_with_options(submodule_resolve_relative_url_usage, options);\n+\n+\treturn resolve_relative_url(argc, argv);\n+}\n+\n static struct test_cmd cmds[] = {\n \t{ \"check-name\", cmd__submodule_check_name },\n \t{ \"is-active\", cmd__submodule_is_active },\n+\t{ \"resolve-relative-url\", cmd__submodule_resolve_relative_url},\n };\n \n int cmd__submodule(int argc, const char **argv)\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 1f2007e62b7..68e29c904a6 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -22,7 +22,7 @@ relative_path() {\n \n test_submodule_relative_url() {\n \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n-\t\tactual=\\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&\n+\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n \t\ttest \\\"\\$actual\\\" = '$4'\n \t\"\n }\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461695","messageId":"patch-v3-09.32-b1eaa6a796b-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 09/32] submodule--helper style: don't separate declared variables with \\n\\n","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:18Z","receivedAt":"2022-08-21T13:58:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The usual style in the codebase is to separate declared variables with\na single newline, not two, let's adjust this code to conform to\nthat. This makes the eventual addition of various \"int ret\" variables\nmore consistent.\n\nIn doing this the comment added in 2964d6e5e1e (submodule: port\nsubcommand 'set-branch' from shell to C, 2020-06-02) might become\nambiguous to some, although it should be clear what it's referring to,\nlet's move it above the 'OPT_NOOP_NOARG('q', \"quiet\")' to make that\nclearer.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 33 +++++----------------------------\n 1 file changed, 5 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7e2986902dd..02552410679 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -368,14 +368,12 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tstruct foreach_cb info = FOREACH_CB_INIT;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n-\n \tstruct option module_foreach_options[] = {\n \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n \t\t\t N_(\"recurse into nested submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule foreach [--quiet] [--recursive] [--] <command>\"),\n \t\tNULL\n@@ -504,12 +502,10 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\n \tstruct option module_init_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for initializing a submodule\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule init [<options>] [<path>]\"),\n \t\tNULL\n@@ -682,14 +678,12 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\n \tstruct option module_status_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule status [--quiet] [--cached] [--recursive] [<path>...]\"),\n \t\tNULL\n@@ -1085,7 +1079,6 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \tenum diff_cmd diff_cmd = DIFF_INDEX;\n \tstruct object_id head_oid;\n \tint ret;\n-\n \tstruct option module_summary_options[] = {\n \t\tOPT_BOOL(0, \"cached\", &cached,\n \t\t\t N_(\"use the commit stored in the index instead of the submodule HEAD\")),\n@@ -1097,7 +1090,6 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \t\t\t     N_(\"limit the summary size\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule summary [<options>] [<commit>] [--] [<path>]\"),\n \t\tNULL\n@@ -1254,14 +1246,12 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n \tint recursive = 0;\n-\n \tstruct option module_sync_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n \t\tOPT_BOOL(0, \"recursive\", &recursive,\n \t\t\tN_(\"recurse into nested submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule sync [--quiet] [--recursive] [<path>]\"),\n \t\tNULL\n@@ -1393,14 +1383,12 @@ static int module_deinit(int argc, const char **argv, const char *prefix)\n \tint quiet = 0;\n \tint force = 0;\n \tint all = 0;\n-\n \tstruct option module_deinit_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT__FORCE(&force, N_(\"remove submodule working trees even if they contain local changes\"), 0),\n \t\tOPT_BOOL(0, \"all\", &all, N_(\"unregister all submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]\"),\n \t\tNULL\n@@ -1669,7 +1657,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options;\n-\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1701,7 +1688,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tOPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule--helper clone [--prefix=<path>] [--quiet] \"\n \t\t   \"[--reference <repository>] [--name <name>] [--depth <depth>] \"\n@@ -2489,7 +2475,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options;\n \tint ret;\n-\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@@ -2533,7 +2518,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\tOPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule [--quiet] update\"\n \t\t\" [--init [--filter=<filter-spec>]] [--remote]\"\n@@ -2682,7 +2666,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tunsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;\n-\n \tstruct option embed_gitdir_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n@@ -2691,7 +2674,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \t\t\tABSORB_GITDIR_RECURSE_SUBMODULES),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule absorbgitdirs [<options>] [<path>...]\"),\n \t\tNULL\n@@ -2715,7 +2697,6 @@ static int module_config(int argc, const char **argv, const char *prefix)\n \t\tCHECK_WRITEABLE = 1,\n \t\tDO_UNSET = 2\n \t} command = 0;\n-\n \tstruct option module_config_options[] = {\n \t\tOPT_CMDMODE(0, \"check-writeable\", &command,\n \t\t\t    N_(\"check if it is safe to write to the .gitmodules file\"),\n@@ -2761,7 +2742,6 @@ static int module_set_url(int argc, const char **argv, const char *prefix)\n \tconst char *newurl;\n \tconst char *path;\n \tchar *config_name;\n-\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for setting url of a submodule\")),\n \t\tOPT_END()\n@@ -2792,13 +2772,13 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \tconst char *opt_branch = NULL;\n \tconst char *path;\n \tchar *config_name;\n-\n-\t/*\n-\t * We accept the `quiet` option for uniformity across subcommands,\n-\t * though there is nothing to make less verbose in this subcommand.\n-\t */\n \tstruct option options[] = {\n+\t\t/*\n+\t\t * We accept the `quiet` option for uniformity across subcommands,\n+\t\t * though there is nothing to make less verbose in this subcommand.\n+\t\t */\n \t\tOPT_NOOP_NOARG('q', \"quiet\"),\n+\n \t\tOPT_BOOL('d', \"default\", &opt_default,\n \t\t\tN_(\"set the default tracking branch to master\")),\n \t\tOPT_STRING('b', \"branch\", &opt_branch, N_(\"branch\"),\n@@ -2833,7 +2813,6 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)\n {\n \tenum branch_track track;\n \tint quiet = 0, force = 0, reflog = 0, dry_run = 0;\n-\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"print only error messages\")),\n \t\tOPT__FORCE(&force, N_(\"force creation\"), 0),\n@@ -3132,7 +3111,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \tint force = 0, quiet = 0, progress = 0, dissociate = 0;\n \tstruct add_data add_data = ADD_DATA_INIT;\n \tchar *to_free = NULL;\n-\n \tstruct option options[] = {\n \t\tOPT_STRING('b', \"branch\", &add_data.branch, N_(\"branch\"),\n \t\t\t   N_(\"branch of repository to add as submodule\")),\n@@ -3149,7 +3127,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \t\tOPT_INTEGER(0, \"depth\", &add_data.depth, N_(\"depth for shallow clones\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule add [<options>] [--] <repository> [<path>]\"),\n \t\tNULL\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461696","messageId":"patch-v3-10.32-fd7fbe08536-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 10/32] submodule--helper style: add \\n\\n after variable declarations","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:19Z","receivedAt":"2022-08-21T13:59:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Since the preceding commit fixed style issues with \\n\\n among the\ndeclared variables let's fix the minor stylistic issues with those\nvariables not being consistently followed by a \\n\\n.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 25 +++++++++++++++++++++++--\n 1 file changed, 23 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 02552410679..a492ea3cfed 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -167,6 +167,7 @@ static int module_list_compute(int argc, const char **argv,\n {\n \tint i, result = 0;\n \tchar *ps_matched = NULL;\n+\n \tparse_pathspec(pathspec, 0,\n \t\t       PATHSPEC_PREFER_FULL,\n \t\t       prefix, argv);\n@@ -248,6 +249,7 @@ static void for_each_listed_submodule(const struct module_list *list,\n \t\t\t\t      each_submodule_fn fn, void *cb_data)\n {\n \tint i;\n+\n \tfor (i = 0; i < list->nr; i++)\n \t\tfn(list->entries[i], cb_data);\n }\n@@ -267,7 +269,6 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tstruct foreach_cb *info = cb_data;\n \tconst char *path = list_item->name;\n \tconst struct object_id *ce_oid = &list_item->oid;\n-\n \tconst struct submodule *sub;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *displaypath;\n@@ -456,6 +457,7 @@ static void init_submodule(const char *path, const char *prefix,\n \t\tif (starts_with_dot_dot_slash(url) ||\n \t\t    starts_with_dot_slash(url)) {\n \t\t\tchar *oldurl = url;\n+\n \t\t\turl = resolve_relative_url(oldurl, NULL, 0);\n \t\t\tfree(oldurl);\n \t\t}\n@@ -493,6 +495,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+\n \tinit_submodule(list_item->name, info->prefix, info->flags);\n }\n \n@@ -562,6 +565,7 @@ static int handle_submodule_head_ref(const char *refname,\n \t\t\t\t     void *cb_data)\n {\n \tstruct object_id *output = cb_data;\n+\n \tif (oid)\n \t\toidcpy(output, oid);\n \n@@ -668,6 +672,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,\n \t\t\t\tvoid *cb_data)\n {\n \tstruct status_cb *info = cb_data;\n+\n \tstatus_submodule(list_item->name, &list_item->oid, list_item->ce_flags,\n \t\t\t info->prefix, info->flags);\n }\n@@ -820,6 +825,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n \tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n \t\t\tstruct ref_store *refs = get_submodule_ref_store(p->sm_path);\n+\n \t\t\tif (refs)\n \t\t\t\trefs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);\n \t\t} else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {\n@@ -1161,6 +1167,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tif (starts_with_dot_dot_slash(sub->url) ||\n \t\t    starts_with_dot_slash(sub->url)) {\n \t\t\tchar *up_path = get_up_path(path);\n+\n \t\t\tsub_origin_url = resolve_relative_url(sub->url, up_path, 1);\n \t\t\tsuper_config_url = resolve_relative_url(sub->url, NULL, 1);\n \t\t\tfree(up_path);\n@@ -1236,6 +1243,7 @@ static void sync_submodule(const char *path, const char *prefix,\n static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct sync_cb *info = cb_data;\n+\n \tsync_submodule(list_item->name, info->prefix, info->flags);\n }\n \n@@ -1315,6 +1323,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \n \t\tif (!(flags & OPT_FORCE)) {\n \t\t\tstruct child_process cp_rm = CHILD_PROCESS_INIT;\n+\n \t\t\tcp_rm.git_cmd = 1;\n \t\t\tstrvec_pushl(&cp_rm.args, \"rm\", \"-qn\",\n \t\t\t\t     path, NULL);\n@@ -1351,6 +1360,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \t/* remove the .git/config entries (unless the user already did it) */\n \tif (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {\n \t\tchar *sub_key = xstrfmt(\"submodule.%s\", sub->name);\n+\n \t\t/*\n \t\t * remove the whole section so we have a clean state when\n \t\t * the user later decides to init this submodule again\n@@ -1588,6 +1598,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tstrvec_pushl(&cp.args, \"--depth\", clone_data->depth, NULL);\n \t\tif (clone_data->reference.nr) {\n \t\t\tstruct string_list_item *item;\n+\n \t\t\tfor_each_string_list_item(item, &clone_data->reference)\n \t\t\t\tstrvec_pushl(&cp.args, \"--reference\",\n \t\t\t\t\t     item->string, NULL);\n@@ -1938,6 +1949,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tstrvec_pushl(&child->args, \"--url\", url, NULL);\n \tif (suc->update_data->references.nr) {\n \t\tstruct string_list_item *item;\n+\n \t\tfor_each_string_list_item(item, &suc->update_data->references)\n \t\t\tstrvec_pushl(&child->args, \"--reference\", item->string, NULL);\n \t}\n@@ -1970,6 +1982,7 @@ static int update_clone_get_next_task(struct child_process *child,\n \t\tce = suc->update_data->list.entries[suc->current];\n \t\tif (prepare_to_clone_next_submodule(ce, child, suc, err)) {\n \t\t\tint *p = xmalloc(sizeof(*p));\n+\n \t\t\t*p = suc->current;\n \t\t\t*idx_task_cb = p;\n \t\t\tsuc->current++;\n@@ -1985,6 +1998,7 @@ static int update_clone_get_next_task(struct child_process *child,\n \tindex = suc->current - suc->update_data->list.nr;\n \tif (index < suc->failed_clones_nr) {\n \t\tint *p;\n+\n \t\tce = suc->failed_clones[index];\n \t\tif (!prepare_to_clone_next_submodule(ce, child, suc, err)) {\n \t\t\tsuc->current ++;\n@@ -2008,6 +2022,7 @@ static int update_clone_start_failure(struct strbuf *err,\n \t\t\t\t      void *idx_task_cb)\n {\n \tstruct submodule_update_clone *suc = suc_cb;\n+\n \tsuc->quickstop = 1;\n \treturn 1;\n }\n@@ -2019,9 +2034,9 @@ static int update_clone_task_finished(int result,\n {\n \tconst struct cache_entry *ce;\n \tstruct submodule_update_clone *suc = suc_cb;\n-\n \tint *idxP = idx_task_cb;\n \tint idx = *idxP;\n+\n \tfree(idxP);\n \n \tif (!result)\n@@ -2054,6 +2069,7 @@ static int git_update_clone_config(const char *var, const char *value,\n \t\t\t\t   void *cb)\n {\n \tint *max_jobs = cb;\n+\n \tif (!strcmp(var, \"submodule.fetchjobs\"))\n \t\t*max_jobs = parse_submodule_fetchjobs(var, value);\n \treturn 0;\n@@ -2094,6 +2110,7 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \tif (oid) {\n \t\tchar *hex = oid_to_hex(oid);\n \t\tchar *remote = get_default_remote();\n+\n \t\tstrvec_pushl(&cp.args, remote, hex, NULL);\n \t\tfree(remote);\n \t}\n@@ -2343,6 +2360,7 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \n \tif (update_data->references.nr) {\n \t\tstruct string_list_item *item;\n+\n \t\tfor_each_string_list_item(item, &update_data->references)\n \t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n \t}\n@@ -2875,8 +2893,10 @@ static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)\n \tif (!capture_command(&cp_remote, &sb_remote_out, 0)) {\n \t\tchar *next_line;\n \t\tchar *line = sb_remote_out.buf;\n+\n \t\twhile ((next_line = strchr(line, '\\n')) != NULL) {\n \t\t\tsize_t len = next_line - line;\n+\n \t\t\tif (strip_suffix_mem(line, &len, \" (fetch)\"))\n \t\t\t\tstrbuf_addf(msg, \"  %.*s\\n\", (int)len, line);\n \t\t\tline = next_line + 1;\n@@ -3183,6 +3203,7 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \t\tint exit_code = -1;\n \t\tstruct strbuf sb = STRBUF_INIT;\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n \t\tcp.git_cmd = 1;\n \t\tcp.no_stdout = 1;\n \t\tstrvec_pushl(&cp.args, \"add\", \"--dry-run\", \"--ignore-missing\",\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461697","messageId":"patch-v3-11.32-356f07db436-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 11/32] submodule--helper: replace memset() with { 0 }-initialization","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:20Z","receivedAt":"2022-08-21T13:59:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use the less verbose { 0 }-initialization syntax rather than memset()\nin builtin/submodule--helper.c, this doesn't make a difference in\nterms of behavior, but as we're about to modify adjacent code makes\nthis more consistent, and lets us avoid worrying about when the\nmemset() happens v.s. a \"goto cleanup\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 6 ++----\n 1 file changed, 2 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a492ea3cfed..7eb9fb2f00f 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1667,7 +1667,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n {\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n-\tstruct list_objects_filter_options filter_options;\n+\tstruct list_objects_filter_options filter_options = { 0 };\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1707,7 +1707,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tNULL\n \t};\n \n-\tmemset(&filter_options, 0, sizeof(filter_options));\n \targc = parse_options(argc, argv, prefix, module_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n@@ -2491,7 +2490,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n {\n \tstruct pathspec pathspec;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n-\tstruct list_objects_filter_options filter_options;\n+\tstruct list_objects_filter_options filter_options = { 0 };\n \tint ret;\n \tstruct option module_update_options[] = {\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n@@ -2549,7 +2548,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n \tgit_config(git_update_clone_config, &opt.max_jobs);\n \n-\tmemset(&filter_options, 0, sizeof(filter_options));\n \targc = parse_options(argc, argv, prefix, module_update_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461698","messageId":"patch-v3-13.32-f2f412f50c1-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 13/32] submodule--helper: move \"sb\" in clone_submodule() to its own scope","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:22Z","receivedAt":"2022-08-21T13:59:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor the only remaining use of a \"struct strbuf sb\" in\nclone_submodule() to live in its own scope. This makes the code\nclearer by limiting its lifetime.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 21 ++++++++++++++-------\n 1 file changed, 14 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c7833bae81e..2f1f0e1bf34 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1560,16 +1560,24 @@ static void prepare_possible_alternates(const char *sm_name,\n \tfree(error_strategy);\n }\n \n-static int clone_submodule(struct module_clone_data *clone_data)\n+static char *clone_submodule_sm_gitdir(const char *name)\n {\n-\tchar *p, *sm_gitdir;\n-\tchar *sm_alternate = NULL, *error_strategy = NULL;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tchar *sm_gitdir;\n \n-\tsubmodule_name_to_gitdir(&sb, the_repository, clone_data->name);\n+\tsubmodule_name_to_gitdir(&sb, the_repository, name);\n \tsm_gitdir = absolute_pathdup(sb.buf);\n-\tstrbuf_reset(&sb);\n+\tstrbuf_release(&sb);\n+\n+\treturn sm_gitdir;\n+}\n+\n+static int clone_submodule(struct module_clone_data *clone_data)\n+{\n+\tchar *p;\n+\tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n+\tchar *sm_alternate = NULL, *error_strategy = NULL;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \n \tif (!is_absolute_path(clone_data->path))\n \t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n@@ -1658,7 +1666,6 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \tfree(sm_alternate);\n \tfree(error_strategy);\n \n-\tstrbuf_release(&sb);\n \tfree(sm_gitdir);\n \tfree(p);\n \treturn 0;\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461699","messageId":"patch-v3-12.32-241ac5c7eee-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 12/32] submodule--helper: use xstrfmt() in clone_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:21Z","receivedAt":"2022-08-21T13:59:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use xstrfmt() in clone_submodule() instead of a \"struct strbuf\" in two\ncases where we weren't getting anything out of using the \"struct\nstrbuf\".\n\nThis changes code that was was added along with other uses of \"struct\nstrbuf\" in this function in ee8838d1577 (submodule: rewrite\n`module_clone` shell function in C, 2015-09-08).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 17 +++++++++--------\n 1 file changed, 9 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7eb9fb2f00f..c7833bae81e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1571,12 +1571,11 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \tsm_gitdir = absolute_pathdup(sb.buf);\n \tstrbuf_reset(&sb);\n \n-\tif (!is_absolute_path(clone_data->path)) {\n-\t\tstrbuf_addf(&sb, \"%s/%s\", get_git_work_tree(), clone_data->path);\n-\t\tclone_data->path = strbuf_detach(&sb, NULL);\n-\t} else {\n+\tif (!is_absolute_path(clone_data->path))\n+\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n+\t\t\t\t\t   clone_data->path);\n+\telse\n \t\tclone_data->path = xstrdup(clone_data->path);\n-\t}\n \n \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n@@ -1628,14 +1627,16 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n \t\t\t    clone_data->url, clone_data->path);\n \t} else {\n+\t\tchar *path;\n+\n \t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n \t\t    !is_empty_dir(clone_data->path))\n \t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n \t\tif (safe_create_leading_directories_const(clone_data->path) < 0)\n \t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n-\t\tstrbuf_addf(&sb, \"%s/index\", sm_gitdir);\n-\t\tunlink_or_warn(sb.buf);\n-\t\tstrbuf_reset(&sb);\n+\t\tpath = xstrfmt(\"%s/index\", sm_gitdir);\n+\t\tunlink_or_warn(path);\n+\t\tfree(path);\n \t}\n \n \tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461700","messageId":"patch-v3-14.32-ad7848067a9-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 14/32] submodule--helper: add \"const\" to passed \"module_clone_data\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:23Z","receivedAt":"2022-08-21T13:59:20Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add \"const\" to the \"struct module_clone_data\" that we pass to\nclone_submodule(), which makes the ownership clear, and stops us from\nclobbering the \"clone_data->path\".\n\nWe still need to add to the \"reference\" member, which is a \"struct\nstring_list\". Let's do this by having clone_submodule() create its\nown, and copy the contents over, allowing us to pass it as a\nseparate parameter.\n\nThis new \"struct string_list\" still leaks memory, just as the \"struct\nmodule_clone_data\" did before. let's not fix that for now, to fix that\nwe'll need to add some \"goto cleanup\" to the relevant code. That will\neventually be done in follow-up commits, this change makes it easier\nto fix the memory leak.\n\nThe scope of the new \"reference\" variable in add_submodule() could be\nnarrowed to the \"else\" block, but as we'll eventually free it with a\n\"goto cleanup\" let's declare it at the start of the function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 49 ++++++++++++++++++++-----------------\n 1 file changed, 26 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 2f1f0e1bf34..d243c3ddfd3 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1437,7 +1437,6 @@ struct module_clone_data {\n \tconst char *url;\n \tconst char *depth;\n \tstruct list_objects_filter_options *filter_options;\n-\tstruct string_list reference;\n \tunsigned int quiet: 1;\n \tunsigned int progress: 1;\n \tunsigned int dissociate: 1;\n@@ -1445,7 +1444,6 @@ struct module_clone_data {\n \tint single_branch;\n };\n #define MODULE_CLONE_DATA_INIT { \\\n-\t.reference = STRING_LIST_INIT_NODUP, \\\n \t.single_branch = -1, \\\n }\n \n@@ -1572,18 +1570,20 @@ static char *clone_submodule_sm_gitdir(const char *name)\n \treturn sm_gitdir;\n }\n \n-static int clone_submodule(struct module_clone_data *clone_data)\n+static int clone_submodule(const struct module_clone_data *clone_data,\n+\t\t\t   struct string_list *reference)\n {\n \tchar *p;\n \tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n \tchar *sm_alternate = NULL, *error_strategy = NULL;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tconst char *clone_data_path;\n \n \tif (!is_absolute_path(clone_data->path))\n-\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n-\t\t\t\t\t   clone_data->path);\n+\t\tclone_data_path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n+\t\t\t\t\t  clone_data->path);\n \telse\n-\t\tclone_data->path = xstrdup(clone_data->path);\n+\t\tclone_data_path = xstrdup(clone_data->path);\n \n \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n@@ -1593,7 +1593,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\tif (safe_create_leading_directories_const(sm_gitdir) < 0)\n \t\t\tdie(_(\"could not create directory '%s'\"), sm_gitdir);\n \n-\t\tprepare_possible_alternates(clone_data->name, &clone_data->reference);\n+\t\tprepare_possible_alternates(clone_data->name, reference);\n \n \t\tstrvec_push(&cp.args, \"clone\");\n \t\tstrvec_push(&cp.args, \"--no-checkout\");\n@@ -1603,10 +1603,10 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tstrvec_push(&cp.args, \"--progress\");\n \t\tif (clone_data->depth && *(clone_data->depth))\n \t\t\tstrvec_pushl(&cp.args, \"--depth\", clone_data->depth, NULL);\n-\t\tif (clone_data->reference.nr) {\n+\t\tif (reference->nr) {\n \t\t\tstruct string_list_item *item;\n \n-\t\t\tfor_each_string_list_item(item, &clone_data->reference)\n+\t\t\tfor_each_string_list_item(item, reference)\n \t\t\t\tstrvec_pushl(&cp.args, \"--reference\",\n \t\t\t\t\t     item->string, NULL);\n \t\t}\n@@ -1625,7 +1625,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \n \t\tstrvec_push(&cp.args, \"--\");\n \t\tstrvec_push(&cp.args, clone_data->url);\n-\t\tstrvec_push(&cp.args, clone_data->path);\n+\t\tstrvec_push(&cp.args, clone_data_path);\n \n \t\tcp.git_cmd = 1;\n \t\tprepare_submodule_repo_env(&cp.env);\n@@ -1633,25 +1633,25 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \n \t\tif(run_command(&cp))\n \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n-\t\t\t    clone_data->url, clone_data->path);\n+\t\t\t    clone_data->url, clone_data_path);\n \t} else {\n \t\tchar *path;\n \n-\t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n-\t\t    !is_empty_dir(clone_data->path))\n-\t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n-\t\tif (safe_create_leading_directories_const(clone_data->path) < 0)\n-\t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n+\t\tif (clone_data->require_init && !access(clone_data_path, X_OK) &&\n+\t\t    !is_empty_dir(clone_data_path))\n+\t\t\tdie(_(\"directory not empty: '%s'\"), clone_data_path);\n+\t\tif (safe_create_leading_directories_const(clone_data_path) < 0)\n+\t\t\tdie(_(\"could not create directory '%s'\"), clone_data_path);\n \t\tpath = xstrfmt(\"%s/index\", sm_gitdir);\n \t\tunlink_or_warn(path);\n \t\tfree(path);\n \t}\n \n-\tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n+\tconnect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);\n \n-\tp = git_pathdup_submodule(clone_data->path, \"config\");\n+\tp = git_pathdup_submodule(clone_data_path, \"config\");\n \tif (!p)\n-\t\tdie(_(\"could not get submodule directory for '%s'\"), clone_data->path);\n+\t\tdie(_(\"could not get submodule directory for '%s'\"), clone_data_path);\n \n \t/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */\n \tgit_config_get_string(\"submodule.alternateLocation\", &sm_alternate);\n@@ -1676,6 +1676,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options = { 0 };\n+\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1689,7 +1690,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING(0, \"url\", &clone_data.url,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"url where to clone the submodule from\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &clone_data.reference,\n+\t\tOPT_STRING_LIST(0, \"reference\", &reference,\n \t\t\t   N_(\"repo\"),\n \t\t\t   N_(\"reference repository\")),\n \t\tOPT_BOOL(0, \"dissociate\", &dissociate,\n@@ -1728,7 +1729,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_submodule_helper_usage,\n \t\t\t\t   module_clone_options);\n \n-\tclone_submodule(&clone_data);\n+\tclone_submodule(&clone_data, &reference);\n \tlist_objects_filter_release(&filter_options);\n \treturn 0;\n }\n@@ -2916,6 +2917,7 @@ static int add_submodule(const struct add_data *add_data)\n {\n \tchar *submod_gitdir_path;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n+\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n \n \t/* perhaps the path already exists and is already a git repo, else clone it */\n \tif (is_directory(add_data->sm_path)) {\n@@ -2932,6 +2934,7 @@ static int add_submodule(const struct add_data *add_data)\n \t\tfree(submod_gitdir_path);\n \t} else {\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n \t\tsubmod_gitdir_path = xstrfmt(\".git/modules/%s\", add_data->sm_name);\n \n \t\tif (is_directory(submod_gitdir_path)) {\n@@ -2971,13 +2974,13 @@ static int add_submodule(const struct add_data *add_data)\n \t\tclone_data.quiet = add_data->quiet;\n \t\tclone_data.progress = add_data->progress;\n \t\tif (add_data->reference_path)\n-\t\t\tstring_list_append(&clone_data.reference,\n+\t\t\tstring_list_append(&reference,\n \t\t\t\t\t   xstrdup(add_data->reference_path));\n \t\tclone_data.dissociate = add_data->dissociate;\n \t\tif (add_data->depth >= 0)\n \t\t\tclone_data.depth = xstrfmt(\"%d\", add_data->depth);\n \n-\t\tif (clone_submodule(&clone_data))\n+\t\tif (clone_submodule(&clone_data, &reference))\n \t\t\treturn -1;\n \n \t\tprepare_submodule_repo_env(&cp.env);\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461701","messageId":"patch-v3-15.32-ab283479b92-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 15/32] submodule--helper: add \"const\" to copy of \"update_data\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:24Z","receivedAt":"2022-08-21T13:59:22Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nAdd a \"const\" to the copy of \"struct update_data\" that's tracked by\nthe \"struct submodule_update_clone\", as it neither owns nor modifies\nit.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex d243c3ddfd3..829a57ce8a9 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1780,7 +1780,7 @@ struct submodule_update_clone {\n \tint current;\n \n \t/* configuration parameters which are passed on to the children */\n-\tstruct update_data *update_data;\n+\tconst struct update_data *update_data;\n \n \t/* to be consumed by update_submodule() */\n \tstruct update_clone_data *update_clone;\n@@ -1865,7 +1865,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tconst char *update_string;\n \tenum submodule_update_type update_type;\n \tchar *key;\n-\tstruct update_data *ud = suc->update_data;\n+\tconst struct update_data *ud = suc->update_data;\n \tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461702","messageId":"patch-v3-16.32-ab0fd2c60f0-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 16/32] submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:25Z","receivedAt":"2022-08-21T13:59:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nRefactor code added in e83e3333b57 (submodule: port submodule\nsubcommand 'summary' from shell to C, 2020-08-13) so that \"errmsg\" and\n\"errmsg_str\" are folded into one. The distinction between the empty\nstring and NULL is something that's tested for by\ne.g. \"t/t7401-submodule-summary.sh\".\n\nThis is in preparation for fixing a memory leak the \"struct strbuf\" in\nthe pre-image.\n\nLet's also pass a \"const char *\" to print_submodule_summary(), as it\nshould not be modifying the \"errmsg\".\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 14 ++++++--------\n 1 file changed, 6 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 829a57ce8a9..a694b18b55e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -761,7 +761,7 @@ static char *verify_submodule_committish(const char *sm_path,\n \treturn strbuf_detach(&result, NULL);\n }\n \n-static void print_submodule_summary(struct summary_cb *info, char *errmsg,\n+static void print_submodule_summary(struct summary_cb *info, const char *errmsg,\n \t\t\t\t    int total_commits, const char *displaypath,\n \t\t\t\t    const char *src_abbrev, const char *dst_abbrev,\n \t\t\t\t    struct module_cb *p)\n@@ -819,7 +819,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n {\n \tchar *displaypath, *src_abbrev = NULL, *dst_abbrev;\n \tint missing_src = 0, missing_dst = 0;\n-\tchar *errmsg = NULL;\n+\tstruct strbuf errmsg = STRBUF_INIT;\n \tint total_commits = -1;\n \n \tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n@@ -920,23 +920,21 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t\t * submodule, i.e., deleted or changed to blob\n \t\t */\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n-\t\t\tstruct strbuf errmsg_str = STRBUF_INIT;\n \t\t\tif (missing_src && missing_dst) {\n-\t\t\t\tstrbuf_addf(&errmsg_str, \"  Warn: %s doesn't contain commits %s and %s\\n\",\n+\t\t\t\tstrbuf_addf(&errmsg, \"  Warn: %s doesn't contain commits %s and %s\\n\",\n \t\t\t\t\t    displaypath, oid_to_hex(&p->oid_src),\n \t\t\t\t\t    oid_to_hex(&p->oid_dst));\n \t\t\t} else {\n-\t\t\t\tstrbuf_addf(&errmsg_str, \"  Warn: %s doesn't contain commit %s\\n\",\n+\t\t\t\tstrbuf_addf(&errmsg, \"  Warn: %s doesn't contain commit %s\\n\",\n \t\t\t\t\t    displaypath, missing_src ?\n \t\t\t\t\t    oid_to_hex(&p->oid_src) :\n \t\t\t\t\t    oid_to_hex(&p->oid_dst));\n \t\t\t}\n-\t\t\terrmsg = strbuf_detach(&errmsg_str, NULL);\n \t\t}\n \t}\n \n-\tprint_submodule_summary(info, errmsg, total_commits,\n-\t\t\t\tdisplaypath, src_abbrev,\n+\tprint_submodule_summary(info, errmsg.len ? errmsg.buf : NULL,\n+\t\t\t\ttotal_commits, displaypath, src_abbrev,\n \t\t\t\tdst_abbrev, p);\n \n \tfree(displaypath);\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461703","messageId":"patch-v3-17.32-fa2417c7a17-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 17/32] submodule--helper: don't redundantly check \"else if (res)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:26Z","receivedAt":"2022-08-21T13:59:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"res\" variable must be true at this point in update_submodule(),\nas just a few lines above this we've unconditionally:\n\n\tif (!res)\n\t\treturn 0;\n\nSo we don't need to guard the \"return 1\" with an \"else if (res)\", we\nan return unconditionally at this point. See b3c5f5cb048 (submodule:\nmove core cmd_update() logic to C, 2022-03-15) for the initial\nintroduction of this code, this check of \"res\" has always been\nredundant.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a694b18b55e..a9808224f01 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2446,8 +2446,7 @@ static int update_submodule(struct update_data *update_data)\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\treturn 1;\n \t}\n \n \treturn 0;\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461704","messageId":"patch-v3-19.32-92e17c37839-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 19/32] submodule--helper: return \"ret\", not \"1\" from update_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:28Z","receivedAt":"2022-08-21T13:59:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend the update_submodule() function to return the failing \"ret\" on\nerror, instead of overriding it with \"1\".\n\nThis code was added in b3c5f5cb048 (submodule: move core cmd_update()\nlogic to C, 2022-03-15), and this change ends up not making a\ndifference as this function is only called in update_submodules(). If\nwe return non-zero here we'll always in turn return \"1\" in\nmodule_update().\n\nBut if we didn't do that and returned any other non-zero exit code in\nupdate_submodules() we'd fail the test that's being amended\nhere. We're still testing the status quo here.\n\nThis change makes subsequent refactoring of update_submodule() easier,\nas we'll no longer need to worry about clobbering the \"ret\" we get\nfrom the run_command().\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 2 +-\n t/t7406-submodule-update.sh | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex fed92585a02..61468237af2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2446,7 +2446,7 @@ static int update_submodule(struct update_data *update_data)\n \t\t\t    update_data->displaypath);\n \t\tif (ret == 128)\n \t\t\texit(ret);\n-\t\treturn 1;\n+\t\treturn ret;\n \t}\n \n \treturn 0;\ndiff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh\nindex 6cc07460dd2..c5f5dbe55e0 100755\n--- a/t/t7406-submodule-update.sh\n+++ b/t/t7406-submodule-update.sh\n@@ -769,7 +769,7 @@ test_expect_success 'submodule update continues after recursive checkout error'\n \t   echo \"\" > file\n \t  )\n \t ) &&\n-\t test_must_fail git submodule update --recursive &&\n+\t test_expect_code 1 git submodule update --recursive &&\n \t (cd submodule2 &&\n \t  git rev-parse --verify HEAD >../actual\n \t ) &&\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461705","messageId":"patch-v3-18.32-be1ffbf2e26-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 18/32] submodule--helper: rename \"int res\" to \"int ret\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:27Z","receivedAt":"2022-08-21T13:59:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Rename the \"res\" variable added in b3c5f5cb048 (submodule: move core\ncmd_update() logic to C, 2022-03-15) to \"ret\", which is the convention\nin the rest of this file.\n\nEventual follow-up commits will change the code in update_submodule()\nto a \"goto cleanup\" pattern, let's have the post image look consistent\nwith the rest. For update_submodules() let's also use a \"ret\" for\nconsistency, that use was also added in b3c5f5cb048. We'll be\nmodifying that codepath in subsequent commits.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a9808224f01..fed92585a02 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2427,7 +2427,7 @@ static int update_submodule(struct update_data *update_data)\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+\t\tint ret;\n \n \t\tnext.prefix = NULL;\n \t\toidcpy(&next.oid, null_oid());\n@@ -2439,13 +2439,13 @@ static int update_submodule(struct update_data *update_data)\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\tret = run_command(&cp);\n+\t\tif (!ret)\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\tif (ret == 128)\n+\t\t\texit(ret);\n \t\treturn 1;\n \t}\n \n@@ -2454,7 +2454,7 @@ static int update_submodule(struct update_data *update_data)\n \n static int update_submodules(struct update_data *update_data)\n {\n-\tint i, res = 0;\n+\tint i, ret = 0;\n \tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n \n \tsuc.update_data = update_data;\n@@ -2472,7 +2472,7 @@ static int update_submodules(struct update_data *update_data)\n \t * - the listener can avoid doing any work if fetching failed.\n \t */\n \tif (suc.quickstop) {\n-\t\tres = 1;\n+\t\tret = 1;\n \t\tgoto cleanup;\n \t}\n \n@@ -2484,12 +2484,12 @@ static int update_submodules(struct update_data *update_data)\n \t\tupdate_data->sm_path = ucd.sub->path;\n \n \t\tif (update_submodule(update_data))\n-\t\t\tres = 1;\n+\t\t\tret = 1;\n \t}\n \n cleanup:\n \tstring_list_clear(&update_data->references, 0);\n-\treturn res;\n+\treturn ret;\n }\n \n static int module_update(int argc, const char **argv, const char *prefix)\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461706","messageId":"patch-v3-20.32-55e3ea5f9dd-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 20/32] submodule--helper: add missing braces to \"else\" arm","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:29Z","receivedAt":"2022-08-21T13:59:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add missing braces to an \"else\" arm in init_submodule(), this\nstylistic change makes this code conform to the CodingGuidelines, and\nmakes a subsequent commit smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 61468237af2..ebd3e118eb7 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -480,8 +480,9 @@ static void init_submodule(const char *path, const char *prefix,\n \t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n \t\t\t\tsub->name);\n \t\t\tupd = xstrdup(\"none\");\n-\t\t} else\n+\t\t} else {\n \t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n+\t\t}\n \n \t\tif (git_config_set_gently(sb.buf, upd))\n \t\t\tdie(_(\"Failed to register update mode for submodule path '%s'\"), displaypath);\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461707","messageId":"patch-v3-21.32-2bb45302392-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 21/32] submodule--helper: don't call submodule_strategy_to_string() in BUG()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:30Z","receivedAt":"2022-08-21T13:59:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Don't call submodule_strategy_to_string() in a BUG() message. These\ncalls added in c51f8f94e5b (submodule--helper: run update procedures\nfrom C, 2021-08-24) don't need the extra information\nsubmodule_strategy_to_string() gives us, as we'll never reach the\nSM_UPDATE_COMMAND case here.\n\nThat case is the only one where we'd get any information beyond the\nstraightforward number-to-string mapping.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex ebd3e118eb7..75bba8621b2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2158,8 +2158,8 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n+\t\t    ud->update_strategy.type);\n \t}\n \tstrvec_push(&cp.args, oid);\n \n@@ -2184,8 +2184,8 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n+\t\t\t    ud->update_strategy.type);\n \t\t}\n \t\tif (must_die_on_failure)\n \t\t\texit(128);\n@@ -2215,8 +2215,8 @@ static int run_update_command(struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n+\t\t    ud->update_strategy.type);\n \t}\n \n \treturn 0;\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461708","messageId":"patch-v3-22.32-0131c197427-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 22/32] submodule API: don't handle SM_..{UNSPECIFIED,COMMAND} in to_string()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:31Z","receivedAt":"2022-08-21T13:59:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the submodule_strategy_to_string() function added in\n3604242f080 (submodule: port init from shell to C, 2016-04-15) to\nreally return a \"const char *\". In the \"SM_UPDATE_COMMAND\" case it\nwould return a strbuf_detach().\n\nFurthermore, this function would return NULL on SM_UPDATE_UNSPECIFIED,\nso it wasn't safe to xstrdup() its return value in the general case,\nor to use it in a sprintf() format as the code removed in the\npreceding commit did.\n\nBut its callers would never call it with either SM_UPDATE_UNSPECIFIED\nor SM_UPDATE_COMMAND. Let's have its behavior reflect how its only\nuser expects it to behave, and BUG() out on the rest.\n\nBy doing this we can also stop needlessly xstrdup()-ing and free()-ing\nthe memory for the config we're setting. We can instead always use\nconstant strings. We can also use the *_tmp() variant of\ngit_config_get_string().\n\nLet's also rename this submodule_strategy_to_string() function to\nsubmodule_update_type_to_string(). Now that it's only tasked with\nreturning a string version of the \"enum submodule_update_type type\".\nBefore it would look at the \"command\" field in \"struct\nsubmodule_update_strategy\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 10 +++++-----\n submodule.c                 | 12 +++++-------\n submodule.h                 |  2 +-\n 3 files changed, 11 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 75bba8621b2..c83b0897740 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -418,7 +418,8 @@ static void init_submodule(const char *path, const char *prefix,\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tchar *upd = NULL, *url = NULL, *displaypath;\n+\tconst char *upd;\n+\tchar *url = NULL, *displaypath;\n \n \tdisplaypath = get_submodule_displaypath(path, prefix);\n \n@@ -474,14 +475,14 @@ static void init_submodule(const char *path, const char *prefix,\n \n \t/* Copy \"update\" setting when it is not set yet */\n \tstrbuf_addf(&sb, \"submodule.%s.update\", sub->name);\n-\tif (git_config_get_string(sb.buf, &upd) &&\n+\tif (git_config_get_string_tmp(sb.buf, &upd) &&\n \t    sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n \t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND) {\n \t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n \t\t\t\tsub->name);\n-\t\t\tupd = xstrdup(\"none\");\n+\t\t\tupd = \"none\";\n \t\t} else {\n-\t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n+\t\t\tupd = submodule_update_type_to_string(sub->update_strategy.type);\n \t\t}\n \n \t\tif (git_config_set_gently(sb.buf, upd))\n@@ -490,7 +491,6 @@ static void init_submodule(const char *path, const char *prefix,\n \tstrbuf_release(&sb);\n \tfree(displaypath);\n \tfree(url);\n-\tfree(upd);\n }\n \n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\ndiff --git a/submodule.c b/submodule.c\nindex 3fa5db3ecdf..1ebda30c506 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -415,10 +415,9 @@ int parse_submodule_update_strategy(const char *value,\n \treturn 0;\n }\n \n-const char *submodule_strategy_to_string(const struct submodule_update_strategy *s)\n+const char *submodule_update_type_to_string(enum submodule_update_type type)\n {\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tswitch (s->type) {\n+\tswitch (type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\treturn \"checkout\";\n \tcase SM_UPDATE_MERGE:\n@@ -428,12 +427,11 @@ const char *submodule_strategy_to_string(const struct submodule_update_strategy\n \tcase SM_UPDATE_NONE:\n \t\treturn \"none\";\n \tcase SM_UPDATE_UNSPECIFIED:\n-\t\treturn NULL;\n \tcase SM_UPDATE_COMMAND:\n-\t\tstrbuf_addf(&sb, \"!%s\", s->command);\n-\t\treturn strbuf_detach(&sb, NULL);\n+\t\tBUG(\"init_submodule() should handle type %d\", type);\n+\tdefault:\n+\t\tBUG(\"unexpected update strategy type: %d\", type);\n \t}\n-\treturn NULL;\n }\n \n void handle_ignore_submodules_arg(struct diff_options *diffopt,\ndiff --git a/submodule.h b/submodule.h\nindex bfaa9da1868..6a9fec6de11 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -72,7 +72,7 @@ void die_path_inside_submodule(struct index_state *istate,\n enum submodule_update_type parse_submodule_update_type(const char *value);\n int parse_submodule_update_strategy(const char *value,\n \t\t\t\t    struct submodule_update_strategy *dst);\n-const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);\n+const char *submodule_update_type_to_string(enum submodule_update_type type);\n void handle_ignore_submodules_arg(struct diff_options *, const char *);\n void show_submodule_diff_summary(struct diff_options *o, const char *path,\n \t\t\t    struct object_id *one, struct object_id *two,\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461709","messageId":"patch-v3-23.32-6cac6cb2fa6-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 23/32] submodule--helper: use \"code\" in run_update_command()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:32Z","receivedAt":"2022-08-21T13:59:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Apply some DRY principles in run_update_command() and don't have two\n\"switch\" statements over \"ud->update_strategy.type\" determine the same\nthing.\n\nFirst we were setting \"must_die_on_failure = 1\" in all cases except\n\"SM_UPDATE_CHECKOUT\" (and we'd BUG(...) out on the rest). This code\nwas added in c51f8f94e5b (submodule--helper: run update procedures\nfrom C, 2021-08-24).\n\nThen we'd duplicate same \"switch\" logic when we were using the\n\"must_die_on_failure\" variable.\n\nLet's instead have the \"case\" branches in that inner \"switch\"\ndetermine whether or not the \"update must continue\" by picking an exit\ncode.\n\nThis also mostly avoids hardcoding the \"128\" exit code, instead we can\nmake use of the return value of the die_message() function, which\nwe've been calling here since 55b3f12cb54 (submodule update: use\ndie_message(), 2022-03-15). We're still hardcoding it to determine if\nwe \"exit()\", but subsequent commit(s) will address that.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 27 +++++++++++++--------------\n 1 file changed, 13 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c83b0897740..44b08a01c54 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2129,7 +2129,6 @@ static int run_update_command(struct update_data *ud, int subforce)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n-\tint must_die_on_failure = 0;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n@@ -2143,19 +2142,16 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->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\tcp.git_cmd = 1;\n \t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->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\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: %d\",\n@@ -2166,32 +2162,35 @@ static int run_update_command(struct update_data *ud, int subforce)\n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env);\n \tif (run_command(&cp)) {\n+\t\tint ret;\n+\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\t/* the command failed, but update must continue */\n+\t\t\tret = 1;\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n-\t\t\tdie_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t    oid, ud->displaypath);\n+\t\t\tret = die_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t\t\t  oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_MERGE:\n-\t\t\tdie_message(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t    oid, ud->displaypath);\n+\t\t\tret = die_message(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t\t\t  oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_COMMAND:\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\tret = die_message(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\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: %d\",\n \t\t\t    ud->update_strategy.type);\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+\t\tif (ret == 128)\n+\t\t\texit(ret);\n+\t\treturn ret;\n \t}\n \n \tif (ud->quiet)\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461710","messageId":"patch-v3-24.32-6d56f671c7a-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 24/32] submodule--helper: don't exit() on failure, return","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:33Z","receivedAt":"2022-08-21T14:00:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code downstream of module_update() to short-circuit and return\nto the top-level on failure, rather than calling exit().\n\nTo do so we need to diligently check whether we \"must_die_on_failure\",\nwhich is a pattern started in c51f8f94e5b (submodule--helper: run\nupdate procedures from C, 2021-08-24), but which hadn't been completed\nto the point where we could avoid calling exit() here.\n\nThis introduces no functional changes, but makes it easier to both\ncall these routines as a library in the future, and to eventually\navoid leaking memory.\n\nThis and similar control flow in submodule--helper.c could be made\nsimpler by properly \"libifying\" it, i.e. to have it consistently\nreturn -1 on failures, and to early return on any non-success.\n\nBut let's leave that larger project for now, and (mostly) emulate what\nwere doing with the \"exit(128)\" before this change.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 35 +++++++++++++++++++++++++----------\n 1 file changed, 25 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 44b08a01c54..84e5e3beeb5 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2125,7 +2125,8 @@ 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,\n+\t\t\t      int *must_die_on_failure)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n@@ -2189,7 +2190,7 @@ static int run_update_command(struct update_data *ud, int subforce)\n \t\t}\n \n \t\tif (ret == 128)\n-\t\t\texit(ret);\n+\t\t\t*must_die_on_failure = 1;\n \t\treturn ret;\n \t}\n \n@@ -2221,7 +2222,8 @@ static int run_update_command(struct update_data *ud, int subforce)\n \treturn 0;\n }\n \n-static int run_update_procedure(struct update_data *ud)\n+static int run_update_procedure(struct update_data *ud,\n+\t\t\t\tint *must_die_on_failure)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2248,7 +2250,7 @@ static int 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, must_die_on_failure);\n }\n \n static const char *remote_submodule_branch(const char *path)\n@@ -2384,7 +2386,8 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \t\t\t\t    \"--no-single-branch\");\n }\n \n-static int update_submodule(struct update_data *update_data)\n+static int update_submodule(struct update_data *update_data,\n+\t\t\t    int *must_die_on_failure)\n {\n \tensure_core_worktree(update_data->sm_path);\n \n@@ -2420,9 +2423,15 @@ static int update_submodule(struct update_data *update_data)\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+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force) {\n+\t\tint ret;\n+\n+\t\tret = run_update_procedure(update_data, must_die_on_failure);\n+\t\tif (*must_die_on_failure)\n+\t\t\treturn ret;\n+\t\tif (ret)\n \t\t\treturn 1;\n+\t}\n \n \tif (update_data->recursive) {\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2438,14 +2447,13 @@ static int update_submodule(struct update_data *update_data)\n \t\tprepare_submodule_repo_env(&cp.env);\n \t\tupdate_data_to_args(&next, &cp.args);\n \n-\t\t/* die() if child process die()'d */\n \t\tret = run_command(&cp);\n \t\tif (!ret)\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 (ret == 128)\n-\t\t\texit(ret);\n+\t\t\t*must_die_on_failure = 1;\n \t\treturn ret;\n \t}\n \n@@ -2478,12 +2486,19 @@ static int update_submodules(struct update_data *update_data)\n \n \tfor (i = 0; i < suc.update_clone_nr; i++) {\n \t\tstruct update_clone_data ucd = suc.update_clone[i];\n+\t\tint must_die_on_failure = 0;\n+\t\tint code;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n+\t\tif (code)\n+\t\t\tret = code;\n+\t\tif (must_die_on_failure)\n+\t\t\tgoto cleanup;\n+\t\telse if (code)\n \t\t\tret = 1;\n \t}\n \n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461711","messageId":"patch-v3-25.32-dfd5c8bcd61-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 25/32] submodule--helper: libify determine_submodule_update_strategy()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:34Z","receivedAt":"2022-08-21T14:00:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Libify the determine_submodule_update_strategy() by having it invoke\ndie_message() rather than die(), and returning the code die_message()\nreturns on failure.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 39 ++++++++++++++++++++++++-------------\n 1 file changed, 25 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 84e5e3beeb5..4d102f2b32e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1733,24 +1733,27 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void determine_submodule_update_strategy(struct repository *r,\n-\t\t\t\t\t\tint just_cloned,\n-\t\t\t\t\t\tconst char *path,\n-\t\t\t\t\t\tenum submodule_update_type update,\n-\t\t\t\t\t\tstruct submodule_update_strategy *out)\n+static int determine_submodule_update_strategy(struct repository *r,\n+\t\t\t\t\t       int just_cloned,\n+\t\t\t\t\t       const char *path,\n+\t\t\t\t\t       enum submodule_update_type update,\n+\t\t\t\t\t       struct submodule_update_strategy *out)\n {\n \tconst struct submodule *sub = submodule_from_path(r, null_oid(), path);\n \tchar *key;\n \tconst char *val;\n+\tint ret;\n \n \tkey = xstrfmt(\"submodule.%s.update\", sub->name);\n \n \tif (update) {\n \t\tout->type = update;\n \t} else if (!repo_config_get_string_tmp(r, key, &val)) {\n-\t\tif (parse_submodule_update_strategy(val, out) < 0)\n-\t\t\tdie(_(\"Invalid update mode '%s' configured for submodule path '%s'\"),\n-\t\t\t\tval, path);\n+\t\tif (parse_submodule_update_strategy(val, out) < 0) {\n+\t\t\tret = die_message(_(\"Invalid update mode '%s' configured for submodule path '%s'\"),\n+\t\t\t\t\t  val, path);\n+\t\t\tgoto cleanup;\n+\t\t}\n \t} else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n \t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND)\n \t\t\tBUG(\"how did we read update = !command from .gitmodules?\");\n@@ -1765,7 +1768,10 @@ static void determine_submodule_update_strategy(struct repository *r,\n \t     out->type == SM_UPDATE_NONE))\n \t\tout->type = SM_UPDATE_CHECKOUT;\n \n+\tret = 0;\n+cleanup:\n \tfree(key);\n+\treturn ret;\n }\n \n struct update_clone_data {\n@@ -2389,14 +2395,22 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n static int update_submodule(struct update_data *update_data,\n \t\t\t    int *must_die_on_failure)\n {\n+\tint ret;\n+\n \tensure_core_worktree(update_data->sm_path);\n \n \tupdate_data->displaypath = get_submodule_displaypath(\n \t\tupdate_data->sm_path, update_data->prefix);\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+\tret = determine_submodule_update_strategy(the_repository,\n+\t\t\t\t\t\t  update_data->just_cloned,\n+\t\t\t\t\t\t  update_data->sm_path,\n+\t\t\t\t\t\t  update_data->update_default,\n+\t\t\t\t\t\t  &update_data->update_strategy);\n+\tif (ret) {\n+\t\t*must_die_on_failure = 1;\n+\t\treturn ret;\n+\t}\n \n \tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\n@@ -2424,8 +2438,6 @@ 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\tint ret;\n-\n \t\tret = run_update_procedure(update_data, must_die_on_failure);\n \t\tif (*must_die_on_failure)\n \t\t\treturn ret;\n@@ -2436,7 +2448,6 @@ static int update_submodule(struct update_data *update_data,\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 ret;\n \n \t\tnext.prefix = NULL;\n \t\toidcpy(&next.oid, null_oid());\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461712","messageId":"patch-v3-27.32-2795a3738c8-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 27/32] submodule--helper update: don't override 'checkout' exit code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:36Z","receivedAt":"2022-08-21T14:00:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"When \"git submodule update\" runs it might call \"checkout\", \"merge\",\n\"rebase\", or a custom command. Ever since run_update_command() was\nadded in c51f8f94e5b (submodule--helper: run update procedures from C,\n2021-08-24) we'd either exit immediately if the\n\"submodule.<name>.update\" method failed, or in the case of \"checkout\"\ncontinue trying to update other submodules.\n\nThis code used to use the magical \"2\" return code, but in\n55b3f12cb54 (submodule update: use die_message(), 2022-03-15) it was\nmade to exit(128), which in preceding commits has been changed to\nreturn that 128 code to the top-level.\n\nLet's \"libify\" this code even more by not having it arbitrarily\noverride the return code. In practice this doesn't change anything as\nthe code \"git checkout\" would return on any normal failure is \"1\", but\nwe'll now in principle properly abort the operation if \"git checkout\"\nwere to exit with 128.\n\nIt would make sense to follow-up this change with a change to allow\nthe \"submodule.<name>.update = !...\" (SM_UPDATE_COMMAND) method the\nsame liberties as \"checkout\", and perhaps to do the same with a failed\n\"merge\" or \"rebase\". But let's leave that for now.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 9 +++------\n 1 file changed, 3 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9e9d4fe0261..851000ae30e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2135,6 +2135,7 @@ static int run_update_command(struct update_data *ud, int subforce)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n+\tint ret;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n@@ -2167,15 +2168,12 @@ static int run_update_command(struct update_data *ud, int subforce)\n \n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env);\n-\tif (run_command(&cp)) {\n-\t\tint ret;\n-\n+\tif ((ret = run_command(&cp))) {\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\t/* the command failed, but update must continue */\n-\t\t\tret = 1;\n+\t\t\t/* No \"ret\" assignment, use \"git checkout\"'s */\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n \t\t\tret = die_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n@@ -2497,7 +2495,6 @@ static int update_submodules(struct update_data *update_data)\n \t\tret = code;\n \t\tif (ret == 128)\n \t\t\tgoto cleanup;\n-\t\tret = 1;\n \t}\n \n cleanup:\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461713","messageId":"patch-v3-26.32-da1a07afd25-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 26/32] submodule--helper: libify \"must_die_on_failure\" code paths","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:35Z","receivedAt":"2022-08-21T14:00:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In preceding commits the codepaths around update_submodules() were\nchanged from using exit() or die() to ferrying up a\n\"must_die_on_failure\" in the cases where we'd exit(), and in most\ncases where we'd die().\n\nWe needed to do this this to ensure that we'd early exit or otherwise\nabort the update_submodules() processing before it was completed.\n\nNow that those preceding changes have shown that we've converted those\npaths, we can remove the remaining \"ret == 128\" special-cases, leaving\nthe only such special-case in update_submodules(). I.e. we now know\nafter having gone through the various codepaths that we were only\nreturning 128 if we meant to early abort.\n\nIn update_submodules() we'll for now set any non-zero non-128 exit\ncodes to \"1\", but will start ferrying up the exit code as-is in a\nsubsequent commit.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 45 +++++++++++++------------------------\n 1 file changed, 16 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4d102f2b32e..9e9d4fe0261 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2131,8 +2131,7 @@ 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-\t\t\t      int *must_die_on_failure)\n+static int run_update_command(struct update_data *ud, int subforce)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n@@ -2195,8 +2194,6 @@ static int run_update_command(struct update_data *ud, int subforce,\n \t\t\t    ud->update_strategy.type);\n \t\t}\n \n-\t\tif (ret == 128)\n-\t\t\t*must_die_on_failure = 1;\n \t\treturn ret;\n \t}\n \n@@ -2228,8 +2225,7 @@ static int run_update_command(struct update_data *ud, int subforce,\n \treturn 0;\n }\n \n-static int run_update_procedure(struct update_data *ud,\n-\t\t\t\tint *must_die_on_failure)\n+static int run_update_procedure(struct update_data *ud)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2256,7 +2252,7 @@ static int 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, must_die_on_failure);\n+\treturn run_update_command(ud, subforce);\n }\n \n static const char *remote_submodule_branch(const char *path)\n@@ -2392,8 +2388,7 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \t\t\t\t    \"--no-single-branch\");\n }\n \n-static int update_submodule(struct update_data *update_data,\n-\t\t\t    int *must_die_on_failure)\n+static int update_submodule(struct update_data *update_data)\n {\n \tint ret;\n \n@@ -2407,10 +2402,8 @@ static int update_submodule(struct update_data *update_data,\n \t\t\t\t\t\t  update_data->sm_path,\n \t\t\t\t\t\t  update_data->update_default,\n \t\t\t\t\t\t  &update_data->update_strategy);\n-\tif (ret) {\n-\t\t*must_die_on_failure = 1;\n+\tif (ret)\n \t\treturn ret;\n-\t}\n \n \tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\n@@ -2438,11 +2431,9 @@ 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\tret = run_update_procedure(update_data, must_die_on_failure);\n-\t\tif (*must_die_on_failure)\n-\t\t\treturn ret;\n+\t\tret = run_update_procedure(update_data);\n \t\tif (ret)\n-\t\t\treturn 1;\n+\t\t\treturn ret;\n \t}\n \n \tif (update_data->recursive) {\n@@ -2459,12 +2450,9 @@ static int update_submodule(struct update_data *update_data,\n \t\tupdate_data_to_args(&next, &cp.args);\n \n \t\tret = run_command(&cp);\n-\t\tif (!ret)\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 (ret == 128)\n-\t\t\t*must_die_on_failure = 1;\n+\t\tif (ret)\n+\t\t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t\t    update_data->displaypath);\n \t\treturn ret;\n \t}\n \n@@ -2497,20 +2485,19 @@ static int update_submodules(struct update_data *update_data)\n \n \tfor (i = 0; i < suc.update_clone_nr; i++) {\n \t\tstruct update_clone_data ucd = suc.update_clone[i];\n-\t\tint must_die_on_failure = 0;\n \t\tint code;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n-\t\tif (code)\n-\t\t\tret = code;\n-\t\tif (must_die_on_failure)\n+\t\tcode = update_submodule(update_data);\n+\t\tif (!code)\n+\t\t\tcontinue;\n+\t\tret = code;\n+\t\tif (ret == 128)\n \t\t\tgoto cleanup;\n-\t\telse if (code)\n-\t\t\tret = 1;\n+\t\tret = 1;\n \t}\n \n cleanup:\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461714","messageId":"patch-v3-28.32-6d9bccb34c3-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 28/32] submodule--helper: libify \"must_die_on_failure\" code paths (for die)","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:37Z","receivedAt":"2022-08-21T14:00:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Continue the libification of codepaths that previously relied on\n\"must_die_on_failure\". In these cases we've always been early aborting\nby calling die(), but as we know that these codpaths will properly\nhandle return codes of 128 to mean an early abort let's have them use\ndie_message() instead.\n\nThis still isn't a complete migration away from die() for these\ncodepaths, in particular this code in update_submodule() will still call die() in some cases:\n\n\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n\nBut as that code is used by other callers than the \"update\" code let's\nleave converting it for a subsequent commit.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 29 +++++++++++++++++------------\n 1 file changed, 17 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 851000ae30e..5f109d422ea 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2245,9 +2245,9 @@ static int run_update_procedure(struct update_data *ud)\n \t\t */\n \t\tif (!is_tip_reachable(ud->sm_path, &ud->oid) &&\n \t\t    fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, &ud->oid))\n-\t\t\tdie(_(\"Fetched in submodule path '%s', but it did not \"\n-\t\t\t      \"contain %s. Direct fetching of that commit failed.\"),\n-\t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n+\t\t\treturn die_message(_(\"Fetched in submodule path '%s', but it did not \"\n+\t\t\t\t\t     \"contain %s. Direct fetching of that commit failed.\"),\n+\t\t\t\t\t   ud->displaypath, oid_to_hex(&ud->oid));\n \t}\n \n \treturn run_update_command(ud, subforce);\n@@ -2291,13 +2291,14 @@ static const char *remote_submodule_branch(const char *path)\n \treturn branch;\n }\n \n-static void ensure_core_worktree(const char *path)\n+static int ensure_core_worktree(const char *path)\n {\n \tconst char *cw;\n \tstruct repository subrepo;\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+\t\treturn die_message(_(\"could not get a repository handle for submodule '%s'\"),\n+\t\t\t\t   path);\n \n \tif (!repo_config_get_string_tmp(&subrepo, \"core.worktree\", &cw)) {\n \t\tchar *cfg_file, *abs_path;\n@@ -2315,6 +2316,8 @@ static void ensure_core_worktree(const char *path)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n+\n+\treturn 0;\n }\n \n static const char *submodule_update_type_to_label(enum submodule_update_type type)\n@@ -2390,7 +2393,9 @@ static int update_submodule(struct update_data *update_data)\n {\n \tint ret;\n \n-\tensure_core_worktree(update_data->sm_path);\n+\tret = ensure_core_worktree(update_data->sm_path);\n+\tif (ret)\n+\t\treturn ret;\n \n \tupdate_data->displaypath = get_submodule_displaypath(\n \t\tupdate_data->sm_path, update_data->prefix);\n@@ -2406,8 +2411,8 @@ static int update_submodule(struct update_data *update_data)\n \tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\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+\t\treturn die_message(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t\t   update_data->displaypath);\n \n \tif (update_data->remote) {\n \t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n@@ -2417,13 +2422,13 @@ static int update_submodule(struct update_data *update_data)\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\t\treturn die_message(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\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+\t\t\treturn die_message(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t\t\t   remote_ref, update_data->sm_path);\n \n \t\tfree(remote_ref);\n \t}\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461715","messageId":"patch-v3-31.32-1694ccfe882-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 31/32] submodule--helper: libify even more \"die\" paths for module_update()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:40Z","receivedAt":"2022-08-21T14:00:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As noted in a preceding commit the get_default_remote_submodule() and\nremote_submodule_branch() functions would invoke die(), and thus leave\nupdate_submodule() only partially lib-ified. We've addressed the\nformer of those in a preceding commit, let's now address the latter.\n\nIn addition to lib-ifying the function this fixes a potential (but\nobscure) segfault introduced by a logic error in\n1012a5cbc3f (submodule--helper run-update-procedure: learn --remote,\n2022-03-04):\n\nWe were assuming that remote_submodule_branch() would always return\non-NULL, but if the submodule_from_path() call in that function fails\nwe'll return NULL. See its introduction in\n92bbe7ccf1f (submodule--helper: add remote-branch helper, 2016-08-03).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 41 ++++++++++++++++++++++---------------\n 1 file changed, 25 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9e4069b36cb..65909255760 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2267,42 +2267,49 @@ static int run_update_procedure(struct update_data *ud)\n \treturn run_update_command(ud, subforce);\n }\n \n-static const char *remote_submodule_branch(const char *path)\n+static int remote_submodule_branch(const char *path, const char **branch)\n {\n \tconst struct submodule *sub;\n-\tconst char *branch = NULL;\n \tchar *key;\n+\t*branch = NULL;\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \tif (!sub)\n-\t\treturn NULL;\n+\t\treturn die_message(_(\"could not initialize submodule at path '%s'\"),\n+\t\t\t\t   path);\n \n \tkey = xstrfmt(\"submodule.%s.branch\", sub->name);\n-\tif (repo_config_get_string_tmp(the_repository, key, &branch))\n-\t\tbranch = sub->branch;\n+\tif (repo_config_get_string_tmp(the_repository, key, branch))\n+\t\t*branch = sub->branch;\n \tfree(key);\n \n-\tif (!branch)\n-\t\treturn \"HEAD\";\n+\tif (!*branch) {\n+\t\t*branch = \"HEAD\";\n+\t\treturn 0;\n+\t}\n \n-\tif (!strcmp(branch, \".\")) {\n+\tif (!strcmp(*branch, \".\")) {\n \t\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n \n \t\tif (!refname)\n-\t\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\t\treturn die_message(_(\"No such ref: %s\"), \"HEAD\");\n \n \t\t/* detached HEAD */\n \t\tif (!strcmp(refname, \"HEAD\"))\n-\t\t\tdie(_(\"Submodule (%s) branch configured to inherit \"\n-\t\t\t      \"branch from superproject, but the superproject \"\n-\t\t\t      \"is not on any branch\"), sub->name);\n+\t\t\treturn die_message(_(\"Submodule (%s) branch configured to inherit \"\n+\t\t\t\t\t     \"branch from superproject, but the superproject \"\n+\t\t\t\t\t     \"is not on any branch\"), sub->name);\n \n \t\tif (!skip_prefix(refname, \"refs/heads/\", &refname))\n-\t\t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n-\t\treturn refname;\n+\t\t\treturn die_message(_(\"Expecting a full ref name, got %s\"),\n+\t\t\t\t\t   refname);\n+\n+\t\t*branch = refname;\n+\t\treturn 0;\n \t}\n \n-\treturn branch;\n+\t/* Our \"branch\" is coming from repo_config_get_string_tmp() */\n+\treturn 0;\n }\n \n static int ensure_core_worktree(const char *path)\n@@ -2437,7 +2444,9 @@ static int update_submodule(struct update_data *update_data)\n \t\tcode = get_default_remote_submodule(update_data->sm_path, &remote_name);\n \t\tif (code)\n \t\t\treturn code;\n-\t\tbranch = remote_submodule_branch(update_data->sm_path);\n+\t\tcode = remote_submodule_branch(update_data->sm_path, &branch);\n+\t\tif (code)\n+\t\t\treturn code;\n \t\tremote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n \n \t\tif (!update_data->nofetch) {\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461716","messageId":"patch-v3-29.32-d4b55f07a30-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 29/32] submodule--helper: check repo{_submodule,}_init() return values","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:38Z","receivedAt":"2022-08-21T14:00:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix code added in ce125d431aa (submodule: extract path to submodule\ngitdir func, 2021-09-15) and a77c3fcb5ec (submodule--helper: get\nremote names from any repository, 2022-03-04) which failed to check\nthe return values of repo_init() and repo_submodule_init(). If we\nfailed to initialize the repository or submodule we could segfault\nwhen trying to access the invalid repository structs.\n\nLet's also check that these were the only such logic errors in the\ncodebase by making use of the \"warn_unused_result\" attribute. This is\nvalid as of GCC 3.4.0 (and clang will catch it via its faking of\n__GNUC__ ).\n\nAs the comment being added to git-compat-util.h we're piggy-backing on\nthe LAST_ARG_MUST_BE_NULL version check out of lazyness. See\n9fe3edc47f1 (Add the LAST_ARG_MUST_BE_NULL macro, 2013-07-18) for its\naddition. The marginal benefit of covering gcc 3.4.0..4.0.0 is\nnear-zero (or zero) at this point. It mostly matters that we catch\nthis somewhere.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 9 +++++++--\n git-compat-util.h           | 3 +++\n repository.h                | 3 +++\n 3 files changed, 13 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5f109d422ea..88fc01320f3 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -63,7 +63,10 @@ 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+\tif (repo_submodule_init(&subrepo, the_repository, module_path,\n+\t\t\t\tnull_oid()) < 0)\n+\t\tdie(_(\"could not get a repository handle for submodule '%s'\"),\n+\t\t    module_path);\n \treturn repo_get_default_remote(&subrepo);\n }\n \n@@ -1483,7 +1486,9 @@ static int add_possible_reference_from_superproject(\n \t\tstruct strbuf err = STRBUF_INIT;\n \t\tstrbuf_add(&sb, odb->path, len);\n \n-\t\trepo_init(&alternate, sb.buf, NULL);\n+\t\tif (repo_init(&alternate, sb.buf, NULL) < 0)\n+\t\t\tdie(_(\"could not get a repository handle for gitdir '%s'\"),\n+\t\t\t    sb.buf);\n \n \t\t/*\n \t\t * We need to end the new path with '/' to mark it as a dir,\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 36a25ae252f..01d88650ba3 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -568,8 +568,11 @@ static inline int git_has_dir_sep(const char *path)\n /* The sentinel attribute is valid from gcc version 4.0 */\n #if defined(__GNUC__) && (__GNUC__ >= 4)\n #define LAST_ARG_MUST_BE_NULL __attribute__((sentinel))\n+/* warn_unused_result exists as of gcc 3.4.0, but be lazy and check 4.0 */\n+#define RESULT_MUST_BE_USED __attribute__ ((warn_unused_result))\n #else\n #define LAST_ARG_MUST_BE_NULL\n+#define RESULT_MUST_BE_USED\n #endif\n \n #define MAYBE_UNUSED __attribute__((__unused__))\ndiff --git a/repository.h b/repository.h\nindex 797f471cce9..24316ac944e 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -1,6 +1,7 @@\n #ifndef REPOSITORY_H\n #define REPOSITORY_H\n \n+#include \"git-compat-util.h\"\n #include \"path.h\"\n \n struct config_set;\n@@ -186,6 +187,7 @@ void repo_set_gitdir(struct repository *repo, const char *root,\n void repo_set_worktree(struct repository *repo, const char *path);\n void repo_set_hash_algo(struct repository *repo, int algo);\n void initialize_the_repository(void);\n+RESULT_MUST_BE_USED\n int repo_init(struct repository *r, const char *gitdir, const char *worktree);\n \n /*\n@@ -197,6 +199,7 @@ int repo_init(struct repository *r, const char *gitdir, const char *worktree);\n  * Return 0 upon success and a non-zero value upon failure.\n  */\n struct object_id;\n+RESULT_MUST_BE_USED\n int repo_submodule_init(struct repository *subrepo,\n \t\t\tstruct repository *superproject,\n \t\t\tconst char *path,\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461717","messageId":"patch-v3-32.32-d133402462f-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 32/32] submodule--helper: fix bad config API usage","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:41Z","receivedAt":"2022-08-21T14:01:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix bad config API usage added in a452128a36c (submodule--helper:\nintroduce add-config subcommand, 2021-08-06). After\ngit_config_get_string() returns successfully we know the \"char **dest\"\nwill be non-NULL.\n\nA coccinelle patch that transforms this turns up a couple of other\nsuch issues, one in fetch-pack.c, and another in upload-pack.c:\n\n\t@@\n\tidentifier F =~ \"^(repo|git)_config_get_string(_tmp)?$\";\n\tidentifier V;\n\t@@\n\t  !F(..., &V)\n\t- && (V)\n\nBut let's focus narrowly on submodule--helper for now, we can fix\nthose some other time.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 65909255760..e489a0f6b10 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -3108,7 +3108,7 @@ static void configure_added_submodule(struct add_data *add_data)\n \t * is_submodule_active(), since that function needs to find\n \t * out the value of \"submodule.active\" again anyway.\n \t */\n-\tif (!git_config_get_string(\"submodule.active\", &val) && val) {\n+\tif (!git_config_get_string(\"submodule.active\", &val)) {\n \t\t/*\n \t\t * If the submodule being added isn't already covered by the\n \t\t * current configured pathspec, set the submodule's active flag\n-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461718","messageId":"patch-v3-30.32-15c2490a978-20220821T130231Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v3 30/32] submodule--helper: libify more \"die\" paths for module_update()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-21T13:57:39Z","receivedAt":"2022-08-21T14:01:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As noted in a preceding commit the get_default_remote_submodule() and\nremote_submodule_branch() functions would invoke die(), and thus leave\nupdate_submodule() only partially lib-ified. Let's address the former\nof those cases.\n\nChange the functions to return an int exit code (non-zero on failure),\nwhile leaving the get_default_remote() function for the callers that\nstill want the die() semantics.\n\nThis change addresses 1/2 of the \"die\" issue in these two lines in\nupdate_submodule():\n\n\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 58 +++++++++++++++++++++++--------------\n 1 file changed, 37 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 88fc01320f3..9e4069b36cb 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -31,48 +31,57 @@\n typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n \t\t\t\t  void *cb_data);\n \n-static char *repo_get_default_remote(struct repository *repo)\n+static int repo_get_default_remote(struct repository *repo, char **default_remote)\n {\n-\tchar *dest = NULL, *ret;\n+\tchar *dest = NULL;\n \tstruct strbuf sb = STRBUF_INIT;\n \tstruct ref_store *store = get_main_ref_store(repo);\n \tconst char *refname = refs_resolve_ref_unsafe(store, \"HEAD\", 0, NULL,\n \t\t\t\t\t\t      NULL);\n \n \tif (!refname)\n-\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\treturn die_message(_(\"No such ref: %s\"), \"HEAD\");\n \n \t/* detached HEAD */\n-\tif (!strcmp(refname, \"HEAD\"))\n-\t\treturn xstrdup(\"origin\");\n+\tif (!strcmp(refname, \"HEAD\")) {\n+\t\t*default_remote = xstrdup(\"origin\");\n+\t\treturn 0;\n+\t}\n \n \tif (!skip_prefix(refname, \"refs/heads/\", &refname))\n-\t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n+\t\treturn die_message(_(\"Expecting a full ref name, got %s\"),\n+\t\t\t\t   refname);\n \n \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n \tif (repo_config_get_string(repo, sb.buf, &dest))\n-\t\tret = xstrdup(\"origin\");\n+\t\t*default_remote = xstrdup(\"origin\");\n \telse\n-\t\tret = dest;\n+\t\t*default_remote = dest;\n \n \tstrbuf_release(&sb);\n-\treturn ret;\n+\treturn 0;\n }\n \n-static char *get_default_remote_submodule(const char *module_path)\n+static int get_default_remote_submodule(const char *module_path, char **default_remote)\n {\n \tstruct repository subrepo;\n \n \tif (repo_submodule_init(&subrepo, the_repository, module_path,\n \t\t\t\tnull_oid()) < 0)\n-\t\tdie(_(\"could not get a repository handle for submodule '%s'\"),\n-\t\t    module_path);\n-\treturn repo_get_default_remote(&subrepo);\n+\t\treturn die_message(_(\"could not get a repository handle for submodule '%s'\"),\n+\t\t\t\t   module_path);\n+\treturn repo_get_default_remote(&subrepo, default_remote);\n }\n \n static char *get_default_remote(void)\n {\n-\treturn repo_get_default_remote(the_repository);\n+\tchar *default_remote;\n+\tint code = repo_get_default_remote(the_repository, &default_remote);\n+\n+\tif (code)\n+\t\texit(code);\n+\n+\treturn default_remote;\n }\n \n static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)\n@@ -1159,6 +1168,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *sub_config_path = NULL;\n+\tint code;\n \n \tif (!is_submodule_active(the_repository, path))\n \t\treturn;\n@@ -1198,10 +1208,9 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tgoto cleanup;\n \n \tstrbuf_reset(&sb);\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+\tcode = get_default_remote_submodule(path, &default_remote);\n+\tif (code)\n+\t\texit(code);\n \n \tremote_key = xstrfmt(\"remote.%s.url\", default_remote);\n \tfree(default_remote);\n@@ -2420,9 +2429,16 @@ static int update_submodule(struct update_data *update_data)\n \t\t\t\t   update_data->displaypath);\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+\t\tchar *remote_name;\n+\t\tconst char *branch;\n+\t\tchar *remote_ref;\n+\t\tint code;\n+\n+\t\tcode = get_default_remote_submodule(update_data->sm_path, &remote_name);\n+\t\tif (code)\n+\t\t\treturn code;\n+\t\tbranch = remote_submodule_branch(update_data->sm_path);\n+\t\tremote_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-- \n2.37.2.1279.g64dec4e13cf\n\n"},{"id":"461737","messageId":"CAPig+cTB_ei+VKfOtHRAkhCRgzqT=aPkq91DUtfXmjkRtg6FDw@mail.gmail.com","threadId":"58235","inReplyTo":"patch-v3-17.32-fa2417c7a17-20220821T130231Z-avarab@gmail.com","subject":"Re: [PATCH v3 17/32] submodule--helper: don't redundantly check \"else if (res)\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-08-21T16:12:05Z","receivedAt":"2022-08-21T16:12:21Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Aug 21, 2022 at 10:00 AM Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n> The \"res\" variable must be true at this point in update_submodule(),\n> as just a few lines above this we've unconditionally:\n>\n>         if (!res)\n>                 return 0;\n>\n> So we don't need to guard the \"return 1\" with an \"else if (res)\", we\n> an return unconditionally at this point. See b3c5f5cb048 (submodule:\n\ns/an/can/\n\n> move core cmd_update() logic to C, 2022-03-15) for the initial\n> introduction of this code, this check of \"res\" has always been\n> redundant.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n"},{"id":"461882","messageId":"kl6lmtbu4m5d.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v3-01.32-77586985ab3-20220821T130231Z-avarab@gmail.com","subject":"Re: [PATCH v3 01/32] submodule tests: test usage behavior","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-23T22:42:38Z","receivedAt":"2022-08-23T22:42:59Z","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> Test what exit code and output we emit on \"git submodule -h\", how we\n> handle \"--\" when no subcommand is specified, and how the top-level\n> \"--recursive\" option is handled.\n>\n> For \"-h\" this doesn't make sense, but let's test for it so that any\n> subsequent eventual behavior change will become clear.\n>\n> For \"--\" this follows up on 68cabbfda36 (submodule: document default\n> behavior, 2019-02-15) and tests that \"status\" doesn't support\n> the \"--\" delimiter. There's no intrinsically good reason not to\n> support that. We behave this way due to edge cases in\n> git-submodule.sh's implementation, but as with \"-h\" let's assert our\n> current long-standing behavior for now.\n>\n> For \"--recursive\" the exclusion of it from the top-level appears to\n> have been an omission in 15fc56a8536 (git submodule foreach: Add\n> --recursive to recurse into nested submodules, 2009-08-19), there\n> doesn't seem to be a reason not to support it alongside \"--quiet\" and\n> \"--cached\", but let's likewise assert our existing behavior for now.\n>\n> I.e. as long as \"status\" is optional it would make sense to support\n> all of its options when it's omitted, but we only do that with\n> \"--quiet\" and \"--cached\", and curiously omit \"--recursive\".\n\nAh! Okay, this finally makes sense to me now. The usage strings in\nDocumentation/git-submodule.txt and git-submodule.sh document both\n\"--quiet\" and \"--cached\", but that's bogus because we should either:\n\n- pretend that \"git submodule\" doesn't default to \"status\", so we\n  should omit \"--cached\", or\n- be clearer that \"git submodule\" _does_ default to \"status\", so we\n  should include \"--recursive\"\n\nNow that we've acknowledged the existence of top-level \"--recursive\", we\nshould probably amend the usage strings. To be honest, I think a less\nconfusing, more consistent direction would be to just drop this \"default\nto status\" behavior but I doubt we can do that any time soon..\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t7400-submodule-basic.sh | 26 ++++++++++++++++++++++++++\n>  1 file changed, 26 insertions(+)\n>\n> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\n> index e7cec2e457a..b858871a953 100755\n> --- a/t/t7400-submodule-basic.sh\n> +++ b/t/t7400-submodule-basic.sh\n> @@ -14,6 +14,32 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n>  \n>  . ./test-lib.sh\n>  \n> +test_expect_success 'submodule usage: -h' '\n> +\tgit submodule -h >out 2>err &&\n> +\tgrep \"^usage: git submodule\" out &&\n> +\ttest_must_be_empty err\n> +'\n> +\n> +test_expect_success 'submodule usage: --recursive' '\n> +\ttest_expect_code 1 git submodule --recursive >out 2>err &&\n> +\tgrep \"^usage: git submodule\" err &&\n> +\ttest_must_be_empty out\n> +'\n> +\n> +test_expect_success 'submodule usage: status --' '\n> +\ttest_expect_code 1 git submodule -- &&\n> +\ttest_expect_code 1 git submodule --end-of-options\n> +'\n> +\n> +for opt in '--quiet' '--cached'\n> +do\n> +\ttest_expect_success \"submodule usage: status $opt\" '\n> +\t\tgit submodule $opt &&\n> +\t\tgit submodule status $opt &&\n> +\t\tgit submodule $opt status\n> +\t'\n> +done\n> +\n>  test_expect_success 'submodule deinit works on empty repository' '\n>  \tgit submodule deinit --all\n>  '\n> -- \n> 2.37.2.1279.g64dec4e13cf\n"},{"id":"461883","messageId":"kl6lk06y4k39.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v3-28.32-6d9bccb34c3-20220821T130231Z-avarab@gmail.com","subject":"Re: [PATCH v3 28/32] submodule--helper: libify \"must_die_on_failure\" code paths (for die)","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-23T23:27:06Z","receivedAt":"2022-08-23T23:27: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> Continue the libification of codepaths that previously relied on\n> \"must_die_on_failure\". In these cases we've always been early aborting\n> by calling die(), but as we know that these codpaths will properly\n\ns/codpaths/codepaths :p\n\n> handle return codes of 128 to mean an early abort let's have them use\n> die_message() instead.\n>\n> This still isn't a complete migration away from die() for these\n> codepaths, in particular this code in update_submodule() will still call die() in some cases:\n>\n> \tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n> \tconst char *branch = remote_submodule_branch(update_data->sm_path);\n>\n> But as that code is used by other callers than the \"update\" code let's\n> leave converting it for a subsequent commit.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 29 +++++++++++++++++------------\n>  1 file changed, 17 insertions(+), 12 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 851000ae30e..5f109d422ea 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2245,9 +2245,9 @@ static int run_update_procedure(struct update_data *ud)\n>  \t\t */\n>  \t\tif (!is_tip_reachable(ud->sm_path, &ud->oid) &&\n>  \t\t    fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, &ud->oid))\n> -\t\t\tdie(_(\"Fetched in submodule path '%s', but it did not \"\n> -\t\t\t      \"contain %s. Direct fetching of that commit failed.\"),\n> -\t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n> +\t\t\treturn die_message(_(\"Fetched in submodule path '%s', but it did not \"\n> +\t\t\t\t\t     \"contain %s. Direct fetching of that commit failed.\"),\n> +\t\t\t\t\t   ud->displaypath, oid_to_hex(&ud->oid));\n>  \t}\n>  \n>  \treturn run_update_command(ud, subforce);\n> @@ -2291,13 +2291,14 @@ static const char *remote_submodule_branch(const char *path)\n>  \treturn branch;\n>  }\n>  \n> -static void ensure_core_worktree(const char *path)\n> +static int ensure_core_worktree(const char *path)\n>  {\n>  \tconst char *cw;\n>  \tstruct repository subrepo;\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> +\t\treturn die_message(_(\"could not get a repository handle for submodule '%s'\"),\n> +\t\t\t\t   path);\n>  \n>  \tif (!repo_config_get_string_tmp(&subrepo, \"core.worktree\", &cw)) {\n>  \t\tchar *cfg_file, *abs_path;\n> @@ -2315,6 +2316,8 @@ static void ensure_core_worktree(const char *path)\n>  \t\tfree(abs_path);\n>  \t\tstrbuf_release(&sb);\n>  \t}\n> +\n> +\treturn 0;\n>  }\n>  \n>  static const char *submodule_update_type_to_label(enum submodule_update_type type)\n> @@ -2390,7 +2393,9 @@ static int update_submodule(struct update_data *update_data)\n>  {\n>  \tint ret;\n>  \n> -\tensure_core_worktree(update_data->sm_path);\n> +\tret = ensure_core_worktree(update_data->sm_path);\n> +\tif (ret)\n> +\t\treturn ret;\n>  \n>  \tupdate_data->displaypath = get_submodule_displaypath(\n>  \t\tupdate_data->sm_path, update_data->prefix);\n> @@ -2406,8 +2411,8 @@ static int update_submodule(struct update_data *update_data)\n>  \tif (update_data->just_cloned)\n>  \t\toidcpy(&update_data->suboid, null_oid());\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> +\t\treturn die_message(_(\"Unable to find current revision in submodule path '%s'\"),\n> +\t\t\t\t   update_data->displaypath);\n>  \n>  \tif (update_data->remote) {\n>  \t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n> @@ -2417,13 +2422,13 @@ static int update_submodule(struct update_data *update_data)\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\t\treturn die_message(_(\"Unable to fetch in submodule path '%s'\"),\n> +\t\t\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> +\t\t\treturn die_message(_(\"Unable to find %s revision in submodule path '%s'\"),\n> +\t\t\t\t\t   remote_ref, update_data->sm_path);\n>  \n>  \t\tfree(remote_ref);\n>  \t}\n> -- \n> 2.37.2.1279.g64dec4e13cf\n"},{"id":"461884","messageId":"kl6lh7224jk5.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v3-29.32-d4b55f07a30-20220821T130231Z-avarab@gmail.com","subject":"Re: [PATCH v3 29/32] submodule--helper: check repo{_submodule,}_init() return values","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-23T23:38:34Z","receivedAt":"2022-08-23T23:38:39Z","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> Fix code added in ce125d431aa (submodule: extract path to submodule\n> gitdir func, 2021-09-15) and a77c3fcb5ec (submodule--helper: get\n> remote names from any repository, 2022-03-04) which failed to check\n> the return values of repo_init() and repo_submodule_init(). If we\n> failed to initialize the repository or submodule we could segfault\n> when trying to access the invalid repository structs.\n\nYes, this sounds correct. repo_init() and repo_submodule_init() are pure\ninitialization and have no intended side effects, so there's no reason\nto not check the return value.\n\n>\n> Let's also check that these were the only such logic errors in the\n> codebase by making use of the \"warn_unused_result\" attribute. This is\n> valid as of GCC 3.4.0 (and clang will catch it via its faking of\n> __GNUC__ ).\n>\n> As the comment being added to git-compat-util.h we're piggy-backing on\n> the LAST_ARG_MUST_BE_NULL version check out of lazyness. See\n> 9fe3edc47f1 (Add the LAST_ARG_MUST_BE_NULL macro, 2013-07-18) for its\n> addition. The marginal benefit of covering gcc 3.4.0..4.0.0 is\n> near-zero (or zero) at this point. It mostly matters that we catch\n> this somewhere.\n\nI'm not familiar enough with attributes and the requistie compiler\nversions, so I won't comment on this bit.\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 9 +++++++--\n>  git-compat-util.h           | 3 +++\n>  repository.h                | 3 +++\n>  3 files changed, 13 insertions(+), 2 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 5f109d422ea..88fc01320f3 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -63,7 +63,10 @@ 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> +\tif (repo_submodule_init(&subrepo, the_repository, module_path,\n> +\t\t\t\tnull_oid()) < 0)\n> +\t\tdie(_(\"could not get a repository handle for submodule '%s'\"),\n> +\t\t    module_path);\n>  \treturn repo_get_default_remote(&subrepo);\n>  }\n>  \n> @@ -1483,7 +1486,9 @@ static int add_possible_reference_from_superproject(\n>  \t\tstruct strbuf err = STRBUF_INIT;\n>  \t\tstrbuf_add(&sb, odb->path, len);\n>  \n> -\t\trepo_init(&alternate, sb.buf, NULL);\n> +\t\tif (repo_init(&alternate, sb.buf, NULL) < 0)\n> +\t\t\tdie(_(\"could not get a repository handle for gitdir '%s'\"),\n> +\t\t\t    sb.buf);\n>  \n>  \t\t/*\n>  \t\t * We need to end the new path with '/' to mark it as a dir,\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 36a25ae252f..01d88650ba3 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -568,8 +568,11 @@ static inline int git_has_dir_sep(const char *path)\n>  /* The sentinel attribute is valid from gcc version 4.0 */\n>  #if defined(__GNUC__) && (__GNUC__ >= 4)\n>  #define LAST_ARG_MUST_BE_NULL __attribute__((sentinel))\n> +/* warn_unused_result exists as of gcc 3.4.0, but be lazy and check 4.0 */\n> +#define RESULT_MUST_BE_USED __attribute__ ((warn_unused_result))\n>  #else\n>  #define LAST_ARG_MUST_BE_NULL\n> +#define RESULT_MUST_BE_USED\n>  #endif\n>  \n>  #define MAYBE_UNUSED __attribute__((__unused__))\n> diff --git a/repository.h b/repository.h\n> index 797f471cce9..24316ac944e 100644\n> --- a/repository.h\n> +++ b/repository.h\n> @@ -1,6 +1,7 @@\n>  #ifndef REPOSITORY_H\n>  #define REPOSITORY_H\n>  \n> +#include \"git-compat-util.h\"\n>  #include \"path.h\"\n>  \n>  struct config_set;\n> @@ -186,6 +187,7 @@ void repo_set_gitdir(struct repository *repo, const char *root,\n>  void repo_set_worktree(struct repository *repo, const char *path);\n>  void repo_set_hash_algo(struct repository *repo, int algo);\n>  void initialize_the_repository(void);\n> +RESULT_MUST_BE_USED\n>  int repo_init(struct repository *r, const char *gitdir, const char *worktree);\n>  \n>  /*\n> @@ -197,6 +199,7 @@ int repo_init(struct repository *r, const char *gitdir, const char *worktree);\n>   * Return 0 upon success and a non-zero value upon failure.\n>   */\n>  struct object_id;\n> +RESULT_MUST_BE_USED\n>  int repo_submodule_init(struct repository *subrepo,\n>  \t\t\tstruct repository *superproject,\n>  \t\t\tconst char *path,\n> -- \n> 2.37.2.1279.g64dec4e13cf\n"},{"id":"461885","messageId":"kl6lczcq4i7d.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v3-30.32-15c2490a978-20220821T130231Z-avarab@gmail.com","subject":"Re: [PATCH v3 30/32] submodule--helper: libify more \"die\" paths for module_update()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-24T00:07:50Z","receivedAt":"2022-08-24T00:07:57Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> As noted in a preceding commit the get_default_remote_submodule() and\n> remote_submodule_branch() functions would invoke die(), and thus leave\n> update_submodule() only partially lib-ified. Let's address the former\n> of those cases.\n>\n> Change the functions to return an int exit code (non-zero on failure),\n> while leaving the get_default_remote() function for the callers that\n> still want the die() semantics.\n>\n> This change addresses 1/2 of the \"die\" issue in these two lines in\n> update_submodule():\n>\n> \tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n> \tconst char *branch = remote_submodule_branch(update_data->sm_path);\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 58 +++++++++++++++++++++++--------------\n>  1 file changed, 37 insertions(+), 21 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 88fc01320f3..9e4069b36cb 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -31,48 +31,57 @@\n>  typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n>  \t\t\t\t  void *cb_data);\n>  \n> -static char *repo_get_default_remote(struct repository *repo)\n> +static int repo_get_default_remote(struct repository *repo, char **default_remote)\n>  {\n> -\tchar *dest = NULL, *ret;\n> +\tchar *dest = NULL;\n>  \tstruct strbuf sb = STRBUF_INIT;\n>  \tstruct ref_store *store = get_main_ref_store(repo);\n>  \tconst char *refname = refs_resolve_ref_unsafe(store, \"HEAD\", 0, NULL,\n>  \t\t\t\t\t\t      NULL);\n>  \n>  \tif (!refname)\n> -\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n> +\t\treturn die_message(_(\"No such ref: %s\"), \"HEAD\");\n>  \n>  \t/* detached HEAD */\n> -\tif (!strcmp(refname, \"HEAD\"))\n> -\t\treturn xstrdup(\"origin\");\n> +\tif (!strcmp(refname, \"HEAD\")) {\n> +\t\t*default_remote = xstrdup(\"origin\");\n> +\t\treturn 0;\n> +\t}\n>  \n>  \tif (!skip_prefix(refname, \"refs/heads/\", &refname))\n> -\t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n> +\t\treturn die_message(_(\"Expecting a full ref name, got %s\"),\n> +\t\t\t\t   refname);\n>  \n>  \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n>  \tif (repo_config_get_string(repo, sb.buf, &dest))\n> -\t\tret = xstrdup(\"origin\");\n> +\t\t*default_remote = xstrdup(\"origin\");\n>  \telse\n> -\t\tret = dest;\n> +\t\t*default_remote = dest;\n>  \n>  \tstrbuf_release(&sb);\n> -\treturn ret;\n> +\treturn 0;\n>  }\n\nIf we fail to look up the default remote for the branch, we assume it is\n\"origin\", otherwise, it is the default remote. So in the preimage this\nfunction would never return NULL, right? This matters in\nsync_submodule()..\n\n>  \n> -static char *get_default_remote_submodule(const char *module_path)\n> +static int get_default_remote_submodule(const char *module_path, char **default_remote)\n>  {\n>  \tstruct repository subrepo;\n>  \n>  \tif (repo_submodule_init(&subrepo, the_repository, module_path,\n>  \t\t\t\tnull_oid()) < 0)\n> -\t\tdie(_(\"could not get a repository handle for submodule '%s'\"),\n> -\t\t    module_path);\n> -\treturn repo_get_default_remote(&subrepo);\n> +\t\treturn die_message(_(\"could not get a repository handle for submodule '%s'\"),\n> +\t\t\t\t   module_path);\n> +\treturn repo_get_default_remote(&subrepo, default_remote);\n>  }\n>  \n>  static char *get_default_remote(void)\n>  {\n> -\treturn repo_get_default_remote(the_repository);\n> +\tchar *default_remote;\n> +\tint code = repo_get_default_remote(the_repository, &default_remote);\n> +\n> +\tif (code)\n> +\t\texit(code);\n> +\n> +\treturn default_remote;\n>  }\n\nrepo_* usually denotes a difference between \"the_repository\" and \"struct\nrepository\", so I don't really like having [repo_]get_default_remote()\ndie/return differently. But it makes some sense to special case\n\"the_repository\" since it is the top level, so if it fails, something is\nvery wrong. So on the whole, I'm ok with doing this to avoid disrupting\nother callers.\n\n> @@ -1159,6 +1168,7 @@ static void sync_submodule(const char *path, const char *prefix,\n>  \tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n>  \tstruct strbuf sb = STRBUF_INIT;\n>  \tchar *sub_config_path = NULL;\n> +\tint code;\n>  \n>  \tif (!is_submodule_active(the_repository, path))\n>  \t\treturn;\n> @@ -1198,10 +1208,9 @@ static void sync_submodule(const char *path, const char *prefix,\n>  \t\tgoto cleanup;\n>  \n>  \tstrbuf_reset(&sb);\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> +\tcode = get_default_remote_submodule(path, &default_remote);\n> +\tif (code)\n> +\t\texit(code);\n\nIn the preimage, we used to check that default_remote is not NULL, but\nwe don't check this any more. As we noted earlier, default_remote could\nnever be NULL (because we used to die() on failure), so I think we never\nneeded this check and it's ok to drop it.\n\nIs this the same reasoning you had?\n\n"},{"id":"461886","messageId":"kl6la67u4i07.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v3-31.32-1694ccfe882-20220821T130231Z-avarab@gmail.com","subject":"Re: [PATCH v3 31/32] submodule--helper: libify even more \"die\" paths for module_update()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-08-24T00:12:08Z","receivedAt":"2022-08-24T00:12:16Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> As noted in a preceding commit the get_default_remote_submodule() and\n> remote_submodule_branch() functions would invoke die(), and thus leave\n> update_submodule() only partially lib-ified. We've addressed the\n> former of those in a preceding commit, let's now address the latter.\n>\n> In addition to lib-ifying the function this fixes a potential (but\n> obscure) segfault introduced by a logic error in\n> 1012a5cbc3f (submodule--helper run-update-procedure: learn --remote,\n> 2022-03-04):\n\nAh, good catch.\n\n>\n> We were assuming that remote_submodule_branch() would always return\n> on-NULL, but if the submodule_from_path() call in that function fails\n\ns/on-NULL/non-NULL I assume?\n\n> we'll return NULL. See its introduction in\n> 92bbe7ccf1f (submodule--helper: add remote-branch helper, 2016-08-03).\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 41 ++++++++++++++++++++++---------------\n>  1 file changed, 25 insertions(+), 16 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index 9e4069b36cb..65909255760 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -2267,42 +2267,49 @@ static int run_update_procedure(struct update_data *ud)\n>  \treturn run_update_command(ud, subforce);\n>  }\n>  \n> -static const char *remote_submodule_branch(const char *path)\n> +static int remote_submodule_branch(const char *path, const char **branch)\n>  {\n>  \tconst struct submodule *sub;\n> -\tconst char *branch = NULL;\n>  \tchar *key;\n> +\t*branch = NULL;\n>  \n>  \tsub = submodule_from_path(the_repository, null_oid(), path);\n>  \tif (!sub)\n> -\t\treturn NULL;\n> +\t\treturn die_message(_(\"could not initialize submodule at path '%s'\"),\n> +\t\t\t\t   path);\n>  \n>  \tkey = xstrfmt(\"submodule.%s.branch\", sub->name);\n> -\tif (repo_config_get_string_tmp(the_repository, key, &branch))\n> -\t\tbranch = sub->branch;\n> +\tif (repo_config_get_string_tmp(the_repository, key, branch))\n> +\t\t*branch = sub->branch;\n>  \tfree(key);\n>  \n> -\tif (!branch)\n> -\t\treturn \"HEAD\";\n> +\tif (!*branch) {\n> +\t\t*branch = \"HEAD\";\n> +\t\treturn 0;\n> +\t}\n>  \n> -\tif (!strcmp(branch, \".\")) {\n> +\tif (!strcmp(*branch, \".\")) {\n>  \t\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n>  \n>  \t\tif (!refname)\n> -\t\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n> +\t\t\treturn die_message(_(\"No such ref: %s\"), \"HEAD\");\n>  \n>  \t\t/* detached HEAD */\n>  \t\tif (!strcmp(refname, \"HEAD\"))\n> -\t\t\tdie(_(\"Submodule (%s) branch configured to inherit \"\n> -\t\t\t      \"branch from superproject, but the superproject \"\n> -\t\t\t      \"is not on any branch\"), sub->name);\n> +\t\t\treturn die_message(_(\"Submodule (%s) branch configured to inherit \"\n> +\t\t\t\t\t     \"branch from superproject, but the superproject \"\n> +\t\t\t\t\t     \"is not on any branch\"), sub->name);\n>  \n>  \t\tif (!skip_prefix(refname, \"refs/heads/\", &refname))\n> -\t\t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n> -\t\treturn refname;\n> +\t\t\treturn die_message(_(\"Expecting a full ref name, got %s\"),\n> +\t\t\t\t\t   refname);\n> +\n> +\t\t*branch = refname;\n> +\t\treturn 0;\n>  \t}\n>  \n> -\treturn branch;\n> +\t/* Our \"branch\" is coming from repo_config_get_string_tmp() */\n> +\treturn 0;\n>  }\n>  \n>  static int ensure_core_worktree(const char *path)\n> @@ -2437,7 +2444,9 @@ static int update_submodule(struct update_data *update_data)\n>  \t\tcode = get_default_remote_submodule(update_data->sm_path, &remote_name);\n>  \t\tif (code)\n>  \t\t\treturn code;\n> -\t\tbranch = remote_submodule_branch(update_data->sm_path);\n> +\t\tcode = remote_submodule_branch(update_data->sm_path, &branch);\n> +\t\tif (code)\n> +\t\t\treturn code;\n>  \t\tremote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\nThis line is the one that would segfault, I assume?\n\nLooks good.\n>  \n>  \t\tif (!update_data->nofetch) {\n> -- \n> 2.37.2.1279.g64dec4e13cf\n"},{"id":"462354","messageId":"patch-v4-01.33-2e882837026-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 01/33] submodule tests: test usage behavior","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:43Z","receivedAt":"2022-08-31T23:18:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Test what exit code and output we emit on \"git submodule -h\", how we\nhandle \"--\" when no subcommand is specified, and how the top-level\n\"--recursive\" option is handled.\n\nFor \"-h\" this doesn't make sense, but let's test for it so that any\nsubsequent eventual behavior change will become clear.\n\nFor \"--\" this follows up on 68cabbfda36 (submodule: document default\nbehavior, 2019-02-15) and tests that \"status\" doesn't support\nthe \"--\" delimiter. There's no intrinsically good reason not to\nsupport that. We behave this way due to edge cases in\ngit-submodule.sh's implementation, but as with \"-h\" let's assert our\ncurrent long-standing behavior for now.\n\nFor \"--recursive\" the exclusion of it from the top-level appears to\nhave been an omission in 15fc56a8536 (git submodule foreach: Add\n--recursive to recurse into nested submodules, 2009-08-19), there\ndoesn't seem to be a reason not to support it alongside \"--quiet\" and\n\"--cached\", but let's likewise assert our existing behavior for now.\n\nI.e. as long as \"status\" is optional it would make sense to support\nall of its options when it's omitted, but we only do that with\n\"--quiet\" and \"--cached\", and curiously omit \"--recursive\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7400-submodule-basic.sh | 26 ++++++++++++++++++++++++++\n 1 file changed, 26 insertions(+)\n\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex e7cec2e457a..b858871a953 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -14,6 +14,32 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n+test_expect_success 'submodule usage: -h' '\n+\tgit submodule -h >out 2>err &&\n+\tgrep \"^usage: git submodule\" out &&\n+\ttest_must_be_empty err\n+'\n+\n+test_expect_success 'submodule usage: --recursive' '\n+\ttest_expect_code 1 git submodule --recursive >out 2>err &&\n+\tgrep \"^usage: git submodule\" err &&\n+\ttest_must_be_empty out\n+'\n+\n+test_expect_success 'submodule usage: status --' '\n+\ttest_expect_code 1 git submodule -- &&\n+\ttest_expect_code 1 git submodule --end-of-options\n+'\n+\n+for opt in '--quiet' '--cached'\n+do\n+\ttest_expect_success \"submodule usage: status $opt\" '\n+\t\tgit submodule $opt &&\n+\t\tgit submodule status $opt &&\n+\t\tgit submodule $opt status\n+\t'\n+done\n+\n test_expect_success 'submodule deinit works on empty repository' '\n \tgit submodule deinit --all\n '\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462355","messageId":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com","subject":"[PATCH v4 00/33] submodule--helper: add tests, rm dead code, refactor & leak prep","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:42Z","receivedAt":"2022-08-31T23:18:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series is a \"prep\" series for the meaty leak fixes for\nsubmodule--helper, see [1] (which will be re-rolled on top of this\nv3). The v7 re-roll will be at [2].\n\nChanges since v3:\n\n * Addressed (hopefully) all of the small feedback, just typo fixes &\n   commit message clarifications.\n\n * Marked a parameter as \"const\", which helps reason about subsequent\n   things in the \"leak\" series.\n\nHopefully this is ready to proceed past \"seen\" in its current form...\n\n1. https://lore.kernel.org/git/cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/cover-v7-00.17-00000000000-20220831T231003Z-avarab@gmail.com\n\nThis series & passing CI can be seen at:\nhttps://github.com/avar/git/tree/avar/submodule--helper-cleanup-and-tests-4\n\nGlen Choo (2):\n  submodule--helper: add \"const\" to copy of \"update_data\"\n  submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"\n\nÆvar Arnfjörð Bjarmason (31):\n  submodule tests: test usage behavior\n  submodule tests: test for \"add <repository> <abs-path>\"\n  submodule--helper: remove unused \"name\" helper\n  submodule--helper: remove unused \"list\" helper\n  test-tool submodule-config: remove unused \"--url\" handling\n  submodule--helper: move \"is-active\" to a test-tool\n  submodule--helper: move \"check-name\" to a test-tool\n  submodule--helper: move \"resolve-relative-url-test\" to a test-tool\n  submodule--helper style: don't separate declared variables with \\n\\n\n  submodule--helper style: add \\n\\n after variable declarations\n  submodule--helper: replace memset() with { 0 }-initialization\n  submodule--helper: use xstrfmt() in clone_submodule()\n  submodule--helper: move \"sb\" in clone_submodule() to its own scope\n  submodule--helper: add \"const\" to passed \"module_clone_data\"\n  submodule--helper: add \"const\" to passed \"struct update_data\"\n  submodule--helper: don't redundantly check \"else if (res)\"\n  submodule--helper: rename \"int res\" to \"int ret\"\n  submodule--helper: return \"ret\", not \"1\" from update_submodule()\n  submodule--helper: add missing braces to \"else\" arm\n  submodule--helper: don't call submodule_strategy_to_string() in BUG()\n  submodule API: don't handle SM_..{UNSPECIFIED,COMMAND} in to_string()\n  submodule--helper: use \"code\" in run_update_command()\n  submodule--helper: don't exit() on failure, return\n  submodule--helper: libify determine_submodule_update_strategy()\n  submodule--helper: libify \"must_die_on_failure\" code paths\n  submodule--helper update: don't override 'checkout' exit code\n  submodule--helper: libify \"must_die_on_failure\" code paths (for die)\n  submodule--helper: check repo{_submodule,}_init() return values\n  submodule--helper: libify more \"die\" paths for module_update()\n  submodule--helper: libify even more \"die\" paths for module_update()\n  submodule--helper: fix bad config API usage\n\n Makefile                         |   1 +\n builtin/submodule--helper.c      | 546 ++++++++++++++-----------------\n git-compat-util.h                |   3 +\n repository.h                     |   3 +\n submodule.c                      |  12 +-\n submodule.h                      |   2 +-\n t/helper/test-submodule-config.c |  11 +-\n t/helper/test-submodule.c        | 146 +++++++++\n t/helper/test-tool-utils.h       |   9 +\n t/helper/test-tool.c             |   7 +-\n t/helper/test-tool.h             |   1 +\n t/t0060-path-utils.sh            |   2 +-\n t/t7400-submodule-basic.sh       |  56 ++--\n t/t7406-submodule-update.sh      |   2 +-\n t/t7413-submodule-is-active.sh   |  35 +-\n t/t7450-bad-git-dotfiles.sh      |   2 +-\n 16 files changed, 467 insertions(+), 371 deletions(-)\n create mode 100644 t/helper/test-submodule.c\n create mode 100644 t/helper/test-tool-utils.h\n\nRange-diff against v3:\n 1:  77586985ab3 =  1:  2e882837026 submodule tests: test usage behavior\n 2:  7425f0025da =  2:  a015be8e89a submodule tests: test for \"add <repository> <abs-path>\"\n 3:  1be48c0b22f =  3:  27a455d231a submodule--helper: remove unused \"name\" helper\n 4:  10189ba3da7 =  4:  6714a04a5c8 submodule--helper: remove unused \"list\" helper\n 5:  ef66dfcd45f =  5:  83516cdcb5c test-tool submodule-config: remove unused \"--url\" handling\n 6:  4727fbb4b64 =  6:  51d2d946b4f submodule--helper: move \"is-active\" to a test-tool\n 7:  9c644460b1d =  7:  3258b5a609d submodule--helper: move \"check-name\" to a test-tool\n 8:  03c8383b8e7 =  8:  4e6929f05ec submodule--helper: move \"resolve-relative-url-test\" to a test-tool\n 9:  b1eaa6a796b =  9:  76b55b9105f submodule--helper style: don't separate declared variables with \\n\\n\n10:  fd7fbe08536 = 10:  44b27475864 submodule--helper style: add \\n\\n after variable declarations\n11:  356f07db436 = 11:  008c6f4ac59 submodule--helper: replace memset() with { 0 }-initialization\n12:  241ac5c7eee = 12:  84504a86a72 submodule--helper: use xstrfmt() in clone_submodule()\n13:  f2f412f50c1 = 13:  474d1a9e13e submodule--helper: move \"sb\" in clone_submodule() to its own scope\n14:  ad7848067a9 = 14:  e514f0b68c0 submodule--helper: add \"const\" to passed \"module_clone_data\"\n15:  ab283479b92 = 15:  30be00d5cf7 submodule--helper: add \"const\" to copy of \"update_data\"\n -:  ----------- > 16:  b77364015cf submodule--helper: add \"const\" to passed \"struct update_data\"\n16:  ab0fd2c60f0 = 17:  52da0d60b47 submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"\n17:  fa2417c7a17 ! 18:  1786e40ec99 submodule--helper: don't redundantly check \"else if (res)\"\n    @@ Commit message\n                         return 0;\n     \n         So we don't need to guard the \"return 1\" with an \"else if (res)\", we\n    -    an return unconditionally at this point. See b3c5f5cb048 (submodule:\n    +    can return unconditionally at this point. See b3c5f5cb048 (submodule:\n         move core cmd_update() logic to C, 2022-03-15) for the initial\n         introduction of this code, this check of \"res\" has always been\n         redundant.\n18:  be1ffbf2e26 = 19:  bc7d401bfb3 submodule--helper: rename \"int res\" to \"int ret\"\n19:  92e17c37839 = 20:  fdd9ef8b6f6 submodule--helper: return \"ret\", not \"1\" from update_submodule()\n20:  55e3ea5f9dd = 21:  9edd68f9c5a submodule--helper: add missing braces to \"else\" arm\n21:  2bb45302392 ! 22:  f0ada6854c2 submodule--helper: don't call submodule_strategy_to_string() in BUG()\n    @@ Commit message\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      \t\tmust_die_on_failure = 1;\n      \t\tbreak;\n      \tdefault:\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \t}\n      \tstrvec_push(&cp.args, oid);\n      \n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      \t\t\t    ud->update_strategy.command, oid, ud->displaypath);\n      \t\t\tbreak;\n      \t\tdefault:\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \t\t}\n      \t\tif (must_die_on_failure)\n      \t\t\texit(128);\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      \t\t       ud->displaypath, ud->update_strategy.command, oid);\n      \t\tbreak;\n      \tdefault:\n22:  0131c197427 = 23:  d101aa6c8c5 submodule API: don't handle SM_..{UNSPECIFIED,COMMAND} in to_string()\n23:  6cac6cb2fa6 ! 24:  77d21b570e3 submodule--helper: use \"code\" in run_update_command()\n    @@ Commit message\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      {\n      \tstruct child_process cp = CHILD_PROCESS_INIT;\n      \tchar *oid = oid_to_hex(&ud->oid);\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \n      \tswitch (ud->update_strategy.type) {\n      \tcase SM_UPDATE_CHECKOUT:\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      \t\tstrvec_push(&cp.args, \"rebase\");\n      \t\tif (ud->quiet)\n      \t\t\tstrvec_push(&cp.args, \"--quiet\");\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \t\tbreak;\n      \tdefault:\n      \t\tBUG(\"unexpected update strategy type: %d\",\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      \tcp.dir = xstrdup(ud->sm_path);\n      \tprepare_submodule_repo_env(&cp.env);\n      \tif (run_command(&cp)) {\n24:  6d56f671c7a ! 25:  99717171578 submodule--helper: don't exit() on failure, return\n    @@ Commit message\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n    +@@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_path, int depth, int quiet,\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,\n    +-static int run_update_command(const struct update_data *ud, int subforce)\n    ++static int run_update_command(const struct update_data *ud, int subforce,\n     +\t\t\t      int *must_die_on_failure)\n      {\n      \tstruct child_process cp = CHILD_PROCESS_INIT;\n      \tchar *oid = oid_to_hex(&ud->oid);\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      \t\t}\n      \n      \t\tif (ret == 128)\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \t\treturn ret;\n      \t}\n      \n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      \treturn 0;\n      }\n      \n    --static int run_update_procedure(struct update_data *ud)\n    -+static int run_update_procedure(struct update_data *ud,\n    +-static int run_update_procedure(const struct update_data *ud)\n    ++static int run_update_procedure(const struct update_data *ud,\n     +\t\t\t\tint *must_die_on_failure)\n      {\n      \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n      \n    -@@ builtin/submodule--helper.c: static int run_update_procedure(struct update_data *ud)\n    +@@ builtin/submodule--helper.c: static int run_update_procedure(const struct update_data *ud)\n      \t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n      \t}\n      \n    @@ builtin/submodule--helper.c: static int run_update_procedure(struct update_data\n      }\n      \n      static const char *remote_submodule_branch(const char *path)\n    -@@ builtin/submodule--helper.c: static void update_data_to_args(struct update_data *update_data, struct strvec *\n    +@@ builtin/submodule--helper.c: static void update_data_to_args(const struct update_data *update_data,\n      \t\t\t\t    \"--no-single-branch\");\n      }\n      \n25:  dfd5c8bcd61 ! 26:  512106bc6be submodule--helper: libify determine_submodule_update_strategy()\n    @@ builtin/submodule--helper.c: static void determine_submodule_update_strategy(str\n      }\n      \n      struct update_clone_data {\n    -@@ builtin/submodule--helper.c: static void update_data_to_args(struct update_data *update_data, struct strvec *\n    +@@ builtin/submodule--helper.c: static void update_data_to_args(const struct update_data *update_data,\n      static int update_submodule(struct update_data *update_data,\n      \t\t\t    int *must_die_on_failure)\n      {\n26:  da1a07afd25 ! 27:  2b066190739 submodule--helper: libify \"must_die_on_failure\" code paths\n    @@ Commit message\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n    +@@ builtin/submodule--helper.c: static int fetch_in_submodule(const char *module_path, int depth, int quiet,\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(const struct update_data *ud, int subforce,\n     -\t\t\t      int *must_die_on_failure)\n    -+static int run_update_command(struct update_data *ud, int subforce)\n    ++static int run_update_command(const struct update_data *ud, int subforce)\n      {\n      \tstruct child_process cp = CHILD_PROCESS_INIT;\n      \tchar *oid = oid_to_hex(&ud->oid);\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce,\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce,\n      \t\t\t    ud->update_strategy.type);\n      \t\t}\n      \n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \t\treturn ret;\n      \t}\n      \n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce,\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce,\n      \treturn 0;\n      }\n      \n    --static int run_update_procedure(struct update_data *ud,\n    +-static int run_update_procedure(const struct update_data *ud,\n     -\t\t\t\tint *must_die_on_failure)\n    -+static int run_update_procedure(struct update_data *ud)\n    ++static int run_update_procedure(const struct update_data *ud)\n      {\n      \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n      \n    -@@ builtin/submodule--helper.c: static int run_update_procedure(struct update_data *ud,\n    +@@ builtin/submodule--helper.c: static int run_update_procedure(const struct update_data *ud,\n      \t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n      \t}\n      \n    @@ builtin/submodule--helper.c: static int run_update_procedure(struct update_data\n      }\n      \n      static const char *remote_submodule_branch(const char *path)\n    -@@ builtin/submodule--helper.c: static void update_data_to_args(struct update_data *update_data, struct strvec *\n    +@@ builtin/submodule--helper.c: static void update_data_to_args(const struct update_data *update_data,\n      \t\t\t\t    \"--no-single-branch\");\n      }\n      \n27:  2795a3738c8 ! 28:  72e3cdf6543 submodule--helper update: don't override 'checkout' exit code\n    @@ Commit message\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      {\n      \tstruct child_process cp = CHILD_PROCESS_INIT;\n      \tchar *oid = oid_to_hex(&ud->oid);\n    @@ builtin/submodule--helper.c: static int run_update_command(struct update_data *u\n      \n      \tswitch (ud->update_strategy.type) {\n      \tcase SM_UPDATE_CHECKOUT:\n    -@@ builtin/submodule--helper.c: static int run_update_command(struct update_data *ud, int subforce)\n    +@@ builtin/submodule--helper.c: static int run_update_command(const struct update_data *ud, int subforce)\n      \n      \tcp.dir = xstrdup(ud->sm_path);\n      \tprepare_submodule_repo_env(&cp.env);\n28:  6d9bccb34c3 ! 29:  a283ae61e6e submodule--helper: libify \"must_die_on_failure\" code paths (for die)\n    @@ Commit message\n     \n         Continue the libification of codepaths that previously relied on\n         \"must_die_on_failure\". In these cases we've always been early aborting\n    -    by calling die(), but as we know that these codpaths will properly\n    +    by calling die(), but as we know that these codepaths will properly\n         handle return codes of 128 to mean an early abort let's have them use\n         die_message() instead.\n     \n    @@ Commit message\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static int run_update_procedure(struct update_data *ud)\n    +@@ builtin/submodule--helper.c: static int run_update_procedure(const struct update_data *ud)\n      \t\t */\n      \t\tif (!is_tip_reachable(ud->sm_path, &ud->oid) &&\n      \t\t    fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, &ud->oid))\n29:  d4b55f07a30 = 30:  ba5c170c3a4 submodule--helper: check repo{_submodule,}_init() return values\n30:  15c2490a978 ! 31:  a0d71b4e8bb submodule--helper: libify more \"die\" paths for module_update()\n    @@ Commit message\n                 char *remote_name = get_default_remote_submodule(update_data->sm_path);\n                 const char *branch = remote_submodule_branch(update_data->sm_path);\n     \n    +    We can safely remove the \"!default_remote\" case from sync_submodule(),\n    +    because our get_default_remote_submodule() function now returns a\n    +    die_message() on failure, so we can have it an dother callers check if\n    +    the exit code should be non-zero instead.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n31:  1694ccfe882 ! 32:  3254a8ca6eb submodule--helper: libify even more \"die\" paths for module_update()\n    @@ Commit message\n         2022-03-04):\n     \n         We were assuming that remote_submodule_branch() would always return\n    -    on-NULL, but if the submodule_from_path() call in that function fails\n    +    non-NULL, but if the submodule_from_path() call in that function fails\n         we'll return NULL. See its introduction in\n    -    92bbe7ccf1f (submodule--helper: add remote-branch helper, 2016-08-03).\n    +    92bbe7ccf1f (submodule--helper: add remote-branch helper,\n    +    2016-08-03). I.e. we'd previously have segfaulted in the xstrfmt()\n    +    call in update_submodule() seen in the context.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/submodule--helper.c ##\n    -@@ builtin/submodule--helper.c: static int run_update_procedure(struct update_data *ud)\n    +@@ builtin/submodule--helper.c: static int run_update_procedure(const struct update_data *ud)\n      \treturn run_update_command(ud, subforce);\n      }\n      \n32:  d133402462f = 33:  1e38bfa7f95 submodule--helper: fix bad config API usage\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462356","messageId":"patch-v4-02.33-a015be8e89a-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 02/33] submodule tests: test for \"add <repository> <abs-path>\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:44Z","receivedAt":"2022-08-31T23:18:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a missing test for \"\"add <repository> <path>\" where \"<path>\" is an\nabsolute path. This tests code added in [1] and later turned into an\n\"else\" branch in clone_submodule() in [2] that's never been tested.\n\nThis needs to be skipped on WINDOWS because all of $PWD, $(pwd) and\nthe \"$(pwd -P)\" we get via \"$submodurl\" would fail in CI with e.g.:\n\n\tfatal: could not create directory 'D:/a/git/git/t/trash\n\tdirectory.t7400-submodule-basic/.git/modules/D:/a/git/git/t/trash\n\tdirectory.t7400-submodule-basic/add-abs'\n\nI.e. we can't handle these sorts of paths in this context on that\nplatform.\n\nI'm not sure where we run into the edges of \"$PWD\" behavior on\nWindows (see [1] for a previous loose end on the topic), but for the\npurposes of this test it's sufficient that we test this on other\nplatforms.\n\n1. ee8838d1577 (submodule: rewrite `module_clone` shell function in C,\n   2015-09-08)\n2. f8eaa0ba98b (submodule--helper, module_clone: always operate on\n   absolute paths, 2016-03-31)\n\n1. https://lore.kernel.org/git/220630.86edz6c75c.gmgdl@evledraar.gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7400-submodule-basic.sh | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex b858871a953..6a77d817a82 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -178,6 +178,11 @@ test_expect_success 'submodule add' '\n \ttest_must_be_empty untracked\n '\n \n+test_expect_success !WINDOWS 'submodule add (absolute path)' '\n+\ttest_when_finished \"git reset --hard\" &&\n+\tgit submodule add \"$submodurl\" \"$submodurl/add-abs\"\n+'\n+\n test_expect_success 'setup parent and one repository' '\n \ttest_create_repo parent &&\n \ttest_commit -C parent one\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462357","messageId":"patch-v4-03.33-27a455d231a-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 03/33] submodule--helper: remove unused \"name\" helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:45Z","receivedAt":"2022-08-31T23:18:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"name\" helper has not been used since e83e3333b57 (submodule: port\nsubmodule subcommand 'summary' from shell to C, 2020-08-13).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.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 b63f420ecef..fc4d2779da6 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -771,24 +771,6 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int module_name(int argc, const char **argv, const char *prefix)\n-{\n-\tconst struct submodule *sub;\n-\n-\tif (argc != 2)\n-\t\tusage(_(\"git submodule--helper name <path>\"));\n-\n-\tsub = submodule_from_path(the_repository, null_oid(), argv[1]);\n-\n-\tif (!sub)\n-\t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n-\t\t    argv[1]);\n-\n-\tprintf(\"%s\\n\", sub->name);\n-\n-\treturn 0;\n-}\n-\n struct module_cb {\n \tunsigned int mod_src;\n \tunsigned int mod_dst;\n@@ -3362,7 +3344,6 @@ struct cmd_struct {\n \n static struct cmd_struct commands[] = {\n \t{\"list\", module_list, 0},\n-\t{\"name\", module_name, 0},\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462358","messageId":"patch-v4-04.33-6714a04a5c8-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 04/33] submodule--helper: remove unused \"list\" helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:46Z","receivedAt":"2022-08-31T23:18:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the \"submodule--helper list\" sub-command, which hasn't been\nused by git-submodule.sh since 2964d6e5e1e (submodule: port subcommand\n'set-branch' from shell to C, 2020-06-02).\n\nThere was a test added in 2b56bb7a87a (submodule helper list: respect\ncorrect path prefix, 2016-02-24) which relied on it, but the right\nthing to do here is to delete that test as well.\n\nThat test was regression testing the \"list\" subcommand itself. We're\nnot getting anything useful from the \"list | cut -f2\" invocation that\nwe couldn't get from \"foreach 'echo $sm_path'\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 40 -------------------------------------\n t/t7400-submodule-basic.sh  | 25 -----------------------\n 2 files changed, 65 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex fc4d2779da6..24a305151d1 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -266,45 +266,6 @@ static char *get_up_path(const char *path)\n \treturn strbuf_detach(&sb, NULL);\n }\n \n-static int module_list(int argc, const char **argv, const char *prefix)\n-{\n-\tint i;\n-\tstruct pathspec pathspec;\n-\tstruct module_list list = MODULE_LIST_INIT;\n-\n-\tstruct option module_list_options[] = {\n-\t\tOPT_STRING(0, \"prefix\", &prefix,\n-\t\t\t   N_(\"path\"),\n-\t\t\t   N_(\"alternative anchor for relative paths\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tconst char *const git_submodule_helper_usage[] = {\n-\t\tN_(\"git submodule--helper list [--prefix=<path>] [<path>...]\"),\n-\t\tNULL\n-\t};\n-\n-\targc = parse_options(argc, argv, prefix, module_list_options,\n-\t\t\t     git_submodule_helper_usage, 0);\n-\n-\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n-\t\treturn 1;\n-\n-\tfor (i = 0; i < list.nr; i++) {\n-\t\tconst struct cache_entry *ce = list.entries[i];\n-\n-\t\tif (ce_stage(ce))\n-\t\t\tprintf(\"%06o %s U\\t\", ce->ce_mode,\n-\t\t\t       oid_to_hex(null_oid()));\n-\t\telse\n-\t\t\tprintf(\"%06o %s %d\\t\", ce->ce_mode,\n-\t\t\t       oid_to_hex(&ce->oid), ce_stage(ce));\n-\n-\t\tfprintf(stdout, \"%s\\n\", ce->name);\n-\t}\n-\treturn 0;\n-}\n-\n static void for_each_listed_submodule(const struct module_list *list,\n \t\t\t\t      each_submodule_fn fn, void *cb_data)\n {\n@@ -3343,7 +3304,6 @@ struct cmd_struct {\n };\n \n static struct cmd_struct commands[] = {\n-\t{\"list\", module_list, 0},\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex 6a77d817a82..b50db3f1031 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -1255,31 +1255,6 @@ test_expect_success 'submodule add clone shallow submodule' '\n \t)\n '\n \n-test_expect_success 'submodule helper list is not confused by common prefixes' '\n-\tmkdir -p dir1/b &&\n-\t(\n-\t\tcd dir1/b &&\n-\t\tgit init &&\n-\t\techo hi >testfile2 &&\n-\t\tgit add . &&\n-\t\tgit commit -m \"test1\"\n-\t) &&\n-\tmkdir -p dir2/b &&\n-\t(\n-\t\tcd dir2/b &&\n-\t\tgit init &&\n-\t\techo hello >testfile1 &&\n-\t\tgit add .  &&\n-\t\tgit commit -m \"test2\"\n-\t) &&\n-\tgit submodule add /dir1/b dir1/b &&\n-\tgit submodule add /dir2/b dir2/b &&\n-\tgit commit -m \"first submodule commit\" &&\n-\tgit submodule--helper list dir1/b | cut -f 2 >actual &&\n-\techo \"dir1/b\" >expect &&\n-\ttest_cmp expect actual\n-'\n-\n test_expect_success 'setup superproject with submodules' '\n \tgit init sub1 &&\n \ttest_commit -C sub1 test &&\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462359","messageId":"patch-v4-05.33-83516cdcb5c-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 05/33] test-tool submodule-config: remove unused \"--url\" handling","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:47Z","receivedAt":"2022-08-31T23:18:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"No test has used this \"--url\" parameter since the test code that made\nuse of it was removed in 32bc548329d (submodule-config: remove support\nfor overlaying repository config, 2017-08-03).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/helper/test-submodule-config.c | 11 ++---------\n 1 file changed, 2 insertions(+), 9 deletions(-)\n\ndiff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c\nindex e2692746dfd..22a41c40926 100644\n--- a/t/helper/test-submodule-config.c\n+++ b/t/helper/test-submodule-config.c\n@@ -15,14 +15,11 @@ int cmd__submodule_config(int argc, const char **argv)\n {\n \tconst char **arg = argv;\n \tint my_argc = argc;\n-\tint output_url = 0;\n \tint lookup_name = 0;\n \n \targ++;\n \tmy_argc--;\n \twhile (arg[0] && starts_with(arg[0], \"--\")) {\n-\t\tif (!strcmp(arg[0], \"--url\"))\n-\t\t\toutput_url = 1;\n \t\tif (!strcmp(arg[0], \"--name\"))\n \t\t\tlookup_name = 1;\n \t\targ++;\n@@ -57,12 +54,8 @@ int cmd__submodule_config(int argc, const char **argv)\n \t\tif (!submodule)\n \t\t\tdie_usage(argc, argv, \"Submodule not found.\");\n \n-\t\tif (output_url)\n-\t\t\tprintf(\"Submodule url: '%s' for path '%s'\\n\",\n-\t\t\t\t\tsubmodule->url, submodule->path);\n-\t\telse\n-\t\t\tprintf(\"Submodule name: '%s' for path '%s'\\n\",\n-\t\t\t\t\tsubmodule->name, submodule->path);\n+\t\tprintf(\"Submodule name: '%s' for path '%s'\\n\", submodule->name,\n+\t\t       submodule->path);\n \n \t\targ += 2;\n \t}\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462360","messageId":"patch-v4-07.33-3258b5a609d-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 07/33] submodule--helper: move \"check-name\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:49Z","receivedAt":"2022-08-31T23:18:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the \"check-name\" helper to a test-tool, since\na6226fd772b (submodule--helper: convert the bulk of cmd_add() to C,\n2021-08-10) it has only been used by this test, not git-submodule.sh.\n\nAs noted with its introduction in 0383bbb9015 (submodule-config:\nverify submodule names as paths, 2018-04-30) the intent of\nt7450-bad-git-dotfiles.sh has always been to unit test the\ncheck_submodule_name() function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 24 -------------------\n t/helper/test-submodule.c   | 46 +++++++++++++++++++++++++++++++++++++\n t/t7450-bad-git-dotfiles.sh |  2 +-\n 3 files changed, 47 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e10c3ac7550..e8458567976 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2731,29 +2731,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-/*\n- * Exit non-zero if any of the submodule names given on the command line is\n- * invalid. If no names are given, filter stdin to print only valid names\n- * (which is primarily intended for testing).\n- */\n-static int check_name(int argc, const char **argv, const char *prefix)\n-{\n-\tif (argc > 1) {\n-\t\twhile (*++argv) {\n-\t\t\tif (check_submodule_name(*argv) < 0)\n-\t\t\t\treturn 1;\n-\t\t}\n-\t} else {\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n-\t\t\tif (!check_submodule_name(buf.buf))\n-\t\t\t\tprintf(\"%s\\n\", buf.buf);\n-\t\t}\n-\t\tstrbuf_release(&buf);\n-\t}\n-\treturn 0;\n-}\n-\n static int module_config(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -3308,7 +3285,6 @@ static struct cmd_struct commands[] = {\n \t{\"summary\", module_summary, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n-\t{\"check-name\", check_name, 0},\n \t{\"config\", module_config, 0},\n \t{\"set-url\", module_set_url, 0},\n \t{\"set-branch\", module_set_branch, 0},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nindex 494c6558d9f..9f0eb440192 100644\n--- a/t/helper/test-submodule.c\n+++ b/t/helper/test-submodule.c\n@@ -2,8 +2,16 @@\n #include \"test-tool-utils.h\"\n #include \"cache.h\"\n #include \"parse-options.h\"\n+#include \"submodule-config.h\"\n #include \"submodule.h\"\n \n+#define TEST_TOOL_CHECK_NAME_USAGE \\\n+\t\"test-tool submodule check-name <name>\"\n+static const char *submodule_check_name_usage[] = {\n+\tTEST_TOOL_CHECK_NAME_USAGE,\n+\tNULL\n+};\n+\n #define TEST_TOOL_IS_ACTIVE_USAGE \\\n \t\"test-tool submodule is-active <name>\"\n static const char *submodule_is_active_usage[] = {\n@@ -12,10 +20,47 @@ static const char *submodule_is_active_usage[] = {\n };\n \n static const char *submodule_usage[] = {\n+\tTEST_TOOL_CHECK_NAME_USAGE,\n \tTEST_TOOL_IS_ACTIVE_USAGE,\n \tNULL\n };\n \n+/*\n+ * Exit non-zero if any of the submodule names given on the command line is\n+ * invalid. If no names are given, filter stdin to print only valid names\n+ * (which is primarily intended for testing).\n+ */\n+static int check_name(int argc, const char **argv)\n+{\n+\tif (argc > 1) {\n+\t\twhile (*++argv) {\n+\t\t\tif (check_submodule_name(*argv) < 0)\n+\t\t\t\treturn 1;\n+\t\t}\n+\t} else {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\t\twhile (strbuf_getline(&buf, stdin) != EOF) {\n+\t\t\tif (!check_submodule_name(buf.buf))\n+\t\t\t\tprintf(\"%s\\n\", buf.buf);\n+\t\t}\n+\t\tstrbuf_release(&buf);\n+\t}\n+\treturn 0;\n+}\n+\n+static int cmd__submodule_check_name(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_check_name_usage, 0);\n+\tif (argc)\n+\t\tusage_with_options(submodule_check_name_usage, options);\n+\n+\treturn check_name(argc, argv);\n+}\n+\n static int cmd__submodule_is_active(int argc, const char **argv)\n {\n \tstruct option options[] = {\n@@ -32,6 +77,7 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n }\n \n static struct test_cmd cmds[] = {\n+\t{ \"check-name\", cmd__submodule_check_name },\n \t{ \"is-active\", cmd__submodule_is_active },\n };\n \ndiff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh\nindex 41706c1c9ff..2c24f120da3 100755\n--- a/t/t7450-bad-git-dotfiles.sh\n+++ b/t/t7450-bad-git-dotfiles.sh\n@@ -21,7 +21,7 @@ test_expect_success 'check names' '\n \tvalid/with/paths\n \tEOF\n \n-\tgit submodule--helper check-name >actual <<-\\EOF &&\n+\ttest-tool submodule check-name >actual <<-\\EOF &&\n \tvalid\n \tvalid/with/paths\n \n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462361","messageId":"patch-v4-08.33-4e6929f05ec-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 08/33] submodule--helper: move \"resolve-relative-url-test\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:50Z","receivedAt":"2022-08-31T23:18:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As its name suggests the \"resolve-relative-url-test\" has never been\nused outside of the test suite, see 63e95beb085 (submodule: port\nresolve_relative_url from shell to C, 2016-04-15) for its original\naddition.\n\nPerhaps it would make sense to drop this code entirely, as we feel\nthat we've got enough indirect test coverage, but let's leave that\nquestion to a possible follow-up change. For now let's keep the test\ncoverage this gives us.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 23 --------------------\n t/helper/test-submodule.c   | 42 +++++++++++++++++++++++++++++++++++++\n t/t0060-path-utils.sh       |  2 +-\n 3 files changed, 43 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e8458567976..7e2986902dd 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -96,28 +96,6 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int\n \treturn resolved_url;\n }\n \n-static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)\n-{\n-\tchar *remoteurl, *res;\n-\tconst char *up_path, *url;\n-\n-\tif (argc != 4)\n-\t\tdie(\"resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>\");\n-\n-\tup_path = argv[1];\n-\tremoteurl = xstrdup(argv[2]);\n-\turl = argv[3];\n-\n-\tif (!strcmp(up_path, \"(null)\"))\n-\t\tup_path = NULL;\n-\n-\tres = relative_url(remoteurl, url, up_path);\n-\tputs(res);\n-\tfree(res);\n-\tfree(remoteurl);\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 {\n@@ -3276,7 +3254,6 @@ static struct cmd_struct commands[] = {\n \t{\"clone\", module_clone, SUPPORT_SUPER_PREFIX},\n \t{\"add\", module_add, 0},\n \t{\"update\", module_update, SUPPORT_SUPER_PREFIX},\n-\t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, 0},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nindex 9f0eb440192..e0e0c53d386 100644\n--- a/t/helper/test-submodule.c\n+++ b/t/helper/test-submodule.c\n@@ -2,6 +2,7 @@\n #include \"test-tool-utils.h\"\n #include \"cache.h\"\n #include \"parse-options.h\"\n+#include \"remote.h\"\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n \n@@ -19,9 +20,17 @@ static const char *submodule_is_active_usage[] = {\n \tNULL\n };\n \n+#define TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE \\\n+\t\"test-tool submodule resolve-relative-url <up_path> <remoteurl> <url>\"\n+static const char *submodule_resolve_relative_url_usage[] = {\n+\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n+\tNULL,\n+};\n+\n static const char *submodule_usage[] = {\n \tTEST_TOOL_CHECK_NAME_USAGE,\n \tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tTEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,\n \tNULL\n };\n \n@@ -76,9 +85,42 @@ static int cmd__submodule_is_active(int argc, const char **argv)\n \treturn !is_submodule_active(the_repository, argv[0]);\n }\n \n+static int resolve_relative_url(int argc, const char **argv)\n+{\n+\tchar *remoteurl, *res;\n+\tconst char *up_path, *url;\n+\n+\tup_path = argv[0];\n+\tremoteurl = xstrdup(argv[1]);\n+\turl = argv[2];\n+\n+\tif (!strcmp(up_path, \"(null)\"))\n+\t\tup_path = NULL;\n+\n+\tres = relative_url(remoteurl, url, up_path);\n+\tputs(res);\n+\tfree(res);\n+\tfree(remoteurl);\n+\treturn 0;\n+}\n+\n+static int cmd__submodule_resolve_relative_url(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_resolve_relative_url_usage, 0);\n+\tif (argc != 3)\n+\t\tusage_with_options(submodule_resolve_relative_url_usage, options);\n+\n+\treturn resolve_relative_url(argc, argv);\n+}\n+\n static struct test_cmd cmds[] = {\n \t{ \"check-name\", cmd__submodule_check_name },\n \t{ \"is-active\", cmd__submodule_is_active },\n+\t{ \"resolve-relative-url\", cmd__submodule_resolve_relative_url},\n };\n \n int cmd__submodule(int argc, const char **argv)\ndiff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh\nindex 1f2007e62b7..68e29c904a6 100755\n--- a/t/t0060-path-utils.sh\n+++ b/t/t0060-path-utils.sh\n@@ -22,7 +22,7 @@ relative_path() {\n \n test_submodule_relative_url() {\n \ttest_expect_success \"test_submodule_relative_url: $1 $2 $3 => $4\" \"\n-\t\tactual=\\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&\n+\t\tactual=\\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&\n \t\ttest \\\"\\$actual\\\" = '$4'\n \t\"\n }\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462362","messageId":"patch-v4-09.33-76b55b9105f-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 09/33] submodule--helper style: don't separate declared variables with \\n\\n","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:51Z","receivedAt":"2022-08-31T23:18:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The usual style in the codebase is to separate declared variables with\na single newline, not two, let's adjust this code to conform to\nthat. This makes the eventual addition of various \"int ret\" variables\nmore consistent.\n\nIn doing this the comment added in 2964d6e5e1e (submodule: port\nsubcommand 'set-branch' from shell to C, 2020-06-02) might become\nambiguous to some, although it should be clear what it's referring to,\nlet's move it above the 'OPT_NOOP_NOARG('q', \"quiet\")' to make that\nclearer.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 33 +++++----------------------------\n 1 file changed, 5 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7e2986902dd..02552410679 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -368,14 +368,12 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \tstruct foreach_cb info = FOREACH_CB_INIT;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n-\n \tstruct option module_foreach_options[] = {\n \t\tOPT__QUIET(&info.quiet, N_(\"suppress output of entering each submodule command\")),\n \t\tOPT_BOOL(0, \"recursive\", &info.recursive,\n \t\t\t N_(\"recurse into nested submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule foreach [--quiet] [--recursive] [--] <command>\"),\n \t\tNULL\n@@ -504,12 +502,10 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\n \tstruct option module_init_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for initializing a submodule\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule init [<options>] [<path>]\"),\n \t\tNULL\n@@ -682,14 +678,12 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\n \tstruct option module_status_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT_BIT(0, \"cached\", &info.flags, N_(\"use commit stored in the index instead of the one stored in the submodule HEAD\"), OPT_CACHED),\n \t\tOPT_BIT(0, \"recursive\", &info.flags, N_(\"recurse into nested submodules\"), OPT_RECURSIVE),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule status [--quiet] [--cached] [--recursive] [<path>...]\"),\n \t\tNULL\n@@ -1085,7 +1079,6 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \tenum diff_cmd diff_cmd = DIFF_INDEX;\n \tstruct object_id head_oid;\n \tint ret;\n-\n \tstruct option module_summary_options[] = {\n \t\tOPT_BOOL(0, \"cached\", &cached,\n \t\t\t N_(\"use the commit stored in the index instead of the submodule HEAD\")),\n@@ -1097,7 +1090,6 @@ static int module_summary(int argc, const char **argv, const char *prefix)\n \t\t\t     N_(\"limit the summary size\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule summary [<options>] [<commit>] [--] [<path>]\"),\n \t\tNULL\n@@ -1254,14 +1246,12 @@ static int module_sync(int argc, const char **argv, const char *prefix)\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n \tint recursive = 0;\n-\n \tstruct option module_sync_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output of synchronizing submodule url\")),\n \t\tOPT_BOOL(0, \"recursive\", &recursive,\n \t\t\tN_(\"recurse into nested submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule sync [--quiet] [--recursive] [<path>]\"),\n \t\tNULL\n@@ -1393,14 +1383,12 @@ static int module_deinit(int argc, const char **argv, const char *prefix)\n \tint quiet = 0;\n \tint force = 0;\n \tint all = 0;\n-\n \tstruct option module_deinit_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress submodule status output\")),\n \t\tOPT__FORCE(&force, N_(\"remove submodule working trees even if they contain local changes\"), 0),\n \t\tOPT_BOOL(0, \"all\", &all, N_(\"unregister all submodules\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]\"),\n \t\tNULL\n@@ -1669,7 +1657,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options;\n-\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1701,7 +1688,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tOPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule--helper clone [--prefix=<path>] [--quiet] \"\n \t\t   \"[--reference <repository>] [--name <name>] [--depth <depth>] \"\n@@ -2489,7 +2475,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tstruct update_data opt = UPDATE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options;\n \tint ret;\n-\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@@ -2533,7 +2518,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \t\tOPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule [--quiet] update\"\n \t\t\" [--init [--filter=<filter-spec>]] [--remote]\"\n@@ -2682,7 +2666,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tunsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;\n-\n \tstruct option embed_gitdir_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &prefix,\n \t\t\t   N_(\"path\"),\n@@ -2691,7 +2674,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \t\t\tABSORB_GITDIR_RECURSE_SUBMODULES),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const git_submodule_helper_usage[] = {\n \t\tN_(\"git submodule absorbgitdirs [<options>] [<path>...]\"),\n \t\tNULL\n@@ -2715,7 +2697,6 @@ static int module_config(int argc, const char **argv, const char *prefix)\n \t\tCHECK_WRITEABLE = 1,\n \t\tDO_UNSET = 2\n \t} command = 0;\n-\n \tstruct option module_config_options[] = {\n \t\tOPT_CMDMODE(0, \"check-writeable\", &command,\n \t\t\t    N_(\"check if it is safe to write to the .gitmodules file\"),\n@@ -2761,7 +2742,6 @@ static int module_set_url(int argc, const char **argv, const char *prefix)\n \tconst char *newurl;\n \tconst char *path;\n \tchar *config_name;\n-\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"suppress output for setting url of a submodule\")),\n \t\tOPT_END()\n@@ -2792,13 +2772,13 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)\n \tconst char *opt_branch = NULL;\n \tconst char *path;\n \tchar *config_name;\n-\n-\t/*\n-\t * We accept the `quiet` option for uniformity across subcommands,\n-\t * though there is nothing to make less verbose in this subcommand.\n-\t */\n \tstruct option options[] = {\n+\t\t/*\n+\t\t * We accept the `quiet` option for uniformity across subcommands,\n+\t\t * though there is nothing to make less verbose in this subcommand.\n+\t\t */\n \t\tOPT_NOOP_NOARG('q', \"quiet\"),\n+\n \t\tOPT_BOOL('d', \"default\", &opt_default,\n \t\t\tN_(\"set the default tracking branch to master\")),\n \t\tOPT_STRING('b', \"branch\", &opt_branch, N_(\"branch\"),\n@@ -2833,7 +2813,6 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)\n {\n \tenum branch_track track;\n \tint quiet = 0, force = 0, reflog = 0, dry_run = 0;\n-\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"print only error messages\")),\n \t\tOPT__FORCE(&force, N_(\"force creation\"), 0),\n@@ -3132,7 +3111,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \tint force = 0, quiet = 0, progress = 0, dissociate = 0;\n \tstruct add_data add_data = ADD_DATA_INIT;\n \tchar *to_free = NULL;\n-\n \tstruct option options[] = {\n \t\tOPT_STRING('b', \"branch\", &add_data.branch, N_(\"branch\"),\n \t\t\t   N_(\"branch of repository to add as submodule\")),\n@@ -3149,7 +3127,6 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \t\tOPT_INTEGER(0, \"depth\", &add_data.depth, N_(\"depth for shallow clones\")),\n \t\tOPT_END()\n \t};\n-\n \tconst char *const usage[] = {\n \t\tN_(\"git submodule add [<options>] [--] <repository> [<path>]\"),\n \t\tNULL\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462363","messageId":"patch-v4-12.33-84504a86a72-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 12/33] submodule--helper: use xstrfmt() in clone_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:54Z","receivedAt":"2022-08-31T23:18:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use xstrfmt() in clone_submodule() instead of a \"struct strbuf\" in two\ncases where we weren't getting anything out of using the \"struct\nstrbuf\".\n\nThis changes code that was was added along with other uses of \"struct\nstrbuf\" in this function in ee8838d1577 (submodule: rewrite\n`module_clone` shell function in C, 2015-09-08).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 17 +++++++++--------\n 1 file changed, 9 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7eb9fb2f00f..c7833bae81e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1571,12 +1571,11 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \tsm_gitdir = absolute_pathdup(sb.buf);\n \tstrbuf_reset(&sb);\n \n-\tif (!is_absolute_path(clone_data->path)) {\n-\t\tstrbuf_addf(&sb, \"%s/%s\", get_git_work_tree(), clone_data->path);\n-\t\tclone_data->path = strbuf_detach(&sb, NULL);\n-\t} else {\n+\tif (!is_absolute_path(clone_data->path))\n+\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n+\t\t\t\t\t   clone_data->path);\n+\telse\n \t\tclone_data->path = xstrdup(clone_data->path);\n-\t}\n \n \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n@@ -1628,14 +1627,16 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n \t\t\t    clone_data->url, clone_data->path);\n \t} else {\n+\t\tchar *path;\n+\n \t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n \t\t    !is_empty_dir(clone_data->path))\n \t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n \t\tif (safe_create_leading_directories_const(clone_data->path) < 0)\n \t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n-\t\tstrbuf_addf(&sb, \"%s/index\", sm_gitdir);\n-\t\tunlink_or_warn(sb.buf);\n-\t\tstrbuf_reset(&sb);\n+\t\tpath = xstrfmt(\"%s/index\", sm_gitdir);\n+\t\tunlink_or_warn(path);\n+\t\tfree(path);\n \t}\n \n \tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462364","messageId":"patch-v4-11.33-008c6f4ac59-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 11/33] submodule--helper: replace memset() with { 0 }-initialization","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:53Z","receivedAt":"2022-08-31T23:19:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Use the less verbose { 0 }-initialization syntax rather than memset()\nin builtin/submodule--helper.c, this doesn't make a difference in\nterms of behavior, but as we're about to modify adjacent code makes\nthis more consistent, and lets us avoid worrying about when the\nmemset() happens v.s. a \"goto cleanup\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 6 ++----\n 1 file changed, 2 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a492ea3cfed..7eb9fb2f00f 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1667,7 +1667,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n {\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n-\tstruct list_objects_filter_options filter_options;\n+\tstruct list_objects_filter_options filter_options = { 0 };\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1707,7 +1707,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tNULL\n \t};\n \n-\tmemset(&filter_options, 0, sizeof(filter_options));\n \targc = parse_options(argc, argv, prefix, module_clone_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n@@ -2491,7 +2490,7 @@ static int module_update(int argc, const char **argv, const char *prefix)\n {\n \tstruct pathspec pathspec;\n \tstruct update_data opt = UPDATE_DATA_INIT;\n-\tstruct list_objects_filter_options filter_options;\n+\tstruct list_objects_filter_options filter_options = { 0 };\n \tint ret;\n \tstruct option module_update_options[] = {\n \t\tOPT__FORCE(&opt.force, N_(\"force checkout updates\"), 0),\n@@ -2549,7 +2548,6 @@ static int module_update(int argc, const char **argv, const char *prefix)\n \tupdate_clone_config_from_gitmodules(&opt.max_jobs);\n \tgit_config(git_update_clone_config, &opt.max_jobs);\n \n-\tmemset(&filter_options, 0, sizeof(filter_options));\n \targc = parse_options(argc, argv, prefix, module_update_options,\n \t\t\t     git_submodule_helper_usage, 0);\n \n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462365","messageId":"patch-v4-06.33-51d2d946b4f-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 06/33] submodule--helper: move \"is-active\" to a test-tool","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:48Z","receivedAt":"2022-08-31T23:19:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Create a new \"test-tool submodule\" and move the \"is-active\" subcommand\nover to it. It was added in 5c2bd8b77ae (submodule--helper: add\nis-active subcommand, 2017-03-16), since\na452128a36c (submodule--helper: introduce add-config subcommand,\n2021-08-06) it hasn't been used by git-submodule.sh.\n\nSince we're creating a command dispatch similar to test-tool.c itself\nlet's split out the \"struct test_cmd\" into a new test-tool-utils.h,\nwhich both this new code and test-tool.c itself can use.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile                       |  1 +\n builtin/submodule--helper.c    |  9 ------\n t/helper/test-submodule.c      | 58 ++++++++++++++++++++++++++++++++++\n t/helper/test-tool-utils.h     |  9 ++++++\n t/helper/test-tool.c           |  7 ++--\n t/helper/test-tool.h           |  1 +\n t/t7413-submodule-is-active.sh | 35 ++++++++++----------\n 7 files changed, 90 insertions(+), 30 deletions(-)\n create mode 100644 t/helper/test-submodule.c\n create mode 100644 t/helper/test-tool-utils.h\n\ndiff --git a/Makefile b/Makefile\nindex eac30126e29..e0daec07306 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -786,6 +786,7 @@ TEST_BUILTINS_OBJS += test-strcmp-offset.o\n TEST_BUILTINS_OBJS += test-string-list.o\n TEST_BUILTINS_OBJS += test-submodule-config.o\n TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o\n+TEST_BUILTINS_OBJS += test-submodule.o\n TEST_BUILTINS_OBJS += test-subprocess.o\n TEST_BUILTINS_OBJS += test-trace2.o\n TEST_BUILTINS_OBJS += test-urlmatch-normalization.o\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 24a305151d1..e10c3ac7550 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2731,14 +2731,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static int is_active(int argc, const char **argv, const char *prefix)\n-{\n-\tif (argc != 2)\n-\t\tdie(\"submodule--helper is-active takes exactly 1 argument\");\n-\n-\treturn !is_submodule_active(the_repository, argv[1]);\n-}\n-\n /*\n  * Exit non-zero if any of the submodule names given on the command line is\n  * invalid. If no names are given, filter stdin to print only valid names\n@@ -3316,7 +3308,6 @@ static struct cmd_struct commands[] = {\n \t{\"summary\", module_summary, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorbgitdirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\n-\t{\"is-active\", is_active, 0},\n \t{\"check-name\", check_name, 0},\n \t{\"config\", module_config, 0},\n \t{\"set-url\", module_set_url, 0},\ndiff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c\nnew file mode 100644\nindex 00000000000..494c6558d9f\n--- /dev/null\n+++ b/t/helper/test-submodule.c\n@@ -0,0 +1,58 @@\n+#include \"test-tool.h\"\n+#include \"test-tool-utils.h\"\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+#include \"submodule.h\"\n+\n+#define TEST_TOOL_IS_ACTIVE_USAGE \\\n+\t\"test-tool submodule is-active <name>\"\n+static const char *submodule_is_active_usage[] = {\n+\tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tNULL\n+};\n+\n+static const char *submodule_usage[] = {\n+\tTEST_TOOL_IS_ACTIVE_USAGE,\n+\tNULL\n+};\n+\n+static int cmd__submodule_is_active(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, \"test-tools\", options,\n+\t\t\t     submodule_is_active_usage, 0);\n+\tif (argc != 1)\n+\t\tusage_with_options(submodule_is_active_usage, options);\n+\n+\tsetup_git_directory();\n+\n+\treturn !is_submodule_active(the_repository, argv[0]);\n+}\n+\n+static struct test_cmd cmds[] = {\n+\t{ \"is-active\", cmd__submodule_is_active },\n+};\n+\n+int cmd__submodule(int argc, const char **argv)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\tsize_t i;\n+\n+\targc = parse_options(argc, argv, \"test-tools\", options, submodule_usage,\n+\t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n+\tif (argc < 1)\n+\t\tusage_with_options(submodule_usage, options);\n+\n+\tfor (i = 0; i < ARRAY_SIZE(cmds); i++)\n+\t\tif (!strcmp(cmds[i].name, argv[0]))\n+\t\t\treturn cmds[i].fn(argc, argv);\n+\n+\tusage_msg_optf(\"unknown subcommand '%s'\", submodule_usage, options,\n+\t\t       argv[0]);\n+\n+\treturn 0;\n+}\ndiff --git a/t/helper/test-tool-utils.h b/t/helper/test-tool-utils.h\nnew file mode 100644\nindex 00000000000..6a0e5e0074f\n--- /dev/null\n+++ b/t/helper/test-tool-utils.h\n@@ -0,0 +1,9 @@\n+#ifndef TEST_TOOL_UTILS_H\n+#define TEST_TOOL_UTILS_H\n+\n+struct test_cmd {\n+\tconst char *name;\n+\tint (*fn)(int argc, const char **argv);\n+};\n+\n+#endif\ndiff --git a/t/helper/test-tool.c b/t/helper/test-tool.c\nindex d6a560f8325..50a6ae38a7d 100644\n--- a/t/helper/test-tool.c\n+++ b/t/helper/test-tool.c\n@@ -1,5 +1,6 @@\n #include \"git-compat-util.h\"\n #include \"test-tool.h\"\n+#include \"test-tool-utils.h\"\n #include \"trace2.h\"\n #include \"parse-options.h\"\n \n@@ -8,11 +9,6 @@ static const char * const test_tool_usage[] = {\n \tNULL\n };\n \n-struct test_cmd {\n-\tconst char *name;\n-\tint (*fn)(int argc, const char **argv);\n-};\n-\n static struct test_cmd cmds[] = {\n \t{ \"advise\", cmd__advise_if_enabled },\n \t{ \"bitmap\", cmd__bitmap },\n@@ -79,6 +75,7 @@ static struct test_cmd cmds[] = {\n \t{ \"simple-ipc\", cmd__simple_ipc },\n \t{ \"strcmp-offset\", cmd__strcmp_offset },\n \t{ \"string-list\", cmd__string_list },\n+\t{ \"submodule\", cmd__submodule },\n \t{ \"submodule-config\", cmd__submodule_config },\n \t{ \"submodule-nested-repo-config\", cmd__submodule_nested_repo_config },\n \t{ \"subprocess\", cmd__subprocess },\ndiff --git a/t/helper/test-tool.h b/t/helper/test-tool.h\nindex 21a91b10195..6921a6fc2c5 100644\n--- a/t/helper/test-tool.h\n+++ b/t/helper/test-tool.h\n@@ -69,6 +69,7 @@ int cmd__sigchain(int argc, const char **argv);\n int cmd__simple_ipc(int argc, const char **argv);\n int cmd__strcmp_offset(int argc, const char **argv);\n int cmd__string_list(int argc, const char **argv);\n+int cmd__submodule(int argc, const char **argv);\n int cmd__submodule_config(int argc, const char **argv);\n int cmd__submodule_nested_repo_config(int argc, const char **argv);\n int cmd__subprocess(int argc, const char **argv);\ndiff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh\nindex c8e7e983317..ede6f02dbd5 100755\n--- a/t/t7413-submodule-is-active.sh\n+++ b/t/t7413-submodule-is-active.sh\n@@ -1,9 +1,12 @@\n #!/bin/sh\n \n-test_description='Test submodule--helper is-active\n+test_description='Test with test-tool submodule is-active\n \n-This test verifies that `git submodue--helper is-active` correctly identifies\n+This test verifies that `test-tool submodule is-active` correctly identifies\n submodules which are \"active\" and interesting to the user.\n+\n+This is a unit test of the submodule.c is_submodule_active() function,\n+which is also indirectly tested elsewhere.\n '\n \n . ./test-lib.sh\n@@ -25,13 +28,13 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'is-active works with urls' '\n-\tgit -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2 &&\n+\ttest-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2 &&\n \n \tgit -C super config --unset submodule.sub1.URL &&\n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n \tgit -C super config submodule.sub1.URL ../sub &&\n-\tgit -C super submodule--helper is-active sub1\n+\ttest-tool -C super submodule is-active sub1\n '\n \n test_expect_success 'is-active works with submodule.<name>.active config' '\n@@ -39,11 +42,11 @@ test_expect_success 'is-active works with submodule.<name>.active config' '\n \ttest_when_finished \"git -C super config submodule.sub1.URL ../sub\" &&\n \n \tgit -C super config --bool submodule.sub1.active \"false\" &&\n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n \n \tgit -C super config --bool submodule.sub1.active \"true\" &&\n \tgit -C super config --unset submodule.sub1.URL &&\n-\tgit -C super submodule--helper is-active sub1\n+\ttest-tool -C super submodule is-active sub1\n '\n \n test_expect_success 'is-active works with basic submodule.active config' '\n@@ -53,17 +56,17 @@ test_expect_success 'is-active works with basic submodule.active config' '\n \tgit -C super config --add submodule.active \".\" &&\n \tgit -C super config --unset submodule.sub1.URL &&\n \n-\tgit -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active correctly works with paths that are not submodules' '\n \ttest_when_finished \"git -C super config --unset-all submodule.active\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active not-a-submodule &&\n+\ttest_must_fail test-tool -C super submodule is-active not-a-submodule &&\n \n \tgit -C super config --add submodule.active \".\" &&\n-\ttest_must_fail git -C super submodule--helper is-active not-a-submodule\n+\ttest_must_fail test-tool -C super submodule is-active not-a-submodule\n '\n \n test_expect_success 'is-active works with exclusions in submodule.active config' '\n@@ -72,8 +75,8 @@ test_expect_success 'is-active works with exclusions in submodule.active config'\n \tgit -C super config --add submodule.active \".\" &&\n \tgit -C super config --add submodule.active \":(exclude)sub1\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active with submodule.active and submodule.<name>.active' '\n@@ -85,8 +88,8 @@ test_expect_success 'is-active with submodule.active and submodule.<name>.active\n \tgit -C super config --bool submodule.sub1.active \"false\" &&\n \tgit -C super config --bool submodule.sub2.active \"true\" &&\n \n-\ttest_must_fail git -C super submodule--helper is-active sub1 &&\n-\tgit -C super submodule--helper is-active sub2\n+\ttest_must_fail test-tool -C super submodule is-active sub1 &&\n+\ttest-tool -C super submodule is-active sub2\n '\n \n test_expect_success 'is-active, submodule.active and submodule add' '\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462366","messageId":"patch-v4-10.33-44b27475864-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 10/33] submodule--helper style: add \\n\\n after variable declarations","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:52Z","receivedAt":"2022-08-31T23:19:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Since the preceding commit fixed style issues with \\n\\n among the\ndeclared variables let's fix the minor stylistic issues with those\nvariables not being consistently followed by a \\n\\n.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 25 +++++++++++++++++++++++--\n 1 file changed, 23 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 02552410679..a492ea3cfed 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -167,6 +167,7 @@ static int module_list_compute(int argc, const char **argv,\n {\n \tint i, result = 0;\n \tchar *ps_matched = NULL;\n+\n \tparse_pathspec(pathspec, 0,\n \t\t       PATHSPEC_PREFER_FULL,\n \t\t       prefix, argv);\n@@ -248,6 +249,7 @@ static void for_each_listed_submodule(const struct module_list *list,\n \t\t\t\t      each_submodule_fn fn, void *cb_data)\n {\n \tint i;\n+\n \tfor (i = 0; i < list->nr; i++)\n \t\tfn(list->entries[i], cb_data);\n }\n@@ -267,7 +269,6 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \tstruct foreach_cb *info = cb_data;\n \tconst char *path = list_item->name;\n \tconst struct object_id *ce_oid = &list_item->oid;\n-\n \tconst struct submodule *sub;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *displaypath;\n@@ -456,6 +457,7 @@ static void init_submodule(const char *path, const char *prefix,\n \t\tif (starts_with_dot_dot_slash(url) ||\n \t\t    starts_with_dot_slash(url)) {\n \t\t\tchar *oldurl = url;\n+\n \t\t\turl = resolve_relative_url(oldurl, NULL, 0);\n \t\t\tfree(oldurl);\n \t\t}\n@@ -493,6 +495,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+\n \tinit_submodule(list_item->name, info->prefix, info->flags);\n }\n \n@@ -562,6 +565,7 @@ static int handle_submodule_head_ref(const char *refname,\n \t\t\t\t     void *cb_data)\n {\n \tstruct object_id *output = cb_data;\n+\n \tif (oid)\n \t\toidcpy(output, oid);\n \n@@ -668,6 +672,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,\n \t\t\t\tvoid *cb_data)\n {\n \tstruct status_cb *info = cb_data;\n+\n \tstatus_submodule(list_item->name, &list_item->oid, list_item->ce_flags,\n \t\t\t info->prefix, info->flags);\n }\n@@ -820,6 +825,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n \tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n \t\t\tstruct ref_store *refs = get_submodule_ref_store(p->sm_path);\n+\n \t\t\tif (refs)\n \t\t\t\trefs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);\n \t\t} else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {\n@@ -1161,6 +1167,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tif (starts_with_dot_dot_slash(sub->url) ||\n \t\t    starts_with_dot_slash(sub->url)) {\n \t\t\tchar *up_path = get_up_path(path);\n+\n \t\t\tsub_origin_url = resolve_relative_url(sub->url, up_path, 1);\n \t\t\tsuper_config_url = resolve_relative_url(sub->url, NULL, 1);\n \t\t\tfree(up_path);\n@@ -1236,6 +1243,7 @@ static void sync_submodule(const char *path, const char *prefix,\n static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data)\n {\n \tstruct sync_cb *info = cb_data;\n+\n \tsync_submodule(list_item->name, info->prefix, info->flags);\n }\n \n@@ -1315,6 +1323,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \n \t\tif (!(flags & OPT_FORCE)) {\n \t\t\tstruct child_process cp_rm = CHILD_PROCESS_INIT;\n+\n \t\t\tcp_rm.git_cmd = 1;\n \t\t\tstrvec_pushl(&cp_rm.args, \"rm\", \"-qn\",\n \t\t\t\t     path, NULL);\n@@ -1351,6 +1360,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \t/* remove the .git/config entries (unless the user already did it) */\n \tif (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {\n \t\tchar *sub_key = xstrfmt(\"submodule.%s\", sub->name);\n+\n \t\t/*\n \t\t * remove the whole section so we have a clean state when\n \t\t * the user later decides to init this submodule again\n@@ -1588,6 +1598,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tstrvec_pushl(&cp.args, \"--depth\", clone_data->depth, NULL);\n \t\tif (clone_data->reference.nr) {\n \t\t\tstruct string_list_item *item;\n+\n \t\t\tfor_each_string_list_item(item, &clone_data->reference)\n \t\t\t\tstrvec_pushl(&cp.args, \"--reference\",\n \t\t\t\t\t     item->string, NULL);\n@@ -1938,6 +1949,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tstrvec_pushl(&child->args, \"--url\", url, NULL);\n \tif (suc->update_data->references.nr) {\n \t\tstruct string_list_item *item;\n+\n \t\tfor_each_string_list_item(item, &suc->update_data->references)\n \t\t\tstrvec_pushl(&child->args, \"--reference\", item->string, NULL);\n \t}\n@@ -1970,6 +1982,7 @@ static int update_clone_get_next_task(struct child_process *child,\n \t\tce = suc->update_data->list.entries[suc->current];\n \t\tif (prepare_to_clone_next_submodule(ce, child, suc, err)) {\n \t\t\tint *p = xmalloc(sizeof(*p));\n+\n \t\t\t*p = suc->current;\n \t\t\t*idx_task_cb = p;\n \t\t\tsuc->current++;\n@@ -1985,6 +1998,7 @@ static int update_clone_get_next_task(struct child_process *child,\n \tindex = suc->current - suc->update_data->list.nr;\n \tif (index < suc->failed_clones_nr) {\n \t\tint *p;\n+\n \t\tce = suc->failed_clones[index];\n \t\tif (!prepare_to_clone_next_submodule(ce, child, suc, err)) {\n \t\t\tsuc->current ++;\n@@ -2008,6 +2022,7 @@ static int update_clone_start_failure(struct strbuf *err,\n \t\t\t\t      void *idx_task_cb)\n {\n \tstruct submodule_update_clone *suc = suc_cb;\n+\n \tsuc->quickstop = 1;\n \treturn 1;\n }\n@@ -2019,9 +2034,9 @@ static int update_clone_task_finished(int result,\n {\n \tconst struct cache_entry *ce;\n \tstruct submodule_update_clone *suc = suc_cb;\n-\n \tint *idxP = idx_task_cb;\n \tint idx = *idxP;\n+\n \tfree(idxP);\n \n \tif (!result)\n@@ -2054,6 +2069,7 @@ static int git_update_clone_config(const char *var, const char *value,\n \t\t\t\t   void *cb)\n {\n \tint *max_jobs = cb;\n+\n \tif (!strcmp(var, \"submodule.fetchjobs\"))\n \t\t*max_jobs = parse_submodule_fetchjobs(var, value);\n \treturn 0;\n@@ -2094,6 +2110,7 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str\n \tif (oid) {\n \t\tchar *hex = oid_to_hex(oid);\n \t\tchar *remote = get_default_remote();\n+\n \t\tstrvec_pushl(&cp.args, remote, hex, NULL);\n \t\tfree(remote);\n \t}\n@@ -2343,6 +2360,7 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *\n \n \tif (update_data->references.nr) {\n \t\tstruct string_list_item *item;\n+\n \t\tfor_each_string_list_item(item, &update_data->references)\n \t\t\tstrvec_pushl(args, \"--reference\", item->string, NULL);\n \t}\n@@ -2875,8 +2893,10 @@ static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)\n \tif (!capture_command(&cp_remote, &sb_remote_out, 0)) {\n \t\tchar *next_line;\n \t\tchar *line = sb_remote_out.buf;\n+\n \t\twhile ((next_line = strchr(line, '\\n')) != NULL) {\n \t\t\tsize_t len = next_line - line;\n+\n \t\t\tif (strip_suffix_mem(line, &len, \" (fetch)\"))\n \t\t\t\tstrbuf_addf(msg, \"  %.*s\\n\", (int)len, line);\n \t\t\tline = next_line + 1;\n@@ -3183,6 +3203,7 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \t\tint exit_code = -1;\n \t\tstruct strbuf sb = STRBUF_INIT;\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n \t\tcp.git_cmd = 1;\n \t\tcp.no_stdout = 1;\n \t\tstrvec_pushl(&cp.args, \"add\", \"--dry-run\", \"--ignore-missing\",\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462367","messageId":"patch-v4-16.33-b77364015cf-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 16/33] submodule--helper: add \"const\" to passed \"struct update_data\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:58Z","receivedAt":"2022-08-31T23:19:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a \"const\" to the \"struct update_data\" passed to\nrun_update_procedure(), which it in turn passes along (peeled) to\nis_tip_reachable() and fetch_in_submodule()).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 829a57ce8a9..4e3bb54afa2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2083,7 +2083,7 @@ static int git_update_clone_config(const char *var, const char *value,\n \treturn 0;\n }\n \n-static int is_tip_reachable(const char *path, struct object_id *oid)\n+static int is_tip_reachable(const char *path, const struct object_id *oid)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tstruct strbuf rev = STRBUF_INIT;\n@@ -2102,7 +2102,8 @@ static int is_tip_reachable(const char *path, struct object_id *oid)\n \treturn 1;\n }\n \n-static int fetch_in_submodule(const char *module_path, int depth, int quiet, struct object_id *oid)\n+static int fetch_in_submodule(const char *module_path, int depth, int quiet,\n+\t\t\t      const struct object_id *oid)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \n@@ -2126,7 +2127,7 @@ 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(const struct update_data *ud, int subforce)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n@@ -2223,7 +2224,7 @@ static int run_update_command(struct update_data *ud, int subforce)\n \treturn 0;\n }\n \n-static int run_update_procedure(struct update_data *ud)\n+static int run_update_procedure(const struct update_data *ud)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2334,7 +2335,8 @@ static const char *submodule_update_type_to_label(enum submodule_update_type typ\n \tBUG(\"unreachable with type %d\", type);\n }\n \n-static void update_data_to_args(struct update_data *update_data, struct strvec *args)\n+static void update_data_to_args(const struct update_data *update_data,\n+\t\t\t\tstruct strvec *args)\n {\n \tenum submodule_update_type update_type = update_data->update_default;\n \n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462368","messageId":"patch-v4-14.33-e514f0b68c0-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 14/33] submodule--helper: add \"const\" to passed \"module_clone_data\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:56Z","receivedAt":"2022-08-31T23:19:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add \"const\" to the \"struct module_clone_data\" that we pass to\nclone_submodule(), which makes the ownership clear, and stops us from\nclobbering the \"clone_data->path\".\n\nWe still need to add to the \"reference\" member, which is a \"struct\nstring_list\". Let's do this by having clone_submodule() create its\nown, and copy the contents over, allowing us to pass it as a\nseparate parameter.\n\nThis new \"struct string_list\" still leaks memory, just as the \"struct\nmodule_clone_data\" did before. let's not fix that for now, to fix that\nwe'll need to add some \"goto cleanup\" to the relevant code. That will\neventually be done in follow-up commits, this change makes it easier\nto fix the memory leak.\n\nThe scope of the new \"reference\" variable in add_submodule() could be\nnarrowed to the \"else\" block, but as we'll eventually free it with a\n\"goto cleanup\" let's declare it at the start of the function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 49 ++++++++++++++++++++-----------------\n 1 file changed, 26 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 2f1f0e1bf34..d243c3ddfd3 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1437,7 +1437,6 @@ struct module_clone_data {\n \tconst char *url;\n \tconst char *depth;\n \tstruct list_objects_filter_options *filter_options;\n-\tstruct string_list reference;\n \tunsigned int quiet: 1;\n \tunsigned int progress: 1;\n \tunsigned int dissociate: 1;\n@@ -1445,7 +1444,6 @@ struct module_clone_data {\n \tint single_branch;\n };\n #define MODULE_CLONE_DATA_INIT { \\\n-\t.reference = STRING_LIST_INIT_NODUP, \\\n \t.single_branch = -1, \\\n }\n \n@@ -1572,18 +1570,20 @@ static char *clone_submodule_sm_gitdir(const char *name)\n \treturn sm_gitdir;\n }\n \n-static int clone_submodule(struct module_clone_data *clone_data)\n+static int clone_submodule(const struct module_clone_data *clone_data,\n+\t\t\t   struct string_list *reference)\n {\n \tchar *p;\n \tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n \tchar *sm_alternate = NULL, *error_strategy = NULL;\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tconst char *clone_data_path;\n \n \tif (!is_absolute_path(clone_data->path))\n-\t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n-\t\t\t\t\t   clone_data->path);\n+\t\tclone_data_path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n+\t\t\t\t\t  clone_data->path);\n \telse\n-\t\tclone_data->path = xstrdup(clone_data->path);\n+\t\tclone_data_path = xstrdup(clone_data->path);\n \n \tif (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)\n \t\tdie(_(\"refusing to create/use '%s' in another submodule's \"\n@@ -1593,7 +1593,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\tif (safe_create_leading_directories_const(sm_gitdir) < 0)\n \t\t\tdie(_(\"could not create directory '%s'\"), sm_gitdir);\n \n-\t\tprepare_possible_alternates(clone_data->name, &clone_data->reference);\n+\t\tprepare_possible_alternates(clone_data->name, reference);\n \n \t\tstrvec_push(&cp.args, \"clone\");\n \t\tstrvec_push(&cp.args, \"--no-checkout\");\n@@ -1603,10 +1603,10 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \t\t\tstrvec_push(&cp.args, \"--progress\");\n \t\tif (clone_data->depth && *(clone_data->depth))\n \t\t\tstrvec_pushl(&cp.args, \"--depth\", clone_data->depth, NULL);\n-\t\tif (clone_data->reference.nr) {\n+\t\tif (reference->nr) {\n \t\t\tstruct string_list_item *item;\n \n-\t\t\tfor_each_string_list_item(item, &clone_data->reference)\n+\t\t\tfor_each_string_list_item(item, reference)\n \t\t\t\tstrvec_pushl(&cp.args, \"--reference\",\n \t\t\t\t\t     item->string, NULL);\n \t\t}\n@@ -1625,7 +1625,7 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \n \t\tstrvec_push(&cp.args, \"--\");\n \t\tstrvec_push(&cp.args, clone_data->url);\n-\t\tstrvec_push(&cp.args, clone_data->path);\n+\t\tstrvec_push(&cp.args, clone_data_path);\n \n \t\tcp.git_cmd = 1;\n \t\tprepare_submodule_repo_env(&cp.env);\n@@ -1633,25 +1633,25 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \n \t\tif(run_command(&cp))\n \t\t\tdie(_(\"clone of '%s' into submodule path '%s' failed\"),\n-\t\t\t    clone_data->url, clone_data->path);\n+\t\t\t    clone_data->url, clone_data_path);\n \t} else {\n \t\tchar *path;\n \n-\t\tif (clone_data->require_init && !access(clone_data->path, X_OK) &&\n-\t\t    !is_empty_dir(clone_data->path))\n-\t\t\tdie(_(\"directory not empty: '%s'\"), clone_data->path);\n-\t\tif (safe_create_leading_directories_const(clone_data->path) < 0)\n-\t\t\tdie(_(\"could not create directory '%s'\"), clone_data->path);\n+\t\tif (clone_data->require_init && !access(clone_data_path, X_OK) &&\n+\t\t    !is_empty_dir(clone_data_path))\n+\t\t\tdie(_(\"directory not empty: '%s'\"), clone_data_path);\n+\t\tif (safe_create_leading_directories_const(clone_data_path) < 0)\n+\t\t\tdie(_(\"could not create directory '%s'\"), clone_data_path);\n \t\tpath = xstrfmt(\"%s/index\", sm_gitdir);\n \t\tunlink_or_warn(path);\n \t\tfree(path);\n \t}\n \n-\tconnect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);\n+\tconnect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);\n \n-\tp = git_pathdup_submodule(clone_data->path, \"config\");\n+\tp = git_pathdup_submodule(clone_data_path, \"config\");\n \tif (!p)\n-\t\tdie(_(\"could not get submodule directory for '%s'\"), clone_data->path);\n+\t\tdie(_(\"could not get submodule directory for '%s'\"), clone_data_path);\n \n \t/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */\n \tgit_config_get_string(\"submodule.alternateLocation\", &sm_alternate);\n@@ -1676,6 +1676,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \tint dissociate = 0, quiet = 0, progress = 0, require_init = 0;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n \tstruct list_objects_filter_options filter_options = { 0 };\n+\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n \tstruct option module_clone_options[] = {\n \t\tOPT_STRING(0, \"prefix\", &clone_data.prefix,\n \t\t\t   N_(\"path\"),\n@@ -1689,7 +1690,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING(0, \"url\", &clone_data.url,\n \t\t\t   N_(\"string\"),\n \t\t\t   N_(\"url where to clone the submodule from\")),\n-\t\tOPT_STRING_LIST(0, \"reference\", &clone_data.reference,\n+\t\tOPT_STRING_LIST(0, \"reference\", &reference,\n \t\t\t   N_(\"repo\"),\n \t\t\t   N_(\"reference repository\")),\n \t\tOPT_BOOL(0, \"dissociate\", &dissociate,\n@@ -1728,7 +1729,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_submodule_helper_usage,\n \t\t\t\t   module_clone_options);\n \n-\tclone_submodule(&clone_data);\n+\tclone_submodule(&clone_data, &reference);\n \tlist_objects_filter_release(&filter_options);\n \treturn 0;\n }\n@@ -2916,6 +2917,7 @@ static int add_submodule(const struct add_data *add_data)\n {\n \tchar *submod_gitdir_path;\n \tstruct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;\n+\tstruct string_list reference = STRING_LIST_INIT_NODUP;\n \n \t/* perhaps the path already exists and is already a git repo, else clone it */\n \tif (is_directory(add_data->sm_path)) {\n@@ -2932,6 +2934,7 @@ static int add_submodule(const struct add_data *add_data)\n \t\tfree(submod_gitdir_path);\n \t} else {\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n \t\tsubmod_gitdir_path = xstrfmt(\".git/modules/%s\", add_data->sm_name);\n \n \t\tif (is_directory(submod_gitdir_path)) {\n@@ -2971,13 +2974,13 @@ static int add_submodule(const struct add_data *add_data)\n \t\tclone_data.quiet = add_data->quiet;\n \t\tclone_data.progress = add_data->progress;\n \t\tif (add_data->reference_path)\n-\t\t\tstring_list_append(&clone_data.reference,\n+\t\t\tstring_list_append(&reference,\n \t\t\t\t\t   xstrdup(add_data->reference_path));\n \t\tclone_data.dissociate = add_data->dissociate;\n \t\tif (add_data->depth >= 0)\n \t\t\tclone_data.depth = xstrfmt(\"%d\", add_data->depth);\n \n-\t\tif (clone_submodule(&clone_data))\n+\t\tif (clone_submodule(&clone_data, &reference))\n \t\t\treturn -1;\n \n \t\tprepare_submodule_repo_env(&cp.env);\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462369","messageId":"patch-v4-13.33-474d1a9e13e-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 13/33] submodule--helper: move \"sb\" in clone_submodule() to its own scope","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:55Z","receivedAt":"2022-08-31T23:19:10Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor the only remaining use of a \"struct strbuf sb\" in\nclone_submodule() to live in its own scope. This makes the code\nclearer by limiting its lifetime.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 21 ++++++++++++++-------\n 1 file changed, 14 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c7833bae81e..2f1f0e1bf34 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1560,16 +1560,24 @@ static void prepare_possible_alternates(const char *sm_name,\n \tfree(error_strategy);\n }\n \n-static int clone_submodule(struct module_clone_data *clone_data)\n+static char *clone_submodule_sm_gitdir(const char *name)\n {\n-\tchar *p, *sm_gitdir;\n-\tchar *sm_alternate = NULL, *error_strategy = NULL;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tchar *sm_gitdir;\n \n-\tsubmodule_name_to_gitdir(&sb, the_repository, clone_data->name);\n+\tsubmodule_name_to_gitdir(&sb, the_repository, name);\n \tsm_gitdir = absolute_pathdup(sb.buf);\n-\tstrbuf_reset(&sb);\n+\tstrbuf_release(&sb);\n+\n+\treturn sm_gitdir;\n+}\n+\n+static int clone_submodule(struct module_clone_data *clone_data)\n+{\n+\tchar *p;\n+\tchar *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);\n+\tchar *sm_alternate = NULL, *error_strategy = NULL;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n \n \tif (!is_absolute_path(clone_data->path))\n \t\tclone_data->path = xstrfmt(\"%s/%s\", get_git_work_tree(),\n@@ -1658,7 +1666,6 @@ static int clone_submodule(struct module_clone_data *clone_data)\n \tfree(sm_alternate);\n \tfree(error_strategy);\n \n-\tstrbuf_release(&sb);\n \tfree(sm_gitdir);\n \tfree(p);\n \treturn 0;\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462370","messageId":"patch-v4-19.33-bc7d401bfb3-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 19/33] submodule--helper: rename \"int res\" to \"int ret\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:01Z","receivedAt":"2022-08-31T23:19:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Rename the \"res\" variable added in b3c5f5cb048 (submodule: move core\ncmd_update() logic to C, 2022-03-15) to \"ret\", which is the convention\nin the rest of this file.\n\nEventual follow-up commits will change the code in update_submodule()\nto a \"goto cleanup\" pattern, let's have the post image look consistent\nwith the rest. For update_submodules() let's also use a \"ret\" for\nconsistency, that use was also added in b3c5f5cb048. We'll be\nmodifying that codepath in subsequent commits.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 93ab49defb1..4fbbffb4637 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2429,7 +2429,7 @@ static int update_submodule(struct update_data *update_data)\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+\t\tint ret;\n \n \t\tnext.prefix = NULL;\n \t\toidcpy(&next.oid, null_oid());\n@@ -2441,13 +2441,13 @@ static int update_submodule(struct update_data *update_data)\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\tret = run_command(&cp);\n+\t\tif (!ret)\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\tif (ret == 128)\n+\t\t\texit(ret);\n \t\treturn 1;\n \t}\n \n@@ -2456,7 +2456,7 @@ static int update_submodule(struct update_data *update_data)\n \n static int update_submodules(struct update_data *update_data)\n {\n-\tint i, res = 0;\n+\tint i, ret = 0;\n \tstruct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;\n \n \tsuc.update_data = update_data;\n@@ -2474,7 +2474,7 @@ static int update_submodules(struct update_data *update_data)\n \t * - the listener can avoid doing any work if fetching failed.\n \t */\n \tif (suc.quickstop) {\n-\t\tres = 1;\n+\t\tret = 1;\n \t\tgoto cleanup;\n \t}\n \n@@ -2486,12 +2486,12 @@ static int update_submodules(struct update_data *update_data)\n \t\tupdate_data->sm_path = ucd.sub->path;\n \n \t\tif (update_submodule(update_data))\n-\t\t\tres = 1;\n+\t\t\tret = 1;\n \t}\n \n cleanup:\n \tstring_list_clear(&update_data->references, 0);\n-\treturn res;\n+\treturn ret;\n }\n \n static int module_update(int argc, const char **argv, const char *prefix)\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462371","messageId":"patch-v4-17.33-52da0d60b47-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 17/33] submodule--helper: refactor \"errmsg_str\" to be a \"struct strbuf\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:59Z","receivedAt":"2022-08-31T23:19:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nRefactor code added in e83e3333b57 (submodule: port submodule\nsubcommand 'summary' from shell to C, 2020-08-13) so that \"errmsg\" and\n\"errmsg_str\" are folded into one. The distinction between the empty\nstring and NULL is something that's tested for by\ne.g. \"t/t7401-submodule-summary.sh\".\n\nThis is in preparation for fixing a memory leak the \"struct strbuf\" in\nthe pre-image.\n\nLet's also pass a \"const char *\" to print_submodule_summary(), as it\nshould not be modifying the \"errmsg\".\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 14 ++++++--------\n 1 file changed, 6 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4e3bb54afa2..07a918f7373 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -761,7 +761,7 @@ static char *verify_submodule_committish(const char *sm_path,\n \treturn strbuf_detach(&result, NULL);\n }\n \n-static void print_submodule_summary(struct summary_cb *info, char *errmsg,\n+static void print_submodule_summary(struct summary_cb *info, const char *errmsg,\n \t\t\t\t    int total_commits, const char *displaypath,\n \t\t\t\t    const char *src_abbrev, const char *dst_abbrev,\n \t\t\t\t    struct module_cb *p)\n@@ -819,7 +819,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n {\n \tchar *displaypath, *src_abbrev = NULL, *dst_abbrev;\n \tint missing_src = 0, missing_dst = 0;\n-\tchar *errmsg = NULL;\n+\tstruct strbuf errmsg = STRBUF_INIT;\n \tint total_commits = -1;\n \n \tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n@@ -920,23 +920,21 @@ static void generate_submodule_summary(struct summary_cb *info,\n \t\t * submodule, i.e., deleted or changed to blob\n \t\t */\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n-\t\t\tstruct strbuf errmsg_str = STRBUF_INIT;\n \t\t\tif (missing_src && missing_dst) {\n-\t\t\t\tstrbuf_addf(&errmsg_str, \"  Warn: %s doesn't contain commits %s and %s\\n\",\n+\t\t\t\tstrbuf_addf(&errmsg, \"  Warn: %s doesn't contain commits %s and %s\\n\",\n \t\t\t\t\t    displaypath, oid_to_hex(&p->oid_src),\n \t\t\t\t\t    oid_to_hex(&p->oid_dst));\n \t\t\t} else {\n-\t\t\t\tstrbuf_addf(&errmsg_str, \"  Warn: %s doesn't contain commit %s\\n\",\n+\t\t\t\tstrbuf_addf(&errmsg, \"  Warn: %s doesn't contain commit %s\\n\",\n \t\t\t\t\t    displaypath, missing_src ?\n \t\t\t\t\t    oid_to_hex(&p->oid_src) :\n \t\t\t\t\t    oid_to_hex(&p->oid_dst));\n \t\t\t}\n-\t\t\terrmsg = strbuf_detach(&errmsg_str, NULL);\n \t\t}\n \t}\n \n-\tprint_submodule_summary(info, errmsg, total_commits,\n-\t\t\t\tdisplaypath, src_abbrev,\n+\tprint_submodule_summary(info, errmsg.len ? errmsg.buf : NULL,\n+\t\t\t\ttotal_commits, displaypath, src_abbrev,\n \t\t\t\tdst_abbrev, p);\n \n \tfree(displaypath);\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462372","messageId":"patch-v4-18.33-1786e40ec99-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 18/33] submodule--helper: don't redundantly check \"else if (res)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:00Z","receivedAt":"2022-08-31T23:19:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"res\" variable must be true at this point in update_submodule(),\nas just a few lines above this we've unconditionally:\n\n\tif (!res)\n\t\treturn 0;\n\nSo we don't need to guard the \"return 1\" with an \"else if (res)\", we\ncan return unconditionally at this point. See b3c5f5cb048 (submodule:\nmove core cmd_update() logic to C, 2022-03-15) for the initial\nintroduction of this code, this check of \"res\" has always been\nredundant.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 07a918f7373..93ab49defb1 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2448,8 +2448,7 @@ static int update_submodule(struct update_data *update_data)\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\treturn 1;\n \t}\n \n \treturn 0;\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462373","messageId":"patch-v4-15.33-30be00d5cf7-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 15/33] submodule--helper: add \"const\" to copy of \"update_data\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:17:57Z","receivedAt":"2022-08-31T23:19:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Glen Choo <chooglen@google.com>\n\nAdd a \"const\" to the copy of \"struct update_data\" that's tracked by\nthe \"struct submodule_update_clone\", as it neither owns nor modifies\nit.\n\nSigned-off-by: Glen Choo <chooglen@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex d243c3ddfd3..829a57ce8a9 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1780,7 +1780,7 @@ struct submodule_update_clone {\n \tint current;\n \n \t/* configuration parameters which are passed on to the children */\n-\tstruct update_data *update_data;\n+\tconst struct update_data *update_data;\n \n \t/* to be consumed by update_submodule() */\n \tstruct update_clone_data *update_clone;\n@@ -1865,7 +1865,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \tconst char *update_string;\n \tenum submodule_update_type update_type;\n \tchar *key;\n-\tstruct update_data *ud = suc->update_data;\n+\tconst struct update_data *ud = suc->update_data;\n \tchar *displaypath = get_submodule_displaypath(ce->name, ud->prefix);\n \tstruct strbuf sb = STRBUF_INIT;\n \tint needs_cloning = 0;\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462374","messageId":"patch-v4-21.33-9edd68f9c5a-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 21/33] submodule--helper: add missing braces to \"else\" arm","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:03Z","receivedAt":"2022-08-31T23:19:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add missing braces to an \"else\" arm in init_submodule(), this\nstylistic change makes this code conform to the CodingGuidelines, and\nmakes a subsequent commit smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 59c3a9afe6e..6c40be3170f 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -480,8 +480,9 @@ static void init_submodule(const char *path, const char *prefix,\n \t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n \t\t\t\tsub->name);\n \t\t\tupd = xstrdup(\"none\");\n-\t\t} else\n+\t\t} else {\n \t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n+\t\t}\n \n \t\tif (git_config_set_gently(sb.buf, upd))\n \t\t\tdie(_(\"Failed to register update mode for submodule path '%s'\"), displaypath);\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462375","messageId":"patch-v4-22.33-f0ada6854c2-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 22/33] submodule--helper: don't call submodule_strategy_to_string() in BUG()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:04Z","receivedAt":"2022-08-31T23:19:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Don't call submodule_strategy_to_string() in a BUG() message. These\ncalls added in c51f8f94e5b (submodule--helper: run update procedures\nfrom C, 2021-08-24) don't need the extra information\nsubmodule_strategy_to_string() gives us, as we'll never reach the\nSM_UPDATE_COMMAND case here.\n\nThat case is the only one where we'd get any information beyond the\nstraightforward number-to-string mapping.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 6c40be3170f..965196a005d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2159,8 +2159,8 @@ static int run_update_command(const struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n+\t\t    ud->update_strategy.type);\n \t}\n \tstrvec_push(&cp.args, oid);\n \n@@ -2185,8 +2185,8 @@ static int run_update_command(const struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n+\t\t\t    ud->update_strategy.type);\n \t\t}\n \t\tif (must_die_on_failure)\n \t\t\texit(128);\n@@ -2216,8 +2216,8 @@ static int run_update_command(const struct update_data *ud, int subforce)\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\tBUG(\"unexpected update strategy type: %d\",\n+\t\t    ud->update_strategy.type);\n \t}\n \n \treturn 0;\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462376","messageId":"patch-v4-20.33-fdd9ef8b6f6-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 20/33] submodule--helper: return \"ret\", not \"1\" from update_submodule()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:02Z","receivedAt":"2022-08-31T23:19:21Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend the update_submodule() function to return the failing \"ret\" on\nerror, instead of overriding it with \"1\".\n\nThis code was added in b3c5f5cb048 (submodule: move core cmd_update()\nlogic to C, 2022-03-15), and this change ends up not making a\ndifference as this function is only called in update_submodules(). If\nwe return non-zero here we'll always in turn return \"1\" in\nmodule_update().\n\nBut if we didn't do that and returned any other non-zero exit code in\nupdate_submodules() we'd fail the test that's being amended\nhere. We're still testing the status quo here.\n\nThis change makes subsequent refactoring of update_submodule() easier,\nas we'll no longer need to worry about clobbering the \"ret\" we get\nfrom the run_command().\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 2 +-\n t/t7406-submodule-update.sh | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4fbbffb4637..59c3a9afe6e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2448,7 +2448,7 @@ static int update_submodule(struct update_data *update_data)\n \t\t\t    update_data->displaypath);\n \t\tif (ret == 128)\n \t\t\texit(ret);\n-\t\treturn 1;\n+\t\treturn ret;\n \t}\n \n \treturn 0;\ndiff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh\nindex 6cc07460dd2..c5f5dbe55e0 100755\n--- a/t/t7406-submodule-update.sh\n+++ b/t/t7406-submodule-update.sh\n@@ -769,7 +769,7 @@ test_expect_success 'submodule update continues after recursive checkout error'\n \t   echo \"\" > file\n \t  )\n \t ) &&\n-\t test_must_fail git submodule update --recursive &&\n+\t test_expect_code 1 git submodule update --recursive &&\n \t (cd submodule2 &&\n \t  git rev-parse --verify HEAD >../actual\n \t ) &&\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462377","messageId":"patch-v4-23.33-d101aa6c8c5-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 23/33] submodule API: don't handle SM_..{UNSPECIFIED,COMMAND} in to_string()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:05Z","receivedAt":"2022-08-31T23:19:22Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the submodule_strategy_to_string() function added in\n3604242f080 (submodule: port init from shell to C, 2016-04-15) to\nreally return a \"const char *\". In the \"SM_UPDATE_COMMAND\" case it\nwould return a strbuf_detach().\n\nFurthermore, this function would return NULL on SM_UPDATE_UNSPECIFIED,\nso it wasn't safe to xstrdup() its return value in the general case,\nor to use it in a sprintf() format as the code removed in the\npreceding commit did.\n\nBut its callers would never call it with either SM_UPDATE_UNSPECIFIED\nor SM_UPDATE_COMMAND. Let's have its behavior reflect how its only\nuser expects it to behave, and BUG() out on the rest.\n\nBy doing this we can also stop needlessly xstrdup()-ing and free()-ing\nthe memory for the config we're setting. We can instead always use\nconstant strings. We can also use the *_tmp() variant of\ngit_config_get_string().\n\nLet's also rename this submodule_strategy_to_string() function to\nsubmodule_update_type_to_string(). Now that it's only tasked with\nreturning a string version of the \"enum submodule_update_type type\".\nBefore it would look at the \"command\" field in \"struct\nsubmodule_update_strategy\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 10 +++++-----\n submodule.c                 | 12 +++++-------\n submodule.h                 |  2 +-\n 3 files changed, 11 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 965196a005d..35989c81603 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -418,7 +418,8 @@ static void init_submodule(const char *path, const char *prefix,\n {\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n-\tchar *upd = NULL, *url = NULL, *displaypath;\n+\tconst char *upd;\n+\tchar *url = NULL, *displaypath;\n \n \tdisplaypath = get_submodule_displaypath(path, prefix);\n \n@@ -474,14 +475,14 @@ static void init_submodule(const char *path, const char *prefix,\n \n \t/* Copy \"update\" setting when it is not set yet */\n \tstrbuf_addf(&sb, \"submodule.%s.update\", sub->name);\n-\tif (git_config_get_string(sb.buf, &upd) &&\n+\tif (git_config_get_string_tmp(sb.buf, &upd) &&\n \t    sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n \t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND) {\n \t\t\tfprintf(stderr, _(\"warning: command update mode suggested for submodule '%s'\\n\"),\n \t\t\t\tsub->name);\n-\t\t\tupd = xstrdup(\"none\");\n+\t\t\tupd = \"none\";\n \t\t} else {\n-\t\t\tupd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));\n+\t\t\tupd = submodule_update_type_to_string(sub->update_strategy.type);\n \t\t}\n \n \t\tif (git_config_set_gently(sb.buf, upd))\n@@ -490,7 +491,6 @@ static void init_submodule(const char *path, const char *prefix,\n \tstrbuf_release(&sb);\n \tfree(displaypath);\n \tfree(url);\n-\tfree(upd);\n }\n \n static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)\ndiff --git a/submodule.c b/submodule.c\nindex 3fa5db3ecdf..1ebda30c506 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -415,10 +415,9 @@ int parse_submodule_update_strategy(const char *value,\n \treturn 0;\n }\n \n-const char *submodule_strategy_to_string(const struct submodule_update_strategy *s)\n+const char *submodule_update_type_to_string(enum submodule_update_type type)\n {\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tswitch (s->type) {\n+\tswitch (type) {\n \tcase SM_UPDATE_CHECKOUT:\n \t\treturn \"checkout\";\n \tcase SM_UPDATE_MERGE:\n@@ -428,12 +427,11 @@ const char *submodule_strategy_to_string(const struct submodule_update_strategy\n \tcase SM_UPDATE_NONE:\n \t\treturn \"none\";\n \tcase SM_UPDATE_UNSPECIFIED:\n-\t\treturn NULL;\n \tcase SM_UPDATE_COMMAND:\n-\t\tstrbuf_addf(&sb, \"!%s\", s->command);\n-\t\treturn strbuf_detach(&sb, NULL);\n+\t\tBUG(\"init_submodule() should handle type %d\", type);\n+\tdefault:\n+\t\tBUG(\"unexpected update strategy type: %d\", type);\n \t}\n-\treturn NULL;\n }\n \n void handle_ignore_submodules_arg(struct diff_options *diffopt,\ndiff --git a/submodule.h b/submodule.h\nindex bfaa9da1868..6a9fec6de11 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -72,7 +72,7 @@ void die_path_inside_submodule(struct index_state *istate,\n enum submodule_update_type parse_submodule_update_type(const char *value);\n int parse_submodule_update_strategy(const char *value,\n \t\t\t\t    struct submodule_update_strategy *dst);\n-const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);\n+const char *submodule_update_type_to_string(enum submodule_update_type type);\n void handle_ignore_submodules_arg(struct diff_options *, const char *);\n void show_submodule_diff_summary(struct diff_options *o, const char *path,\n \t\t\t    struct object_id *one, struct object_id *two,\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462378","messageId":"patch-v4-24.33-77d21b570e3-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 24/33] submodule--helper: use \"code\" in run_update_command()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:06Z","receivedAt":"2022-08-31T23:19:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Apply some DRY principles in run_update_command() and don't have two\n\"switch\" statements over \"ud->update_strategy.type\" determine the same\nthing.\n\nFirst we were setting \"must_die_on_failure = 1\" in all cases except\n\"SM_UPDATE_CHECKOUT\" (and we'd BUG(...) out on the rest). This code\nwas added in c51f8f94e5b (submodule--helper: run update procedures\nfrom C, 2021-08-24).\n\nThen we'd duplicate same \"switch\" logic when we were using the\n\"must_die_on_failure\" variable.\n\nLet's instead have the \"case\" branches in that inner \"switch\"\ndetermine whether or not the \"update must continue\" by picking an exit\ncode.\n\nThis also mostly avoids hardcoding the \"128\" exit code, instead we can\nmake use of the return value of the die_message() function, which\nwe've been calling here since 55b3f12cb54 (submodule update: use\ndie_message(), 2022-03-15). We're still hardcoding it to determine if\nwe \"exit()\", but subsequent commit(s) will address that.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 27 +++++++++++++--------------\n 1 file changed, 13 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 35989c81603..234f1f993e1 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2130,7 +2130,6 @@ static int run_update_command(const struct update_data *ud, int subforce)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n-\tint must_die_on_failure = 0;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n@@ -2144,19 +2143,16 @@ static int run_update_command(const struct update_data *ud, int subforce)\n \t\tstrvec_push(&cp.args, \"rebase\");\n \t\tif (ud->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\tcp.git_cmd = 1;\n \t\tstrvec_push(&cp.args, \"merge\");\n \t\tif (ud->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\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: %d\",\n@@ -2167,32 +2163,35 @@ static int run_update_command(const struct update_data *ud, int subforce)\n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env);\n \tif (run_command(&cp)) {\n+\t\tint ret;\n+\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\t/* the command failed, but update must continue */\n+\t\t\tret = 1;\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n-\t\t\tdie_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n-\t\t\t    oid, ud->displaypath);\n+\t\t\tret = die_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n+\t\t\t\t\t  oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_MERGE:\n-\t\t\tdie_message(_(\"Unable to merge '%s' in submodule path '%s'\"),\n-\t\t\t    oid, ud->displaypath);\n+\t\t\tret = die_message(_(\"Unable to merge '%s' in submodule path '%s'\"),\n+\t\t\t\t\t  oid, ud->displaypath);\n \t\t\tbreak;\n \t\tcase SM_UPDATE_COMMAND:\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\tret = die_message(_(\"Execution of '%s %s' failed in submodule path '%s'\"),\n+\t\t\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: %d\",\n \t\t\t    ud->update_strategy.type);\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+\t\tif (ret == 128)\n+\t\t\texit(ret);\n+\t\treturn ret;\n \t}\n \n \tif (ud->quiet)\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462379","messageId":"patch-v4-26.33-512106bc6be-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 26/33] submodule--helper: libify determine_submodule_update_strategy()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:08Z","receivedAt":"2022-08-31T23:19:27Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Libify the determine_submodule_update_strategy() by having it invoke\ndie_message() rather than die(), and returning the code die_message()\nreturns on failure.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 39 ++++++++++++++++++++++++-------------\n 1 file changed, 25 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 166c6aaccb2..2f78529736d 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -1733,24 +1733,27 @@ static int module_clone(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void determine_submodule_update_strategy(struct repository *r,\n-\t\t\t\t\t\tint just_cloned,\n-\t\t\t\t\t\tconst char *path,\n-\t\t\t\t\t\tenum submodule_update_type update,\n-\t\t\t\t\t\tstruct submodule_update_strategy *out)\n+static int determine_submodule_update_strategy(struct repository *r,\n+\t\t\t\t\t       int just_cloned,\n+\t\t\t\t\t       const char *path,\n+\t\t\t\t\t       enum submodule_update_type update,\n+\t\t\t\t\t       struct submodule_update_strategy *out)\n {\n \tconst struct submodule *sub = submodule_from_path(r, null_oid(), path);\n \tchar *key;\n \tconst char *val;\n+\tint ret;\n \n \tkey = xstrfmt(\"submodule.%s.update\", sub->name);\n \n \tif (update) {\n \t\tout->type = update;\n \t} else if (!repo_config_get_string_tmp(r, key, &val)) {\n-\t\tif (parse_submodule_update_strategy(val, out) < 0)\n-\t\t\tdie(_(\"Invalid update mode '%s' configured for submodule path '%s'\"),\n-\t\t\t\tval, path);\n+\t\tif (parse_submodule_update_strategy(val, out) < 0) {\n+\t\t\tret = die_message(_(\"Invalid update mode '%s' configured for submodule path '%s'\"),\n+\t\t\t\t\t  val, path);\n+\t\t\tgoto cleanup;\n+\t\t}\n \t} else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {\n \t\tif (sub->update_strategy.type == SM_UPDATE_COMMAND)\n \t\t\tBUG(\"how did we read update = !command from .gitmodules?\");\n@@ -1765,7 +1768,10 @@ static void determine_submodule_update_strategy(struct repository *r,\n \t     out->type == SM_UPDATE_NONE))\n \t\tout->type = SM_UPDATE_CHECKOUT;\n \n+\tret = 0;\n+cleanup:\n \tfree(key);\n+\treturn ret;\n }\n \n struct update_clone_data {\n@@ -2391,14 +2397,22 @@ static void update_data_to_args(const struct update_data *update_data,\n static int update_submodule(struct update_data *update_data,\n \t\t\t    int *must_die_on_failure)\n {\n+\tint ret;\n+\n \tensure_core_worktree(update_data->sm_path);\n \n \tupdate_data->displaypath = get_submodule_displaypath(\n \t\tupdate_data->sm_path, update_data->prefix);\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+\tret = determine_submodule_update_strategy(the_repository,\n+\t\t\t\t\t\t  update_data->just_cloned,\n+\t\t\t\t\t\t  update_data->sm_path,\n+\t\t\t\t\t\t  update_data->update_default,\n+\t\t\t\t\t\t  &update_data->update_strategy);\n+\tif (ret) {\n+\t\t*must_die_on_failure = 1;\n+\t\treturn ret;\n+\t}\n \n \tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\n@@ -2426,8 +2440,6 @@ 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\tint ret;\n-\n \t\tret = run_update_procedure(update_data, must_die_on_failure);\n \t\tif (*must_die_on_failure)\n \t\t\treturn ret;\n@@ -2438,7 +2450,6 @@ static int update_submodule(struct update_data *update_data,\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 ret;\n \n \t\tnext.prefix = NULL;\n \t\toidcpy(&next.oid, null_oid());\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462380","messageId":"patch-v4-27.33-2b066190739-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 27/33] submodule--helper: libify \"must_die_on_failure\" code paths","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:09Z","receivedAt":"2022-08-31T23:19:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In preceding commits the codepaths around update_submodules() were\nchanged from using exit() or die() to ferrying up a\n\"must_die_on_failure\" in the cases where we'd exit(), and in most\ncases where we'd die().\n\nWe needed to do this this to ensure that we'd early exit or otherwise\nabort the update_submodules() processing before it was completed.\n\nNow that those preceding changes have shown that we've converted those\npaths, we can remove the remaining \"ret == 128\" special-cases, leaving\nthe only such special-case in update_submodules(). I.e. we now know\nafter having gone through the various codepaths that we were only\nreturning 128 if we meant to early abort.\n\nIn update_submodules() we'll for now set any non-zero non-128 exit\ncodes to \"1\", but will start ferrying up the exit code as-is in a\nsubsequent commit.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 45 +++++++++++++------------------------\n 1 file changed, 16 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 2f78529736d..8a086723ba6 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2132,8 +2132,7 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet,\n \treturn run_command(&cp);\n }\n \n-static int run_update_command(const struct update_data *ud, int subforce,\n-\t\t\t      int *must_die_on_failure)\n+static int run_update_command(const struct update_data *ud, int subforce)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n@@ -2196,8 +2195,6 @@ static int run_update_command(const struct update_data *ud, int subforce,\n \t\t\t    ud->update_strategy.type);\n \t\t}\n \n-\t\tif (ret == 128)\n-\t\t\t*must_die_on_failure = 1;\n \t\treturn ret;\n \t}\n \n@@ -2229,8 +2226,7 @@ static int run_update_command(const struct update_data *ud, int subforce,\n \treturn 0;\n }\n \n-static int run_update_procedure(const struct update_data *ud,\n-\t\t\t\tint *must_die_on_failure)\n+static int run_update_procedure(const struct update_data *ud)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2257,7 +2253,7 @@ static int run_update_procedure(const 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, must_die_on_failure);\n+\treturn run_update_command(ud, subforce);\n }\n \n static const char *remote_submodule_branch(const char *path)\n@@ -2394,8 +2390,7 @@ static void update_data_to_args(const struct update_data *update_data,\n \t\t\t\t    \"--no-single-branch\");\n }\n \n-static int update_submodule(struct update_data *update_data,\n-\t\t\t    int *must_die_on_failure)\n+static int update_submodule(struct update_data *update_data)\n {\n \tint ret;\n \n@@ -2409,10 +2404,8 @@ static int update_submodule(struct update_data *update_data,\n \t\t\t\t\t\t  update_data->sm_path,\n \t\t\t\t\t\t  update_data->update_default,\n \t\t\t\t\t\t  &update_data->update_strategy);\n-\tif (ret) {\n-\t\t*must_die_on_failure = 1;\n+\tif (ret)\n \t\treturn ret;\n-\t}\n \n \tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\n@@ -2440,11 +2433,9 @@ 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\tret = run_update_procedure(update_data, must_die_on_failure);\n-\t\tif (*must_die_on_failure)\n-\t\t\treturn ret;\n+\t\tret = run_update_procedure(update_data);\n \t\tif (ret)\n-\t\t\treturn 1;\n+\t\t\treturn ret;\n \t}\n \n \tif (update_data->recursive) {\n@@ -2461,12 +2452,9 @@ static int update_submodule(struct update_data *update_data,\n \t\tupdate_data_to_args(&next, &cp.args);\n \n \t\tret = run_command(&cp);\n-\t\tif (!ret)\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 (ret == 128)\n-\t\t\t*must_die_on_failure = 1;\n+\t\tif (ret)\n+\t\t\tdie_message(_(\"Failed to recurse into submodule path '%s'\"),\n+\t\t\t\t    update_data->displaypath);\n \t\treturn ret;\n \t}\n \n@@ -2499,20 +2487,19 @@ static int update_submodules(struct update_data *update_data)\n \n \tfor (i = 0; i < suc.update_clone_nr; i++) {\n \t\tstruct update_clone_data ucd = suc.update_clone[i];\n-\t\tint must_die_on_failure = 0;\n \t\tint code;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n-\t\tif (code)\n-\t\t\tret = code;\n-\t\tif (must_die_on_failure)\n+\t\tcode = update_submodule(update_data);\n+\t\tif (!code)\n+\t\t\tcontinue;\n+\t\tret = code;\n+\t\tif (ret == 128)\n \t\t\tgoto cleanup;\n-\t\telse if (code)\n-\t\t\tret = 1;\n+\t\tret = 1;\n \t}\n \n cleanup:\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462381","messageId":"patch-v4-25.33-99717171578-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 25/33] submodule--helper: don't exit() on failure, return","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:07Z","receivedAt":"2022-08-31T23:19:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code downstream of module_update() to short-circuit and return\nto the top-level on failure, rather than calling exit().\n\nTo do so we need to diligently check whether we \"must_die_on_failure\",\nwhich is a pattern started in c51f8f94e5b (submodule--helper: run\nupdate procedures from C, 2021-08-24), but which hadn't been completed\nto the point where we could avoid calling exit() here.\n\nThis introduces no functional changes, but makes it easier to both\ncall these routines as a library in the future, and to eventually\navoid leaking memory.\n\nThis and similar control flow in submodule--helper.c could be made\nsimpler by properly \"libifying\" it, i.e. to have it consistently\nreturn -1 on failures, and to early return on any non-success.\n\nBut let's leave that larger project for now, and (mostly) emulate what\nwere doing with the \"exit(128)\" before this change.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 35 +++++++++++++++++++++++++----------\n 1 file changed, 25 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 234f1f993e1..166c6aaccb2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2126,7 +2126,8 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet,\n \treturn run_command(&cp);\n }\n \n-static int run_update_command(const struct update_data *ud, int subforce)\n+static int run_update_command(const struct update_data *ud, int subforce,\n+\t\t\t      int *must_die_on_failure)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n@@ -2190,7 +2191,7 @@ static int run_update_command(const struct update_data *ud, int subforce)\n \t\t}\n \n \t\tif (ret == 128)\n-\t\t\texit(ret);\n+\t\t\t*must_die_on_failure = 1;\n \t\treturn ret;\n \t}\n \n@@ -2222,7 +2223,8 @@ static int run_update_command(const struct update_data *ud, int subforce)\n \treturn 0;\n }\n \n-static int run_update_procedure(const struct update_data *ud)\n+static int run_update_procedure(const struct update_data *ud,\n+\t\t\t\tint *must_die_on_failure)\n {\n \tint subforce = is_null_oid(&ud->suboid) || ud->force;\n \n@@ -2249,7 +2251,7 @@ static int run_update_procedure(const 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, must_die_on_failure);\n }\n \n static const char *remote_submodule_branch(const char *path)\n@@ -2386,7 +2388,8 @@ static void update_data_to_args(const struct update_data *update_data,\n \t\t\t\t    \"--no-single-branch\");\n }\n \n-static int update_submodule(struct update_data *update_data)\n+static int update_submodule(struct update_data *update_data,\n+\t\t\t    int *must_die_on_failure)\n {\n \tensure_core_worktree(update_data->sm_path);\n \n@@ -2422,9 +2425,15 @@ static int update_submodule(struct update_data *update_data)\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+\tif (!oideq(&update_data->oid, &update_data->suboid) || update_data->force) {\n+\t\tint ret;\n+\n+\t\tret = run_update_procedure(update_data, must_die_on_failure);\n+\t\tif (*must_die_on_failure)\n+\t\t\treturn ret;\n+\t\tif (ret)\n \t\t\treturn 1;\n+\t}\n \n \tif (update_data->recursive) {\n \t\tstruct child_process cp = CHILD_PROCESS_INIT;\n@@ -2440,14 +2449,13 @@ static int update_submodule(struct update_data *update_data)\n \t\tprepare_submodule_repo_env(&cp.env);\n \t\tupdate_data_to_args(&next, &cp.args);\n \n-\t\t/* die() if child process die()'d */\n \t\tret = run_command(&cp);\n \t\tif (!ret)\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 (ret == 128)\n-\t\t\texit(ret);\n+\t\t\t*must_die_on_failure = 1;\n \t\treturn ret;\n \t}\n \n@@ -2480,12 +2488,19 @@ static int update_submodules(struct update_data *update_data)\n \n \tfor (i = 0; i < suc.update_clone_nr; i++) {\n \t\tstruct update_clone_data ucd = suc.update_clone[i];\n+\t\tint must_die_on_failure = 0;\n+\t\tint code;\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\tcode = update_submodule(update_data, &must_die_on_failure);\n+\t\tif (code)\n+\t\t\tret = code;\n+\t\tif (must_die_on_failure)\n+\t\t\tgoto cleanup;\n+\t\telse if (code)\n \t\t\tret = 1;\n \t}\n \n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462382","messageId":"patch-v4-28.33-72e3cdf6543-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 28/33] submodule--helper update: don't override 'checkout' exit code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:10Z","receivedAt":"2022-08-31T23:19:36Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"When \"git submodule update\" runs it might call \"checkout\", \"merge\",\n\"rebase\", or a custom command. Ever since run_update_command() was\nadded in c51f8f94e5b (submodule--helper: run update procedures from C,\n2021-08-24) we'd either exit immediately if the\n\"submodule.<name>.update\" method failed, or in the case of \"checkout\"\ncontinue trying to update other submodules.\n\nThis code used to use the magical \"2\" return code, but in\n55b3f12cb54 (submodule update: use die_message(), 2022-03-15) it was\nmade to exit(128), which in preceding commits has been changed to\nreturn that 128 code to the top-level.\n\nLet's \"libify\" this code even more by not having it arbitrarily\noverride the return code. In practice this doesn't change anything as\nthe code \"git checkout\" would return on any normal failure is \"1\", but\nwe'll now in principle properly abort the operation if \"git checkout\"\nwere to exit with 128.\n\nIt would make sense to follow-up this change with a change to allow\nthe \"submodule.<name>.update = !...\" (SM_UPDATE_COMMAND) method the\nsame liberties as \"checkout\", and perhaps to do the same with a failed\n\"merge\" or \"rebase\". But let's leave that for now.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 9 +++------\n 1 file changed, 3 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 8a086723ba6..4252b6d864c 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2136,6 +2136,7 @@ static int run_update_command(const struct update_data *ud, int subforce)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tchar *oid = oid_to_hex(&ud->oid);\n+\tint ret;\n \n \tswitch (ud->update_strategy.type) {\n \tcase SM_UPDATE_CHECKOUT:\n@@ -2168,15 +2169,12 @@ static int run_update_command(const struct update_data *ud, int subforce)\n \n \tcp.dir = xstrdup(ud->sm_path);\n \tprepare_submodule_repo_env(&cp.env);\n-\tif (run_command(&cp)) {\n-\t\tint ret;\n-\n+\tif ((ret = run_command(&cp))) {\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\t/* the command failed, but update must continue */\n-\t\t\tret = 1;\n+\t\t\t/* No \"ret\" assignment, use \"git checkout\"'s */\n \t\t\tbreak;\n \t\tcase SM_UPDATE_REBASE:\n \t\t\tret = die_message(_(\"Unable to rebase '%s' in submodule path '%s'\"),\n@@ -2499,7 +2497,6 @@ static int update_submodules(struct update_data *update_data)\n \t\tret = code;\n \t\tif (ret == 128)\n \t\t\tgoto cleanup;\n-\t\tret = 1;\n \t}\n \n cleanup:\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462383","messageId":"patch-v4-29.33-a283ae61e6e-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 29/33] submodule--helper: libify \"must_die_on_failure\" code paths (for die)","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:11Z","receivedAt":"2022-08-31T23:19:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Continue the libification of codepaths that previously relied on\n\"must_die_on_failure\". In these cases we've always been early aborting\nby calling die(), but as we know that these codepaths will properly\nhandle return codes of 128 to mean an early abort let's have them use\ndie_message() instead.\n\nThis still isn't a complete migration away from die() for these\ncodepaths, in particular this code in update_submodule() will still call die() in some cases:\n\n\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n\nBut as that code is used by other callers than the \"update\" code let's\nleave converting it for a subsequent commit.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 29 +++++++++++++++++------------\n 1 file changed, 17 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4252b6d864c..b99fb7a244e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2246,9 +2246,9 @@ static int run_update_procedure(const struct update_data *ud)\n \t\t */\n \t\tif (!is_tip_reachable(ud->sm_path, &ud->oid) &&\n \t\t    fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, &ud->oid))\n-\t\t\tdie(_(\"Fetched in submodule path '%s', but it did not \"\n-\t\t\t      \"contain %s. Direct fetching of that commit failed.\"),\n-\t\t\t    ud->displaypath, oid_to_hex(&ud->oid));\n+\t\t\treturn die_message(_(\"Fetched in submodule path '%s', but it did not \"\n+\t\t\t\t\t     \"contain %s. Direct fetching of that commit failed.\"),\n+\t\t\t\t\t   ud->displaypath, oid_to_hex(&ud->oid));\n \t}\n \n \treturn run_update_command(ud, subforce);\n@@ -2292,13 +2292,14 @@ static const char *remote_submodule_branch(const char *path)\n \treturn branch;\n }\n \n-static void ensure_core_worktree(const char *path)\n+static int ensure_core_worktree(const char *path)\n {\n \tconst char *cw;\n \tstruct repository subrepo;\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+\t\treturn die_message(_(\"could not get a repository handle for submodule '%s'\"),\n+\t\t\t\t   path);\n \n \tif (!repo_config_get_string_tmp(&subrepo, \"core.worktree\", &cw)) {\n \t\tchar *cfg_file, *abs_path;\n@@ -2316,6 +2317,8 @@ static void ensure_core_worktree(const char *path)\n \t\tfree(abs_path);\n \t\tstrbuf_release(&sb);\n \t}\n+\n+\treturn 0;\n }\n \n static const char *submodule_update_type_to_label(enum submodule_update_type type)\n@@ -2392,7 +2395,9 @@ static int update_submodule(struct update_data *update_data)\n {\n \tint ret;\n \n-\tensure_core_worktree(update_data->sm_path);\n+\tret = ensure_core_worktree(update_data->sm_path);\n+\tif (ret)\n+\t\treturn ret;\n \n \tupdate_data->displaypath = get_submodule_displaypath(\n \t\tupdate_data->sm_path, update_data->prefix);\n@@ -2408,8 +2413,8 @@ static int update_submodule(struct update_data *update_data)\n \tif (update_data->just_cloned)\n \t\toidcpy(&update_data->suboid, null_oid());\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+\t\treturn die_message(_(\"Unable to find current revision in submodule path '%s'\"),\n+\t\t\t\t   update_data->displaypath);\n \n \tif (update_data->remote) {\n \t\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n@@ -2419,13 +2424,13 @@ static int update_submodule(struct update_data *update_data)\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\t\treturn die_message(_(\"Unable to fetch in submodule path '%s'\"),\n+\t\t\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+\t\t\treturn die_message(_(\"Unable to find %s revision in submodule path '%s'\"),\n+\t\t\t\t\t   remote_ref, update_data->sm_path);\n \n \t\tfree(remote_ref);\n \t}\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462384","messageId":"patch-v4-30.33-ba5c170c3a4-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 30/33] submodule--helper: check repo{_submodule,}_init() return values","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:12Z","receivedAt":"2022-08-31T23:19:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix code added in ce125d431aa (submodule: extract path to submodule\ngitdir func, 2021-09-15) and a77c3fcb5ec (submodule--helper: get\nremote names from any repository, 2022-03-04) which failed to check\nthe return values of repo_init() and repo_submodule_init(). If we\nfailed to initialize the repository or submodule we could segfault\nwhen trying to access the invalid repository structs.\n\nLet's also check that these were the only such logic errors in the\ncodebase by making use of the \"warn_unused_result\" attribute. This is\nvalid as of GCC 3.4.0 (and clang will catch it via its faking of\n__GNUC__ ).\n\nAs the comment being added to git-compat-util.h we're piggy-backing on\nthe LAST_ARG_MUST_BE_NULL version check out of lazyness. See\n9fe3edc47f1 (Add the LAST_ARG_MUST_BE_NULL macro, 2013-07-18) for its\naddition. The marginal benefit of covering gcc 3.4.0..4.0.0 is\nnear-zero (or zero) at this point. It mostly matters that we catch\nthis somewhere.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 9 +++++++--\n git-compat-util.h           | 3 +++\n repository.h                | 3 +++\n 3 files changed, 13 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex b99fb7a244e..dfd71f0f2b2 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -63,7 +63,10 @@ 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+\tif (repo_submodule_init(&subrepo, the_repository, module_path,\n+\t\t\t\tnull_oid()) < 0)\n+\t\tdie(_(\"could not get a repository handle for submodule '%s'\"),\n+\t\t    module_path);\n \treturn repo_get_default_remote(&subrepo);\n }\n \n@@ -1483,7 +1486,9 @@ static int add_possible_reference_from_superproject(\n \t\tstruct strbuf err = STRBUF_INIT;\n \t\tstrbuf_add(&sb, odb->path, len);\n \n-\t\trepo_init(&alternate, sb.buf, NULL);\n+\t\tif (repo_init(&alternate, sb.buf, NULL) < 0)\n+\t\t\tdie(_(\"could not get a repository handle for gitdir '%s'\"),\n+\t\t\t    sb.buf);\n \n \t\t/*\n \t\t * We need to end the new path with '/' to mark it as a dir,\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 4e51a1c48bc..7ebae122d40 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -569,8 +569,11 @@ static inline int git_has_dir_sep(const char *path)\n /* The sentinel attribute is valid from gcc version 4.0 */\n #if defined(__GNUC__) && (__GNUC__ >= 4)\n #define LAST_ARG_MUST_BE_NULL __attribute__((sentinel))\n+/* warn_unused_result exists as of gcc 3.4.0, but be lazy and check 4.0 */\n+#define RESULT_MUST_BE_USED __attribute__ ((warn_unused_result))\n #else\n #define LAST_ARG_MUST_BE_NULL\n+#define RESULT_MUST_BE_USED\n #endif\n \n #define MAYBE_UNUSED __attribute__((__unused__))\ndiff --git a/repository.h b/repository.h\nindex 797f471cce9..24316ac944e 100644\n--- a/repository.h\n+++ b/repository.h\n@@ -1,6 +1,7 @@\n #ifndef REPOSITORY_H\n #define REPOSITORY_H\n \n+#include \"git-compat-util.h\"\n #include \"path.h\"\n \n struct config_set;\n@@ -186,6 +187,7 @@ void repo_set_gitdir(struct repository *repo, const char *root,\n void repo_set_worktree(struct repository *repo, const char *path);\n void repo_set_hash_algo(struct repository *repo, int algo);\n void initialize_the_repository(void);\n+RESULT_MUST_BE_USED\n int repo_init(struct repository *r, const char *gitdir, const char *worktree);\n \n /*\n@@ -197,6 +199,7 @@ int repo_init(struct repository *r, const char *gitdir, const char *worktree);\n  * Return 0 upon success and a non-zero value upon failure.\n  */\n struct object_id;\n+RESULT_MUST_BE_USED\n int repo_submodule_init(struct repository *subrepo,\n \t\t\tstruct repository *superproject,\n \t\t\tconst char *path,\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462385","messageId":"patch-v4-32.33-3254a8ca6eb-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 32/33] submodule--helper: libify even more \"die\" paths for module_update()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:14Z","receivedAt":"2022-08-31T23:19:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As noted in a preceding commit the get_default_remote_submodule() and\nremote_submodule_branch() functions would invoke die(), and thus leave\nupdate_submodule() only partially lib-ified. We've addressed the\nformer of those in a preceding commit, let's now address the latter.\n\nIn addition to lib-ifying the function this fixes a potential (but\nobscure) segfault introduced by a logic error in\n1012a5cbc3f (submodule--helper run-update-procedure: learn --remote,\n2022-03-04):\n\nWe were assuming that remote_submodule_branch() would always return\nnon-NULL, but if the submodule_from_path() call in that function fails\nwe'll return NULL. See its introduction in\n92bbe7ccf1f (submodule--helper: add remote-branch helper,\n2016-08-03). I.e. we'd previously have segfaulted in the xstrfmt()\ncall in update_submodule() seen in the context.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 41 ++++++++++++++++++++++---------------\n 1 file changed, 25 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9de3a3c921a..3f822eac3a1 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -2268,42 +2268,49 @@ static int run_update_procedure(const struct update_data *ud)\n \treturn run_update_command(ud, subforce);\n }\n \n-static const char *remote_submodule_branch(const char *path)\n+static int remote_submodule_branch(const char *path, const char **branch)\n {\n \tconst struct submodule *sub;\n-\tconst char *branch = NULL;\n \tchar *key;\n+\t*branch = NULL;\n \n \tsub = submodule_from_path(the_repository, null_oid(), path);\n \tif (!sub)\n-\t\treturn NULL;\n+\t\treturn die_message(_(\"could not initialize submodule at path '%s'\"),\n+\t\t\t\t   path);\n \n \tkey = xstrfmt(\"submodule.%s.branch\", sub->name);\n-\tif (repo_config_get_string_tmp(the_repository, key, &branch))\n-\t\tbranch = sub->branch;\n+\tif (repo_config_get_string_tmp(the_repository, key, branch))\n+\t\t*branch = sub->branch;\n \tfree(key);\n \n-\tif (!branch)\n-\t\treturn \"HEAD\";\n+\tif (!*branch) {\n+\t\t*branch = \"HEAD\";\n+\t\treturn 0;\n+\t}\n \n-\tif (!strcmp(branch, \".\")) {\n+\tif (!strcmp(*branch, \".\")) {\n \t\tconst char *refname = resolve_ref_unsafe(\"HEAD\", 0, NULL, NULL);\n \n \t\tif (!refname)\n-\t\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\t\treturn die_message(_(\"No such ref: %s\"), \"HEAD\");\n \n \t\t/* detached HEAD */\n \t\tif (!strcmp(refname, \"HEAD\"))\n-\t\t\tdie(_(\"Submodule (%s) branch configured to inherit \"\n-\t\t\t      \"branch from superproject, but the superproject \"\n-\t\t\t      \"is not on any branch\"), sub->name);\n+\t\t\treturn die_message(_(\"Submodule (%s) branch configured to inherit \"\n+\t\t\t\t\t     \"branch from superproject, but the superproject \"\n+\t\t\t\t\t     \"is not on any branch\"), sub->name);\n \n \t\tif (!skip_prefix(refname, \"refs/heads/\", &refname))\n-\t\t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n-\t\treturn refname;\n+\t\t\treturn die_message(_(\"Expecting a full ref name, got %s\"),\n+\t\t\t\t\t   refname);\n+\n+\t\t*branch = refname;\n+\t\treturn 0;\n \t}\n \n-\treturn branch;\n+\t/* Our \"branch\" is coming from repo_config_get_string_tmp() */\n+\treturn 0;\n }\n \n static int ensure_core_worktree(const char *path)\n@@ -2439,7 +2446,9 @@ static int update_submodule(struct update_data *update_data)\n \t\tcode = get_default_remote_submodule(update_data->sm_path, &remote_name);\n \t\tif (code)\n \t\t\treturn code;\n-\t\tbranch = remote_submodule_branch(update_data->sm_path);\n+\t\tcode = remote_submodule_branch(update_data->sm_path, &branch);\n+\t\tif (code)\n+\t\t\treturn code;\n \t\tremote_ref = xstrfmt(\"refs/remotes/%s/%s\", remote_name, branch);\n \n \t\tif (!update_data->nofetch) {\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462386","messageId":"patch-v4-31.33-a0d71b4e8bb-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 31/33] submodule--helper: libify more \"die\" paths for module_update()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:13Z","receivedAt":"2022-08-31T23:19:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As noted in a preceding commit the get_default_remote_submodule() and\nremote_submodule_branch() functions would invoke die(), and thus leave\nupdate_submodule() only partially lib-ified. Let's address the former\nof those cases.\n\nChange the functions to return an int exit code (non-zero on failure),\nwhile leaving the get_default_remote() function for the callers that\nstill want the die() semantics.\n\nThis change addresses 1/2 of the \"die\" issue in these two lines in\nupdate_submodule():\n\n\tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n\tconst char *branch = remote_submodule_branch(update_data->sm_path);\n\nWe can safely remove the \"!default_remote\" case from sync_submodule(),\nbecause our get_default_remote_submodule() function now returns a\ndie_message() on failure, so we can have it an dother callers check if\nthe exit code should be non-zero instead.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 58 +++++++++++++++++++++++--------------\n 1 file changed, 37 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex dfd71f0f2b2..9de3a3c921a 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -31,48 +31,57 @@\n typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n \t\t\t\t  void *cb_data);\n \n-static char *repo_get_default_remote(struct repository *repo)\n+static int repo_get_default_remote(struct repository *repo, char **default_remote)\n {\n-\tchar *dest = NULL, *ret;\n+\tchar *dest = NULL;\n \tstruct strbuf sb = STRBUF_INIT;\n \tstruct ref_store *store = get_main_ref_store(repo);\n \tconst char *refname = refs_resolve_ref_unsafe(store, \"HEAD\", 0, NULL,\n \t\t\t\t\t\t      NULL);\n \n \tif (!refname)\n-\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\treturn die_message(_(\"No such ref: %s\"), \"HEAD\");\n \n \t/* detached HEAD */\n-\tif (!strcmp(refname, \"HEAD\"))\n-\t\treturn xstrdup(\"origin\");\n+\tif (!strcmp(refname, \"HEAD\")) {\n+\t\t*default_remote = xstrdup(\"origin\");\n+\t\treturn 0;\n+\t}\n \n \tif (!skip_prefix(refname, \"refs/heads/\", &refname))\n-\t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n+\t\treturn die_message(_(\"Expecting a full ref name, got %s\"),\n+\t\t\t\t   refname);\n \n \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n \tif (repo_config_get_string(repo, sb.buf, &dest))\n-\t\tret = xstrdup(\"origin\");\n+\t\t*default_remote = xstrdup(\"origin\");\n \telse\n-\t\tret = dest;\n+\t\t*default_remote = dest;\n \n \tstrbuf_release(&sb);\n-\treturn ret;\n+\treturn 0;\n }\n \n-static char *get_default_remote_submodule(const char *module_path)\n+static int get_default_remote_submodule(const char *module_path, char **default_remote)\n {\n \tstruct repository subrepo;\n \n \tif (repo_submodule_init(&subrepo, the_repository, module_path,\n \t\t\t\tnull_oid()) < 0)\n-\t\tdie(_(\"could not get a repository handle for submodule '%s'\"),\n-\t\t    module_path);\n-\treturn repo_get_default_remote(&subrepo);\n+\t\treturn die_message(_(\"could not get a repository handle for submodule '%s'\"),\n+\t\t\t\t   module_path);\n+\treturn repo_get_default_remote(&subrepo, default_remote);\n }\n \n static char *get_default_remote(void)\n {\n-\treturn repo_get_default_remote(the_repository);\n+\tchar *default_remote;\n+\tint code = repo_get_default_remote(the_repository, &default_remote);\n+\n+\tif (code)\n+\t\texit(code);\n+\n+\treturn default_remote;\n }\n \n static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)\n@@ -1159,6 +1168,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *sub_config_path = NULL;\n+\tint code;\n \n \tif (!is_submodule_active(the_repository, path))\n \t\treturn;\n@@ -1198,10 +1208,9 @@ static void sync_submodule(const char *path, const char *prefix,\n \t\tgoto cleanup;\n \n \tstrbuf_reset(&sb);\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+\tcode = get_default_remote_submodule(path, &default_remote);\n+\tif (code)\n+\t\texit(code);\n \n \tremote_key = xstrfmt(\"remote.%s.url\", default_remote);\n \tfree(default_remote);\n@@ -2422,9 +2431,16 @@ static int update_submodule(struct update_data *update_data)\n \t\t\t\t   update_data->displaypath);\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+\t\tchar *remote_name;\n+\t\tconst char *branch;\n+\t\tchar *remote_ref;\n+\t\tint code;\n+\n+\t\tcode = get_default_remote_submodule(update_data->sm_path, &remote_name);\n+\t\tif (code)\n+\t\t\treturn code;\n+\t\tbranch = remote_submodule_branch(update_data->sm_path);\n+\t\tremote_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-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462387","messageId":"patch-v4-33.33-1e38bfa7f95-20220831T230519Z-avarab@gmail.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"[PATCH v4 33/33] submodule--helper: fix bad config API usage","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-08-31T23:18:15Z","receivedAt":"2022-08-31T23:19:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix bad config API usage added in a452128a36c (submodule--helper:\nintroduce add-config subcommand, 2021-08-06). After\ngit_config_get_string() returns successfully we know the \"char **dest\"\nwill be non-NULL.\n\nA coccinelle patch that transforms this turns up a couple of other\nsuch issues, one in fetch-pack.c, and another in upload-pack.c:\n\n\t@@\n\tidentifier F =~ \"^(repo|git)_config_get_string(_tmp)?$\";\n\tidentifier V;\n\t@@\n\t  !F(..., &V)\n\t- && (V)\n\nBut let's focus narrowly on submodule--helper for now, we can fix\nthose some other time.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/submodule--helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 3f822eac3a1..c4149f11e7f 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -3110,7 +3110,7 @@ static void configure_added_submodule(struct add_data *add_data)\n \t * is_submodule_active(), since that function needs to find\n \t * out the value of \"submodule.active\" again anyway.\n \t */\n-\tif (!git_config_get_string(\"submodule.active\", &val) && val) {\n+\tif (!git_config_get_string(\"submodule.active\", &val)) {\n \t\t/*\n \t\t * If the submodule being added isn't already covered by the\n \t\t * current configured pathspec, set the submodule's active flag\n-- \n2.37.3.1420.g76f8a3d556c\n\n"},{"id":"462490","messageId":"kl6lzgfibyrf.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"patch-v4-31.33-a0d71b4e8bb-20220831T230519Z-avarab@gmail.com","subject":"Re: [PATCH v4 31/33] submodule--helper: libify more \"die\" paths for module_update()","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-09-01T20:55:32Z","receivedAt":"2022-09-01T20:55:42Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Ævar Arnfjörð Bjarmason         <avarab@gmail.com> writes:\n\n> As noted in a preceding commit the get_default_remote_submodule() and\n> remote_submodule_branch() functions would invoke die(), and thus leave\n> update_submodule() only partially lib-ified. Let's address the former\n> of those cases.\n>\n> Change the functions to return an int exit code (non-zero on failure),\n> while leaving the get_default_remote() function for the callers that\n> still want the die() semantics.\n>\n> This change addresses 1/2 of the \"die\" issue in these two lines in\n> update_submodule():\n>\n> \tchar *remote_name = get_default_remote_submodule(update_data->sm_path);\n> \tconst char *branch = remote_submodule_branch(update_data->sm_path);\n>\n> We can safely remove the \"!default_remote\" case from sync_submodule(),\n> because our get_default_remote_submodule() function now returns a\n> die_message() on failure, so we can have it an dother callers check if\n\nIf I'm reading this correctly, s/an dother/and other ?\n\n> the exit code should be non-zero instead.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 58 +++++++++++++++++++++++--------------\n>  1 file changed, 37 insertions(+), 21 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index dfd71f0f2b2..9de3a3c921a 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -31,48 +31,57 @@\n>  typedef void (*each_submodule_fn)(const struct cache_entry *list_item,\n>  \t\t\t\t  void *cb_data);\n>  \n> -static char *repo_get_default_remote(struct repository *repo)\n> +static int repo_get_default_remote(struct repository *repo, char **default_remote)\n>  {\n> -\tchar *dest = NULL, *ret;\n> +\tchar *dest = NULL;\n>  \tstruct strbuf sb = STRBUF_INIT;\n>  \tstruct ref_store *store = get_main_ref_store(repo);\n>  \tconst char *refname = refs_resolve_ref_unsafe(store, \"HEAD\", 0, NULL,\n>  \t\t\t\t\t\t      NULL);\n>  \n>  \tif (!refname)\n> -\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n> +\t\treturn die_message(_(\"No such ref: %s\"), \"HEAD\");\n>  \n>  \t/* detached HEAD */\n> -\tif (!strcmp(refname, \"HEAD\"))\n> -\t\treturn xstrdup(\"origin\");\n> +\tif (!strcmp(refname, \"HEAD\")) {\n> +\t\t*default_remote = xstrdup(\"origin\");\n> +\t\treturn 0;\n> +\t}\n>  \n>  \tif (!skip_prefix(refname, \"refs/heads/\", &refname))\n> -\t\tdie(_(\"Expecting a full ref name, got %s\"), refname);\n> +\t\treturn die_message(_(\"Expecting a full ref name, got %s\"),\n> +\t\t\t\t   refname);\n>  \n>  \tstrbuf_addf(&sb, \"branch.%s.remote\", refname);\n>  \tif (repo_config_get_string(repo, sb.buf, &dest))\n> -\t\tret = xstrdup(\"origin\");\n> +\t\t*default_remote = xstrdup(\"origin\");\n>  \telse\n> -\t\tret = dest;\n> +\t\t*default_remote = dest;\n>  \n>  \tstrbuf_release(&sb);\n> -\treturn ret;\n> +\treturn 0;\n>  }\n>  \n> -static char *get_default_remote_submodule(const char *module_path)\n> +static int get_default_remote_submodule(const char *module_path, char **default_remote)\n>  {\n>  \tstruct repository subrepo;\n>  \n>  \tif (repo_submodule_init(&subrepo, the_repository, module_path,\n>  \t\t\t\tnull_oid()) < 0)\n> -\t\tdie(_(\"could not get a repository handle for submodule '%s'\"),\n> -\t\t    module_path);\n> -\treturn repo_get_default_remote(&subrepo);\n> +\t\treturn die_message(_(\"could not get a repository handle for submodule '%s'\"),\n> +\t\t\t\t   module_path);\n> +\treturn repo_get_default_remote(&subrepo, default_remote);\n>  }\n>  \n>  static char *get_default_remote(void)\n>  {\n> -\treturn repo_get_default_remote(the_repository);\n> +\tchar *default_remote;\n> +\tint code = repo_get_default_remote(the_repository, &default_remote);\n> +\n> +\tif (code)\n> +\t\texit(code);\n> +\n> +\treturn default_remote;\n>  }\n>  \n>  static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)\n> @@ -1159,6 +1168,7 @@ static void sync_submodule(const char *path, const char *prefix,\n>  \tchar *sub_origin_url, *super_config_url, *displaypath, *default_remote;\n>  \tstruct strbuf sb = STRBUF_INIT;\n>  \tchar *sub_config_path = NULL;\n> +\tint code;\n>  \n>  \tif (!is_submodule_active(the_repository, path))\n>  \t\treturn;\n> @@ -1198,10 +1208,9 @@ static void sync_submodule(const char *path, const char *prefix,\n>  \t\tgoto cleanup;\n>  \n>  \tstrbuf_reset(&sb);\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> +\tcode = get_default_remote_submodule(path, &default_remote);\n> +\tif (code)\n> +\t\texit(code);\n>  \n>  \tremote_key = xstrfmt(\"remote.%s.url\", default_remote);\n>  \tfree(default_remote);\n> @@ -2422,9 +2431,16 @@ static int update_submodule(struct update_data *update_data)\n>  \t\t\t\t   update_data->displaypath);\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> +\t\tchar *remote_name;\n> +\t\tconst char *branch;\n> +\t\tchar *remote_ref;\n> +\t\tint code;\n> +\n> +\t\tcode = get_default_remote_submodule(update_data->sm_path, &remote_name);\n> +\t\tif (code)\n> +\t\t\treturn code;\n> +\t\tbranch = remote_submodule_branch(update_data->sm_path);\n> +\t\tremote_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> -- \n> 2.37.3.1420.g76f8a3d556c\n"},{"id":"462491","messageId":"kl6lwnambylk.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"58235","inReplyTo":"cover-v4-00.33-00000000000-20220831T230519Z-avarab@gmail.com","subject":"Re: [PATCH v4 00/33] submodule--helper: add tests, rm dead code, refactor & leak prep","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2022-09-01T20:59:03Z","receivedAt":"2022-09-01T21:00:38Z","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> This series is a \"prep\" series for the meaty leak fixes for\n> submodule--helper, see [1] (which will be re-rolled on top of this\n> v3). The v7 re-roll will be at [2].\n>\n> Changes since v3:\n>\n>  * Addressed (hopefully) all of the small feedback, just typo fixes &\n>    commit message clarifications.\n>\n>  * Marked a parameter as \"const\", which helps reason about subsequent\n>    things in the \"leak\" series.\n>\n> Hopefully this is ready to proceed past \"seen\" in its current form...\n>\n> 1. https://lore.kernel.org/git/cover-v3-00.32-00000000000-20220821T130231Z-avarab@gmail.com/\n> 2. https://lore.kernel.org/git/cover-v7-00.17-00000000000-20220831T231003Z-avarab@gmail.com\n\nThanks!\n\nI still have no comments on the attributes and macros on 30/33. Others\nmay want to take look at that.\n\nI spotted one typo in 31/33's commit message, but maybe that can be\nfixed on patch application.\n\nOtherwise, everything else LGTM.\n\n  Reviewed-by: Glen Choo <chooglen@google.com>\n"}]}