[PATCH] git-submodule - allow a relative path as the subproject url

Subsystems: documentation, the rest

DORMANTno replies

4 messages, 3 authors, 2016-06-15 · open the first message on its own page

[PATCH] git-submodule - allow a relative path as the subproject url

From: Mark Levedahl <hidden>
Date: 2016-06-15 22:43:36

This allows a subproject's location to be specified and stored as relative
to the parent project's location (e.g., ./foo, or ../foo). This url is
stored in .gitmodules as given. It is resolved into an absolute url be
appending it to the parent project's url when the information is written
to .git/config (i.e., during submodule add for the originator, and
submodule init for a downstream recipient). This allows cloning of the
project to work "as expected" if the project is hosted on a different
server than when the subprojects were added.

Signed-off-by: Mark Levedahl <redacted>
---
 Documentation/git-submodule.txt |    3 +++
 git-submodule.sh                |   34 ++++++++++++++++++++++++++++++----
 2 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 2c48936..d421677 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -21,6 +21,9 @@ add::
 	repository is cloned at the specified path, added to the
 	changeset and registered in .gitmodules.   If no path is
 	specified, the path is deduced from the repository specification.
+        If the repository url begins with ./ or ../, it is stored as
+        given but resolved as a relative path from the main project's
+        url when cloning.
 
 status::
 	Show the status of the submodules. This will print the SHA-1 of the
diff --git a/git-submodule.sh b/git-submodule.sh
index 3320998..c553e14 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -39,6 +39,19 @@ get_repo_base() {
 	) 2>/dev/null
 }
 
+# Get parent project's url
+get_parent_url ()
+{
+	# need to append this on parent project's url
+	branch="$(git branch --no-color | sed -ne 's/^\* //p')"
+	test -n "$branch" || die "I do not know what branch you are on: $branch"
+	upstream="$(git config branch.$branch.remote)"
+	test -n "$upstream" || die "Cannot find upstream repo for branch $branch"
+	uprepo="$(git config remote.$upstream.url)"
+	test -n "$upstream" || die "Cannot find url for repo $uprepo"
+	echo "$uprepo"
+}
+
 #
 # Map submodule path to submodule name
 #
@@ -105,9 +118,16 @@ module_add()
 
 	# Turn the source into an absolute path if
 	# it is local
-	if base=$(get_repo_base "$repo"); then
-		repo="$base"
-	fi
+	case $repo in
+	.*)
+		realrepo="$(get_parent_url)/$repo" ;;
+	*)
+		if base=$(get_repo_base "$repo"); then
+			repo="$base"
+			realrepo=$repo
+		fi
+		;;
+	esac
 
 	# Guess path from repo if not specified or strip trailing slashes
 	if test -z "$path"; then
@@ -122,7 +142,7 @@ module_add()
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
 	die "'$path' already exists in the index"
 
-	module_clone "$path" "$repo" || exit
+	module_clone "$path" "$realrepo" || exit
 	(unset GIT_DIR && cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) ||
 	die "Unable to checkout submodule '$path'"
 	git add "$path" ||
@@ -153,6 +173,12 @@ modules_init()
 		test -z "$url" &&
 		die "No url found for submodule path '$path' in .gitmodules"
 
+		# Possibly a url relative to parent
+		case $url in
+		.*)
+			url="$(get_parent_url)/$url";;
+		esac
+
 		git config submodule."$name".url "$url" ||
 		die "Failed to register url for submodule path '$path'"
 
-- 
1.5.3.1.36.gf01e8

Re: [PATCH] git-submodule - allow a relative path as the subproject url

From: Michael Smith <hidden>
Date: 2016-06-15 22:43:36

Mark Levedahl <mdl123 <at> verizon.net> writes:
This allows a subproject's location to be specified and stored as relative
to the parent project's location (e.g., ./foo, or ../foo). This url is
stored in .gitmodules as given. 
This allows cloning of the project to work "as expected" if the project
is hosted on a different server than when the subprojects were added.
Hi Mark,

I have a use case where this would be very handy -- two teams geographically
separated. But in the end I think I disagree with it: it's not up to me, as the
person creating a superproject, to decide that anyone who forks or clones it
also has to clone all the submodules.

Instead they can decide themselves by editing .git/config between "git submodule
init" and "git submodule update", or by branching .gitmodules.

By the way:
+# Get parent project's url
+get_parent_url ()
+{
+	# need to append this on parent project's url
+	branch="$(git branch --no-color | sed -ne 's/^\* //p')"
+	test -n "$branch" || die "I do not know what branch you are on: $branch"
+	upstream="$(git config branch.$branch.remote)"
+	test -n "$upstream" || die "Cannot find upstream repo for branch $branch"
+	uprepo="$(git config remote.$upstream.url)"
+	test -n "$upstream" || die "Cannot find url for repo $uprepo"
+	echo "$uprepo"
+}
...
+	case $repo in
+	.*)
+		realrepo="$(get_parent_url)/$repo" ;;
If you source git-parse-remote, you can use

                realrepo="$(get_remote_url "$(get_default_remote)")$repo"

Mike

[PATCH] git-submodule - allow a relative path as the subproject url

From: Mark Levedahl <hidden>
Date: 2016-06-15 22:43:36

