builtin/checkout: add --recurse-submodules switch

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>

Stefan Beller committed Mar 14, 2017 at 14:46 UTC 1fc458d958be0e8347d7704933ae647afeabcd91
4 files changed +62 -5
Documentation/git-checkout.txt
+7
@@ -256,6 +256,13 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
256 out anyway. In other words, the ref can be held by more than one
257 worktree.
258
259 +--[no-]recurse-submodules::
260 + Using --recurse-submodules will update the content of all initialized
261 + submodules according to the commit recorded in the superproject. If
262 + local modifications in a submodule would be overwritten the checkout
263 + will fail unless `-f` is used. If nothing (or --no-recurse-submodules)
264 + is used, the work trees of submodules will not be updated.
265 +
266 <branch>::
267 Branch to checkout; if it refers to a branch (i.e., a name that,
268 when prepended with "refs/heads/", is a valid ref), then that
builtin/checkout.c
+28
@@ -21,12 +21,31 @@
21 #include "submodule-config.h"
22 #include "submodule.h"
23
24 +static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
25 +
26 static const char * const checkout_usage[] = {
27 N_("git checkout [<options>] <branch>"),
28 N_("git checkout [<options>] [<branch>] -- <file>..."),
29 NULL,
30 };
31
32 +static int option_parse_recurse_submodules(const struct option *opt,
33 + const char *arg, int unset)
34 +{
35 + if (unset) {
36 + recurse_submodules = RECURSE_SUBMODULES_OFF;
37 + return 0;
38 + }
39 + if (arg)
40 + recurse_submodules =
41 + parse_update_recurse_submodules_arg(opt->long_name,
42 + arg);
43 + else
44 + recurse_submodules = RECURSE_SUBMODULES_ON;
45 +
46 + return 0;
47 +}
48 +
49 struct checkout_opts {
50 int patch_mode;
51 int quiet;
@@ -1163,6 +1182,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
1182 N_("second guess 'git checkout <no-such-branch>'")),
1183 OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
1184 N_("do not check if another worktree is holding the given ref")),
1185 + { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
1186 + "checkout", "control recursive updating of submodules",
1187 + PARSE_OPT_OPTARG, option_parse_recurse_submodules },
1188 OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")),
1189 OPT_END(),
1190 };
@@ -1193,6 +1215,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
1215 git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
1216 }
1217
1218 + if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
1219 + git_config(submodule_config, NULL);
1220 + if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)
1221 + set_config_update_recurse_submodules(recurse_submodules);
1222 + }
1223 +
1224 if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
1225 die(_("-b, -B and --orphan are mutually exclusive"));
1226
t/lib-submodule-update.sh
+21 -5
@@ -782,6 +782,16 @@ test_submodule_forced_switch () {
782
783 test_submodule_switch_recursing () {
784 command="$1"
785 + RESULTDS=success
786 + if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
787 + then
788 + RESULTDS=failure
789 + fi
790 + RESULTR=success
791 + if test "$KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED" = 1
792 + then
793 + RESULTR=failure
794 + fi
795 ######################### Appearing submodule #########################
796 # Switching to a commit letting a submodule appear checks it out ...
797 test_expect_success "$command: added submodule is checked out" '
@@ -891,7 +901,7 @@ test_submodule_switch_recursing () {
901 '
902 # Replacing a submodule with files in a directory must succeeds
903 # when the submodule is clean
894 - test_expect_success "$command: replace submodule with a directory" '
904 + test_expect_$RESULTDS "$command: replace submodule with a directory" '
905 prolog &&
906 reset_work_tree_to_interested add_sub1 &&
907 (
@@ -903,7 +913,7 @@ test_submodule_switch_recursing () {
913 )
914 '
915 # ... absorbing a .git directory.
906 - test_expect_success "$command: replace submodule containing a .git directory with a directory must absorb the git dir" '
916 + test_expect_$RESULTDS "$command: replace submodule containing a .git directory with a directory must absorb the git dir" '
917 prolog &&
918 reset_work_tree_to_interested add_sub1 &&
919 (
@@ -931,7 +941,7 @@ test_submodule_switch_recursing () {
941 '
942
943 # ... must check its local work tree for untracked files
934 - test_expect_success "$command: replace submodule with a file must fail with untracked files" '
944 + test_expect_$RESULTDS "$command: replace submodule with a file must fail with untracked files" '
945 prolog &&
946 reset_work_tree_to_interested add_sub1 &&
947 (
@@ -987,7 +997,8 @@ test_submodule_switch_recursing () {
997 )
998 '
999
990 - test_expect_success "$command: modified submodule updates submodule recursively" '
1000 + # recursing deeper than one level doesn't work yet.
1001 + test_expect_$RESULTR "$command: modified submodule updates submodule recursively" '
1002 prolog &&
1003 reset_work_tree_to_interested add_nested_sub &&
1004 (
@@ -1006,6 +1017,11 @@ test_submodule_switch_recursing () {
1017 # the superproject as well as the submodule is allowed.
1018 test_submodule_forced_switch_recursing () {
1019 command="$1"
1020 + RESULT=success
1021 + if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
1022 + then
1023 + RESULT=failure
1024 + fi
1025 ######################### Appearing submodule #########################
1026 # Switching to a commit letting a submodule appear creates empty dir ...
1027 test_expect_success "$command: added submodule is checked out" '
@@ -1151,7 +1167,7 @@ test_submodule_forced_switch_recursing () {
1167 '
1168
1169 # ... but stops for untracked files that would be lost
1154 - test_expect_success "$command: replace submodule with a file" '
1170 + test_expect_$RESULT "$command: replace submodule with a file stops for untracked files" '
1171 prolog &&
1172 reset_work_tree_to_interested add_sub1 &&
1173 (
t/t2013-checkout-submodule.sh
+6
@@ -63,6 +63,12 @@ test_expect_success '"checkout <submodule>" honors submodule.*.ignore from .git/
63 ! test -s actual
64 '
65
66 +KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
67 +KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1
68 +test_submodule_switch_recursing "git checkout --recurse-submodules"
69 +
70 +test_submodule_forced_switch_recursing "git checkout -f --recurse-submodules"
71 +
72 test_submodule_switch "git checkout"
73
74 test_submodule_forced_switch "git checkout -f"