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

[PATCH v4 3/4] git-submodule update: Add --branch option

From
W. Trevor King <wking@tremily.us>
Date
Nov 26, 2012, 21:00 UTC
Message-ID
<95edff1c97c513c555652014f9c2bbf61c8e7560.1353962698.git.wking@tremily.us>
In-Reply-To
<cover.1353962698.git.wking@tremily.us>
From: "W. Trevor King" <wking@tremily.us>

This allows users to checkout the current superproject-recorded-submodule-sha as a branch, avoiding the detached head state that the standard submodule update creates. This may be useful for the existing --rebase/--merge workflows which already avoid detached heads.

It is also useful if you want easy tracking of upstream branches. The particular upstream branch to be tracked is configured locally with .git/modules/<name>/config. With the new option Ævar's suggested

  $ git submodule foreach 'git checkout $(git config --file $toplevel/.gitm
odules submodule.$name.branch) && git pull'
reduces to a
  $ git submodule update --branch
after each supermodule .gitmodules edit, and a
  $ git submodule foreach 'git pull'

whenever you feel like updating the submodules. Your still on you're own to commit (or not) the updated submodule hashes in the superproject's .gitmodules.

Signed-off-by: W. Trevor King <wking@tremily.us>
---
 Documentation/git-submodule.txt | 20 +++++++++++------
 git-submodule.sh                | 48 +++++++++++++++++++++++++++++----------
 t/t7406-submodule-update.sh     | 50 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 98 insertions(+), 20 deletions(-)
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index d0b4436..34392a1 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -13,7 +13,7 @@ SYNOPSIS
 	      [-f|--force] [--reference <repository>] [--] <repository> [<path>]
 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] init [--] [<path>...]