This allows a subproject's location to be specified and stored as relative
to the parent project's location (e.g., ./foo, or ../foo). This url is
stored in .gitmodules as given. It is resolved into an absolute url by
appending it to the parent project's url when the information is written
to .git/config (i.e., during submodule add for the originator, and
submodule init for a downstream recipient). This allows cloning of the
project to work "as expected" if the project is hosted on a different
server than when the subprojects were added.

Signed-off-by: Mark Levedahl <redacted>
---
This patch is slightly improved as it removes embedded ./ and ../ sequences
from the url constructed from a base and relative part. It also avoids use
of git-branch in favor of git-symbolic-ref.

 Documentation/git-submodule.txt |    3 ++
 git-submodule.sh                |   53 ++++++++++++++++++++++++++++++++++----
 2 files changed, 50 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 2c48936..d421677 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -21,6 +21,9 @@ add::
 	repository is cloned at the specified path, added to the
 	changeset and registered in .gitmodules.   If no path is
 	specified, the path is deduced from the repository specification.
+        If the repository url begins with ./ or ../, it is stored as
+        given but resolved as a relative path from the main project's
+        url when cloning.

 status::
 	Show the status of the submodules. This will print the SHA-1 of the
diff --git a/git-submodule.sh b/git-submodule.sh
index 3320998..5bf4551 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -39,6 +39,32 @@ get_repo_base() {
 	) 2>/dev/null
 }

+# Resolve relative url by appending to parent's url
+resolve_relative_url ()
+{
+	branch="$(git symbolic-ref HEAD 2>/dev/null)"
+	remote="$(git config branch.${branch#refs/heads/}.remote)"
+	remote="${remote:-origin}"
+	remoteurl="$(git config remote.$remote.url)" ||
+		die "remote ($remote) does not have a url in .git/config"
+	url="$1"
+	while test -n "$url"
+	do
+		case "$url" in
+		../*)
+			url="${url#../}"
+			remoteurl="${remoteurl%/*}"
+			;;
+		./*)
+			url="${url#./}"
+			;;
+		*)
+			break;;
+		esac
+	done
+	echo "$remoteurl/$url"
+}
+
 #
 # Map submodule path to submodule name
 #
@@ -103,11 +129,19 @@ module_add()
 		usage
 	fi

-	# Turn the source into an absolute path if
-	# it is local
-	if base=$(get_repo_base "$repo"); then
-		repo="$base"
-	fi
+	case $repo in
+	./*|../*)
+		# dereference source url relative to parent's url
+		realrepo="$(resolve_relative_url $repo)" ;;
+	*)
+		# Turn the source into an absolute path if
+		# it is local
+		if base=$(get_repo_base "$repo"); then
+			repo="$base"
+			realrepo=$repo
+		fi
+		;;
+	esac

 	# Guess path from repo if not specified or strip trailing slashes
 	if test -z "$path"; then
@@ -122,7 +156,7 @@ module_add()
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
 	die "'$path' already exists in the index"

-	module_clone "$path" "$repo" || exit
+	module_clone "$path" "$realrepo" || exit
 	(unset GIT_DIR && cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) ||
 	die "Unable to checkout submodule '$path'"
 	git add "$path" ||
@@ -153,6 +187,13 @@ modules_init()
 		test -z "$url" &&
 		die "No url found for submodule path '$path' in .gitmodules"

+		# Possibly a url relative to parent
+		case $url in
+		./*|../*)
+			url="$(resolve_relative_url $url)"
+			;;
+		esac
+
 		git config submodule."$name".url "$url" ||
 		die "Failed to register url for submodule path '$path'"

--
1.5.3.2.9.g69b29

Re: [PATCH] git-submodule - allow a relative path as the subproject url

From: Mark Levedahl <hidden>
Date: 2016-06-15 22:43:36

Michael Smith wrote:
Hi Mark,

I have a use case where this would be very handy -- two teams geographically
separated. But in the end I think I disagree with it: it's not up to me, as the
person creating a superproject, to decide that anyone who forks or clones it
also has to clone all the submodules.

  
With or without the patch, the cloner has to execute "submodule init" 
and "submodule update" to actually check things out. Absolutely nothing 
has changed there: it still requires the same explicit actions to get 
the submodules.

This patch does not alter any existing behavior: it provides an 
additional option, and one that is very useful in a world of mirrors. My 
particular use case is for a geographically distributed work flow 
involving several mirrors, all of which are behind firewalls and/or 
connected only to a LAN. There is no single server that is available to 
everyone, hence no single url for a submodule is usable across the 
group. By offering the *option* (and it is only an option) to make the 
urls relative to the super-project, the super-project can be usefully 
shared.
Instead they can decide themselves by editing .git/config between "git submodule
init" and "git submodule update", or by branching .gitmodules.
  
Yes, a person can edit .gitmodules, or can edit .git/config, in order to 
tell git where things are. But why should they *have* to when relative 
urls will suffice and git can take care of this transparently.
If you source git-parse-remote, you can use

                realrepo="$(get_remote_url "$(get_default_remote)")$repo"

Mike
  
Yes, the patch itself can be improved, am sending a revised one.

Mark
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help