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

[PATCH 1/3] git-submodule - Follow top-level remote on init/update/clone

From
Mark Levedahl <mlevedahl@gmail.com>
Date
Feb 9, 2008, 16:57 UTC
Message-ID
<1202576245-284-1-git-send-email-mlevedahl@gmail.com>

This change allows the remote used for relative submodules (those defined using a url that is relative to their parent) to be defined by explicit definition on the command line or through the top-level project's branch.<name>.remote configuration. This override is applied *only* to submodules defined using a url relative to the top-level project's url, under the assumption that such modules are logically part of the same project and managed as a unit. For relative submodules, the given remote will be defined in each submodule using the relative url applied to the top-level's url the first time the remote is used. Any existing remote definition is unaffected, so this can be changed manually by the user at any time.

Submodules defined using an absolute url are unaffected.
Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
---
 Documentation/git-submodule.txt |   16 +++++++-
 git-submodule.sh                |   76 ++++++++++++++++++++++++++++++++-------
 2 files changed, 77 insertions(+), 15 deletions(-)
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index e818e6e..4fc17f6 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -9,9 +9,9 @@ git-submodule - Initialize, update or inspect submodules
 SYNOPSIS
 --------
 [verse]
-'git-submodule' [--quiet] add [-b branch] [--] <repository> [<path>]
+'git-submodule' [--quiet] add [-b branch] [-r <remote>] [--] <repository> [<path>]
 'git-submodule' [--quiet] status [--cached] [--] [<path>...]
-'git-submodule' [--quiet] [init|update] [--] [<path>...]
+'git-submodule' [--quiet] [init|update] [-r <remote>] [--] [<path>...]
 
 
 COMMANDS
@@ -55,6 +55,18 @@ OPTIONS
 -b, --branch::
 	Branch of repository to add as submodule.
 
+-r remote::
+	Name of remote to use or define when working with relative submodules
+	(i.e., submodules whose url is given relative to the top-level
+	project). If this value is undefined, the top-level project's
+	branch.<name>.remote is used, and if that is undefined the default
+	"origin" is used. The remote will be defined in each relative
+	submodule as needed by appending the relative url to the top level
+	project's url. This option has no effect upon submodules defined
+	using an absolute url: such project's are cloned using the default
+	"origin," and are updated using the submodule's branch.<name>.remote
+	machinery and defaulting to "origin."
+
 --cached::
 	Display the SHA-1 stored in the index, not the SHA-1 of the currently
 	checked out submodule commit. This option is only valid for the
diff --git a/git-submodule.sh b/git-submodule.sh
index a6aaf40..b97bf18 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -4,15 +4,17 @@
 #
 # Copyright (c) 2007 Lars Hjemli
 
-USAGE='[--quiet] [--cached] [add <repo> [-b branch]|status|init|update] [--] [<path>...]'
+USAGE='[--quiet] [--cached] [add [-r remote] <repo> [-b branch]|status|init [-r remote]|update [-r remote]] [--] [<path>...]'
 OPTIONS_SPEC=
 . git-sh-setup
+. git-parse-remote
 require_work_tree
 
 command=
 branch=
 quiet=
 cached=
+remote=
 
 #
 # print stuff on stdout unless -q was specified
@@ -40,11 +42,13 @@ get_repo_base() {
 # 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"
+	remote="${remote:-$(get_default_remote)}"
+	remoteurl=$(git config remote.$remote.url)
+	if test -z "$remoteurl" ; then
+		echo >&2 "remote ($remote) does not have a url defined in .git/config"
+		return 1
+	fi
+	remoteurl="${remoteurl%/.git}"
 	url="$1"
 	while test -n "$url"
 	do
@@ -92,6 +96,7 @@ module_clone()
 {
 	path=$1
 	url=$2
+	remote=$3
 
 	# If there already is a directory at the submodule path,
 	# expect it to be empty (since that is the default checkout
@@ -107,7 +112,7 @@ module_clone()
 	test -e "$path" &&
 	die "A file already exist at path '$path'"
 
-	git-clone -n "$url" "$path" ||
+	git-clone -n -o "$remote" "$url" "$path" ||
 	die "Clone of '$url' into submodule path '$path' failed"
 }
 
@@ -129,6 +134,14 @@ cmd_add()
 			branch=$2
 			shift
 			;;
+		-r)
+			case "$2" in
+			'')
+				usage
+				;;
+			esac
+			remote="$2"; shift
+			;;
 		-q|--quiet)
 			quiet=1
 			;;
