Subject: [PATCH 1/3] git-submodule: allow submodule name and path to differ

From: Lars Hjemli <[email-masked]>
Date: Sat, 9 Jun 2007 23:38:50 +0200

This teaches git-submodule to check module.*.path when looking for the
config for a submodule path. If no match is found it falls back to the
current behaviour (module.$path).

With this change a submodule can be checked out at different paths in
different revisions of the superproject without changing the submodule
properties in .git/config.

While at it, add a new testscript for named submodules. This is basically
the same tests as can be found in t7400, but modified for a submodule
with name != path.

Signed-off-by: Lars Hjemli <[email-masked]>
---
 Documentation/git-submodule.txt                    |   16 ++++---
 git-submodule.sh                                   |   44 +++++++++++++------
 ...submodule-basic.sh => t7401-submodule-named.sh} |   27 ++++++++----
 3 files changed, 59 insertions(+), 28 deletions(-)
 copy t/{t7400-submodule-basic.sh => t7401-submodule-named.sh} (82%)

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index f8fb80f..176e16d 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -24,8 +24,8 @@ status::
 
 init::
 	Initialize the submodules, i.e. register in .git/config each submodule
-	path and url found in .gitmodules. The key used in git/config is
-	`submodule.$path.url`. This command does not alter existing information
+	name and url found in .gitmodules. The key used in git/config is
+	`submodule.$name.url`. This command does not alter existing information
 	in .git/config.
 
 update::
@@ -50,11 +50,15 @@ OPTIONS
 
 FILES
 -----
-When initializing submodules, a .gitmodules file in the top-level directory
-of the containing repository is used to find the url of each submodule.
-This file should be formatted in the same way as $GIR_DIR/config. The key
-to each submodule url is "module.$path.url".
+The .gitmodules file in the top-level directory of the containing repository
+is used to map submodule path to submodule name. The map consist of keys
+named `module.$name.path` with a value matching the path found in the index of
+the containing repository. If no such key is found for a specific path, the
+submodule path is used as submodule name.
 
+During `git-submodule init` the url for each submodule is registered in
+.git/config of the containing repository. The url is located under the key
+`module.$name.url` in .gitmodules.
 
 AUTHOR
 ------
diff --git a/git-submodule.sh b/git-submodule.sh
index 8bdd99a..d9f0c91 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -25,6 +25,18 @@ say()
 	fi
 }
 
+#
+# Resolve submodule name from path, use path as name if no mapping exist
+#
+# $1 = path
+#
+module_name()
+{
+	name=$(GIT_CONFIG=.gitmodules git-config --get-regexp '^module\..*\.path$' "$1" |
+		sed -nre 's/^module\.(.+)\.path .+$/\1/p')
+	test -z "$name" && name="$1"
+	echo $name
+}
 
 #
 # Clone a submodule
@@ -62,18 +74,19 @@ modules_init()
 	git ls-files --stage -- "$@" | grep -e '^160000 ' |
 	while read mode sha1 stage path
 	do
-		# Skip already registered paths
-		url=$(git-config submodule."$path".url)
+		# Skip already registered submodules
+		name=$(module_name "$path")
+		url=$(git-config submodule."$name".url)
 		test -z "$url" || continue
 
-		url=$(GIT_CONFIG=.gitmodules git-config module."$path".url)
+		url=$(GIT_CONFIG=.gitmodules git-config module."$name".url)
 		test -z "$url" &&
-		die "No url found for submodule '$path' in .gitmodules"
+		die "No url found for submodule '$name', path '$path' in .gitmodules"
 
-		git-config submodule."$path".url "$url" ||
-		die "Failed to register url for submodule '$path'"
+		git-config submodule."$name".url "$url" ||
+		die "Failed to register url for submodule '$name', path '$path'"
 
-		say "Submodule '$path' registered with url '$url'"
+		say "Submodule '$name', path '$path' registered with url '$url'"
 	done
 }
 
@@ -87,13 +100,14 @@ modules_update()
 	git ls-files --stage -- "$@" | grep -e '^160000 ' |
 	while read mode sha1 stage path
 	do
-		url=$(git-config submodule."$path".url)
+		name=$(module_name "$path")
+		url=$(git-config submodule."$name".url)
 		if test -z "$url"
 		then
 			# Only mention uninitialized submodules when its
 			# path have been specified
 			test "$#" != "0" &&
-			say "Submodule '$path' not initialized"
+			say "Submodule '$name', path '$path' not initialized"
 			continue
 		fi
 
