From 1e7f2aad7dd9b0b5ec8bbae2e3015915687e2cd2 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Sun, 16 Aug 2009 03:10:08 +0200 Subject: [PATCH 1/9] git submodule foreach: Provide access to submodule name, as '$name' The argument to 'git submodule foreach' already has access to the variables '$path' (the path to the submodule, relative to the superproject) and '$sha1' (the submodule commit recorded by the superproject). This patch adds another variable -- '$name' -- which contains the name of the submodule, as recorded in the superproject's .gitmodules file. Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 3 ++- git-submodule.sh | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 7dd73ae14e..97c32fe264 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -131,7 +131,8 @@ summary:: foreach:: Evaluates an arbitrary shell command in each checked out submodule. - The command has access to the variables $path and $sha1: + The command has access to the variables $name, $path and $sha1: + $name is the name of the relevant submodule section in .gitmodules, $path is the name of the submodule directory relative to the superproject, and $sha1 is the commit as recorded in the superproject. Any submodules defined in the superproject but not checked out are diff --git a/git-submodule.sh b/git-submodule.sh index ebed711da4..d8ecdb91fe 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -243,6 +243,7 @@ cmd_foreach() if test -e "$path"/.git then say "Entering '$path'" + name=$(module_name "$path") (cd "$path" && eval "$@") || die "Stopping at '$path'; script returned non-zero status." fi From 1d5bec8b9cee65b1f98a118ba79120ea686252e3 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Wed, 19 Aug 2009 03:45:19 +0200 Subject: [PATCH 2/9] git submodule: Cleanup usage string and add option parsing to cmd_foreach() Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- git-submodule.sh | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index d8ecdb91fe..f48f682ab6 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -4,9 +4,14 @@ # # Copyright (c) 2007 Lars Hjemli -USAGE="[--quiet] [--cached] \ -[add [-b branch] ]|[status|init|update [-i|--init] [-N|--no-fetch] [--rebase|--merge]|summary [-n|--summary-limit ] []] \ -[--] [...]|[foreach ]|[sync [--] [...]]" +dashless=$(basename "$0" | sed -e 's/-/ /') +USAGE="[--quiet] add [-b branch] [--reference ] [--] + or: $dashless [--quiet] status [--cached] [--] [...] + or: $dashless [--quiet] init [--] [...] + or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--] [...] + or: $dashless [--quiet] summary [--cached] [--summary-limit ] [commit] [--] [...] + or: $dashless [--quiet] foreach + or: $dashless [--quiet] sync [--] [...]" OPTIONS_SPEC= . git-sh-setup . git-parse-remote @@ -237,6 +242,23 @@ cmd_add() # cmd_foreach() { + # parse $args after "submodule ... foreach". + while test $# -ne 0 + do + case "$1" in + -q|--quiet) + GIT_QUIET=1 + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift + done + module_list | while read mode sha1 stage path do From d69ecf6f0ed2c1a31875a3f642deef0358ac9377 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Wed, 19 Aug 2009 03:45:20 +0200 Subject: [PATCH 3/9] Add selftest for 'git submodule foreach' The selftest verifies that: - only checked out submodules are visited by 'git submodule foreach' - the $path, and $sha1 variables are set correctly for each submodule Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- t/t7407-submodule-foreach.sh | 79 ++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100755 t/t7407-submodule-foreach.sh diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh new file mode 100755 index 0000000000..76e0734cea --- /dev/null +++ b/t/t7407-submodule-foreach.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# +# Copyright (c) 2009 Johan Herland +# + +test_description='Test "git submodule foreach" + +This test verifies that "git submodule foreach" correctly visits all submodules +that are currently checked out. +' + +. ./test-lib.sh + + +test_expect_success 'setup a submodule tree' ' + echo file > file && + git add file && + test_tick && + git commit -m upstream + git clone . super && + git clone super submodule && + ( + cd super && + git submodule add ../submodule sub1 && + git submodule add ../submodule sub2 && + git submodule add ../submodule sub3 && + git config -f .gitmodules --rename-section \ + submodule.sub1 submodule.foo1 && + git config -f .gitmodules --rename-section \ + submodule.sub2 submodule.foo2 && + git config -f .gitmodules --rename-section \ + submodule.sub3 submodule.foo3 && + git add .gitmodules + test_tick && + git commit -m "submodules" && + git submodule init sub1 && + git submodule init sub2 && + git submodule init sub3 + ) && + ( + cd submodule && + echo different > file && + git add file && + test_tick && + git commit -m "different" + ) && + ( + cd super && + ( + cd sub3 && + git pull + ) && + git add sub3 && + test_tick && + git commit -m "update sub3" + ) +' + +sub1sha1=$(cd super/sub1 && git rev-parse HEAD) +sub3sha1=$(cd super/sub3 && git rev-parse HEAD) + +cat > expect < ../actual + ) && + test_cmp expect actual +' + +test_done From 9aec7e0ba69334cf9bfc6bca6abbea7e84d676b2 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Wed, 19 Aug 2009 03:45:21 +0200 Subject: [PATCH 4/9] git submodule foreach: test access to submodule name as '$name' Add verification of the behaviour of '$name' to the git submodule foreach selftest. Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- t/t7407-submodule-foreach.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 76e0734cea..991aa80c8a 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -61,9 +61,9 @@ sub3sha1=$(cd super/sub3 && git rev-parse HEAD) cat > expect < ../actual + git submodule foreach "echo \$name-\$path-\$sha1" > ../actual ) && test_cmp expect actual ' From 15fc56a853648c60697df691c5cd8a11ad718611 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Wed, 19 Aug 2009 03:45:22 +0200 Subject: [PATCH 5/9] git submodule foreach: Add --recursive to recurse into nested submodules In very large and hierarchically structured projects, one may encounter nested submodules. In these situations, it is valuable to not only operate on all the submodules in the current repo (which is what is currently done by 'git submodule foreach'), but also to operate on all submodules at all levels (i.e. recursing into nested submodules as well). This patch teaches the new --recursive option to the 'git submodule foreach' command. The patch also includes documentation and selftests. Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 10 +++- git-submodule.sh | 19 ++++++- 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 ] [--merge] [--] [...] 'git submodule' [--quiet] summary [--cached] [--summary-limit ] [commit] [--] [...] -'git submodule' [--quiet] foreach +'git submodule' [--quiet] foreach [--recursive] 'git submodule' [--quiet] sync [--] [...] @@ -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). + ...:: 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 ] [--]