@@ -156,13 +169,16 @@ cmd_add()
 	case "$repo" in
 	./*|../*)
 		# dereference source url relative to parent's url
-		realrepo="$(resolve_relative_url $repo)" ;;
+		realremote=${remote:-$(get_default_remote)}
+		realrepo=$(resolve_relative_url $repo) || exit 1
+		;;
 	*)
 		# Turn the source into an absolute path if
 		# it is local
 		if base=$(get_repo_base "$repo"); then
 			repo="$base"
 		fi
+		realremote=origin
 		realrepo=$repo
 		;;
 	esac
@@ -180,8 +196,8 @@ cmd_add()
 	git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
 	die "'$path' already exists in the index"
 
-	module_clone "$path" "$realrepo" || exit
-	(unset GIT_DIR; cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) ||
+	module_clone "$path" "$realrepo" "$realremote" || exit
+	(unset GIT_DIR; cd "$path" && git checkout -q ${branch:+-b "$branch" "$realremote/$branch"}) ||
 	die "Unable to checkout submodule '$path'"
 	git add "$path" ||
 	die "Failed to add submodule '$path'"
@@ -206,6 +222,14 @@ cmd_init()
 		-q|--quiet)
 			quiet=1
 			;;
+		-r)
+			case "$2" in
+			'')
+				usage
+				;;
+			esac
+			remote="$2"; shift
+			;;
 		--)
 			shift
 			break
@@ -235,7 +259,7 @@ cmd_init()
 		# Possibly a url relative to parent
 		case "$url" in
 		./*|../*)
-			url="$(resolve_relative_url "$url")"
+			url=$(resolve_relative_url "$url") || exit 1
 			;;
 		esac
 
@@ -248,6 +272,8 @@ cmd_init()
 
 #
 # Update each submodule path to correct revision, using clone and checkout as needed
+# For relative submodules (defined using relative url), we use master project's remote
+# and define that in each submodule if not already there
 #
 # $@ = requested paths (default to all)
 #
@@ -260,6 +286,14 @@ cmd_update()
 		-q|--quiet)
 			quiet=1
 			;;
+		-r)
+			case "$2" in
+			'')
+				usage
+				;;
+			esac
+			remote="$2"; shift
+			;;
 		--)
 			shift
 			break
@@ -274,6 +308,7 @@ cmd_update()
 		shift
 	done
 
+	remote=${remote:-$(get_default_remote)}
 	git ls-files --stage -- "$@" | grep -e '^160000 ' |
 	while read mode sha1 stage path
 	do
@@ -290,7 +325,7 @@ cmd_update()
 
 		if ! test -d "$path"/.git
 		then
-			module_clone "$path" "$url" || exit
+			module_clone "$path" "$url" "$remote" || exit
 			subsha1=
 		else
 			subsha1=$(unset GIT_DIR; cd "$path" &&
@@ -298,9 +333,24 @@ cmd_update()
 			die "Unable to find current revision in submodule path '$path'"
 		fi
 
+		baseurl="$(GIT_CONFIG=.gitmodules git config submodule."$name".url)"
+		case "$baseurl" in
+		./*|../*)
+			fetch_remote=$remote
+			absurl=$(resolve_relative_url $baseurl) || exit 1
+			(unset GIT_DIR ; cd "$path" && git config remote."$fetch_remote".url > /dev/null) ||
+			(
+				unset GIT_DIR; cd "$path" && git remote add "$fetch_remote" "$absurl"
+			) || die "Unable to define remote '$fetch_remote' in submodule path '$path'"
+			;;
+		*)
+			fetch_remote=
+			;;
+		esac
+
 		if test "$subsha1" != "$sha1"
 		then
-			(unset GIT_DIR; cd "$path" && git-fetch &&
+			(unset GIT_DIR; cd "$path" && git-fetch $fetch_remote &&
 				git-checkout -q "$sha1") ||
 			die "Unable to checkout '$sha1' in submodule path '$path'"
 
-- 
1.5.4.47.gcca7b3
Next: Mark Levedahl
Message 1 of 8 in “git-submodule - Follow top-level remote on init/update/clone”
  1. 1/3 git-submodule - Follow top-level remote on init/update/cloneMark Levedahl, Feb 9, 2008
  2. 2/3 git-submodule - Allow adding a submodule in-placeMark Levedahl, Feb 9, 2008
  3. 3/3 Add t/t7401 - test submodule interaction with remotes machineryMark Levedahl, Feb 9, 2008
  4. Ping YinMar 3, 2008
  5. Johannes SchindelinFeb 11, 2008
  6. Mark LevedahlFeb 12, 2008
  7. Johannes SchindelinFeb 12, 2008
  8. Mark LevedahlFeb 12, 2008

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.