@@ -104,15 +118,15 @@ modules_update()
 
 		subsha1=$(unset GIT_DIR && cd "$path" &&
 			git-rev-parse --verify HEAD) ||
-		die "Unable to find current revision of submodule '$path'"
+		die "Unable to find current revision of submodule '$name', path '$path'"
 
 		if test "$subsha1" != "$sha1"
 		then
 			(unset GIT_DIR && cd "$path" && git-fetch &&
 				git-checkout -q "$sha1") ||
-			die "Unable to checkout '$sha1' in submodule '$path'"
+			die "Unable to checkout '$sha1' in submodule '$name', path '$path'"
 
-			say "Submodule '$path': checked out '$sha1'"
+			say "Submodule '$name', path '$path': checked out '$sha1'"
 		fi
 	done
 }
@@ -132,10 +146,12 @@ modules_list()
 	git ls-files --stage -- "$@" | grep -e '^160000 ' |
 	while read mode sha1 stage path
 	do
-		if ! test -d "$path"/.git
+		name=$(module_name "$path")
+		url=$(git-config submodule."$name".url)
+		if test -z "$url" || ! test -d "$path"/.git
 		then
 			say "-$sha1 $path"
-			continue;
+			continue
 		fi
 		revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1)
 		if git diff-files --quiet -- "$path"
diff --git a/t/t7400-submodule-basic.sh b/t/t7401-submodule-named.sh
similarity index 82%
copy from t/t7400-submodule-basic.sh
copy to t/t7401-submodule-named.sh
index 3940433..3c3d195 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7401-submodule-named.sh
@@ -3,10 +3,10 @@
 # Copyright (c) 2007 Lars Hjemli
 #
 
-test_description='Basic porcelain support for submodules
+test_description='Basic porcelain support for named submodules
 
 This test tries to verify basic sanity of the init, update and status
-subcommands of git-submodule.
+subcommands of git-submodule when a submodule name differs from its path.
 '
 
 . ./test-lib.sh
@@ -18,7 +18,7 @@ subcommands of git-submodule.
 #  -add directory lib to 'superproject', this creates a DIRLINK entry
 #  -add a couple of regular files to enable testing of submodule filtering
 #  -mv lib subrepo
-#  -add an entry to .gitmodules for path 'lib'
+#  -add an entry to .gitmodules for submodule 'foo'
 #
 test_expect_success 'Prepare submodule testing' '
 	mkdir lib &&
@@ -40,7 +40,7 @@ test_expect_success 'Prepare submodule testing' '
 	git-add a lib z &&
 	git-commit -m "super commit 1" &&
 	mv lib .subrepo &&
-	GIT_CONFIG=.gitmodules git-config module.lib.url git://example.com/lib.git
+	GIT_CONFIG=.gitmodules git-config module.foo.url git://example.com/libfoo.git
 '
 
 test_expect_success 'status should only print one line' '
@@ -52,14 +52,25 @@ test_expect_success 'status should initially be "missing"' '
 	git-submodule status | grep "^-$rev1"
 '
 
+test_expect_success 'init should fail when map from path to name is missing' '
+	if git-submodule init
+	then
+		echo "[OOPS] init should have failed"
+		false
+	elif ! GIT_CONFIG=.gitmodules git-config module.foo.path lib
+	then
+		echo "[OOPS] init failed but so did git-config"
+	fi
+'
+
 test_expect_success 'init should register submodule url in .git/config' '
 	git-submodule init &&
-	url=$(git-config submodule.lib.url) &&
-	if test "$url" != "git://example.com/lib.git"
+	url=$(git-config submodule.foo.url) &&
+	if test "$url" != "git://example.com/libfoo.git"
 	then
 		echo "[OOPS] init succeeded but submodule url is wrong"
 		false
-	elif ! git-config submodule.lib.url ./.subrepo
+	elif ! git-config submodule.foo.url ./.subrepo
 	then
 		echo "[OOPS] init succeeded but update of url failed"
 		false
@@ -72,7 +83,7 @@ test_expect_success 'update should fail when path is used by a file' '
 	then
 		echo "[OOPS] update should have failed"
 		false
-	elif test -f lib && test "$(cat lib)" != "hello"
+	elif test "$(cat lib)" != "hello"
 	then
 		echo "[OOPS] update failed but lib file was molested"
 		false
-- 
1.5.2.1.914.gbd3a7