...] or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--] [...] or: $dashless [--quiet] summary [--cached] [--summary-limit ] [commit] [--] [...] - or: $dashless [--quiet] foreach + or: $dashless [--quiet] foreach [--recursive] or: $dashless [--quiet] sync [--] [...]" 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 < ../actual + ) && + test_cmp expect actual +' + +cat > expect < ../actual + ) && + test_cmp expect actual +' + test_done From b13fd5c1a2bd450cdf7b853e0c4861f361882a18 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Wed, 19 Aug 2009 03:45:23 +0200 Subject: [PATCH 6/9] git submodule update: Introduce --recursive to update nested submodules In very large and hierarchically structured projects, one may encounter nested submodules. In these situations, it is valuable to not only update the submodules in the current repo (which is what is currently done by 'git submodule update'), but also to operate on all submodules at all levels (i.e. recursing into nested submodules as well). This patch teaches the new --recursive option to the 'git submodule update' command. The patch also includes documentation and selftests. Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 7 +++++-- git-submodule.sh | 13 ++++++++++++- t/t7407-submodule-foreach.sh | 19 +++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 326136a85b..55bbc4f930 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -14,7 +14,7 @@ SYNOPSIS 'git submodule' [--quiet] status [--cached] [--] [...] 'git submodule' [--quiet] init [--] [...] 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase] - [--reference ] [--merge] [--] [...] + [--reference ] [--merge] [--recursive] [--] [...] 'git submodule' [--quiet] summary [--cached] [--summary-limit ] [commit] [--] [...] 'git submodule' [--quiet] foreach [--recursive] 'git submodule' [--quiet] sync [--] [...] @@ -122,6 +122,9 @@ update:: If the submodule is not yet initialized, and you just want to use the setting as stored in .gitmodules, you can automatically initialize the submodule with the --init option. ++ +If '--recursive' is specified, this command will recurse into the +registered submodules, and update any nested submodules within. summary:: Show commit summary between the given commit (defaults to HEAD) and @@ -213,7 +216,7 @@ OPTIONS for linkgit:git-clone[1]'s --reference and --shared options carefully. --recursive:: - This option is only valid for the foreach command. + This option is only valid for foreach and update commands. 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). diff --git a/git-submodule.sh b/git-submodule.sh index c501b7eafa..d8b98ff88f 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -8,7 +8,7 @@ dashless=$(basename "$0" | sed -e 's/-/ /') USAGE="[--quiet] add [-b branch] [--reference ] [--] or: $dashless [--quiet] status [--cached] [--] [...] or: $dashless [--quiet] init [--] [...] - or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--] [...] + or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] or: $dashless [--quiet] summary [--cached] [--summary-limit ] [commit] [--] [...] or: $dashless [--quiet] foreach [--recursive] or: $dashless [--quiet] sync [--] [...]" @@ -352,6 +352,7 @@ cmd_init() cmd_update() { # parse $args after "submodule ... update". + orig_args="$@" while test $# -ne 0 do case "$1" in @@ -384,6 +385,10 @@ cmd_update() shift update="merge" ;; + --recursive) + shift + recursive=1 + ;; --) shift break @@ -470,6 +475,12 @@ cmd_update() die "Unable to $action '$sha1' in submodule path '$path'" say "Submodule path '$path': $msg '$sha1'" fi + + if test -n "$recursive" + then + (unset GIT_DIR; cd "$path" && cmd_update $orig_args) || + die "Failed to recurse into submodule path '$path'" + fi done } diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index be122c7f8c..9122bfef35 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -175,4 +175,23 @@ test_expect_success 'test "foreach --quiet --recursive"' ' test_cmp expect actual ' +test_expect_success 'use "update --recursive" to checkout all submodules' ' + git clone super clone3 && + ( + cd clone3 && + test ! -d sub1/.git && + test ! -d sub2/.git && + test ! -d sub3/.git && + test ! -d nested1/.git && + git submodule update --init --recursive && + test -d sub1/.git && + test -d sub2/.git && + test -d sub3/.git && + test -d nested1/.git && + test -d nested1/nested2/.git && + test -d nested1/nested2/nested3/.git && + test -d nested1/nested2/nested3/submodule/.git + ) +' + test_done From 64b19ffeddda499e7380b38b43a3dee579734905 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Wed, 19 Aug 2009 03:45:24 +0200 Subject: [PATCH 7/9] git submodule status: Add --recursive to recurse into nested submodules In very large and hierarchically structured projects, one may encounter nested submodules. In these situations, it is valuable to not only show status for all the submodules in the current repo (which is what is currently done by 'git submodule status'), but also to show status for all submodules at all levels (i.e. recursing into nested submodules as well). This patch teaches the new --recursive option to the 'git submodule status' command. The patch also includes documentation and selftests. Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 7 +++++-- git-submodule.sh | 24 ++++++++++++++++++++---- t/t7407-submodule-foreach.sh | 26 ++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 55bbc4f930..b81c830c28 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -11,7 +11,7 @@ SYNOPSIS [verse] 'git submodule' [--quiet] add [-b branch] [--reference ] [--] -'git submodule' [--quiet] status [--cached] [--] [...] +'git submodule' [--quiet] status [--cached] [--recursive] [--] [...] 'git submodule' [--quiet] init [--] [...] 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] @@ -100,6 +100,9 @@ status:: initialized and `+` if the currently checked out submodule commit does not match the SHA-1 found in the index of the containing repository. This command is the default command for 'git-submodule'. ++ +If '--recursive' is specified, this command will recurse into nested +submodules, and show their status as well. init:: Initialize the submodules, i.e. register each submodule name @@ -216,7 +219,7 @@ OPTIONS for linkgit:git-clone[1]'s --reference and --shared options carefully. --recursive:: - This option is only valid for foreach and update commands. + This option is only valid for foreach, update and status commands. 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). diff --git a/git-submodule.sh b/git-submodule.sh index d8b98ff88f..446bbc0a10 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -6,7 +6,7 @@ dashless=$(basename "$0" | sed -e 's/-/ /') USAGE="[--quiet] add [-b branch] [--reference ] [--] - or: $dashless [--quiet] status [--cached] [--] [...] + or: $dashless [--quiet] status [--cached] [--recursive] [--] [...] or: $dashless [--quiet] init [--] [...] or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] or: $dashless [--quiet] summary [--cached] [--summary-limit ] [commit] [--] [...] @@ -690,6 +690,7 @@ cmd_summary() { cmd_status() { # parse $args after "submodule ... status". + orig_args="$@" while test $# -ne 0 do case "$1" in @@ -699,6 +700,9 @@ cmd_status() --cached) cached=1 ;; + --recursive) + recursive=1 + ;; --) shift break @@ -718,22 +722,34 @@ cmd_status() do name=$(module_name "$path") || exit url=$(git config submodule."$name".url) + displaypath="$prefix$path" if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git then - say "-$sha1 $path" + say "-$sha1 $displaypath" continue; fi set_name_rev "$path" "$sha1" if git diff-files --quiet -- "$path" then - say " $sha1 $path$revname" + say " $sha1 $displaypath$revname" else if test -z "$cached" then sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD) set_name_rev "$path" "$sha1" fi - say "+$sha1 $path$revname" + say "+$sha1 $displaypath$revname" + fi + + if test -n "$recursive" + then + ( + prefix="$displaypath/" + unset GIT_DIR + cd "$path" && + cmd_status $orig_args + ) || + die "Failed to recurse into submodule path '$path'" fi done } diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 9122bfef35..de1730d638 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -194,4 +194,30 @@ test_expect_success 'use "update --recursive" to checkout all submodules' ' ) ' +nested1sha1=$(cd clone3/nested1 && git rev-parse HEAD) +nested2sha1=$(cd clone3/nested1/nested2 && git rev-parse HEAD) +nested3sha1=$(cd clone3/nested1/nested2/nested3 && git rev-parse HEAD) +submodulesha1=$(cd clone3/nested1/nested2/nested3/submodule && git rev-parse HEAD) +sub1sha1=$(cd clone3/sub1 && git rev-parse HEAD) +sub2sha1=$(cd clone3/sub2 && git rev-parse HEAD) +sub3sha1=$(cd clone3/sub3 && git rev-parse HEAD) + +cat > expect < ../actual + ) && + test_cmp expect actual +' + test_done From e3ae4a8613151c93ffce78c674ac91c1ee34eef6 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Thu, 20 Aug 2009 11:24:54 +0200 Subject: [PATCH 8/9] t7407: Use 'rev-parse --short' rather than bash's substring expansion notation The substring expansion notation is a bashism that we have not so far adopted. Use 'git rev-parse --short' instead, as this also handles the case where the unique abbreviation is longer than 7 characters. Also fix the typo; the object name for submodule #2 was copied from submodule #1's by mistake. Suggested-by: Brandon Casey Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- t/t7407-submodule-foreach.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index de1730d638..519db49ea6 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -201,14 +201,16 @@ submodulesha1=$(cd clone3/nested1/nested2/nested3/submodule && git rev-parse HEA sub1sha1=$(cd clone3/sub1 && git rev-parse HEAD) sub2sha1=$(cd clone3/sub2 && git rev-parse HEAD) sub3sha1=$(cd clone3/sub3 && git rev-parse HEAD) +sub1sha1_short=$(cd clone3/sub1 && git rev-parse --short HEAD) +sub2sha1_short=$(cd clone3/sub2 && git rev-parse --short HEAD) cat > expect < Date: Thu, 20 Aug 2009 01:07:43 +0200 Subject: [PATCH 9/9] git clone: Add --recursive to automatically checkout (nested) submodules Many projects using submodules expect all submodules to be checked out in order to build/work correctly. A common command sequence for developers on such projects is: git clone url/to/project cd project git submodule update --init (--recursive) This patch introduces the --recursive option to git-clone. The new option causes git-clone to recursively clone and checkout all submodules of the cloned project. Hence, the above command sequence can be reduced to: git clone --recursive url/to/project --recursive is ignored if no checkout is done by the git-clone. The patch also includes documentation and a selftest. Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/git-clone.txt | 10 +++++++++- builtin-clone.c | 11 ++++++++++- t/t7407-submodule-foreach.sh | 12 ++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index b14de6c407..5a685ceec9 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -12,7 +12,7 @@ SYNOPSIS 'git clone' [--template=] [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror] [-o ] [-u ] [--reference ] - [--depth ] [--] [] + [--depth ] [--recursive] [--] [] DESCRIPTION ----------- @@ -139,6 +139,14 @@ then the cloned repository will become corrupt. with a long history, and would want to send in fixes as patches. +--recursive:: + After the clone is created, initialize all submodules within, + using their default settings. This is equivalent to running + 'git submodule update --init --recursive' immediately after + the clone is finished. This option is ignored if the cloned + repository does not have a worktree/checkout (i.e. if any of + `--no-checkout`/`-n`, `--bare`, or `--mirror` is given) + :: The (possibly remote) repository to clone from. See the <> section below for more information on specifying diff --git a/builtin-clone.c b/builtin-clone.c index 32dea74d78..0d2b4a8200 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -38,7 +38,7 @@ static const char * const builtin_clone_usage[] = { }; static int option_quiet, option_no_checkout, option_bare, option_mirror; -static int option_local, option_no_hardlinks, option_shared; +static int option_local, option_no_hardlinks, option_shared, option_recursive; static char *option_template, *option_reference, *option_depth; static char *option_origin = NULL; static char *option_upload_pack = "git-upload-pack"; @@ -59,6 +59,8 @@ static struct option builtin_clone_options[] = { "don't use local hardlinks, always copy"), OPT_BOOLEAN('s', "shared", &option_shared, "setup as shared repository"), + OPT_BOOLEAN(0, "recursive", &option_recursive, + "setup as shared repository"), OPT_STRING(0, "template", &option_template, "path", "path the template repository"), OPT_STRING(0, "reference", &option_reference, "repo", @@ -73,6 +75,10 @@ static struct option builtin_clone_options[] = { OPT_END() }; +static const char *argv_submodule[] = { + "submodule", "update", "--init", "--recursive", NULL +}; + static char *get_repo_path(const char *repo, int *is_bundle) { static char *suffix[] = { "/.git", ".git", "" }; @@ -608,6 +614,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1), sha1_to_hex(remote_head->old_sha1), "1", NULL); + + if (!err && option_recursive) + err = run_command_v_opt(argv_submodule, RUN_GIT_CMD); } strbuf_release(&reflog_msg); diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 519db49ea6..2a527750ce 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -222,4 +222,16 @@ test_expect_success 'test "status --recursive"' ' test_cmp expect actual ' +test_expect_success 'use "git clone --recursive" to checkout all submodules' ' + git clone --recursive super clone4 && + test -d clone4/.git && + test -d clone4/sub1/.git && + test -d clone4/sub2/.git && + test -d clone4/sub3/.git && + test -d clone4/nested1/.git && + test -d clone4/nested1/nested2/.git && + test -d clone4/nested1/nested2/nested3/.git && + test -d clone4/nested1/nested2/nested3/submodule/.git +' + test_done