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

[RFC/PATCH] add update to branch support for "floating submodules"

From
Heiko Voigt <hvoigt@hvoigt.net>
Date
Nov 9, 2011, 17:40 UTC
Message-ID
<20111109174027.GA28825@book.fritz.box>

This adds the capability to configure a branch which submodule update will use to checkout the tips sha1 instead of the registered one.

It will first attempt to read the configuration directly from the currently checked out .gitmodules file from the key submodule.$name.branch. This configuration can be overridden by local user configuration values. The parameter --branch can be used to specify/override the branch using the commandline. The parameter --checkout can be used to switch to the exact model for all submodules.

Such a thing is helpful if a user wants to follow a defined branches tip in the submodule. Image such a branch is the stable branch for some central library or similar.

When the newly checked out tip will not match the registered sha1 in the superproject it will show up as a change as usual. You can imagine this as a configuration which lets the upstream project tell a user the branch it usually updates to. The usual revision control is still in place. ---

This is almost ready but I would like to know what users of the "floating submodule" think about this.

 Documentation/git-submodule.txt |   26 +++++++++--
 git-submodule.sh                |   47 ++++++++++++++++++++
 t/t7406-submodule-update.sh     |   93 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 162 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 6ec3fef..b8affa3 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -133,9 +133,11 @@ init::
 update::
 	Update the registered submodules, i.e. clone missing submodules and
 	checkout the commit specified in the index of the containing repository.
-	This will make the submodules HEAD be detached unless `--rebase` or
-	`--merge` is specified or the key `submodule.$name.update` is set to
-	`rebase`, `merge` or `none`.
+	This will make the submodules HEAD be detached. This will not
+	happen if `--rebase`, `--merge` or `--branch` are specified.
+	Also if the key `submodule.$name.update` is set to `rebase`,
+	`merge` or `none`. If `submodule.$name.branch` is set to some
+	local branch this will also not happen.
 +
 If the submodule is not yet initialized, and you just want to use the
 setting as stored in .gitmodules, you can automatically initialize the
@@ -146,7 +148,16 @@ registered submodules, and update any nested submodules within.
 +
 If the configuration key `submodule.$name.update` is set to `none` the
 submodule with name `$name` will not be updated by default. This can be
-overriden by adding `--checkout` to the command.
+overriden by adding `--checkout` to the command. `--checkout` can also
+be used to enforce exact checkout of submodule sha1's.
++
+If the configuration key `submodule.$name.branch` is set to some valid
+branch in the submodule named by `$name` the submodule will be updated
+to the tip of that branch instead of the registered sha1. This option
+can either be set in .gitmodules or via git's configuration. Gits local
+configuration takes precedence over .gitmodules. If you want to override
+the branch checkout you can use the value `HEAD` to tell git to checkout
+exactly the registered sha1.
 
 summary::
 	Show commit summary between the given commit (defaults to HEAD) and
@@ -252,6 +263,13 @@ OPTIONS
 	If the key `submodule.$name.update` is set to `rebase`, this option is
 	implicit.
 
+--branch::
+	This option is only valid for the update command. You can use
+	this parameter to specify which branch you want to update all
+	submodules to. This is helpful if you want to update all
+	submodules to the tip of a certain branch or need to work on a
+	branch for all submodules for some time.
+
 --init::
 	This option is only valid for the update command.
 	Initialize all submodules for which "git submodule init" has not been
diff --git a/git-submodule.sh b/git-submodule.sh
index 3adab93..a4b117b 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -465,6 +465,14 @@ cmd_update()
 		--checkout)
 			update="checkout"
 			;;
+		--branch=*)
+			case "$1" in
+			*=*)
+				update="checkout"
+				branch=`expr "z$1" : 'z--[^=]*=\(.*\)'` ;;
+			*)
+				usage ;;
+			esac ;;
 		--)
 			shift
 			break
@@ -504,6 +512,45 @@ cmd_update()
 			update_module=$(git config submodule."$name".update)
 		fi
 
+		if ! test -z "$branch"
+		then
+			branch_module=$branch
+		else
+			if test "$update" != "checkout"
+			then
+				branch_module=$(git config submodule."$name".branch)
+				if test -z "$branch_module"
+				then
+					branch_module=$(git config -f .gitmodules --get submodule."$name".branch)
+				fi
+			fi
+		fi
+
+		if test "$branch_module" = "HEAD"
+		then
+			branch_module=
+		fi
+
+		if ! test -z "$branch_module"
+		then
+			(clear_local_git_env; cd "$path" &&
+			 if test ! $nofetch
+			 then
+				git-fetch --all >/dev/null 2>/dev/null || exit 1
+			 fi) ||
+			die "$(eval_gettext "Unable to fetch submodule in path '\$path'")"
+
+			sha1=$(clear_local_git_env; cd "$path" &&
+				git rev-parse $branch_module) ||
+			say "$(eval_gettext "Unable to find branch '\$branch_module' in submodule path '\$path'")"
+		fi
+
+		if test "$branch" -a "$update" != "checkout"
+		then
+			die "$(eval_gettext "You can not set update='\$update' and
+use a branch for submodule '\$path'")"
+		fi
+
 		if test "$update_module" = "none"
 		then
 			echo "Skipping submodule '$path'"
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 33b292b..517ed83 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -611,4 +611,97 @@ test_expect_success 'submodule update places git-dir in superprojects git-dir re
 	)
 '
 
