Subject: [PATCH/RFC] Pinning of submodules

From: Anders Ro <[email-masked]>
Date: Thu, 3 Sep 2015 01:34:24 +0200

Patch to make it possible to pin submodules so that they are not
affected by the --remote option in "git submodule".

Anders Ro (2):
  git-submodule.sh: pin submodule when branch name is '@'
  t7412: add test case for pinned submodules

 Documentation/git-submodule.txt |  3 +-
 git-submodule.sh                |  9 ++++-
 t/t7412-submodule-pinning.sh    | 73
+++++++++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 2 deletions(-)
 create mode 100755 t/t7412-submodule-pinning.sh

From 32b25aded0c4e30c68ac3ab75f4cbb63302ca147 Mon Sep 17 00:00:00 2001
From: Anders Ro <[email-masked]>
Date: Fri, 28 Nov 2014 01:39:37 +0100
Subject: [PATCH 1/2] git-submodule.sh: pin submodule when branch name is '@'

Setting branch name to '@' for a submodule will disable 'git submodule
update --remote' calls for that specific submodule. I.e. instead of
follow the unspecified default choice of master, nothing is being
updated. This is useful when multiple submodules exist but not all
should follow the remote branch head.

Signed-off-by: Anders Ro <[email-masked]>
---
 Documentation/git-submodule.txt | 3 ++-
 git-submodule.sh                | 9 ++++++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index f17687e..bd0cced 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -289,7 +289,8 @@ OPTIONS
 	The remote branch used defaults to `master`, but the branch name may
 	be overridden by setting the `submodule.<name>.branch` option in
 	either `.gitmodules` or `.git/config` (with `.git/config` taking
-	precedence).
+	precedence). Setting the branch name to the invalid branch name '@'
+	disables this option, i.e. pins the submodule at the recorded SHA-1.
 +
 This works for any of the supported update procedures (`--checkout`,
 `--rebase`, etc.).  The only change is the source of the target SHA-1.
diff --git a/git-submodule.sh b/git-submodule.sh
index 25b1ddf..1bb2bb1 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -843,7 +843,8 @@ Maybe you want to use 'update --init'?")"
 			die "$(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")"
 		fi
 
-		if test -n "$remote"
+		# Fetch latest in remote unless branch name in config is '@'
+		if test -n "$remote" -a "$branch" != "@"
 		then
 			if test -z "$nofetch"
 			then
@@ -857,6 +858,12 @@ Maybe you want to use 'update --init'?")"
 			die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")"
 		fi
 
+		# Inform that the current sm is pinned and use of '--remote' ignored
+		if test -n "$remote" -a "$branch" = "@"
+		then
+			say "$(eval_gettext "Submodule path '\$displaypath' pinned, remote update ignored")"
+		fi
+
 		if test "$subsha1" != "$sha1" || test -n "$force"
 		then
 			subforce=$force
-- 
2.1.4

From 98e6677325bada62301eba18b81f4884793d7c02 Mon Sep 17 00:00:00 2001
From: Anders Ro <[email-masked]>
Date: Thu, 3 Sep 2015 00:03:15 +0200
Subject: [PATCH 2/2] t7412: add test case for pinned submodules

Signed-off-by: Anders Ro <[email-masked]>
---
 t/t7412-submodule-pinning.sh | 73 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100755 t/t7412-submodule-pinning.sh

diff --git a/t/t7412-submodule-pinning.sh b/t/t7412-submodule-pinning.sh
new file mode 100755
index 0000000..2844b1e
--- /dev/null
+++ b/t/t7412-submodule-pinning.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+#
+# Copyright (c) 2015 Anders Ronnbrant
+#
+
+test_description="Branch name '@' disables submodule update --remote calls"
+
+. ./test-lib.sh
+
+get_sha() {
+  cd $1 && git rev-list --max-count=1 HEAD
+}
+
+equal_sha() {
+  test "$(get_sha $1)" = "$(get_sha $2)"
+}
+
+not_equal_sha() {
+  test "$(get_sha $1)" != "$(get_sha $2)"
+}
+
+test_expect_success 'setup submodule tree structure' '
+for i in 1 2 3; do echo file$i > file$i; git add file$i; git commit -m file$i; done &&
+test_tick &&
+git clone . super &&
+git clone . follow &&
+git clone . pinned &&
+(cd super && git submodule add -b master ../follow follow) &&
+(cd super && git submodule add           ../pinned pinned)
+'
+
+test_expect_success 'verify submodules have the same SHA' '
+equal_sha super/follow super/pinned
+'
+
+
+test_expect_success 'switch submodule pinned to HEAD~1 and commit super' '
+(cd super/pinned && git checkout master && git reset --hard HEAD~1) &&
+(cd super && git add pinned && git commit -m "Submodule pinned @ HEAD~1") &&
+(cd super && git submodule status)
+'
+
+
+test_expect_success 'verify submodules not have the same SHA anymore' '
+not_equal_sha super/follow super/pinned
+'
+
+
+test_expect_success 'set branch name to "@" for submodule pinned' '
+(cd super && git config --replace-all submodule.pinned.branch "@") &&
+test "$(cd super && git config --get submodule.pinned.branch)" = "@"
+'
+
+
+test_expect_success 'run submodule update --remote and expect no change' '
+(cd super && git submodule update --remote) &&
+not_equal_sha super/follow super/pinned
+'
+
+
+test_expect_success 'remove branch name "@" for submodule pinned (unpin)' '
+(cd super && git config --unset-all submodule.pinned.branch) &&
+(cd super && git config --list)
+'
+
+
+test_expect_success 'run submodule update --remote and expect same SHA1 again' '
+(cd super && git submodule update --remote) &&
+equal_sha super/follow super/pinned
+'
+
+
+test_done
-- 
2.1.4