diff options
-rw-r--r-- | Documentation/git-submodule.txt | 10 | ||||
-rwxr-xr-x | git-submodule.sh | 19 | ||||
-rwxr-xr-x | t/t7407-submodule-foreach.sh | 99 |
3 files changed, 124 insertions, 4 deletions
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 97c32fe264..326136a85b 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -16,7 +16,7 @@ SYNOPSIS 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--] [<path>...] 'git submodule' [--quiet] summary [--cached] [--summary-limit <n>] [commit] [--] [<path>...] -'git submodule' [--quiet] foreach <command> +'git submodule' [--quiet] foreach [--recursive] <command> 'git submodule' [--quiet] sync [--] [<path>...] @@ -138,6 +138,8 @@ foreach:: Any submodules defined in the superproject but not checked out are ignored by this command. Unless given --quiet, foreach prints the name of each submodule before evaluating the command. + If --recursive is given, submodules are traversed recursively (i.e. + the given shell command is evaluated in nested submodules as well). A non-zero return from the command in any submodule causes the processing to terminate. This can be overridden by adding '|| :' to the end of the command. @@ -210,6 +212,12 @@ OPTIONS *NOTE*: Do *not* use this option unless you have read the note for linkgit:git-clone[1]'s --reference and --shared options carefully. +--recursive:: + This option is only valid for the foreach command. + Traverse submodules recursively. The operation is performed not + only in the submodules of the current repo, but also + in any nested submodules inside those submodules (and so on). + <path>...:: Paths to submodule(s). When specified this will restrict the command to only operate on the submodules found at the specified paths. diff --git a/git-submodule.sh b/git-submodule.sh index f48f682ab6..c501b7eafa 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -10,7 +10,7 @@ USAGE="[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <p or: $dashless [--quiet] init [--] [<path>...] or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--] [<path>...] or: $dashless [--quiet] summary [--cached] [--summary-limit <n>] [commit] [--] [<path>...] - or: $dashless [--quiet] foreach <command> + or: $dashless [--quiet] foreach [--recursive] <command> or: $dashless [--quiet] sync [--] [<path>...]" OPTIONS_SPEC= . git-sh-setup @@ -23,6 +23,7 @@ reference= cached= nofetch= update= +prefix= # Resolve relative url by appending to parent's url resolve_relative_url () @@ -249,6 +250,9 @@ cmd_foreach() -q|--quiet) GIT_QUIET=1 ;; + --recursive) + recursive=1 + ;; -*) usage ;; @@ -264,9 +268,18 @@ cmd_foreach() do if test -e "$path"/.git then - say "Entering '$path'" + say "Entering '$prefix$path'" name=$(module_name "$path") - (cd "$path" && eval "$@") || + ( + prefix="$prefix$path/" + unset GIT_DIR + cd "$path" && + eval "$@" && + if test -n "$recursive" + then + cmd_foreach "--recursive" "$@" + fi + ) || die "Stopping at '$path'; script returned non-zero status." fi done diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 991aa80c8a..be122c7f8c 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -76,4 +76,103 @@ test_expect_success 'test basic "submodule foreach" usage' ' test_cmp expect actual ' +test_expect_success 'setup nested submodules' ' + git clone submodule nested1 && + git clone submodule nested2 && + git clone submodule nested3 && + ( + cd nested3 && + git submodule add ../submodule submodule && + test_tick && + git commit -m "submodule" && + git submodule init submodule + ) && + ( + cd nested2 && + git submodule add ../nested3 nested3 && + test_tick && + git commit -m "nested3" && + git submodule init nested3 + ) && + ( + cd nested1 && + git submodule add ../nested2 nested2 && + test_tick && + git commit -m "nested2" && + git submodule init nested2 + ) && + ( + cd super && + git submodule add ../nested1 nested1 && + test_tick && + git commit -m "nested1" && + git submodule init nested1 + ) +' + +test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' ' + git clone super clone2 && + ( + cd clone2 && + test ! -d sub1/.git && + test ! -d sub2/.git && + test ! -d sub3/.git && + test ! -d nested1/.git && + git submodule update --init && + test -d sub1/.git && + test -d sub2/.git && + test -d sub3/.git && + test -d nested1/.git && + test ! -d nested1/nested2/.git && + git submodule foreach "git submodule update --init" && + test -d nested1/nested2/.git && + test ! -d nested1/nested2/nested3/.git + ) +' + +test_expect_success 'use "foreach --recursive" to checkout all submodules' ' + ( + cd clone2 && + git submodule foreach --recursive "git submodule update --init" && + test -d nested1/nested2/nested3/.git && + test -d nested1/nested2/nested3/submodule/.git + ) +' + +cat > expect <<EOF +Entering 'nested1' +Entering 'nested1/nested2' +Entering 'nested1/nested2/nested3' +Entering 'nested1/nested2/nested3/submodule' +Entering 'sub1' +Entering 'sub2' +Entering 'sub3' +EOF + +test_expect_success 'test messages from "foreach --recursive"' ' + ( + cd clone2 && + git submodule foreach --recursive "true" > ../actual + ) && + test_cmp expect actual +' + +cat > expect <<EOF +nested1-nested1 +nested2-nested2 +nested3-nested3 +submodule-submodule +foo1-sub1 +foo2-sub2 +foo3-sub3 +EOF + +test_expect_success 'test "foreach --quiet --recursive"' ' + ( + cd clone2 && + git submodule foreach -q --recursive "echo \$name-\$path" > ../actual + ) && + test_cmp expect actual +' + test_done |