git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 2/3] git-submodule foreach: export .gitmodules settings as variables

From
W. Trevor King <wking@tremily.us>
Date
Nov 9, 2012, 03:35 UTC
Message-ID
<2121ce36cf4eb02385255cbd5b0bbd1dcc803113.1352431675.git.wking@tremily.us>
In-Reply-To
<cover.1352431674.git.wking@tremily.us>
From: "W. Trevor King" <wking@tremily.us>
This makes it easy to access per-submodule variables.  For example,
  git submodule foreach 'git checkout $(git config --file $toplevel/.gitmodules submodule.$name.branch) && git pull'
can now be reduced to
  git submodule foreach 'git checkout $submodule_branch && git pull'

Every submodule.<name>.<opt> setting from .gitmodules is available as a $submodule_<sanitized-opt> variable. These variables are not propagated recursively into nested submodules.

Signed-off-by: W. Trevor King <wking@tremily.us>
Based-on-patch-by: Phil Hord <phil.hord@gmail.com>
---
 Documentation/git-submodule.txt |  3 +++
 git-sh-setup.sh                 | 20 ++++++++++++++++++++
 git-submodule.sh                | 16 ++++++++++++++++
 t/t7407-submodule-foreach.sh    | 29 +++++++++++++++++++++++++++++
 4 files changed, 68 insertions(+)
 mode change 100644 => 100755 git-sh-setup.sh
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index cbec363..9a99826 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -175,6 +175,9 @@ foreach::
 	$path is the name of the submodule directory relative to the
 	superproject, $sha1 is the commit as recorded in the superproject,
 	and $toplevel is the absolute path to the top-level of the superproject.
+	In addition, every submodule.<name>.<opt> setting from .gitmodules
+	is available as the variable $submodule_<sanitized_opt>.  These
+	variables are not propagated recursively into nested submodules.
 	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.
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
old mode 100644
new mode 100755
index ee0e0bc..179a920
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -222,6 +222,26 @@ clear_local_git_env() {
 	unset $(git rev-parse --local-env-vars)
 }
 
