OSDN Git Service

builtin/checkout: add --recurse-submodules switch
authorStefan Beller <sbeller@google.com>
Tue, 14 Mar 2017 21:46:41 +0000 (14:46 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 16 Mar 2017 21:07:16 +0000 (14:07 -0700)
This exposes a flag to recurse into submodules
in builtin/checkout making use of the code implemented
in prior patches.

A new failure mode is introduced in the submodule
update library, as the directory/submodule conflict
is not solved in prior patches.

Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-checkout.txt
builtin/checkout.c
t/lib-submodule-update.sh
t/t2013-checkout-submodule.sh

index 8e2c066..d6399c0 100644 (file)
@@ -256,6 +256,13 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
        out anyway. In other words, the ref can be held by more than one
        worktree.
 
+--[no-]recurse-submodules::
+       Using --recurse-submodules will update the content of all initialized
+       submodules according to the commit recorded in the superproject. If
+       local modifications in a submodule would be overwritten the checkout
+       will fail unless `-f` is used. If nothing (or --no-recurse-submodules)
+       is used, the work trees of submodules will not be updated.
+
 <branch>::
        Branch to checkout; if it refers to a branch (i.e., a name that,
        when prepended with "refs/heads/", is a valid ref), then that
index f174f50..e9c5fcf 100644 (file)
 #include "submodule-config.h"
 #include "submodule.h"
 
+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+
 static const char * const checkout_usage[] = {
        N_("git checkout [<options>] <branch>"),
        N_("git checkout [<options>] [<branch>] -- <file>..."),
        NULL,
 };
 
+static int option_parse_recurse_submodules(const struct option *opt,
+                                          const char *arg, int unset)
+{
+       if (unset) {
+               recurse_submodules = RECURSE_SUBMODULES_OFF;
+               return 0;
+       }
+       if (arg)
+               recurse_submodules =
+                       parse_update_recurse_submodules_arg(opt->long_name,
+                                                           arg);
+       else
+               recurse_submodules = RECURSE_SUBMODULES_ON;
+
+       return 0;
+}
+
 struct checkout_opts {
        int patch_mode;
        int quiet;
@@ -1163,6 +1182,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                                N_("second guess 'git checkout <no-such-branch>'")),
                OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
                         N_("do not check if another worktree is holding the given ref")),
+               { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
+                           "checkout", "control recursive updating of submodules",
+                           PARSE_OPT_OPTARG, option_parse_recurse_submodules },
                OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")),
                OPT_END(),
        };
@@ -1193,6 +1215,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
        }
 
+       if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
+               git_config(submodule_config, NULL);
+               if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)
+                       set_config_update_recurse_submodules(recurse_submodules);
+       }
+
        if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
                die(_("-b, -B and --orphan are mutually exclusive"));
 
index ae560dc..4e775a3 100755 (executable)
@@ -782,6 +782,16 @@ test_submodule_forced_switch () {
 
 test_submodule_switch_recursing () {
        command="$1"
+       RESULTDS=success
+       if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
+       then
+               RESULTDS=failure
+       fi
+       RESULTR=success
+       if test "$KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED" = 1
+       then
+               RESULTR=failure
+       fi
        ######################### Appearing submodule #########################
        # Switching to a commit letting a submodule appear checks it out ...
        test_expect_success "$command: added submodule is checked out" '
@@ -891,7 +901,7 @@ test_submodule_switch_recursing () {
        '
        # Replacing a submodule with files in a directory must succeeds
        # when the submodule is clean
-       test_expect_success "$command: replace submodule with a directory" '
+       test_expect_$RESULTDS "$command: replace submodule with a directory" '
                prolog &&
                reset_work_tree_to_interested add_sub1 &&
                (
@@ -903,7 +913,7 @@ test_submodule_switch_recursing () {
                )
        '
        # ... absorbing a .git directory.
-       test_expect_success "$command: replace submodule containing a .git directory with a directory must absorb the git dir" '
+       test_expect_$RESULTDS "$command: replace submodule containing a .git directory with a directory must absorb the git dir" '
                prolog &&
                reset_work_tree_to_interested add_sub1 &&
                (
@@ -931,7 +941,7 @@ test_submodule_switch_recursing () {
        '
 
        # ... must check its local work tree for untracked files
-       test_expect_success "$command: replace submodule with a file must fail with untracked files" '
+       test_expect_$RESULTDS "$command: replace submodule with a file must fail with untracked files" '
                prolog &&
                reset_work_tree_to_interested add_sub1 &&
                (
@@ -987,7 +997,8 @@ test_submodule_switch_recursing () {
                )
        '
 
-       test_expect_success "$command: modified submodule updates submodule recursively" '
+       # recursing deeper than one level doesn't work yet.
+       test_expect_$RESULTR "$command: modified submodule updates submodule recursively" '
                prolog &&
                reset_work_tree_to_interested add_nested_sub &&
                (
@@ -1006,6 +1017,11 @@ test_submodule_switch_recursing () {
 # the superproject as well as the submodule is allowed.
 test_submodule_forced_switch_recursing () {
        command="$1"
+       RESULT=success
+       if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
+       then
+               RESULT=failure
+       fi
        ######################### Appearing submodule #########################
        # Switching to a commit letting a submodule appear creates empty dir ...
        test_expect_success "$command: added submodule is checked out" '
@@ -1151,7 +1167,7 @@ test_submodule_forced_switch_recursing () {
        '
 
        # ... but stops for untracked files that would be lost
-       test_expect_success "$command: replace submodule with a file" '
+       test_expect_$RESULT "$command: replace submodule with a file stops for untracked files" '
                prolog &&
                reset_work_tree_to_interested add_sub1 &&
                (
index 6847f75..e8f70b8 100755 (executable)
@@ -63,6 +63,12 @@ test_expect_success '"checkout <submodule>" honors submodule.*.ignore from .git/
        ! test -s actual
 '
 
+KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
+KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1
+test_submodule_switch_recursing "git checkout --recurse-submodules"
+
+test_submodule_forced_switch_recursing "git checkout -f --recurse-submodules"
+
 test_submodule_switch "git checkout"
 
 test_submodule_forced_switch "git checkout -f"