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

[PATCH v4 2/2] submodule: fix handling of relative superproject origin URLs

From
Jon Seymour <jon.seymour@gmail.com>
Date
May 23, 2012, 16:45 UTC
Message-ID
<1337791554-31294-3-git-send-email-jon.seymour@gmail.com>
In-Reply-To
<1337791554-31294-1-git-send-email-jon.seymour@gmail.com>

When the origin URL of the superproject is itself relative, an operation such as git submodule add, init or sync may result in either the submodule.{name}.url configuration property of the superproject referring to the incorrect location or remote.origin.url configuration property of the submodule referring to the incorrect location or both these conditions. In some cases, git submodule fails to update the configuration and fails with an error condition.

The issue arises in these cases because the origin URL of the superproject needs to be prepended with a prefix that navigates from the submodule to the superproject so that when the submodule URL is concatenated the resulting URL is relative to the working tree of the submodule.

This change fixes handling for relative superproject origin URLs
for 6 cases:
  foo
  foo/bar
  ./foo
  ./foo/bar
  ../foo
  ../foo/bar

In each case, the configuration properties in the superproject's configuration and the submodule's configuration refer to the correct, relative, location of the submodule's origin repo. In all cases, the configured paths are relative to the working trees of the repositories containing the configuration.

Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
---
 git-submodule.sh           | 17 +++++++++++++++--
 t/t7400-submodule-basic.sh | 12 +++++-------
 t/t7403-submodule-sync.sh  | 21 +++++++++++----------
 3 files changed, 31 insertions(+), 19 deletions(-)
diff --git a/git-submodule.sh b/git-submodule.sh
index 64a70d6..3e943de 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -37,6 +37,8 @@ resolve_relative_url ()
 	remoteurl=$(git config "remote.$remote.url") ||
 		remoteurl=$(pwd) # the repository is its own authoritative upstream
 	url="$1"
+	prefix="$2"
+	remoteurl=$(echo "$remoteurl" | sed "s|^[^/:\\.][^:]*\$|./&|")
 	remoteurl=${remoteurl%/}
 	sep=/
 	while test -n "$url"
@@ -45,6 +47,11 @@ resolve_relative_url ()
 		../*)
 			url="${url#../}"
 			case "$remoteurl" in
+			.*/*)
+				remoteurl="${remoteurl%/*}"
+				remoteurl="${remoteurl#./}"
+				remoteurl="${prefix}${remoteurl}"
+				;;
 			*/*)
 				remoteurl="${remoteurl%/*}"
 				;;
@@ -64,7 +71,7 @@ resolve_relative_url ()
 			break;;
 		esac
 	done
-	echo "$remoteurl$sep${url%/}"
+	echo "${remoteurl%/.}$sep${url%/}"
 }
 
 #
@@ -964,8 +971,14 @@ cmd_sync()
 		# Possibly a url relative to parent
 		case "$url" in
 		./*|../*)
+			up_path="$(echo "$sm_path" | sed "s/[^/]*/../g")" &&
+			up_path=${up_path%/}/ &&
+			remoteurl=$(resolve_relative_url "$url" "$up_path") &&
 			url=$(resolve_relative_url "$url") || exit
 			;;
+		*)
+			remoteurl="$url"
+			;;
 		esac
 
 		if git config "submodule.$name.url" >/dev/null 2>/dev/null
@@ -979,7 +992,7 @@ cmd_sync()
 				clear_local_git_env
 				cd "$sm_path"
 				remote=$(get_default_remote)
-				git config remote."$remote".url "$url"
+				git config remote."$remote".url "$remoteurl"
 			)
 			fi
 		fi
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 97e7a73..f2f907f 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -507,17 +507,15 @@ test_expect_success 'relative path works with user@host:path' '
 	)
 '
 
-test_expect_success 'relative path works with foo' "
+test_expect_success 'relative path works with foo' '
 	(
 		cd reltest &&
 		cp pristine-.git-config .git/config &&
 		git config remote.origin.url foo &&
-		echo \"cannot strip one component off url 'foo'\" >expect &&
-		test_must_fail git submodule init 2>actual &&
-		cat actual &&
-		test_cmp expect actual
+		git submodule init &&
+		test "$(git config submodule.sub.url)" = ./subrepo
 	)