+test_expect_success '--branch updates follow the given branch' '
+	git clone . branch &&
+	(cd branch &&
+		git submodule add ./submodule submodule1 &&
+		git submodule add ./submodule submodule2 &&
+		(cd submodule1 &&
+			git rev-parse HEAD >../expected1 &&
+			git checkout HEAD^) &&
+		(cd submodule2 &&
+			git rev-parse HEAD >../expected2 &&
+			git checkout HEAD^) &&
+		git add submodule1 &&
+		git add submodule2 &&
+		git commit -m "add submodule1 and submodule2" &&
+		git submodule update --branch=origin/master &&
+		(cd submodule1 && git rev-parse HEAD >../actual1) &&
+		(cd submodule2 && git rev-parse HEAD >../actual2) &&
+		test_cmp expected1 actual1 &&
+		test_cmp expected2 actual2
+	)
+'
+
+cat >branch/expect_status <<EOF
+ M submodule1
+EOF
+
+check_submodule_one_follows()
+{
+	(cd submodule1 &&
+		git rev-parse origin/master >../expected1 &&
+		git rev-parse HEAD >../actual1) &&
+	(cd submodule2 &&
+		git rev-parse origin/master^ >../expected2 &&
+		git rev-parse HEAD >../actual2) &&
+	test_cmp expected1 actual1 &&
+	test_cmp expected2 actual2 &&
+	git status --porcelain --untracked-files=no >actual_status &&
+	test_cmp expect_status actual_status
+}
+
+check_both_submodules_exact()
+{
+	(cd submodule1 &&
+		git rev-parse origin/master^ >../expected1 &&
+		git rev-parse HEAD >../actual1) &&
+	(cd submodule2 &&
+		git rev-parse origin/master^ >../expected2 &&
+		git rev-parse HEAD >../actual2) &&
+	test_cmp expected1 actual1 &&
+	test_cmp expected2 actual2 &&
+	test -z "$(git status --porcelain --untracked-files=no)"
+}
+
+test_expect_success 'local branch configuration follows branch' '
+	(cd branch &&
+		git submodule update &&
+		check_both_submodules_exact &&
+		git config submodule.submodule1.branch origin/master &&
+		git submodule update &&
+		check_submodule_one_follows
+	)
+'
+
+test_expect_success '.gitmodules branch configuration follows branch' '
+	(cd branch &&
+		git config --unset submodule.submodule1.branch &&
+		git submodule update &&
+		check_both_submodules_exact &&
+		git config -f .gitmodules submodule.submodule1.branch origin/master &&
+		git add .gitmodules &&
+		git commit -m ".gitmodules follows branch" &&
+		git submodule update &&
+		check_submodule_one_follows
+	)
+'
+
+test_expect_success '--checkout commandline overrides branch config' '
+	(cd branch &&
+		git submodule update --checkout &&
+		check_both_submodules_exact
+	)
+'
+
+test_expect_success 'local config overrides .gitmodules branch config' '
+	(cd branch &&
+		git submodule update &&
+		check_submodule_one_follows &&
+		git config submodule.submodule1.branch HEAD &&
+		git submodule update &&
+		check_both_submodules_exact
+	)
+'
+
 test_done
-- 
1.7.7.433.gcf1e7
Next: Junio C Hamano
Message 1 of 27 in “add update to branch support for "floating submodules"”
  1. add update to branch support for "floating submodules"Heiko Voigt, Nov 9, 2011
  2. Junio C HamanoNov 9, 2011
  3. Heiko VoigtNov 29, 2011
  4. Leif GruenwoldtDec 10, 2011
  5. Jonathan NiederDec 10, 2011
  6. Junio C HamanoDec 10, 2011
  7. Leif GruenwoldtDec 10, 2011
  8. Andreas T.AuerDec 12, 2011
  9. Leif GruenwoldtDec 12, 2011
  10. Andreas T.AuerDec 12, 2011
  11. Leif GruenwoldtDec 12, 2011
  12. Jens LehmannDec 12, 2011
  13. Phil HordDec 12, 2011
  14. Marc BranchaudDec 13, 2011
  15. Jens LehmannDec 13, 2011
  16. Marc BranchaudDec 13, 2011
  17. Junio C HamanoDec 12, 2011
  18. Phil HordDec 13, 2011
  19. Jens LehmannDec 13, 2011
  20. Phil HordJan 30, 2012
  21. Jens LehmannJan 31, 2012
  22. Phil HordJan 31, 2012
  23. Jens LehmannFeb 1, 2012
  24. Phil HordFeb 6, 2012
  25. Jens LehmannFeb 6, 2012
  26. Brandon CaseyDec 13, 2011
  27. Gioele BarabucciDec 10, 2011

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.