{"thread":{"id":"46052","subject":"[PATCH 1/8] submodule recursing: do not write a config variable twice","startedAt":"2017-05-26T19:10:47Z","lastAt":"2017-06-01T00:31:23Z","messageCount":15,"participants":["Stefan Beller","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"320837","messageId":"20170526191017.19155-2-sbeller@google.com","threadId":"46052","inReplyTo":"20170526191017.19155-1-sbeller@google.com","subject":"[PATCH 1/8] submodule recursing: do not write a config variable twice","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-26T19:10:10Z","receivedAt":"2017-05-26T19:10:47Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"The command line option for '--recurse-submodules' is implemented\nusing an OPTION_CALLBACK, which takes both the callback (that sets\nthe file static global variable) as well as passes the same file\nstatic global variable to the option parsing machinery to assign it.\nThis is fixed in this commit by passing NULL as the variable. The\ncallback sets it instead\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/checkout.c  | 2 +-\n builtin/read-tree.c | 2 +-\n builtin/reset.c     | 2 +-\n 3 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex bfa5419f33..0fd57672cc 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1181,7 +1181,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t\tN_(\"second guess 'git checkout <no-such-branch>'\")),\n \t\tOPT_BOOL(0, \"ignore-other-worktrees\", &opts.ignore_other_worktrees,\n \t\t\t N_(\"do not check if another worktree is holding the given ref\")),\n-\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", &recurse_submodules,\n+\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", NULL,\n \t\t\t    \"checkout\", \"control recursive updating of submodules\",\n \t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules },\n \t\tOPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex 23e212ee8c..2a1b8a530e 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -157,7 +157,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \t\t\t N_(\"skip applying sparse checkout filter\")),\n \t\tOPT_BOOL(0, \"debug-unpack\", &opts.debug_unpack,\n \t\t\t N_(\"debug unpack-trees\")),\n-\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", &recurse_submodules,\n+\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", NULL,\n \t\t\t    \"checkout\", \"control recursive updating of submodules\",\n \t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules },\n \t\tOPT_END()\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 5ce27fcaed..1e5f85b1fb 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -304,7 +304,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\t\tN_(\"reset HEAD, index and working tree\"), MERGE),\n \t\tOPT_SET_INT(0, \"keep\", &reset_type,\n \t\t\t\tN_(\"reset HEAD but keep local changes\"), KEEP),\n-\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", &recurse_submodules,\n+\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", NULL,\n \t\t\t    \"reset\", \"control recursive updating of submodules\",\n \t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules },\n \t\tOPT_BOOL('p', \"patch\", &patch_mode, N_(\"select hunks interactively\")),\n-- \n2.13.0.17.g582985b1e4\n\n"},{"id":"320838","messageId":"20170526191017.19155-5-sbeller@google.com","threadId":"46052","inReplyTo":"20170526191017.19155-1-sbeller@google.com","subject":"[PATCH 4/8] submodule loading: separate code path for .gitmodules and config overlay","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-26T19:10:13Z","receivedAt":"2017-05-26T19:10:50Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"The .gitmodules file is not supposed to have all the options available,\nthat are available in the configuration so separate it out.\n\nA configuration option such as the hypothetical submodule.color.diff\nthat determines in which color a submodule change is printed,\nis a very user specific thing, that the .gitmodules file should\nnot tamper with.\n\nThe .gitmodules file should only be used for settings that required\nto setup the project in which the .gitmodules file is tracked. As the\nminimum this would only include the name<->path mapping of the\nsubmodule and its URL and branch.\n\nAny further setting (such as 'fetch.recursesubmodules' or\n'submodule.<name>.{update, ignore, shallow}') is not specific\nto the project setup requirements, but rather is a distribution\nof suggested developer configurations.  In other areas of Git\na suggested developer configuration is not transported in-tree\nbut via other means.  In an organisation this could be done\nby deploying an opinionated system wide config (/etc/gitconfig)\nor by putting the settings in the users home directory when\nthey start at the organisation. In open source projects this\nis often accomplished via extensive READMEs (cf. our\nSubmittingPatches/CodingGuidlines).\n\nAs a later patch in this series wants to introduce\na generic submodule recursion option, we want to make\nsure that switch is not exposed via the gitmodules file.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n submodule.c | 14 +++++++++++---\n 1 file changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/submodule.c b/submodule.c\nindex c9e764b519..78cccb7563 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -153,7 +153,8 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n \t}\n }\n \n-int submodule_config(const char *var, const char *value, void *cb)\n+/* For loading from the .gitmodules file. */\n+static int git_modules_config(const char *var, const char *value, void *cb)\n {\n \tif (!strcmp(var, \"submodule.fetchjobs\")) {\n \t\tparallel_jobs = git_config_int(var, value);\n@@ -169,6 +170,12 @@ int submodule_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n+/* Loads all submodule settings from the config */\n+int submodule_config(const char *var, const char *value, void *cb)\n+{\n+\treturn git_modules_config(var, value, cb);\n+}\n+\n int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\n \t\t\t\t\t\t     const char *arg, int unset)\n {\n@@ -222,7 +229,8 @@ void gitmodules_config(void)\n \t\t}\n \n \t\tif (!gitmodules_is_unmerged)\n-\t\t\tgit_config_from_file(submodule_config, gitmodules_path.buf, NULL);\n+\t\t\tgit_config_from_file(git_modules_config,\n+\t\t\t\tgitmodules_path.buf, NULL);\n \t\tstrbuf_release(&gitmodules_path);\n \t}\n }\n@@ -233,7 +241,7 @@ void gitmodules_config_sha1(const unsigned char *commit_sha1)\n \tunsigned char sha1[20];\n \n \tif (gitmodule_sha1_from_commit(commit_sha1, sha1, &rev)) {\n-\t\tgit_config_from_blob_sha1(submodule_config, rev.buf,\n+\t\tgit_config_from_blob_sha1(git_modules_config, rev.buf,\n \t\t\t\t\t  sha1, NULL);\n \t}\n \tstrbuf_release(&rev);\n-- \n2.13.0.17.g582985b1e4\n\n"},{"id":"320840","messageId":"20170526191017.19155-9-sbeller@google.com","threadId":"46052","inReplyTo":"20170526191017.19155-1-sbeller@google.com","subject":"[PATCH 8/8] builtin/fetch.c: respect 'submodule.recurse' option","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-26T19:10:17Z","receivedAt":"2017-05-26T19:11:18Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Signed-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/fetch.c             |  7 +++++++\n t/t5526-fetch-submodules.sh | 10 ++++++++++\n 2 files changed, 17 insertions(+)\n\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 5f2c2ab23e..c1ec3b03c3 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -73,6 +73,13 @@ static int git_fetch_config(const char *k, const char *v, void *cb)\n \t\tfetch_prune_config = git_config_bool(k, v);\n \t\treturn 0;\n \t}\n+\n+\tif (!strcmp(k, \"submodule.recurse\")) {\n+\t\tint r = git_config_bool(k, v) ?\n+\t\t\tRECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;\n+\t\trecurse_submodules = r;\n+\t}\n+\n \treturn git_default_config(k, v, cb);\n }\n \ndiff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh\nindex f3b0a8d30a..162baf101f 100755\n--- a/t/t5526-fetch-submodules.sh\n+++ b/t/t5526-fetch-submodules.sh\n@@ -71,6 +71,16 @@ test_expect_success \"fetch --recurse-submodules recurses into submodules\" '\n \ttest_i18ncmp expect.err actual.err\n '\n \n+test_expect_success \"submodule.recurse option triggers recursive fetch\" '\n+\tadd_upstream_commit &&\n+\t(\n+\t\tcd downstream &&\n+\t\tgit -c submodule.recurse fetch >../actual.out 2>../actual.err\n+\t) &&\n+\ttest_must_be_empty actual.out &&\n+\ttest_i18ncmp expect.err actual.err\n+'\n+\n test_expect_success \"fetch --recurse-submodules -j2 has the same output behaviour\" '\n \tadd_upstream_commit &&\n \t(\n-- \n2.13.0.17.g582985b1e4\n\n"},{"id":"320842","messageId":"20170526191017.19155-6-sbeller@google.com","threadId":"46052","inReplyTo":"20170526191017.19155-1-sbeller@google.com","subject":"[PATCH 5/8] Introduce 'submodule.recurse' option for worktree manipulators","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-26T19:10:14Z","receivedAt":"2017-05-26T19:11:47Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Any command that understands '--recurse-submodules' can have its\ndefault changed to true, by setting the new 'submodule.recurse'\noption.\n\nThis patch includes read-tree/checkout/reset for working tree\nmanipulating commands. Later patches will cover other commands.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n Documentation/config.txt  |  5 +++++\n builtin/checkout.c        |  2 +-\n builtin/read-tree.c       | 10 +++++++++-\n builtin/reset.c           | 10 +++++++++-\n submodule.c               | 23 +++++++++++++++++++++--\n submodule.h               |  1 +\n t/lib-submodule-update.sh | 12 ++++++++++++\n 7 files changed, 58 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 475e874d51..e367becf72 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -3063,6 +3063,11 @@ submodule.active::\n \tsubmodule's path to determine if the submodule is of interest to git\n \tcommands.\n \n+submodule.recurse::\n+\tSpecifies if commands recurse into submodules by default. This\n+\tapplies to all commands that have a `--recurse-submodules` option.\n+\tDefaults to false.\n+\n submodule.fetchJobs::\n \tSpecifies how many submodules are fetched/cloned at the same time.\n \tA positive integer allows up to that number of submodules fetched\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex acff6039d6..9ccc4a1d52 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -854,7 +854,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb)\n \t}\n \n \tif (starts_with(var, \"submodule.\"))\n-\t\treturn parse_submodule_config_option(var, value);\n+\t\treturn submodule_config(var, value, NULL);\n \n \treturn git_xmerge_config(var, value, NULL);\n }\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex 8a889ef4c3..6dd70cd430 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -98,6 +98,14 @@ static int debug_merge(const struct cache_entry * const *stages,\n \treturn 0;\n }\n \n+int git_read_tree_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"submodule.recurse\"))\n+\t\treturn git_default_submodule_config(var, value, cb);\n+\n+\treturn git_default_config(var, value, cb);\n+}\n+\n static struct lock_file lock_file;\n \n int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n@@ -150,7 +158,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \topts.src_index = &the_index;\n \topts.dst_index = &the_index;\n \n-\tgit_config(git_default_config, NULL);\n+\tgit_config(git_read_tree_config, NULL);\n \n \targc = parse_options(argc, argv, unused_prefix, read_tree_options,\n \t\t\t     read_tree_usage, 0);\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 6f89dc5494..8ccdb7437e 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -266,6 +266,14 @@ static int reset_refs(const char *rev, const struct object_id *oid)\n \treturn update_ref_status;\n }\n \n+int git_reset_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"submodule.recurse\"))\n+\t\treturn git_default_submodule_config(var, value, cb);\n+\n+\treturn git_default_config(var, value, cb);\n+}\n+\n int cmd_reset(int argc, const char **argv, const char *prefix)\n {\n \tint reset_type = NONE, update_ref_status = 0, quiet = 0;\n@@ -294,7 +302,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\tgit_config(git_default_config, NULL);\n+\tgit_config(git_reset_config, NULL);\n \n \targc = parse_options(argc, argv, prefix, options, git_reset_usage,\n \t\t\t\t\t\tPARSE_OPT_KEEP_DASHDASH);\ndiff --git a/submodule.c b/submodule.c\nindex 78cccb7563..2b157dc995 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -16,6 +16,7 @@\n #include \"quote.h\"\n #include \"remote.h\"\n #include \"worktree.h\"\n+#include \"parse-options.h\"\n \n static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n@@ -170,10 +171,28 @@ static int git_modules_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/* Loads all submodule settings from the config */\n+/* Loads all submodule settings from the config. */\n int submodule_config(const char *var, const char *value, void *cb)\n {\n-\treturn git_modules_config(var, value, cb);\n+\tif (!strcmp(var, \"submodule.recurse\")) {\n+\t\tint v = git_config_bool(var, value) ?\n+\t\t\tRECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;\n+\t\tconfig_update_recurse_submodules = v;\n+\t\treturn 0;\n+\t} else {\n+\t\treturn git_modules_config(var, value, cb);\n+\t}\n+}\n+\n+/* Cheap function that only determines if we're interested in submodules at all */\n+int git_default_submodule_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"submodule.recurse\")) {\n+\t\tint v = git_config_bool(var, value) ?\n+\t\t\tRECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;\n+\t\tconfig_update_recurse_submodules = v;\n+\t}\n+\treturn 0;\n }\n \n int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\ndiff --git a/submodule.h b/submodule.h\nindex b13f120f76..d920ca1d5a 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -39,6 +39,7 @@ extern void stage_updated_gitmodules(void);\n extern void set_diffopt_flags_from_submodule_config(struct diff_options *,\n \t\tconst char *path);\n extern int submodule_config(const char *var, const char *value, void *cb);\n+extern int git_default_submodule_config(const char *var, const char *value, void *cb);\n \n struct option;\n int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 0272c4d8ca..52beadad96 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -990,6 +990,18 @@ test_submodule_switch_recursing_with_args () {\n \t\t)\n \t'\n \n+\ttest_expect_success \"git -c submodule.recurse=true $cmd_args: modified submodule updates submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to_interested add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\tgit -c submodule.recurse=true $cmd_args modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\n \t# Updating a submodule to an invalid sha1 doesn't update the\n \t# superproject nor the submodule's work tree.\n \ttest_expect_success \"$command: updating to a missing submodule commit fails\" '\n-- \n2.13.0.17.g582985b1e4\n\n"},{"id":"320843","messageId":"20170526191017.19155-1-sbeller@google.com","threadId":"46052","inReplyTo":null,"subject":"[PATCHv2 0/8] A reroll of sb/submodule-blanket-recursive","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-26T19:10:09Z","receivedAt":"2017-05-26T19:11:48Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"v2:\n* A reroll of sb/submodule-blanket-recursive.\n* This requires ab/grep-preparatory-cleanup \n* It changed a lot from v1, as in v1 the tests did not work,\n  hence the code was broken. Now it actually works.\n* it also includes grep, fetch, push in addition to plain working tree\n  manipulators.\n\nThanks,\nStefan\n\nStefan Beller (8):\n  submodule recursing: do not write a config variable twice\n  submodule test invocation: only pass additional arguments\n  reset/checkout/read-tree: unify config callback for submodule\n    recursion\n  submodule loading: separate code path for .gitmodules and config\n    overlay\n  Introduce 'submodule.recurse' option for worktree manipulators\n  builtin/grep.c: respect 'submodule.recurse' option\n  builtin/push.c: respect 'submodule.recurse' option\n  builtin/fetch.c: respect 'submodule.recurse' option\n\n Documentation/config.txt           |  5 +++\n builtin/checkout.c                 | 31 ++----------------\n builtin/fetch.c                    |  7 +++++\n builtin/grep.c                     |  3 ++\n builtin/push.c                     |  4 +++\n builtin/read-tree.c                | 32 ++++++-------------\n builtin/reset.c                    | 39 +++++++----------------\n submodule.c                        | 64 +++++++++++++++++++++++++++++++++-----\n submodule.h                        |  7 ++++-\n t/lib-submodule-update.sh          | 22 ++++++++++---\n t/t1013-read-tree-submodule.sh     |  4 +--\n t/t2013-checkout-submodule.sh      |  4 +--\n t/t5526-fetch-submodules.sh        | 10 ++++++\n t/t5531-deep-submodule-push.sh     | 21 +++++++++++++\n t/t7112-reset-submodule.sh         |  4 +--\n t/t7814-grep-recurse-submodules.sh | 18 +++++++++++\n 16 files changed, 178 insertions(+), 97 deletions(-)\n\n-- \n2.13.0.17.g582985b1e4\n\n"},{"id":"320844","messageId":"20170526191017.19155-4-sbeller@google.com","threadId":"46052","inReplyTo":"20170526191017.19155-1-sbeller@google.com","subject":"[PATCH 3/8] reset/checkout/read-tree: unify config callback for submodule recursion","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-26T19:10:12Z","receivedAt":"2017-05-26T19:12:11Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"The callback function is essentially duplicated 3 times. Remove all\nof them and offer a new callback function, that lives in submodule.c\n\nBy putting the callback function there, we no longer need the function\n'set_config_update_recurse_submodules', nor duplicate the global variable\nin each builtin as well as submodule.c\n\nIn the three builtins we have different 2 ways how to load the .gitmodules\nand config file, which are slightly different. git-checkout has to load\nthe submodule config all the time due to 23b4c7bcc5 (checkout: Use\nsubmodule.*.ignore settings from .git/config and .gitmodules, 2010-08-28)\n\ngit-reset and git-read-tree do not respect these diff settings, so loading\nthe submodule configuration is optional. Also put that into submodule.c\nfor code deduplication.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n builtin/checkout.c  | 27 +--------------------------\n builtin/read-tree.c | 28 +++-------------------------\n builtin/reset.c     | 27 ++-------------------------\n submodule.c         | 33 +++++++++++++++++++++++++++------\n submodule.h         |  6 +++++-\n 5 files changed, 38 insertions(+), 83 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 0fd57672cc..acff6039d6 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -21,31 +21,12 @@\n #include \"submodule-config.h\"\n #include \"submodule.h\"\n \n-static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n-\n static const char * const checkout_usage[] = {\n \tN_(\"git checkout [<options>] <branch>\"),\n \tN_(\"git checkout [<options>] [<branch>] -- <file>...\"),\n \tNULL,\n };\n \n-static int option_parse_recurse_submodules(const struct option *opt,\n-\t\t\t\t\t   const char *arg, int unset)\n-{\n-\tif (unset) {\n-\t\trecurse_submodules = RECURSE_SUBMODULES_OFF;\n-\t\treturn 0;\n-\t}\n-\tif (arg)\n-\t\trecurse_submodules =\n-\t\t\tparse_update_recurse_submodules_arg(opt->long_name,\n-\t\t\t\t\t\t\t    arg);\n-\telse\n-\t\trecurse_submodules = RECURSE_SUBMODULES_ON;\n-\n-\treturn 0;\n-}\n-\n struct checkout_opts {\n \tint patch_mode;\n \tint quiet;\n@@ -1183,7 +1164,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"do not check if another worktree is holding the given ref\")),\n \t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", NULL,\n \t\t\t    \"checkout\", \"control recursive updating of submodules\",\n-\t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules },\n+\t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n \t\tOPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n \t\tOPT_END(),\n \t};\n@@ -1214,12 +1195,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\tgit_xmerge_config(\"merge.conflictstyle\", conflict_style, NULL);\n \t}\n \n-\tif (recurse_submodules != RECURSE_SUBMODULES_OFF) {\n-\t\tgit_config(submodule_config, NULL);\n-\t\tif (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)\n-\t\t\tset_config_update_recurse_submodules(recurse_submodules);\n-\t}\n-\n \tif ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)\n \t\tdie(_(\"-b, -B and --orphan are mutually exclusive\"));\n \ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex 2a1b8a530e..8a889ef4c3 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -21,7 +21,6 @@\n static int nr_trees;\n static int read_empty;\n static struct tree *trees[MAX_UNPACK_TREES];\n-static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n \n static int list_tree(unsigned char *sha1)\n {\n@@ -99,23 +98,6 @@ static int debug_merge(const struct cache_entry * const *stages,\n \treturn 0;\n }\n \n-static int option_parse_recurse_submodules(const struct option *opt,\n-\t\t\t\t\t   const char *arg, int unset)\n-{\n-\tif (unset) {\n-\t\trecurse_submodules = RECURSE_SUBMODULES_OFF;\n-\t\treturn 0;\n-\t}\n-\tif (arg)\n-\t\trecurse_submodules =\n-\t\t\tparse_update_recurse_submodules_arg(opt->long_name,\n-\t\t\t\t\t\t\t    arg);\n-\telse\n-\t\trecurse_submodules = RECURSE_SUBMODULES_ON;\n-\n-\treturn 0;\n-}\n-\n static struct lock_file lock_file;\n \n int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n@@ -159,7 +141,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \t\t\t N_(\"debug unpack-trees\")),\n \t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", NULL,\n \t\t\t    \"checkout\", \"control recursive updating of submodules\",\n-\t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules },\n+\t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n \t\tOPT_END()\n \t};\n \n@@ -173,13 +155,9 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \targc = parse_options(argc, argv, unused_prefix, read_tree_options,\n \t\t\t     read_tree_usage, 0);\n \n-\thold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);\n+\tload_submodule_cache();\n \n-\tif (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) {\n-\t\tgitmodules_config();\n-\t\tgit_config(submodule_config, NULL);\n-\t\tset_config_update_recurse_submodules(RECURSE_SUBMODULES_ON);\n-\t}\n+\thold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);\n \n \tprefix_set = opts.prefix ? 1 : 0;\n \tif (1 < opts.merge + opts.reset + prefix_set)\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 1e5f85b1fb..6f89dc5494 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -24,25 +24,6 @@\n #include \"submodule.h\"\n #include \"submodule-config.h\"\n \n-static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n-\n-static int option_parse_recurse_submodules(const struct option *opt,\n-\t\t\t\t\t   const char *arg, int unset)\n-{\n-\tif (unset) {\n-\t\trecurse_submodules = RECURSE_SUBMODULES_OFF;\n-\t\treturn 0;\n-\t}\n-\tif (arg)\n-\t\trecurse_submodules =\n-\t\t\tparse_update_recurse_submodules_arg(opt->long_name,\n-\t\t\t\t\t\t\t    arg);\n-\telse\n-\t\trecurse_submodules = RECURSE_SUBMODULES_ON;\n-\n-\treturn 0;\n-}\n-\n static const char * const git_reset_usage[] = {\n \tN_(\"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]\"),\n \tN_(\"git reset [-q] [<tree-ish>] [--] <paths>...\"),\n@@ -306,7 +287,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\t\tN_(\"reset HEAD but keep local changes\"), KEEP),\n \t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", NULL,\n \t\t\t    \"reset\", \"control recursive updating of submodules\",\n-\t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules },\n+\t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n \t\tOPT_BOOL('p', \"patch\", &patch_mode, N_(\"select hunks interactively\")),\n \t\tOPT_BOOL('N', \"intent-to-add\", &intent_to_add,\n \t\t\t\tN_(\"record only the fact that removed paths will be added later\")),\n@@ -319,11 +300,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\t\t\t\tPARSE_OPT_KEEP_DASHDASH);\n \tparse_args(&pathspec, argv, prefix, patch_mode, &rev);\n \n-\tif (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) {\n-\t\tgitmodules_config();\n-\t\tgit_config(submodule_config, NULL);\n-\t\tset_config_update_recurse_submodules(RECURSE_SUBMODULES_ON);\n-\t}\n+\tload_submodule_cache();\n \n \tunborn = !strcmp(rev, \"HEAD\") && get_sha1(\"HEAD\", oid.hash);\n \tif (unborn) {\ndiff --git a/submodule.c b/submodule.c\nindex 54825100b2..c9e764b519 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -18,7 +18,7 @@\n #include \"worktree.h\"\n \n static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n-static int config_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n+static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n static int parallel_jobs = 1;\n static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP;\n static int initialized_fetch_ref_tips;\n@@ -169,6 +169,32 @@ int submodule_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n+int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\n+\t\t\t\t\t\t     const char *arg, int unset)\n+{\n+\tif (unset) {\n+\t\tconfig_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n+\t\treturn 0;\n+\t}\n+\tif (arg)\n+\t\tconfig_update_recurse_submodules =\n+\t\t\tparse_update_recurse_submodules_arg(opt->long_name,\n+\t\t\t\t\t\t\t    arg);\n+\telse\n+\t\tconfig_update_recurse_submodules = RECURSE_SUBMODULES_ON;\n+\n+\treturn 0;\n+}\n+\n+void load_submodule_cache(void)\n+{\n+\tif (config_update_recurse_submodules == RECURSE_SUBMODULES_OFF)\n+\t\treturn;\n+\n+\tgitmodules_config();\n+\tgit_config(submodule_config, NULL);\n+}\n+\n void gitmodules_config(void)\n {\n \tconst char *work_tree = get_git_work_tree();\n@@ -596,11 +622,6 @@ void set_config_fetch_recurse_submodules(int value)\n \tconfig_fetch_recurse_submodules = value;\n }\n \n-void set_config_update_recurse_submodules(int value)\n-{\n-\tconfig_update_recurse_submodules = value;\n-}\n-\n int should_update_submodules(void)\n {\n \treturn config_update_recurse_submodules == RECURSE_SUBMODULES_ON;\ndiff --git a/submodule.h b/submodule.h\nindex 1277480add..b13f120f76 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -39,6 +39,11 @@ extern void stage_updated_gitmodules(void);\n extern void set_diffopt_flags_from_submodule_config(struct diff_options *,\n \t\tconst char *path);\n extern int submodule_config(const char *var, const char *value, void *cb);\n+\n+struct option;\n+int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\n+\t\t\t\t\t\t     const char *arg, int unset);\n+void load_submodule_cache(void);\n extern void gitmodules_config(void);\n extern void gitmodules_config_sha1(const unsigned char *commit_sha1);\n extern int is_submodule_initialized(const char *path);\n@@ -65,7 +70,6 @@ extern void show_submodule_inline_diff(FILE *f, const char *path,\n \t\tconst char *del, const char *add, const char *reset,\n \t\tconst struct diff_options *opt);\n extern void set_config_fetch_recurse_submodules(int value);\n-extern void set_config_update_recurse_submodules(int value);\n /* Check if we want to update any submodule.*/\n extern int should_update_submodules(void);\n /*\n-- \n2.13.0.17.g582985b1e4\n\n"},{"id":"320845","messageId":"20170526191017.19155-7-sbeller@google.com","threadId":"46052","inReplyTo":"20170526191017.19155-1-sbeller@google.com","subject":"[PATCH 6/8] builtin/grep.c: respect 'submodule.recurse' option","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-26T19:10:15Z","receivedAt":"2017-05-26T19:12:23Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"In builtin/grep.c we parse the config before evaluating the command line\noptions. This makes the task of teaching grep to respect the new config\noption 'submodule.recurse' very easy by just parsing that option.\n\nAs an alternative I had implemented a similar structure to treat\nsubmodules as the fetch/push command have, including\n* aligning the meaning of the 'recurse_submodules' to possible submodule\n  values RECURSE_SUBMODULES_* as defined in submodule.h.\n* having a callback to parse the value and\n* reacting to the RECURSE_SUBMODULES_DEFAULT state that was the initial\n  state.\n\nHowever all this is not needed for a true boolean value, so let's keep\nit simple. However this adds another place where \"submodule.recurse\" is\nparsed.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/grep.c                     |  3 +++\n t/t7814-grep-recurse-submodules.sh | 18 ++++++++++++++++++\n 2 files changed, 21 insertions(+)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex b1095362fb..454e263820 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -302,6 +302,9 @@ static int grep_cmd_config(const char *var, const char *value, void *cb)\n #endif\n \t}\n \n+\tif (!strcmp(var, \"submodule.recurse\"))\n+\t\trecurse_submodules = git_config_bool(var, value);\n+\n \treturn st;\n }\n \ndiff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh\nindex 3a58197f47..7184113b9b 100755\n--- a/t/t7814-grep-recurse-submodules.sh\n+++ b/t/t7814-grep-recurse-submodules.sh\n@@ -33,6 +33,24 @@ test_expect_success 'grep correctly finds patterns in a submodule' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'grep finds patterns in a submodule via config' '\n+\ttest_config submodule.recurse true &&\n+\t# expect from previous test\n+\tgit grep -e \"(3|4)\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'grep --no-recurse-submodules overrides config' '\n+\ttest_config submodule.recurse true &&\n+\tcat >expect <<-\\EOF &&\n+\ta:(1|2)d(3|4)\n+\tb/b:(3|4)\n+\tEOF\n+\n+\tgit grep -e \"(3|4)\" --no-recurse-submodules >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'grep and basic pathspecs' '\n \tcat >expect <<-\\EOF &&\n \tsubmodule/a:(1|2)d(3|4)\n-- \n2.13.0.17.g582985b1e4\n\n"},{"id":"320846","messageId":"20170526191017.19155-3-sbeller@google.com","threadId":"46052","inReplyTo":"20170526191017.19155-1-sbeller@google.com","subject":"[PATCH 2/8] submodule test invocation: only pass additional arguments","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-26T19:10:11Z","receivedAt":"2017-05-26T19:12:38Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"In a later patch we want to introduce a config option to trigger the\nsubmodule recursing by default. As this option should be available and\nuniform across all commands that deal with submodules we'd want to test\nfor this option in the submodule update library.\n\nSo instead of calling the whole test set again for\n\"git -c submodule.recurse foo\" instead of \"git foo --recurse-submodules\",\nwe'd only want to introduce one basic test that tests if the option is\nrecognized and respected to not overload the test suite.\n\nChange the test functions by taking only the argument and assemble the\ncommand inside the test function by embedding the arguments into the\ncommand that is \"git $arguments --recurse-submodules\".\n\nIt would be nice to do this for all functions in lib-submodule-update,\nbut we cannot do that for the non-recursing tests, as there we do not\njust pass in a git command but whole functions. (See t3426 for example)\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n t/lib-submodule-update.sh      | 10 ++++++----\n t/t1013-read-tree-submodule.sh |  4 ++--\n t/t2013-checkout-submodule.sh  |  4 ++--\n t/t7112-reset-submodule.sh     |  4 ++--\n 4 files changed, 12 insertions(+), 10 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex f0b1b18206..0272c4d8ca 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -781,8 +781,9 @@ test_submodule_forced_switch () {\n # - Removing a submodule with a git directory absorbs the submodules\n #   git directory first into the superproject.\n \n-test_submodule_switch_recursing () {\n-\tcommand=\"$1\"\n+test_submodule_switch_recursing_with_args () {\n+\tcmd_args=\"$1\"\n+\tcommand=\"git $cmd_args --recurse-submodules\"\n \tRESULTDS=success\n \tif test \"$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS\" = 1\n \tthen\n@@ -1021,8 +1022,9 @@ test_submodule_switch_recursing () {\n # Test that submodule contents are updated when switching between commits\n # that change a submodule, but throwing away local changes in\n # the superproject as well as the submodule is allowed.\n-test_submodule_forced_switch_recursing () {\n-\tcommand=\"$1\"\n+test_submodule_forced_switch_recursing_with_args () {\n+\tcmd_args=\"$1\"\n+\tcommand=\"git $cmd_args --recurse-submodules\"\n \tRESULT=success\n \tif test \"$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS\" = 1\n \tthen\ndiff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh\nindex de1ba02dc5..2c8d620324 100755\n--- a/t/t1013-read-tree-submodule.sh\n+++ b/t/t1013-read-tree-submodule.sh\n@@ -9,9 +9,9 @@ KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1\n KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1\n KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1\n \n-test_submodule_switch_recursing \"git read-tree --recurse-submodules -u -m\"\n+test_submodule_switch_recursing_with_args \"read-tree -u -m\"\n \n-test_submodule_forced_switch_recursing \"git read-tree --recurse-submodules -u --reset\"\n+test_submodule_forced_switch_recursing_with_args \"read-tree -u --reset\"\n \n test_submodule_switch \"git read-tree -u -m\"\n \ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex e8f70b806f..c962a02277 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -65,9 +65,9 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .git/\n \n KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1\n KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1\n-test_submodule_switch_recursing \"git checkout --recurse-submodules\"\n+test_submodule_switch_recursing_with_args \"checkout\"\n \n-test_submodule_forced_switch_recursing \"git checkout -f --recurse-submodules\"\n+test_submodule_forced_switch_recursing_with_args \"checkout -f\"\n \n test_submodule_switch \"git checkout\"\n \ndiff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh\nindex f86ccdf215..a1cb9ff858 100755\n--- a/t/t7112-reset-submodule.sh\n+++ b/t/t7112-reset-submodule.sh\n@@ -9,9 +9,9 @@ KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1\n KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1\n KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1\n \n-test_submodule_switch_recursing \"git reset --recurse-submodules --keep\"\n+test_submodule_switch_recursing_with_args \"reset --keep\"\n \n-test_submodule_forced_switch_recursing \"git reset --hard --recurse-submodules\"\n+test_submodule_forced_switch_recursing_with_args \"reset --hard\"\n \n test_submodule_switch \"git reset --keep\"\n \n-- \n2.13.0.17.g582985b1e4\n\n"},{"id":"320847","messageId":"20170526191017.19155-8-sbeller@google.com","threadId":"46052","inReplyTo":"20170526191017.19155-1-sbeller@google.com","subject":"[PATCH 7/8] builtin/push.c: respect 'submodule.recurse' option","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-05-26T19:10:16Z","receivedAt":"2017-05-26T19:12:52Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"The closest mapping from the boolean 'submodule.recurse' set to \"yes\"\nto the variety of submodule push modes is \"on-demand\", so implement that.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/push.c                 |  4 ++++\n t/t5531-deep-submodule-push.sh | 21 +++++++++++++++++++++\n 2 files changed, 25 insertions(+)\n\ndiff --git a/builtin/push.c b/builtin/push.c\nindex a597759d8f..258648d5fd 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -498,6 +498,10 @@ static int git_push_config(const char *k, const char *v, void *cb)\n \t\tconst char *value;\n \t\tif (!git_config_get_value(\"push.recursesubmodules\", &value))\n \t\t\trecurse_submodules = parse_push_recurse_submodules_arg(k, value);\n+\t} else if (!strcmp(k, \"submodule.recurse\")) {\n+\t\tint val = git_config_bool(k, v) ?\n+\t\t\tRECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;\n+\t\trecurse_submodules = val;\n \t}\n \n \treturn git_default_config(k, v, NULL);\ndiff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh\nindex 57ba322628..712c595fd8 100755\n--- a/t/t5531-deep-submodule-push.sh\n+++ b/t/t5531-deep-submodule-push.sh\n@@ -126,6 +126,27 @@ test_expect_success 'push succeeds if submodule commit not on remote but using o\n \t)\n '\n \n+test_expect_success 'push succeeds if submodule commit not on remote but using auto-on-demand via submodule.recurse config' '\n+\t(\n+\t\tcd work/gar/bage &&\n+\t\t>recurse-on-demand-from-submodule-recurse-config &&\n+\t\tgit add recurse-on-demand-from-submodule-recurse-config &&\n+\t\tgit commit -m \"Recurse submodule.recurse from config junk\"\n+\t) &&\n+\t(\n+\t\tcd work &&\n+\t\tgit add gar/bage &&\n+\t\tgit commit -m \"Recurse submodule.recurse from config for gar/bage\" &&\n+\t\tgit -c submodule.recurse push ../pub.git master &&\n+\t\t# Check that the supermodule commit got there\n+\t\tgit fetch ../pub.git &&\n+\t\tgit diff --quiet FETCH_HEAD master &&\n+\t\t# Check that the submodule commit got there too\n+\t\tcd gar/bage &&\n+\t\tgit diff --quiet origin/master master\n+\t)\n+'\n+\n test_expect_success 'push recurse-submodules on command line overrides config' '\n \t(\n \t\tcd work/gar/bage &&\n-- \n2.13.0.17.g582985b1e4\n\n"},{"id":"320998","messageId":"xmqqa85udi92.fsf@gitster.mtv.corp.google.com","threadId":"46052","inReplyTo":"20170526191017.19155-1-sbeller@google.com","subject":"Re: [PATCHv2 0/8] A reroll of sb/submodule-blanket-recursive","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-05-30T05:30:01Z","receivedAt":"2017-05-30T05:30:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n> v2:\n> * A reroll of sb/submodule-blanket-recursive.\n> * This requires ab/grep-preparatory-cleanup \n\n2/8 seems to be more stale than sb/checkout-recurse-submodules that\nwas merged at f1101cef to 'master'.  I'll try to merge Ævar's series\nto 'master' before that merge, queue these patches and see if the\nresulting history is too messy.\n\nThanks.\n"},{"id":"321228","messageId":"20170601003050.4221-1-sbeller@google.com","threadId":"46052","inReplyTo":"xmqqa85udi92.fsf@gitster.mtv.corp.google.com","subject":"[PATCHv3 0/4] A reroll of sb/submodule-blanket-recursive","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T00:30:46Z","receivedAt":"2017-06-01T00:31:01Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"v3:\n* rerolling only the top-4 patches of sb/submodule-blanket-recursive.\n  (base: 1d789d089280539ca39b83aabb67860929d39b75)\n* fixes function declarations that should be static, thanks Ramsay!\n\nv2:\n* A reroll of sb/submodule-blanket-recursive.\n* This requires ab/grep-preparatory-cleanup\n* It changed a lot from v1, as in v1 the tests did not work,\n  hence the code was broken. Now it actually works.\n* it also includes grep, fetch, push in addition to plain working tree\n  manipulators.\n\nThanks,\nStefan\n\nStefan Beller (4):\n  Introduce 'submodule.recurse' option for worktree manipulators\n  builtin/grep.c: respect 'submodule.recurse' option\n  builtin/push.c: respect 'submodule.recurse' option\n  builtin/fetch.c: respect 'submodule.recurse' option\n\n Documentation/config.txt           |  5 +++++\n builtin/checkout.c                 |  2 +-\n builtin/fetch.c                    |  7 +++++++\n builtin/grep.c                     |  3 +++\n builtin/push.c                     |  4 ++++\n builtin/read-tree.c                | 10 +++++++++-\n builtin/reset.c                    | 10 +++++++++-\n submodule.c                        | 23 +++++++++++++++++++++--\n submodule.h                        |  1 +\n t/lib-submodule-update.sh          | 12 ++++++++++++\n t/t5526-fetch-submodules.sh        | 10 ++++++++++\n t/t5531-deep-submodule-push.sh     | 21 +++++++++++++++++++++\n t/t7814-grep-recurse-submodules.sh | 18 ++++++++++++++++++\n 13 files changed, 121 insertions(+), 5 deletions(-)\n\n-- \n2.13.0.17.gab62347cd9\n\n"},{"id":"321229","messageId":"20170601003050.4221-2-sbeller@google.com","threadId":"46052","inReplyTo":"20170601003050.4221-1-sbeller@google.com","subject":"[PATCHv3 1/4] Introduce 'submodule.recurse' option for worktree manipulators","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T00:30:47Z","receivedAt":"2017-06-01T00:31:04Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Any command that understands '--recurse-submodules' can have its\ndefault changed to true, by setting the new 'submodule.recurse'\noption.\n\nThis patch includes read-tree/checkout/reset for working tree\nmanipulating commands. Later patches will cover other commands.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/config.txt  |  5 +++++\n builtin/checkout.c        |  2 +-\n builtin/read-tree.c       | 10 +++++++++-\n builtin/reset.c           | 10 +++++++++-\n submodule.c               | 23 +++++++++++++++++++++--\n submodule.h               |  1 +\n t/lib-submodule-update.sh | 12 ++++++++++++\n 7 files changed, 58 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex e0b9fd0bc3..f60c504e86 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -3065,6 +3065,11 @@ submodule.active::\n \tsubmodule's path to determine if the submodule is of interest to git\n \tcommands.\n \n+submodule.recurse::\n+\tSpecifies if commands recurse into submodules by default. This\n+\tapplies to all commands that have a `--recurse-submodules` option.\n+\tDefaults to false.\n+\n submodule.fetchJobs::\n \tSpecifies how many submodules are fetched/cloned at the same time.\n \tA positive integer allows up to that number of submodules fetched\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 56ea723b75..e289b7d477 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -855,7 +855,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb)\n \t}\n \n \tif (starts_with(var, \"submodule.\"))\n-\t\treturn parse_submodule_config_option(var, value);\n+\t\treturn submodule_config(var, value, NULL);\n \n \treturn git_xmerge_config(var, value, NULL);\n }\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex 8a889ef4c3..7fd55140db 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -98,6 +98,14 @@ static int debug_merge(const struct cache_entry * const *stages,\n \treturn 0;\n }\n \n+static int git_read_tree_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"submodule.recurse\"))\n+\t\treturn git_default_submodule_config(var, value, cb);\n+\n+\treturn git_default_config(var, value, cb);\n+}\n+\n static struct lock_file lock_file;\n \n int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n@@ -150,7 +158,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \topts.src_index = &the_index;\n \topts.dst_index = &the_index;\n \n-\tgit_config(git_default_config, NULL);\n+\tgit_config(git_read_tree_config, NULL);\n \n \targc = parse_options(argc, argv, unused_prefix, read_tree_options,\n \t\t\t     read_tree_usage, 0);\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 6f89dc5494..585cfe0745 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -266,6 +266,14 @@ static int reset_refs(const char *rev, const struct object_id *oid)\n \treturn update_ref_status;\n }\n \n+static int git_reset_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"submodule.recurse\"))\n+\t\treturn git_default_submodule_config(var, value, cb);\n+\n+\treturn git_default_config(var, value, cb);\n+}\n+\n int cmd_reset(int argc, const char **argv, const char *prefix)\n {\n \tint reset_type = NONE, update_ref_status = 0, quiet = 0;\n@@ -294,7 +302,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\tgit_config(git_default_config, NULL);\n+\tgit_config(git_reset_config, NULL);\n \n \targc = parse_options(argc, argv, prefix, options, git_reset_usage,\n \t\t\t\t\t\tPARSE_OPT_KEEP_DASHDASH);\ndiff --git a/submodule.c b/submodule.c\nindex 78cccb7563..2b157dc995 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -16,6 +16,7 @@\n #include \"quote.h\"\n #include \"remote.h\"\n #include \"worktree.h\"\n+#include \"parse-options.h\"\n \n static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n@@ -170,10 +171,28 @@ static int git_modules_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/* Loads all submodule settings from the config */\n+/* Loads all submodule settings from the config. */\n int submodule_config(const char *var, const char *value, void *cb)\n {\n-\treturn git_modules_config(var, value, cb);\n+\tif (!strcmp(var, \"submodule.recurse\")) {\n+\t\tint v = git_config_bool(var, value) ?\n+\t\t\tRECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;\n+\t\tconfig_update_recurse_submodules = v;\n+\t\treturn 0;\n+\t} else {\n+\t\treturn git_modules_config(var, value, cb);\n+\t}\n+}\n+\n+/* Cheap function that only determines if we're interested in submodules at all */\n+int git_default_submodule_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"submodule.recurse\")) {\n+\t\tint v = git_config_bool(var, value) ?\n+\t\t\tRECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;\n+\t\tconfig_update_recurse_submodules = v;\n+\t}\n+\treturn 0;\n }\n \n int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\ndiff --git a/submodule.h b/submodule.h\nindex b13f120f76..d920ca1d5a 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -39,6 +39,7 @@ extern void stage_updated_gitmodules(void);\n extern void set_diffopt_flags_from_submodule_config(struct diff_options *,\n \t\tconst char *path);\n extern int submodule_config(const char *var, const char *value, void *cb);\n+extern int git_default_submodule_config(const char *var, const char *value, void *cb);\n \n struct option;\n int option_parse_recurse_submodules_worktree_updater(const struct option *opt,\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 0272c4d8ca..52beadad96 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -990,6 +990,18 @@ test_submodule_switch_recursing_with_args () {\n \t\t)\n \t'\n \n+\ttest_expect_success \"git -c submodule.recurse=true $cmd_args: modified submodule updates submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to_interested add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\tgit -c submodule.recurse=true $cmd_args modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\n \t# Updating a submodule to an invalid sha1 doesn't update the\n \t# superproject nor the submodule's work tree.\n \ttest_expect_success \"$command: updating to a missing submodule commit fails\" '\n-- \n2.13.0.17.gab62347cd9\n\n"},{"id":"321230","messageId":"20170601003050.4221-4-sbeller@google.com","threadId":"46052","inReplyTo":"20170601003050.4221-1-sbeller@google.com","subject":"[PATCHv3 3/4] builtin/push.c: respect 'submodule.recurse' option","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T00:30:49Z","receivedAt":"2017-06-01T00:31:06Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"The closest mapping from the boolean 'submodule.recurse' set to \"yes\"\nto the variety of submodule push modes is \"on-demand\", so implement that.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/push.c                 |  4 ++++\n t/t5531-deep-submodule-push.sh | 21 +++++++++++++++++++++\n 2 files changed, 25 insertions(+)\n\ndiff --git a/builtin/push.c b/builtin/push.c\nindex a597759d8f..258648d5fd 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -498,6 +498,10 @@ static int git_push_config(const char *k, const char *v, void *cb)\n \t\tconst char *value;\n \t\tif (!git_config_get_value(\"push.recursesubmodules\", &value))\n \t\t\trecurse_submodules = parse_push_recurse_submodules_arg(k, value);\n+\t} else if (!strcmp(k, \"submodule.recurse\")) {\n+\t\tint val = git_config_bool(k, v) ?\n+\t\t\tRECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;\n+\t\trecurse_submodules = val;\n \t}\n \n \treturn git_default_config(k, v, NULL);\ndiff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh\nindex 57ba322628..712c595fd8 100755\n--- a/t/t5531-deep-submodule-push.sh\n+++ b/t/t5531-deep-submodule-push.sh\n@@ -126,6 +126,27 @@ test_expect_success 'push succeeds if submodule commit not on remote but using o\n \t)\n '\n \n+test_expect_success 'push succeeds if submodule commit not on remote but using auto-on-demand via submodule.recurse config' '\n+\t(\n+\t\tcd work/gar/bage &&\n+\t\t>recurse-on-demand-from-submodule-recurse-config &&\n+\t\tgit add recurse-on-demand-from-submodule-recurse-config &&\n+\t\tgit commit -m \"Recurse submodule.recurse from config junk\"\n+\t) &&\n+\t(\n+\t\tcd work &&\n+\t\tgit add gar/bage &&\n+\t\tgit commit -m \"Recurse submodule.recurse from config for gar/bage\" &&\n+\t\tgit -c submodule.recurse push ../pub.git master &&\n+\t\t# Check that the supermodule commit got there\n+\t\tgit fetch ../pub.git &&\n+\t\tgit diff --quiet FETCH_HEAD master &&\n+\t\t# Check that the submodule commit got there too\n+\t\tcd gar/bage &&\n+\t\tgit diff --quiet origin/master master\n+\t)\n+'\n+\n test_expect_success 'push recurse-submodules on command line overrides config' '\n \t(\n \t\tcd work/gar/bage &&\n-- \n2.13.0.17.gab62347cd9\n\n"},{"id":"321231","messageId":"20170601003050.4221-3-sbeller@google.com","threadId":"46052","inReplyTo":"20170601003050.4221-1-sbeller@google.com","subject":"[PATCHv3 2/4] builtin/grep.c: respect 'submodule.recurse' option","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T00:30:48Z","receivedAt":"2017-06-01T00:31:16Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"In builtin/grep.c we parse the config before evaluating the command line\noptions. This makes the task of teaching grep to respect the new config\noption 'submodule.recurse' very easy by just parsing that option.\n\nAs an alternative I had implemented a similar structure to treat\nsubmodules as the fetch/push command have, including\n* aligning the meaning of the 'recurse_submodules' to possible submodule\n  values RECURSE_SUBMODULES_* as defined in submodule.h.\n* having a callback to parse the value and\n* reacting to the RECURSE_SUBMODULES_DEFAULT state that was the initial\n  state.\n\nHowever all this is not needed for a true boolean value, so let's keep\nit simple. However this adds another place where \"submodule.recurse\" is\nparsed.\n\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/grep.c                     |  3 +++\n t/t7814-grep-recurse-submodules.sh | 18 ++++++++++++++++++\n 2 files changed, 21 insertions(+)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex b1095362fb..454e263820 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -302,6 +302,9 @@ static int grep_cmd_config(const char *var, const char *value, void *cb)\n #endif\n \t}\n \n+\tif (!strcmp(var, \"submodule.recurse\"))\n+\t\trecurse_submodules = git_config_bool(var, value);\n+\n \treturn st;\n }\n \ndiff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh\nindex 3a58197f47..7184113b9b 100755\n--- a/t/t7814-grep-recurse-submodules.sh\n+++ b/t/t7814-grep-recurse-submodules.sh\n@@ -33,6 +33,24 @@ test_expect_success 'grep correctly finds patterns in a submodule' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'grep finds patterns in a submodule via config' '\n+\ttest_config submodule.recurse true &&\n+\t# expect from previous test\n+\tgit grep -e \"(3|4)\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'grep --no-recurse-submodules overrides config' '\n+\ttest_config submodule.recurse true &&\n+\tcat >expect <<-\\EOF &&\n+\ta:(1|2)d(3|4)\n+\tb/b:(3|4)\n+\tEOF\n+\n+\tgit grep -e \"(3|4)\" --no-recurse-submodules >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'grep and basic pathspecs' '\n \tcat >expect <<-\\EOF &&\n \tsubmodule/a:(1|2)d(3|4)\n-- \n2.13.0.17.gab62347cd9\n\n"},{"id":"321232","messageId":"20170601003050.4221-5-sbeller@google.com","threadId":"46052","inReplyTo":"20170601003050.4221-1-sbeller@google.com","subject":"[PATCHv3 4/4] builtin/fetch.c: respect 'submodule.recurse' option","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-01T00:30:50Z","receivedAt":"2017-06-01T00:31:23Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Signed-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/fetch.c             |  7 +++++++\n t/t5526-fetch-submodules.sh | 10 ++++++++++\n 2 files changed, 17 insertions(+)\n\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 5f2c2ab23e..c1ec3b03c3 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -73,6 +73,13 @@ static int git_fetch_config(const char *k, const char *v, void *cb)\n \t\tfetch_prune_config = git_config_bool(k, v);\n \t\treturn 0;\n \t}\n+\n+\tif (!strcmp(k, \"submodule.recurse\")) {\n+\t\tint r = git_config_bool(k, v) ?\n+\t\t\tRECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;\n+\t\trecurse_submodules = r;\n+\t}\n+\n \treturn git_default_config(k, v, cb);\n }\n \ndiff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh\nindex f3b0a8d30a..162baf101f 100755\n--- a/t/t5526-fetch-submodules.sh\n+++ b/t/t5526-fetch-submodules.sh\n@@ -71,6 +71,16 @@ test_expect_success \"fetch --recurse-submodules recurses into submodules\" '\n \ttest_i18ncmp expect.err actual.err\n '\n \n+test_expect_success \"submodule.recurse option triggers recursive fetch\" '\n+\tadd_upstream_commit &&\n+\t(\n+\t\tcd downstream &&\n+\t\tgit -c submodule.recurse fetch >../actual.out 2>../actual.err\n+\t) &&\n+\ttest_must_be_empty actual.out &&\n+\ttest_i18ncmp expect.err actual.err\n+'\n+\n test_expect_success \"fetch --recurse-submodules -j2 has the same output behaviour\" '\n \tadd_upstream_commit &&\n \t(\n-- \n2.13.0.17.gab62347cd9\n\n"}]}