+# Remove any suspect characters from a user-generated variable name.
+sanitize_variable_name() {
+	VAR_NAME="$1"
+	printf '%s' "$VAR_NAME" |
+	sed -e 's/^[^a-zA-Z]/_/' -e 's/[^a-zA-Z0-9]/_/g'
+}
+
+# Return a command for setting a new variable.
+# Neither the variable name nor the variable value passed to this
+# function need to be sanitized.  You need to eval the returned
+# string, because new variables set by the function itself don't
+# effect the calling process.
+set_user_variable() {
+	VAR_NAME="$1"
+	VAR_VALUE="$2"
+	VAR_NAME=$(sanitize_variable_name "$VAR_NAME")
+	VAR_VALUE=$(printf '%s' "$VAR_VALUE" |
+		sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')
+	printf '%s=%s;\n' "$VAR_NAME" "\"$VAR_VALUE\""
+}
 
 # Platform specific tweaks to work around some commands
 case $(uname -s) in
diff --git a/git-submodule.sh b/git-submodule.sh
index bc33112..e4d26f9 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -434,8 +434,24 @@ cmd_foreach()
 				clear_local_git_env
 				# we make $path available to scripts ...
 				path=$sm_path
+
+				# make all submodule variables available to scripts
+				eval $(
+					git config -f .gitmodules --get-regexp "^submodule\.${name}\..*" |
+					sed -e "s|^submodule\.${name}\.||" |
+					while read VAR_NAME VAR_VALUE ; do
+						VAR_NAME=$(printf '%s' "$VAR_NAME" | tr A-Z a-z)
+						set_user_variable "submodule_${VAR_NAME}" "$VAR_VALUE"
+					done)
+				UNSET_CMD=$(set |
+					sed -n -e 's|^\(submodule_[a-z_]*\)=.*$|\1|p' |
+					while read VAR_NAME ; do
+						printf 'unset %s;\n' "$VAR_NAME"
+					done)
+
 				cd "$sm_path" &&
 				eval "$@" &&
+				eval "$UNSET_CMD" &&
 				if test -n "$recursive"
 				then
 					cmd_foreach "--recursive" "$@"
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 9b69fe2..46ac746 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -313,4 +313,33 @@ test_expect_success 'command passed to foreach --recursive retains notion of std
 	test_cmp expected actual
 '
 
+cat > expect <<EOF
+Entering 'nested1'
+nested1 nested1 wonky"value
+Entering 'nested1/nested2'
+nested2 nested2 another wonky"value
+Entering 'nested1/nested2/nested3'
+nested3 nested3
+Entering 'nested1/nested2/nested3/submodule'
+submodule submodule
+Entering 'sub1'
+sub1 sub1
+Entering 'sub2'
+sub2 sub2
+Entering 'sub3'
+sub3 sub3
+EOF
+
+test_expect_success 'test foreach environment variables' '
+	(
+		cd clone2 &&
+		git config -f .gitmodules submodule.nested1.wonky-var "wonky\"value" &&
+		git config -f nested1/.gitmodules submodule.nested2.wonky-var "another wonky\"value" &&
+		git submodule foreach --recursive "echo \$path \$submodule_path \$submodule_wonky_var" > ../actual
+	) &&
+	test_i18ncmp expect actual
+'
+#
+#"echo \$toplevel-\$name-\$submodule_path-\$submodule_url"
+
 test_done
-- 
1.8.0.3.gc2eb43a
Previous: Heiko VoigtNext: Heiko Voigt
Message 45 of 49 in “git-submodule add: Add -r/--record option”
  1. 0/3 git-submodule add: Add -r/--record optionW. Trevor King, Nov 9, 2012
  2. 1/3 git-submodule add: Add -r/--record optionW. Trevor King, Nov 9, 2012
  3. Junio C HamanoNov 9, 2012
  4. Heiko VoigtNov 9, 2012
  5. W. Trevor KingNov 10, 2012
  6. W. Trevor KingNov 10, 2012
  7. Heiko VoigtNov 17, 2012
  8. Junio C HamanoNov 11, 2012
  9. W. Trevor KingNov 11, 2012
  10. Heiko VoigtNov 17, 2012
  11. W. Trevor KingNov 17, 2012
  12. Heiko VoigtNov 17, 2012
  13. W. Trevor KingNov 17, 2012
  14. Junio C HamanoNov 20, 2012
  15. W. Trevor KingNov 20, 2012
  16. Junio C HamanoNov 20, 2012
  17. W. Trevor KingNov 20, 2012
  18. Junio C HamanoNov 20, 2012
  19. Heiko VoigtNov 23, 2012
  20. Sascha CunzNov 23, 2012
  21. Heiko VoigtNov 23, 2012
  22. W. Trevor KingNov 23, 2012
  23. W. Trevor KingNov 23, 2012
  24. W. Trevor KingNov 23, 2012
  25. 0/4 git-submodule add: Add --local-branch optionW. Trevor King, Nov 26, 2012
  26. 1/4 git-submodule add: Add --local-branch optionW. Trevor King, Nov 26, 2012
  27. 2/4 git-submodule init: Record submodule.<name>.branch in repository config.W. Trevor King, Nov 26, 2012
  28. Jens LehmannNov 27, 2012
  29. W. Trevor KingNov 28, 2012
  30. 3/4 git-submodule update: Add --branch optionW. Trevor King, Nov 26, 2012
  31. Heiko VoigtNov 27, 2012
  32. W. Trevor KingNov 27, 2012
  33. [RFC] git-submodule update: Add --commit optionW. Trevor King, Nov 29, 2012
  34. W. Trevor KingNov 29, 2012
  35. W. Trevor KingNov 29, 2012
  36. 4/4 Hack fix for 'submodule update does not fetch already present commits'W. Trevor King, Nov 26, 2012
  37. W. Trevor KingNov 27, 2012
  38. Heiko VoigtNov 27, 2012
  39. W. Trevor KingNov 27, 2012
  40. Heiko VoigtNov 27, 2012
  41. W. Trevor KingNov 28, 2012
  42. Phil HordNov 29, 2012
  43. W. Trevor KingNov 27, 2012
  44. Heiko VoigtNov 27, 2012
  45. 2/3 git-submodule foreach: export .gitmodules settings as variablesW. Trevor King, Nov 9, 2012
  46. Heiko VoigtNov 9, 2012
  47. W. Trevor KingNov 10, 2012
  48. 3/3 git-submodule: Motivate --record with an example use caseW. Trevor King, Nov 9, 2012
  49. W. Trevor KingNov 10, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.