-"
+'
 
 test_expect_success 'relative path works with foo/bar' '
 	(
@@ -545,7 +543,7 @@ test_expect_success 'relative path works with ./foo/bar' '
 		cp pristine-.git-config .git/config &&
 		git config remote.origin.url ./foo/bar &&
 		git submodule init &&
-		test "$(git config submodule.sub.url)" = ./foo/subrepo
+		test "$(git config submodule.sub.url)" = foo/subrepo
 	)
 '
 
diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
index 3784c9b..583fe21 100755
--- a/t/t7403-submodule-sync.sh
+++ b/t/t7403-submodule-sync.sh
@@ -88,21 +88,22 @@ test_expect_success '"git submodule sync" should not vivify uninteresting submod
 	)
 '
 
-test_expect_success '"git submodule sync" handles origin URL of the form foo' "
+test_expect_success '"git submodule sync" handles origin URL of the form foo' '
 	(cd relative-clone &&
 	 git remote set-url origin foo
-	 echo \"cannot strip one component off url 'foo'\" > expect &&
-	 test_must_fail git submodule sync 2> actual &&
-	 test_cmp expect actual
+	 git submodule sync &&
+	(cd submodule &&
+	 test "$(git config remote.origin.url)" == "../submodule"
 	)
-"
+	)
+'
 
 test_expect_success '"git submodule sync" handles origin URL of the form foo/bar' '
 	(cd relative-clone &&
 	 git remote set-url origin foo/bar
 	 git submodule sync &&
 	(cd submodule &&
-	 test "$(git config remote.origin.url)" == "foo/submodule"
+	 test "$(git config remote.origin.url)" == "../foo/submodule"
 	)
 	)
 '
@@ -112,7 +113,7 @@ test_expect_success '"git submodule sync" handles origin URL of the form ./foo'
 	 git remote set-url origin ./foo
 	 git submodule sync &&
 	(cd submodule &&
-	 test "$(git config remote.origin.url)" == "./submodule"
+	 test "$(git config remote.origin.url)" == "../submodule"
 	)
 	)
 '
@@ -122,7 +123,7 @@ test_expect_success '"git submodule sync" handles origin URL of the form ./foo/b
 	 git remote set-url origin ./foo/bar
 	 git submodule sync &&
 	(cd submodule &&
-	 test "$(git config remote.origin.url)" == "./foo/submodule"
+	 test "$(git config remote.origin.url)" == "../foo/submodule"
 	)
 	)
 '
@@ -132,7 +133,7 @@ test_expect_success '"git submodule sync" handles origin URL of the form ../foo'
 	 git remote set-url origin ../foo
 	 git submodule sync &&
 	(cd submodule &&
-	 test "$(git config remote.origin.url)" == "../submodule"
+	 test "$(git config remote.origin.url)" == "../../submodule"
 	)
 	)
 '
@@ -142,7 +143,7 @@ test_expect_success '"git submodule sync" handles origin URL of the form ../foo/
 	 git remote set-url origin ../foo/bar
 	 git submodule sync &&
 	(cd submodule &&
-	 test "$(git config remote.origin.url)" == "../foo/submodule"
+	 test "$(git config remote.origin.url)" == "../../foo/submodule"
 	)
 	)
 '
-- 
1.7.10.2.594.g24e850d
Previous: Jon SeymourNext: Jens Lehmann
Message 7 of 10 in “submodule: fix handling of relative superproject origin URLs”
  1. 0/2 submodule: fix handling of relative superproject origin URLsJon Seymour, May 23, 2012
  2. 1/2 submodule: document handling of relative superproject origin URLsJon Seymour, May 23, 2012
  3. Jens LehmannMay 23, 2012
  4. Junio C HamanoMay 23, 2012
  5. Jens LehmannMay 23, 2012
  6. Jon SeymourMay 23, 2012
  7. 2/2 submodule: fix handling of relative superproject origin URLsJon Seymour, May 23, 2012
  8. Jens LehmannMay 23, 2012
  9. Jon SeymourMay 23, 2012
  10. Jon SeymourMay 24, 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.