-'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
+'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--branch] [--rebase]
 	      [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
 	      [commit] [--] [<path>...]
@@ -136,11 +136,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`. `none` can be overridden by specifying
-	`--checkout`.
+	checkout the commit specified in the index of the containing
+	repository.  This will make the submodules HEAD be detached unless
+	`--branch`, `--rebase`, `--merge` is specified or the key
+	`submodule.$name.update` is set to `branch`, `rebase`, `merge` or
+	`none`. `none` can be overridden by specifying `--checkout`.
 +
 If the submodule is not yet initialized, and you just want to use the
 setting as stored in .gitmodules, you can automatically initialize the
@@ -207,7 +207,13 @@ OPTIONS
 
 -b::
 --branch::
-	Branch of repository to add as submodule.
+	When used with the add command, gives the branch of repository to
+	add as submodule.
++
+When used with the update command, checks out a branch named
+`submodule.<name>.branch` (as set by `--local-branch`) pointing at the
+current HEAD SHA-1.  This is useful for commands like `update
+--rebase` that do not work on detached heads.
 
 --local-branch::
 	Record a branch name used as `submodule.<path>.branch` in
diff --git a/git-submodule.sh b/git-submodule.sh
index c51b6ae..28eb4b1 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -8,7 +8,7 @@ dashless=$(basename "$0" | sed -e 's/-/ /')
 USAGE="[--quiet] add [-b branch] [--local-branch[=<branch>]] [-f|--force] [--reference <repository>] [--] <repository> [<path>]
    or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] init [--] [<path>...]
-   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
+   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--branch] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
    or: $dashless [--quiet] foreach [--recursive] <command>
    or: $dashless [--quiet] sync [--] [<path>...]"
@@ -539,6 +539,9 @@ cmd_update()
 		-f|--force)
 			force=$1
 			;;
+		-b|--branch)
+			update="branch"
+			;;
 		-r|--rebase)
 			update="rebase"
 			;;
@@ -593,6 +596,7 @@ cmd_update()
 		fi
 		name=$(module_name "$sm_path") || exit
 		url=$(git config submodule."$name".url)
+		branch=$(git config submodule."$name".branch)
 		if ! test -z "$update"
 		then
 			update_module=$update
@@ -627,7 +631,7 @@ Maybe you want to use 'update --init'?")"
 			die "$(eval_gettext "Unable to find current revision in submodule path '\$sm_path'")"
 		fi
 
-		if test "$subsha1" != "$sha1" -o -n "$force"
+		if test "$subsha1" != "$sha1" -o -n "$force" -o "$update_module" = "branch"
 		then
 			subforce=$force
 			# If we don't already have a -f flag and the submodule has never been checked out
@@ -650,16 +654,21 @@ Maybe you want to use 'update --init'?")"
 			case ";$cloned_modules;" in
 			*";$name;"*)
 				# then there is no local change to integrate
-				update_module= ;;
+				case "$update_module" in
+					rebase|merge)
+						update_module=
+						;;
+				esac
+				;;
 			esac
 
 			must_die_on_failure=
 			case "$update_module" in
 			rebase)
 				command="git rebase"
-				die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$sm_path'")"
+				die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$sm_path'")"	
 				say_msg="$(eval_gettext "Submodule path '\$sm_path': rebased into '\$sha1'")"
-				must_die_on_failure=yes
+			must_die_on_failure=yes
 				;;
 			merge)
 				command="git merge"
@@ -674,15 +683,30 @@ Maybe you want to use 'update --init'?")"
 				;;
 			esac
 
-			if (clear_local_git_env; cd "$sm_path" && $command "$sha1")
+			if test "$subsha1" != "$sha1" -o -n "$force"
 			then
-				say "$say_msg"
-			elif test -n "$must_die_on_failure"
+				if (clear_local_git_env; cd "$sm_path" && $command "$sha1")
+				then
+					say "$say_msg"
+				elif test -n "$must_die_on_failure"
+				then
+					die_with_status 2 "$die_msg"
+				else
+					err="${err};$die_msg"
+					continue
+				fi
+			fi
+
+			if test "$update_module" = "branch" -a -n "$branch"
 			then
-				die_with_status 2 "$die_msg"
-			else
-				err="${err};$die_msg"
-				continue
+				if (clear_local_git_env; cd "$sm_path" &&
+					git branch -f "$branch" "$sha1" &&
+					git checkout "$branch")
+				then
+					say "$(eval_gettext "Submodule path '\$sm_path': checked out branch '\$branch'")"
+				else
+					err="${err};$(eval_gettext "Unable to checkout branch '\$branch' in submodule path '\$sm_path'")"
+				fi
 			fi
 		fi
 
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 1542653..c876a8b 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -6,7 +6,8 @@
 test_description='Test updating submodules
 
 This test verifies that "git submodule update" detaches the HEAD of the
-submodule and "git submodule update --rebase/--merge" does not detach the HEAD.
+submodule and "git submodule update --branch/--rebase/--merge" does not
+detach the HEAD.
 '
 
 . ./test-lib.sh
@@ -135,6 +136,53 @@ test_expect_success 'submodule update --force forcibly checks out submodules' '
 	)
 '
 
+test_expect_success 'submodule update --branch detaches without submodule.<name>.branch' '
+	(cd super/submodule &&
+	  git checkout master
+	) &&
+	(cd super &&
+	 (cd submodule &&
+	  compare_head
+	 ) &&
+	 git submodule update --branch submodule &&
+	 (cd submodule &&
+	  test "$(git status -s file)" = ""
+	 )
+	)
+'
+
+test_expect_success 'submodule update --branch staying on master' '
+	(cd super/submodule &&
+	  git checkout master
+	) &&
+	(cd super &&
+	 (cd submodule &&
+	  compare_head
+	 ) &&
+	 git config submodule.submodule.branch master
+	 git submodule update --branch submodule &&
+	 cd submodule &&
+	 test "refs/heads/master" = "$(git symbolic-ref -q HEAD)" &&
+	 compare_head
+	)
+'
+
+test_expect_success 'submodule update --branch creating a new branch' '
+	(cd super/submodule &&
+	  git checkout master
+	) &&
+	(cd super &&
+	 (cd submodule &&
+	  compare_head
+	 ) &&
+	 git config submodule.submodule.branch new-branch
+	 git submodule update --branch submodule &&
+	 cd submodule &&
+	 test "refs/heads/new-branch" = "$(git symbolic-ref -q HEAD)" &&
+	 compare_head
+	)
+'
+
 test_expect_success 'submodule update --rebase staying on master' '
 	(cd super/submodule &&
 	  git checkout master
-- 
1.8.0.3.g95edff1.dirty
Previous: W. Trevor KingNext: Heiko Voigt
Message 30 of 49 in “git-submodule add: Add -r/--record option”
  1. 0/3 git-submodule add: Add -r/--record optionW. Trevor King, Nov 9, 2012
  2. 1/3 git-submodule add: Add -r/--record optionW. Trevor King, Nov 9, 2012
  3. Junio C HamanoNov 9, 2012
  4. Heiko VoigtNov 9, 2012
  5. W. Trevor KingNov 10, 2012
  6. W. Trevor KingNov 10, 2012
  7. Heiko VoigtNov 17, 2012
  8. Junio C HamanoNov 11, 2012
  9. W. Trevor KingNov 11, 2012
  10. Heiko VoigtNov 17, 2012
  11. W. Trevor KingNov 17, 2012
  12. Heiko VoigtNov 17, 2012
  13. W. Trevor KingNov 17, 2012
  14. Junio C HamanoNov 20, 2012
  15. W. Trevor KingNov 20, 2012
  16. Junio C HamanoNov 20, 2012
  17. W. Trevor KingNov 20, 2012
  18. Junio C HamanoNov 20, 2012
  19. Heiko VoigtNov 23, 2012
  20. Sascha CunzNov 23, 2012
  21. Heiko VoigtNov 23, 2012
  22. W. Trevor KingNov 23, 2012
  23. W. Trevor KingNov 23, 2012
  24. W. Trevor KingNov 23, 2012
  25. 0/4 git-submodule add: Add --local-branch optionW. Trevor King, Nov 26, 2012
  26. 1/4 git-submodule add: Add --local-branch optionW. Trevor King, Nov 26, 2012
  27. 2/4 git-submodule init: Record submodule.<name>.branch in repository config.W. Trevor King, Nov 26, 2012
  28. Jens LehmannNov 27, 2012
  29. W. Trevor KingNov 28, 2012
  30. 3/4 git-submodule update: Add --branch optionW. Trevor King, Nov 26, 2012
  31. Heiko VoigtNov 27, 2012
  32. W. Trevor KingNov 27, 2012
  33. [RFC] git-submodule update: Add --commit optionW. Trevor King, Nov 29, 2012
  34. W. Trevor KingNov 29, 2012
  35. W. Trevor KingNov 29, 2012
  36. 4/4 Hack fix for 'submodule update does not fetch already present commits'W. Trevor King, Nov 26, 2012
  37. W. Trevor KingNov 27, 2012
  38. Heiko VoigtNov 27, 2012
  39. W. Trevor KingNov 27, 2012
  40. Heiko VoigtNov 27, 2012
  41. W. Trevor KingNov 28, 2012
  42. Phil HordNov 29, 2012
  43. W. Trevor KingNov 27, 2012
  44. Heiko VoigtNov 27, 2012
  45. 2/3 git-submodule foreach: export .gitmodules settings as variablesW. Trevor King, Nov 9, 2012
  46. Heiko VoigtNov 9, 2012
  47. W. Trevor KingNov 10, 2012
  48. 3/3 git-submodule: Motivate --record with an example use caseW. Trevor King, Nov 9, 2012
  49. W. Trevor KingNov 10, 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.