{"thread":{"id":"20660","subject":"[RFC/PATCH 0/6] Git submodule: 'foreach' enhancements and nested submodule handling","startedAt":"2009-08-19T01:45:18Z","lastAt":"2009-08-19T23:07:43Z","messageCount":8,"participants":["Johan Herland"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"121195","messageId":"1250646324-961-1-git-send-email-johan@herland.net","threadId":"20660","inReplyTo":null,"subject":"[RFC/PATCH 0/6] Git submodule: 'foreach' enhancements and nested submodule handling","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2009-08-19T01:45:18Z","receivedAt":"2009-08-19T01:45:18Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Hi,\n\nThis patch series attempts to expand 'git submodule' command in two\nregards:\n\n1. Clean up, selftest, and enhance the 'git submodule foreach' command.\n2. Provide better handling for nested submodules where the user want to\n   operate on _all_ submodules simultenously.\n\nThe first 3 patches in the series are fairly trivial and straightforward.\nThe last 3 patches are slightly more RFC in nature, although their\nimplementation is still fairly straighforward.\n\nPatch 3/6 is a resend of a patch that I sent stand-alone on 2009-08-16.\n\n\nHave fun! :)\n\n...Johan\n\n\nJohan Herland (6):\n  git submodule: Cleanup usage string and add option parsing to cmd_foreach()\n  Add selftest for 'git submodule foreach'\n  git submodule foreach: Provide access to submodule name, as '$name'\n  git submodule foreach: Add --recursive to recurse into nested submodules\n  git submodule update: Introduce --recursive to update nested submodules\n  git submodule status: Add --recursive to recurse into nested submodules\n\n Documentation/git-submodule.txt |   23 ++++-\n git-submodule.sh                |   79 ++++++++++++--\n t/t7407-submodule-foreach.sh    |  223 +++++++++++++++++++++++++++++++++++++++\n 3 files changed, 313 insertions(+), 12 deletions(-)\n create mode 100755 t/t7407-submodule-foreach.sh\n"},{"id":"121197","messageId":"1250646324-961-2-git-send-email-johan@herland.net","threadId":"20660","inReplyTo":"1250646324-961-1-git-send-email-johan@herland.net","subject":"[RFC/PATCH 1/6] git submodule: Cleanup usage string and add option parsing to cmd_foreach()","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2009-08-19T01:45:19Z","receivedAt":"2009-08-19T01:45:19Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Signed-off-by: Johan Herland <johan@herland.net>\n---\n git-submodule.sh |   28 +++++++++++++++++++++++++---\n 1 files changed, 25 insertions(+), 3 deletions(-)\n\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 9bdd6ea..c58eca4 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -4,9 +4,14 @@\n #\n # Copyright (c) 2007 Lars Hjemli\n \n-USAGE=\"[--quiet] [--cached|--files] \\\n-[add [-b branch] <repo> <path>]|[status|init|update [-i|--init] [-N|--no-fetch] [--rebase|--merge]|summary [-n|--summary-limit <n>] [<commit>]] \\\n-[--] [<path>...]|[foreach <command>]|[sync [--] [<path>...]]\"\n+dashless=$(basename \"$0\" | sed -e 's/-/ /')\n+USAGE=\"[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <path>\n+   or: $dashless [--quiet] status [--cached] [--] [<path>...]\n+   or: $dashless [--quiet] init [--] [<path>...]\n+   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--] [<path>...]\n+   or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n+   or: $dashless [--quiet] foreach <command>\n+   or: $dashless [--quiet] sync [--] [<path>...]\"\n OPTIONS_SPEC=\n . git-sh-setup\n . git-parse-remote\n@@ -238,6 +243,23 @@ cmd_add()\n #\n cmd_foreach()\n {\n+\t# parse $args after \"submodule ... foreach\".\n+\twhile test $# -ne 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-q|--quiet)\n+\t\t\tGIT_QUIET=1\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tusage\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n \tmodule_list |\n \twhile read mode sha1 stage path\n \tdo\n-- \n1.6.4.304.g1365c.dirty\n"},{"id":"121201","messageId":"1250646324-961-3-git-send-email-johan@herland.net","threadId":"20660","inReplyTo":"1250646324-961-1-git-send-email-johan@herland.net","subject":"[RFC/PATCH 2/6] Add selftest for 'git submodule foreach'","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2009-08-19T01:45:20Z","receivedAt":"2009-08-19T01:45:20Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"The selftest verifies that:\n- only checked out submodules are visited by 'git submodule foreach'\n- the $path, and $sha1 variables are set correctly for each submodule\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n t/t7407-submodule-foreach.sh |   79 ++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 79 insertions(+), 0 deletions(-)\n create mode 100755 t/t7407-submodule-foreach.sh\n\ndiff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh\nnew file mode 100755\nindex 0000000..76e0734\n--- /dev/null\n+++ b/t/t7407-submodule-foreach.sh\n@@ -0,0 +1,79 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2009 Johan Herland\n+#\n+\n+test_description='Test \"git submodule foreach\"\n+\n+This test verifies that \"git submodule foreach\" correctly visits all submodules\n+that are currently checked out.\n+'\n+\n+. ./test-lib.sh\n+\n+\n+test_expect_success 'setup a submodule tree' '\n+\techo file > file &&\n+\tgit add file &&\n+\ttest_tick &&\n+\tgit commit -m upstream\n+\tgit clone . super &&\n+\tgit clone super submodule &&\n+\t(\n+\t\tcd super &&\n+\t\tgit submodule add ../submodule sub1 &&\n+\t\tgit submodule add ../submodule sub2 &&\n+\t\tgit submodule add ../submodule sub3 &&\n+\t\tgit config -f .gitmodules --rename-section \\\n+\t\t\tsubmodule.sub1 submodule.foo1 &&\n+\t\tgit config -f .gitmodules --rename-section \\\n+\t\t\tsubmodule.sub2 submodule.foo2 &&\n+\t\tgit config -f .gitmodules --rename-section \\\n+\t\t\tsubmodule.sub3 submodule.foo3 &&\n+\t\tgit add .gitmodules\n+\t\ttest_tick &&\n+\t\tgit commit -m \"submodules\" &&\n+\t\tgit submodule init sub1 &&\n+\t\tgit submodule init sub2 &&\n+\t\tgit submodule init sub3\n+\t) &&\n+\t(\n+\t\tcd submodule &&\n+\t\techo different > file &&\n+\t\tgit add file &&\n+\t\ttest_tick &&\n+\t\tgit commit -m \"different\"\n+\t) &&\n+\t(\n+\t\tcd super &&\n+\t\t(\n+\t\t\tcd sub3 &&\n+\t\t\tgit pull\n+\t\t) &&\n+\t\tgit add sub3 &&\n+\t\ttest_tick &&\n+\t\tgit commit -m \"update sub3\"\n+\t)\n+'\n+\n+sub1sha1=$(cd super/sub1 && git rev-parse HEAD)\n+sub3sha1=$(cd super/sub3 && git rev-parse HEAD)\n+\n+cat > expect <<EOF\n+Entering 'sub1'\n+sub1-$sub1sha1\n+Entering 'sub3'\n+sub3-$sub3sha1\n+EOF\n+\n+test_expect_success 'test basic \"submodule foreach\" usage' '\n+\tgit clone super clone &&\n+\t(\n+\t\tcd clone &&\n+\t\tgit submodule update --init -- sub1 sub3 &&\n+\t\tgit submodule foreach \"echo \\$path-\\$sha1\" > ../actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n1.6.4.304.g1365c.dirty\n"},{"id":"121196","messageId":"1250646324-961-4-git-send-email-johan@herland.net","threadId":"20660","inReplyTo":"1250646324-961-1-git-send-email-johan@herland.net","subject":"[RFC/PATCH 3/6] git submodule foreach: Provide access to submodule name, as '$name'","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2009-08-19T01:45:21Z","receivedAt":"2009-08-19T01:45:21Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"The argument to 'git submodule foreach' already has access to the variables\n'$path' (the path to the submodule, relative to the superproject) and '$sha1'\n(the submodule commit recorded by the superproject).\n\nThis patch adds another variable - '$name' - which contains the name of the\nsubmodule, as recorded in the superproject's .gitmodules file.\n\nVerification of the behaviour of '$name' is also added to the git submodule\nforeach selftest.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n\nThis patch was initially sent stand-alone on 2009-08-16.\n\n\n...Johan\n\n\n Documentation/git-submodule.txt |    3 ++-\n git-submodule.sh                |    1 +\n t/t7407-submodule-foreach.sh    |    6 +++---\n 3 files changed, 6 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex bb7d159..cfa8d73 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -135,7 +135,8 @@ summary::\n \n foreach::\n \tEvaluates an arbitrary shell command in each checked out submodule.\n-\tThe command has access to the variables $path and $sha1:\n+\tThe command has access to the variables $name, $path and $sha1:\n+\t$name is the name of the relevant submodule section in .gitmodules,\n \t$path is the name of the submodule directory relative to the\n \tsuperproject, and $sha1 is the commit as recorded in the superproject.\n \tAny submodules defined in the superproject but not checked out are\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex c58eca4..6163d01 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -266,6 +266,7 @@ cmd_foreach()\n \t\tif test -e \"$path\"/.git\n \t\tthen\n \t\t\tsay \"Entering '$path'\"\n+\t\t\tname=$(module_name \"$path\")\n \t\t\t(cd \"$path\" && eval \"$@\") ||\n \t\t\tdie \"Stopping at '$path'; script returned non-zero status.\"\n \t\tfi\ndiff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh\nindex 76e0734..991aa80 100755\n--- a/t/t7407-submodule-foreach.sh\n+++ b/t/t7407-submodule-foreach.sh\n@@ -61,9 +61,9 @@ sub3sha1=$(cd super/sub3 && git rev-parse HEAD)\n \n cat > expect <<EOF\n Entering 'sub1'\n-sub1-$sub1sha1\n+foo1-sub1-$sub1sha1\n Entering 'sub3'\n-sub3-$sub3sha1\n+foo3-sub3-$sub3sha1\n EOF\n \n test_expect_success 'test basic \"submodule foreach\" usage' '\n@@ -71,7 +71,7 @@ test_expect_success 'test basic \"submodule foreach\" usage' '\n \t(\n \t\tcd clone &&\n \t\tgit submodule update --init -- sub1 sub3 &&\n-\t\tgit submodule foreach \"echo \\$path-\\$sha1\" > ../actual\n+\t\tgit submodule foreach \"echo \\$name-\\$path-\\$sha1\" > ../actual\n \t) &&\n \ttest_cmp expect actual\n '\n-- \n1.6.4.304.g1365c.dirty\n"},{"id":"121199","messageId":"1250646324-961-5-git-send-email-johan@herland.net","threadId":"20660","inReplyTo":"1250646324-961-1-git-send-email-johan@herland.net","subject":"[RFC/PATCH 4/6] git submodule foreach: Add --recursive to recurse into nested submodules","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2009-08-19T01:45:22Z","receivedAt":"2009-08-19T01:45:22Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"In very large and hierarchically structured projects, one may encounter\nnested submodules. In these situations, it is valuable to not only operate\non all the submodules in the current repo (which is what is currently done\nby 'git submodule foreach'), but also to operate on all submodules at all\nlevels (i.e. recursing into nested submodules as well).\n\nThis patch teaches the new --recursive option to the 'git submodule foreach'\ncommand. The patch also includes documentation and selftests.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n Documentation/git-submodule.txt |   10 ++++-\n git-submodule.sh                |   19 ++++++-\n t/t7407-submodule-foreach.sh    |   99 +++++++++++++++++++++++++++++++++++++++\n 3 files changed, 124 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex cfa8d73..c604550 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -16,7 +16,7 @@ SYNOPSIS\n 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]\n \t      [--reference <repository>] [--merge] [--] [<path>...]\n 'git submodule' [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n-'git submodule' [--quiet] foreach <command>\n+'git submodule' [--quiet] foreach [--recursive] <command>\n 'git submodule' [--quiet] sync [--] [<path>...]\n \n \n@@ -142,6 +142,8 @@ foreach::\n \tAny submodules defined in the superproject but not checked out are\n \tignored by this command. Unless given --quiet, foreach prints the name\n \tof each submodule before evaluating the command.\n+\tIf --recursive is given, submodules are traversed recursively (i.e.\n+\tthe given shell command is evaluated in nested submodules as well).\n \tA non-zero return from the command in any submodule causes\n \tthe processing to terminate. This can be overridden by adding '|| :'\n \tto the end of the command.\n@@ -219,6 +221,12 @@ OPTIONS\n *NOTE*: Do *not* use this option unless you have read the note\n for linkgit:git-clone[1]'s --reference and --shared options carefully.\n \n+--recursive::\n+\tThis option is only valid for the foreach command.\n+\tTraverse submodules recursively. The operation is performed not\n+\tonly in the submodules of the current repo, but also\n+\tin any nested submodules inside those submodules (and so on).\n+\n <path>...::\n \tPaths to submodule(s). When specified this will restrict the command\n \tto only operate on the submodules found at the specified paths.\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 6163d01..dbfc483 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -10,7 +10,7 @@ USAGE=\"[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <p\n    or: $dashless [--quiet] init [--] [<path>...]\n    or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--] [<path>...]\n    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n-   or: $dashless [--quiet] foreach <command>\n+   or: $dashless [--quiet] foreach [--recursive] <command>\n    or: $dashless [--quiet] sync [--] [<path>...]\"\n OPTIONS_SPEC=\n . git-sh-setup\n@@ -24,6 +24,7 @@ cached=\n files=\n nofetch=\n update=\n+prefix=\n \n # Resolve relative url by appending to parent's url\n resolve_relative_url ()\n@@ -250,6 +251,9 @@ cmd_foreach()\n \t\t-q|--quiet)\n \t\t\tGIT_QUIET=1\n \t\t\t;;\n+\t\t--recursive)\n+\t\t\trecursive=1\n+\t\t\t;;\n \t\t-*)\n \t\t\tusage\n \t\t\t;;\n@@ -265,9 +269,18 @@ cmd_foreach()\n \tdo\n \t\tif test -e \"$path\"/.git\n \t\tthen\n-\t\t\tsay \"Entering '$path'\"\n+\t\t\tsay \"Entering '$prefix$path'\"\n \t\t\tname=$(module_name \"$path\")\n-\t\t\t(cd \"$path\" && eval \"$@\") ||\n+\t\t\t(\n+\t\t\t\tprefix=\"$prefix$path/\"\n+\t\t\t\tunset GIT_DIR\n+\t\t\t\tcd \"$path\" &&\n+\t\t\t\teval \"$@\" &&\n+\t\t\t\tif test -n \"$recursive\"\n+\t\t\t\tthen\n+\t\t\t\t\tcmd_foreach \"--recursive\" \"$@\"\n+\t\t\t\tfi\n+\t\t\t) ||\n \t\t\tdie \"Stopping at '$path'; script returned non-zero status.\"\n \t\tfi\n \tdone\ndiff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh\nindex 991aa80..be122c7 100755\n--- a/t/t7407-submodule-foreach.sh\n+++ b/t/t7407-submodule-foreach.sh\n@@ -76,4 +76,103 @@ test_expect_success 'test basic \"submodule foreach\" usage' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'setup nested submodules' '\n+\tgit clone submodule nested1 &&\n+\tgit clone submodule nested2 &&\n+\tgit clone submodule nested3 &&\n+\t(\n+\t\tcd nested3 &&\n+\t\tgit submodule add ../submodule submodule &&\n+\t\ttest_tick &&\n+\t\tgit commit -m \"submodule\" &&\n+\t\tgit submodule init submodule\n+\t) &&\n+\t(\n+\t\tcd nested2 &&\n+\t\tgit submodule add ../nested3 nested3 &&\n+\t\ttest_tick &&\n+\t\tgit commit -m \"nested3\" &&\n+\t\tgit submodule init nested3\n+\t) &&\n+\t(\n+\t\tcd nested1 &&\n+\t\tgit submodule add ../nested2 nested2 &&\n+\t\ttest_tick &&\n+\t\tgit commit -m \"nested2\" &&\n+\t\tgit submodule init nested2\n+\t) &&\n+\t(\n+\t\tcd super &&\n+\t\tgit submodule add ../nested1 nested1 &&\n+\t\ttest_tick &&\n+\t\tgit commit -m \"nested1\" &&\n+\t\tgit submodule init nested1\n+\t)\n+'\n+\n+test_expect_success 'use \"submodule foreach\" to checkout 2nd level submodule' '\n+\tgit clone super clone2 &&\n+\t(\n+\t\tcd clone2 &&\n+\t\ttest ! -d sub1/.git &&\n+\t\ttest ! -d sub2/.git &&\n+\t\ttest ! -d sub3/.git &&\n+\t\ttest ! -d nested1/.git &&\n+\t\tgit submodule update --init &&\n+\t\ttest -d sub1/.git &&\n+\t\ttest -d sub2/.git &&\n+\t\ttest -d sub3/.git &&\n+\t\ttest -d nested1/.git &&\n+\t\ttest ! -d nested1/nested2/.git &&\n+\t\tgit submodule foreach \"git submodule update --init\" &&\n+\t\ttest -d nested1/nested2/.git &&\n+\t\ttest ! -d nested1/nested2/nested3/.git\n+\t)\n+'\n+\n+test_expect_success 'use \"foreach --recursive\" to checkout all submodules' '\n+\t(\n+\t\tcd clone2 &&\n+\t\tgit submodule foreach --recursive \"git submodule update --init\" &&\n+\t\ttest -d nested1/nested2/nested3/.git &&\n+\t\ttest -d nested1/nested2/nested3/submodule/.git\n+\t)\n+'\n+\n+cat > expect <<EOF\n+Entering 'nested1'\n+Entering 'nested1/nested2'\n+Entering 'nested1/nested2/nested3'\n+Entering 'nested1/nested2/nested3/submodule'\n+Entering 'sub1'\n+Entering 'sub2'\n+Entering 'sub3'\n+EOF\n+\n+test_expect_success 'test messages from \"foreach --recursive\"' '\n+\t(\n+\t\tcd clone2 &&\n+\t\tgit submodule foreach --recursive \"true\" > ../actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+cat > expect <<EOF\n+nested1-nested1\n+nested2-nested2\n+nested3-nested3\n+submodule-submodule\n+foo1-sub1\n+foo2-sub2\n+foo3-sub3\n+EOF\n+\n+test_expect_success 'test \"foreach --quiet --recursive\"' '\n+\t(\n+\t\tcd clone2 &&\n+\t\tgit submodule foreach -q --recursive \"echo \\$name-\\$path\" > ../actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n1.6.4.304.g1365c.dirty\n"},{"id":"121200","messageId":"1250646324-961-6-git-send-email-johan@herland.net","threadId":"20660","inReplyTo":"1250646324-961-1-git-send-email-johan@herland.net","subject":"[RFC/PATCH 5/6] git submodule update: Introduce --recursive to update nested submodules","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2009-08-19T01:45:23Z","receivedAt":"2009-08-19T01:45:23Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"In very large and hierarchically structured projects, one may encounter\nnested submodules. In these situations, it is valuable to not only update\nthe submodules in the current repo (which is what is currently done by\n'git submodule update'), but also to operate on all submodules at all\nlevels (i.e. recursing into nested submodules as well).\n\nThis patch teaches the new --recursive option to the 'git submodule update'\ncommand. The patch also includes documentation and selftests.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n Documentation/git-submodule.txt |    7 +++++--\n git-submodule.sh                |   13 ++++++++++++-\n t/t7407-submodule-foreach.sh    |   19 +++++++++++++++++++\n 3 files changed, 36 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex c604550..cd74da9 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -14,7 +14,7 @@ SYNOPSIS\n 'git submodule' [--quiet] status [--cached] [--] [<path>...]\n 'git submodule' [--quiet] init [--] [<path>...]\n 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]\n-\t      [--reference <repository>] [--merge] [--] [<path>...]\n+\t      [--reference <repository>] [--merge] [--recursive] [--] [<path>...]\n 'git submodule' [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n 'git submodule' [--quiet] foreach [--recursive] <command>\n 'git submodule' [--quiet] sync [--] [<path>...]\n@@ -122,6 +122,9 @@ update::\n If the submodule is not yet initialized, and you just want to use the\n setting as stored in .gitmodules, you can automatically initialize the\n submodule with the --init option.\n++\n+If '--recursive' is specified, this command will recurse into the\n+registered submodules, and update any nested submodules within.\n \n summary::\n \tShow commit summary between the given commit (defaults to HEAD) and\n@@ -222,7 +225,7 @@ OPTIONS\n for linkgit:git-clone[1]'s --reference and --shared options carefully.\n \n --recursive::\n-\tThis option is only valid for the foreach command.\n+\tThis option is only valid for foreach and update commands.\n \tTraverse submodules recursively. The operation is performed not\n \tonly in the submodules of the current repo, but also\n \tin any nested submodules inside those submodules (and so on).\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex dbfc483..e48c309 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -8,7 +8,7 @@ dashless=$(basename \"$0\" | sed -e 's/-/ /')\n USAGE=\"[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <path>\n    or: $dashless [--quiet] status [--cached] [--] [<path>...]\n    or: $dashless [--quiet] init [--] [<path>...]\n-   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--] [<path>...]\n+   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]\n    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n    or: $dashless [--quiet] foreach [--recursive] <command>\n    or: $dashless [--quiet] sync [--] [<path>...]\"\n@@ -353,6 +353,7 @@ cmd_init()\n cmd_update()\n {\n \t# parse $args after \"submodule ... update\".\n+\torig_args=\"$@\"\n \twhile test $# -ne 0\n \tdo\n \t\tcase \"$1\" in\n@@ -385,6 +386,10 @@ cmd_update()\n \t\t\tshift\n \t\t\tupdate=\"merge\"\n \t\t\t;;\n+\t\t--recursive)\n+\t\t\tshift\n+\t\t\trecursive=1\n+\t\t\t;;\n \t\t--)\n \t\t\tshift\n \t\t\tbreak\n@@ -471,6 +476,12 @@ cmd_update()\n \t\t\tdie \"Unable to $action '$sha1' in submodule path '$path'\"\n \t\t\tsay \"Submodule path '$path': $msg '$sha1'\"\n \t\tfi\n+\n+\t\tif test -n \"$recursive\"\n+\t\tthen\n+\t\t\t(unset GIT_DIR; cd \"$path\" && cmd_update $orig_args) ||\n+\t\t\tdie \"Failed to recurse into submodule path '$path'\"\n+\t\tfi\n \tdone\n }\n \ndiff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh\nindex be122c7..9122bfe 100755\n--- a/t/t7407-submodule-foreach.sh\n+++ b/t/t7407-submodule-foreach.sh\n@@ -175,4 +175,23 @@ test_expect_success 'test \"foreach --quiet --recursive\"' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'use \"update --recursive\" to checkout all submodules' '\n+\tgit clone super clone3 &&\n+\t(\n+\t\tcd clone3 &&\n+\t\ttest ! -d sub1/.git &&\n+\t\ttest ! -d sub2/.git &&\n+\t\ttest ! -d sub3/.git &&\n+\t\ttest ! -d nested1/.git &&\n+\t\tgit submodule update --init --recursive &&\n+\t\ttest -d sub1/.git &&\n+\t\ttest -d sub2/.git &&\n+\t\ttest -d sub3/.git &&\n+\t\ttest -d nested1/.git &&\n+\t\ttest -d nested1/nested2/.git &&\n+\t\ttest -d nested1/nested2/nested3/.git &&\n+\t\ttest -d nested1/nested2/nested3/submodule/.git\n+\t)\n+'\n+\n test_done\n-- \n1.6.4.304.g1365c.dirty\n"},{"id":"121198","messageId":"1250646324-961-7-git-send-email-johan@herland.net","threadId":"20660","inReplyTo":"1250646324-961-1-git-send-email-johan@herland.net","subject":"[RFC/PATCH 6/6] git submodule status: Add --recursive to recurse into nested submodules","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2009-08-19T01:45:24Z","receivedAt":"2009-08-19T01:45:24Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"In very large and hierarchically structured projects, one may encounter\nnested submodules. In these situations, it is valuable to not only show\nstatus for all the submodules in the current repo (which is what is\ncurrently done by 'git submodule status'), but also to show status for\nall submodules at all levels (i.e. recursing into nested submodules as\nwell).\n\nThis patch teaches the new --recursive option to the 'git submodule status'\ncommand. The patch also includes documentation and selftests.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n Documentation/git-submodule.txt |    7 +++++--\n git-submodule.sh                |   24 ++++++++++++++++++++----\n t/t7407-submodule-foreach.sh    |   26 ++++++++++++++++++++++++++\n 3 files changed, 51 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex cd74da9..5ccdd18 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -11,7 +11,7 @@ SYNOPSIS\n [verse]\n 'git submodule' [--quiet] add [-b branch]\n \t      [--reference <repository>] [--] <repository> <path>\n-'git submodule' [--quiet] status [--cached] [--] [<path>...]\n+'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]\n 'git submodule' [--quiet] init [--] [<path>...]\n 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]\n \t      [--reference <repository>] [--merge] [--recursive] [--] [<path>...]\n@@ -100,6 +100,9 @@ status::\n \tinitialized and `+` if the currently checked out submodule commit\n \tdoes not match the SHA-1 found in the index of the containing\n \trepository. This command is the default command for 'git-submodule'.\n++\n+If '--recursive' is specified, this command will recurse into nested\n+submodules, and show their status as well.\n \n init::\n \tInitialize the submodules, i.e. register each submodule name\n@@ -225,7 +228,7 @@ OPTIONS\n for linkgit:git-clone[1]'s --reference and --shared options carefully.\n \n --recursive::\n-\tThis option is only valid for foreach and update commands.\n+\tThis option is only valid for foreach, update and status commands.\n \tTraverse submodules recursively. The operation is performed not\n \tonly in the submodules of the current repo, but also\n \tin any nested submodules inside those submodules (and so on).\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex e48c309..bfbd36b 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -6,7 +6,7 @@\n \n dashless=$(basename \"$0\" | sed -e 's/-/ /')\n USAGE=\"[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <path>\n-   or: $dashless [--quiet] status [--cached] [--] [<path>...]\n+   or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]\n    or: $dashless [--quiet] init [--] [<path>...]\n    or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]\n    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n@@ -703,6 +703,7 @@ cmd_summary() {\n cmd_status()\n {\n \t# parse $args after \"submodule ... status\".\n+\torig_args=\"$@\"\n \twhile test $# -ne 0\n \tdo\n \t\tcase \"$1\" in\n@@ -712,6 +713,9 @@ cmd_status()\n \t\t--cached)\n \t\t\tcached=1\n \t\t\t;;\n+\t\t--recursive)\n+\t\t\trecursive=1\n+\t\t\t;;\n \t\t--)\n \t\t\tshift\n \t\t\tbreak\n@@ -731,22 +735,34 @@ cmd_status()\n \tdo\n \t\tname=$(module_name \"$path\") || exit\n \t\turl=$(git config submodule.\"$name\".url)\n+\t\tdisplaypath=\"$prefix$path\"\n \t\tif test -z \"$url\" || ! test -d \"$path\"/.git -o -f \"$path\"/.git\n \t\tthen\n-\t\t\tsay \"-$sha1 $path\"\n+\t\t\tsay \"-$sha1 $displaypath\"\n \t\t\tcontinue;\n \t\tfi\n \t\tset_name_rev \"$path\" \"$sha1\"\n \t\tif git diff-files --quiet -- \"$path\"\n \t\tthen\n-\t\t\tsay \" $sha1 $path$revname\"\n+\t\t\tsay \" $sha1 $displaypath$revname\"\n \t\telse\n \t\t\tif test -z \"$cached\"\n \t\t\tthen\n \t\t\t\tsha1=$(unset GIT_DIR; cd \"$path\" && git rev-parse --verify HEAD)\n \t\t\t\tset_name_rev \"$path\" \"$sha1\"\n \t\t\tfi\n-\t\t\tsay \"+$sha1 $path$revname\"\n+\t\t\tsay \"+$sha1 $displaypath$revname\"\n+\t\tfi\n+\n+\t\tif test -n \"$recursive\"\n+\t\tthen\n+\t\t\t(\n+\t\t\t\tprefix=\"$displaypath/\"\n+\t\t\t\tunset GIT_DIR\n+\t\t\t\tcd \"$path\" &&\n+\t\t\t\tcmd_status $orig_args\n+\t\t\t) ||\n+\t\t\tdie \"Failed to recurse into submodule path '$path'\"\n \t\tfi\n \tdone\n }\ndiff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh\nindex 9122bfe..de1730d 100755\n--- a/t/t7407-submodule-foreach.sh\n+++ b/t/t7407-submodule-foreach.sh\n@@ -194,4 +194,30 @@ test_expect_success 'use \"update --recursive\" to checkout all submodules' '\n \t)\n '\n \n+nested1sha1=$(cd clone3/nested1 && git rev-parse HEAD)\n+nested2sha1=$(cd clone3/nested1/nested2 && git rev-parse HEAD)\n+nested3sha1=$(cd clone3/nested1/nested2/nested3 && git rev-parse HEAD)\n+submodulesha1=$(cd clone3/nested1/nested2/nested3/submodule && git rev-parse HEAD)\n+sub1sha1=$(cd clone3/sub1 && git rev-parse HEAD)\n+sub2sha1=$(cd clone3/sub2 && git rev-parse HEAD)\n+sub3sha1=$(cd clone3/sub3 && git rev-parse HEAD)\n+\n+cat > expect <<EOF\n+ $nested1sha1 nested1 (heads/master)\n+ $nested2sha1 nested1/nested2 (heads/master)\n+ $nested3sha1 nested1/nested2/nested3 (heads/master)\n+ $submodulesha1 nested1/nested2/nested3/submodule (heads/master)\n+ $sub1sha1 sub1 (${sub1sha1:0:7})\n+ $sub2sha1 sub2 (${sub1sha1:0:7})\n+ $sub3sha1 sub3 (heads/master)\n+EOF\n+\n+test_expect_success 'test \"status --recursive\"' '\n+\t(\n+\t\tcd clone3 &&\n+\t\tgit submodule status --recursive > ../actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n1.6.4.304.g1365c.dirty\n"},{"id":"121299","messageId":"200908200107.43146.johan@herland.net","threadId":"20660","inReplyTo":"1250646324-961-1-git-send-email-johan@herland.net","subject":"[RFC/PATCH 7/6] git clone: Add --recursive to automatically checkout (nested) submodules","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2009-08-19T23:07:43Z","receivedAt":"2009-08-19T23:07:43Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Many projects using submodules expect all submodules to be checked out\nin order to build/work correctly. A common command sequence for\ndevelopers on such projects is:\n\n\tgit clone url/to/project\n\tcd project\n\tgit submodule update --init (--recursive)\n\nThis patch introduces the --recursive option to git-clone. The new\noption causes git-clone to recursively clone and checkout all\nsubmodules of the cloned project. Hence, the above command sequence\ncan be reduced to:\n\n\tgit clone --recursive url/to/project\n\n--recursive is ignored if no checkout is done by the git-clone.\n\nThe patch also includes documentation and a selftest.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n\nHi,\n\nIt just hit me today that yesterday's patch series missed the last part\nof the puzzle...\n\nI'm not at all married to the '--recursive' name for this option, but\nI wasn't able to think of anything better that wasn't too long.\n\n\nHave fun! :)\n\n...Johan\n\n\n Documentation/git-clone.txt  |   10 +++++++++-\n builtin-clone.c              |   11 ++++++++++-\n t/t7407-submodule-foreach.sh |   12 ++++++++++++\n 3 files changed, 31 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt\nindex 2c63a0f..88ea272 100644\n--- a/Documentation/git-clone.txt\n+++ b/Documentation/git-clone.txt\n@@ -12,7 +12,7 @@ SYNOPSIS\n 'git clone' [--template=<template_directory>]\n \t  [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]\n \t  [-o <name>] [-u <upload-pack>] [--reference <repository>]\n-\t  [--depth <depth>] [--] <repository> [<directory>]\n+\t  [--depth <depth>] [--recursive] [--] <repository> [<directory>]\n \n DESCRIPTION\n -----------\n@@ -147,6 +147,14 @@ objects from the source repository into a pack in the cloned repository.\n \twith a long history, and would want to send in fixes\n \tas patches.\n \n+--recursive::\n+\tAfter the clone is created, initialize all submodules within,\n+\tusing their default settings. This is equivalent to running\n+\t'git submodule update --init --recursive' immediately after\n+\tthe clone is finished. This option is ignored if the cloned\n+\trepository does not have a worktree/checkout (i.e. if any of\n+\t`--no-checkout`/`-n`, `--bare`, or `--mirror` is given)\n+\n <repository>::\n \tThe (possibly remote) repository to clone from.  See the\n \t<<URLS,URLS>> section below for more information on specifying\ndiff --git a/builtin-clone.c b/builtin-clone.c\nindex 32dea74..0d2b4a8 100644\n--- a/builtin-clone.c\n+++ b/builtin-clone.c\n@@ -38,7 +38,7 @@ static const char * const builtin_clone_usage[] = {\n };\n \n static int option_quiet, option_no_checkout, option_bare, option_mirror;\n-static int option_local, option_no_hardlinks, option_shared;\n+static int option_local, option_no_hardlinks, option_shared, option_recursive;\n static char *option_template, *option_reference, *option_depth;\n static char *option_origin = NULL;\n static char *option_upload_pack = \"git-upload-pack\";\n@@ -59,6 +59,8 @@ static struct option builtin_clone_options[] = {\n \t\t    \"don't use local hardlinks, always copy\"),\n \tOPT_BOOLEAN('s', \"shared\", &option_shared,\n \t\t    \"setup as shared repository\"),\n+\tOPT_BOOLEAN(0, \"recursive\", &option_recursive,\n+\t\t    \"setup as shared repository\"),\n \tOPT_STRING(0, \"template\", &option_template, \"path\",\n \t\t   \"path the template repository\"),\n \tOPT_STRING(0, \"reference\", &option_reference, \"repo\",\n@@ -73,6 +75,10 @@ static struct option builtin_clone_options[] = {\n \tOPT_END()\n };\n \n+static const char *argv_submodule[] = {\n+\t\"submodule\", \"update\", \"--init\", \"--recursive\", NULL\n+};\n+\n static char *get_repo_path(const char *repo, int *is_bundle)\n {\n \tstatic char *suffix[] = { \"/.git\", \".git\", \"\" };\n@@ -608,6 +614,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \n \t\terr |= run_hook(NULL, \"post-checkout\", sha1_to_hex(null_sha1),\n \t\t\t\tsha1_to_hex(remote_head->old_sha1), \"1\", NULL);\n+\n+\t\tif (!err && option_recursive)\n+\t\t\terr = run_command_v_opt(argv_submodule, RUN_GIT_CMD);\n \t}\n \n \tstrbuf_release(&reflog_msg);\ndiff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh\nindex de1730d..25ec281 100755\n--- a/t/t7407-submodule-foreach.sh\n+++ b/t/t7407-submodule-foreach.sh\n@@ -220,4 +220,16 @@ test_expect_success 'test \"status --recursive\"' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'use \"git clone --recursive\" to checkout all submodules' '\n+\tgit clone --recursive super clone4 &&\n+\ttest -d clone4/.git &&\n+\ttest -d clone4/sub1/.git &&\n+\ttest -d clone4/sub2/.git &&\n+\ttest -d clone4/sub3/.git &&\n+\ttest -d clone4/nested1/.git &&\n+\ttest -d clone4/nested1/nested2/.git &&\n+\ttest -d clone4/nested1/nested2/nested3/.git &&\n+\ttest -d clone4/nested1/nested2/nested3/submodule/.git\n+'\n+\n test_done\n-- \n1.6.4.304.g1365c.dirty\n"}]}