Skip to content

Commit 1fc458d

Browse files
stefanbellergitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6d14eac commit 1fc458d

File tree

4 files changed

+62
-5
lines changed

4 files changed

+62
-5
lines changed

Documentation/git-checkout.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,13 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
256256
out anyway. In other words, the ref can be held by more than one
257257
worktree.
258258

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+
259266
<branch>::
260267
Branch to checkout; if it refers to a branch (i.e., a name that,
261268
when prepended with "refs/heads/", is a valid ref), then that

builtin/checkout.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,31 @@
2121
#include "submodule-config.h"
2222
#include "submodule.h"
2323

24+
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
25+
2426
static const char * const checkout_usage[] = {
2527
N_("git checkout [<options>] <branch>"),
2628
N_("git checkout [<options>] [<branch>] -- <file>..."),
2729
NULL,
2830
};
2931

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+
3049
struct checkout_opts {
3150
int patch_mode;
3251
int quiet;
@@ -1163,6 +1182,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
11631182
N_("second guess 'git checkout <no-such-branch>'")),
11641183
OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
11651184
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 },
11661188
OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")),
11671189
OPT_END(),
11681190
};
@@ -1193,6 +1215,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
11931215
git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
11941216
}
11951217

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+
11961224
if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
11971225
die(_("-b, -B and --orphan are mutually exclusive"));
11981226

t/lib-submodule-update.sh

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,16 @@ test_submodule_forced_switch () {
782782

783783
test_submodule_switch_recursing () {
784784
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
785795
######################### Appearing submodule #########################
786796
# Switching to a commit letting a submodule appear checks it out ...
787797
test_expect_success "$command: added submodule is checked out" '
@@ -891,7 +901,7 @@ test_submodule_switch_recursing () {
891901
'
892902
# Replacing a submodule with files in a directory must succeeds
893903
# 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" '
895905
prolog &&
896906
reset_work_tree_to_interested add_sub1 &&
897907
(
@@ -903,7 +913,7 @@ test_submodule_switch_recursing () {
903913
)
904914
'
905915
# ... 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" '
907917
prolog &&
908918
reset_work_tree_to_interested add_sub1 &&
909919
(
@@ -931,7 +941,7 @@ test_submodule_switch_recursing () {
931941
'
932942

933943
# ... 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" '
935945
prolog &&
936946
reset_work_tree_to_interested add_sub1 &&
937947
(
@@ -987,7 +997,8 @@ test_submodule_switch_recursing () {
987997
)
988998
'
989999

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" '
9911002
prolog &&
9921003
reset_work_tree_to_interested add_nested_sub &&
9931004
(
@@ -1006,6 +1017,11 @@ test_submodule_switch_recursing () {
10061017
# the superproject as well as the submodule is allowed.
10071018
test_submodule_forced_switch_recursing () {
10081019
command="$1"
1020+
RESULT=success
1021+
if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
1022+
then
1023+
RESULT=failure
1024+
fi
10091025
######################### Appearing submodule #########################
10101026
# Switching to a commit letting a submodule appear creates empty dir ...
10111027
test_expect_success "$command: added submodule is checked out" '
@@ -1151,7 +1167,7 @@ test_submodule_forced_switch_recursing () {
11511167
'
11521168

11531169
# ... 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" '
11551171
prolog &&
11561172
reset_work_tree_to_interested add_sub1 &&
11571173
(

t/t2013-checkout-submodule.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ test_expect_success '"checkout <submodule>" honors submodule.*.ignore from .git/
6363
! test -s actual
6464
'
6565

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+
6672
test_submodule_switch "git checkout"
6773

6874
test_submodule_forced_switch "git checkout -f"

0 commit comments

Comments
 (0)