]> git.ipfire.org Git - thirdparty/git.git/commitdiff
pull: do not let submodule.recurse override fetch.recurseSubmodules
authorGlen Choo <chooglen@google.com>
Tue, 10 May 2022 19:25:47 +0000 (19:25 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 11 May 2022 22:42:30 +0000 (15:42 -0700)
Fix a bug in "git pull" where `submodule.recurse` is preferred over
`fetch.recurseSubmodules` when performing a fetch
(Documentation/config/fetch.txt says that `fetch.recurseSubmodules`
should be preferred.). Do this by passing the value of the
"--recurse-submodules" CLI option to the underlying fetch, instead of
passing a value that combines the CLI option and config variables.

In other words, this bug occurred because builtin/pull.c is conflating
two similar-sounding, but different concepts:

- Whether "git pull" itself should care about submodules e.g. whether it
  should update the submodule worktrees after performing a merge.
- The value of "--recurse-submodules" to pass to the underlying "git
  fetch".

Thus, when `submodule.recurse` is set, the underlying "git fetch" gets
invoked with "--recurse-submodules[=value]", overriding the value of
`fetch.recurseSubmodules`.

An alternative (and more obvious) approach to fix the bug would be to
teach "git pull" to understand `fetch.recurseSubmodules`, but the
proposed solution works better because:

- We don't maintain two identical config-parsing implementions in "git
  pull" and "git fetch".
- It works better with other commands invoked by "git pull" e.g. "git
  merge" won't accidentally respect `fetch.recurseSubmodules`.

Reported-by: Huang Zou <huang.zou@schrodinger.com>
Helped-by: Philippe Blain <levraiphilippeblain@gmail.com>
Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/pull.c
t/t5572-pull-submodule.sh

index aa56ebcdd0dce08f61fcaa5d1762d4efb8876adc..de266db09d5d314cb6309f7947605ab09df269d9 100644 (file)
@@ -72,6 +72,7 @@ static const char * const pull_usage[] = {
 static int opt_verbosity;
 static char *opt_progress;
 static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
 
 /* Options passed to git-merge or git-rebase */
 static enum rebase_type opt_rebase = -1;
@@ -119,7 +120,7 @@ static struct option pull_options[] = {
                N_("force progress reporting"),
                PARSE_OPT_NOARG),
        OPT_CALLBACK_F(0, "recurse-submodules",
-                  &recurse_submodules, N_("on-demand"),
+                  &recurse_submodules_cli, N_("on-demand"),
                   N_("control for recursive fetching of submodules"),
                   PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
 
@@ -545,8 +546,8 @@ static int run_fetch(const char *repo, const char **refspecs)
                strvec_push(&args, opt_tags);
        if (opt_prune)
                strvec_push(&args, opt_prune);
-       if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)
-               switch (recurse_submodules) {
+       if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
+               switch (recurse_submodules_cli) {
                case RECURSE_SUBMODULES_ON:
                        strvec_push(&args, "--recurse-submodules=on");
                        break;
@@ -939,6 +940,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
        argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
 
+       if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
+               recurse_submodules = recurse_submodules_cli;
+
        if (cleanup_arg)
                /*
                 * this only checks the validity of cleanup_arg; we don't need
index 37fd06b0be8f488889554696fceb7d0be615f89f..c415278da928f20c85c5e04f31761f4cedf8ec02 100755 (executable)
@@ -101,6 +101,32 @@ test_expect_success " --[no-]recurse-submodule and submodule.recurse" '
        test_path_is_file super/sub/merge_strategy_4.t
 '
 
+test_expect_success "fetch.recurseSubmodules option triggers recursive fetch (but not recursive update)" '
+       test_commit -C child merge_strategy_5 &&
+       # Omit the parent commit, otherwise this passes with the
+       # default "pull" behavior.
+
+       git -C super -c fetch.recursesubmodules=true pull --no-rebase &&
+       # Check that the submodule commit was fetched
+       sub_oid=$(git -C child rev-parse HEAD) &&
+       git -C super/sub cat-file -e $sub_oid &&
+       # Check that the submodule worktree did not update
+       ! test_path_is_file super/sub/merge_strategy_5.t
+'
+
+test_expect_success "fetch.recurseSubmodules takes precedence over submodule.recurse" '
+       test_commit -C child merge_strategy_6 &&
+       # Omit the parent commit, otherwise this passes with the
+       # default "pull" behavior.
+
+       git -C super -c submodule.recurse=false -c fetch.recursesubmodules=true pull --no-rebase &&
+       # Check that the submodule commit was fetched
+       sub_oid=$(git -C child rev-parse HEAD) &&
+       git -C super/sub cat-file -e $sub_oid &&
+       # Check that the submodule worktree did not update
+       ! test_path_is_file super/sub/merge_strategy_6.t
+'
+
 test_expect_success 'pull --rebase --recurse-submodules (remote superproject submodule changes, local submodule changes)' '
        # This tests the following scenario :
        # - local submodule has new commits