submodule update: add --remote for submodule's upstream changes

The current `update` command incorporates the superproject's gitlinked SHA-1 ($sha1) into the submodule HEAD ($subsha1). Depending on the options you use, it may checkout $sha1, rebase the $subsha1 onto $sha1, or merge $sha1 into $subsha1. This helps you keep up with changes in the upstream superproject. However, it's also useful to stay up to date with changes in the upstream subproject. Previous workflows for incorporating such changes include the ungainly: $ git submodule foreach 'git checkout $(git config --file $toplevel/.gitmodules submodule.$name.branch) && git pull' With this patch, all of the useful functionality for incorporating superproject changes can be reused to incorporate upstream subproject updates. When you specify --remote, the target $sha1 is replaced with a $sha1 of the submodule's origin/master tracking branch. If you want to merge a different tracking branch, you can configure the `submodule.<name>.branch` option in `.gitmodules`. You can override the `.gitmodules` configuration setting for a particular superproject by configuring the option in that superproject's default configuration (using the usual configuration hierarchy, e.g. `.git/config`, `~/.gitconfig`, etc.). Previous use of submodule.<name>.branch ======================================= Because we're adding a new configuration option, it's a good idea to check if anyone else is already using the option. The foreach-pull example above was described by Ævar in commit f030c96d8643fa0a1a9b2bd9c2f36a77721fb61f Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Date: Fri May 21 16:10:10 2010 +0000 git-submodule foreach: Add $toplevel variable Gerrit uses the same interpretation for the setting, but because Gerrit has direct access to the subproject repositories, it updates the superproject repositories automatically when a subproject changes. Gerrit also accepts the special value '.', which it expands into the superproject's branch name. Although the --remote functionality is using `submodule.<name>.branch` slightly differently, the effect is the same. The foreach-pull example uses the option to record the name of the local branch to checkout before pulls. The tracking branch to be pulled is recorded in `.git/modules/<name>/config`, which was initialized by the module clone during `submodule add` or `submodule init`. Because the branch name stored in `submodule.<name>.branch` was likely the same as the branch name used during the initial `submodule add`, the same branch will be pulled in each workflow. Implementation details ====================== In order to ensure a current tracking branch state, `update --remote` fetches the submodule's remote repository before calculating the SHA-1. However, I didn't change the logic guarding the existing fetch: if test -z "$nofetch" then # Run fetch only if $sha1 isn't present or it # is not reachable from a ref. (clear_local_git_env; cd "$path" && ( (rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) && test -z "$rev") || git-fetch)) || die "$(eval_gettext "Unable to fetch in submodule path '\$path'")" fi There will not be a double-fetch, because the new $sha1 determined after the `--remote` triggered fetch should always exist in the repository. If it doesn't, it's because some racy process removed it from the submodule's repository and we *should* be re-fetching. Signed-off-by: W. Trevor King <wking@tremily.us> Signed-off-by: Junio C Hamano <gitster@pobox.com>

W. Trevor King committed Dec 19, 2012 at 11:03 UTC 06b1abb5bd38b3cb1972907b059c7f95a197a7a5
5 files changed +84 -2
Documentation/config.txt
+6
@@ -1994,6 +1994,12 @@ submodule.<name>.update::
1994 URL and other values found in the `.gitmodules` file. See
1995 linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
1996
1997 +submodule.<name>.branch::
1998 + The remote branch name for a submodule, used by `git submodule
1999 + update --remote`. Set this option to override the value found in
2000 + the `.gitmodules` file. See linkgit:git-submodule[1] and
2001 + linkgit:gitmodules[5] for details.
2002 +
2003 submodule.<name>.fetchRecurseSubmodules::
2004 This option can be used to control recursive fetching of this
2005 submodule. It can be overridden by using the --[no-]recurse-submodules
Documentation/git-submodule.txt
+22 -1
@@ -13,7 +13,7 @@ SYNOPSIS
13 [--reference <repository>] [--] <repository> [<path>]
14 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
15 'git submodule' [--quiet] init [--] [<path>...]
16 -'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
16 +'git submodule' [--quiet] update [--init] [--remote] [-N|--no-fetch] [--rebase]
17 [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
18 'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
19 [commit] [--] [<path>...]
@@ -236,6 +236,27 @@ OPTIONS
236 (the default). This limit only applies to modified submodules. The
237 size is always limited to 1 for added/deleted/typechanged submodules.
238
239 +--remote::
240 + This option is only valid for the update command. Instead of using
241 + the superproject's recorded SHA-1 to update the submodule, use the
242 + status of the submodule's remote tracking branch. The remote used
243 + is branch's remote (`branch.<name>.remote`), defaulting to `origin`.
244 + The remote branch used defaults to `master`, but the branch name may
245 + be overridden by setting the `submodule.<name>.branch` option in
246 + either `.gitmodules` or `.git/config` (with `.git/config` taking
247 + precedence).
248 ++
249 +This works for any of the supported update procedures (`--checkout`,
250 +`--rebase`, etc.). The only change is the source of the target SHA-1.
251 +For example, `submodule update --remote --merge` will merge upstream
252 +submodule changes into the submodules, while `submodule update
253 +--merge` will merge superproject gitlink changes into the submodules.
254 ++
255 +In order to ensure a current tracking branch state, `update --remote`
256 +fetches the submodule's remote repository before calculating the
257 +SHA-1. If you don't want to fetch, you should use `submodule update
258 +--remote --no-fetch`.
259 +
260 -N::
261 --no-fetch::
262 This option is only valid for the update command.
Documentation/gitmodules.txt
+5
@@ -49,6 +49,11 @@ submodule.<name>.update::
49 This config option is overridden if 'git submodule update' is given
50 the '--merge', '--rebase' or '--checkout' options.
51
52 +submodule.<name>.branch::
53 + A remote branch name for tracking updates in the upstream submodule.
54 + If the option is not specified, it defaults to 'master'. See the
55 + `--remote` documentation in linkgit:git-submodule[1] for details.
56 +
57 submodule.<name>.fetchRecurseSubmodules::
58 This option can be used to control recursive fetching of this
59 submodule. If this option is also present in the submodules entry in
git-submodule.sh
+20 -1
@@ -8,7 +8,7 @@ dashless=$(basename "$0" | sed -e 's/-/ /')
8 USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
9 or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
10 or: $dashless [--quiet] init [--] [<path>...]
11 - or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
11 + or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
12 or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
13 or: $dashless [--quiet] foreach [--recursive] <command>
14 or: $dashless [--quiet] sync [--recursive] [--] [<path>...]"
@@ -26,6 +26,7 @@ cached=
26 recursive=
27 init=
28 files=
29 +remote=
30 nofetch=
31 update=
32 prefix=
@@ -559,6 +560,9 @@ cmd_update()
560 -i|--init)
561 init=1
562 ;;
563 + --remote)
564 + remote=1
565 + ;;
566 -N|--no-fetch)
567 nofetch=1
568 ;;
@@ -619,6 +623,7 @@ cmd_update()
623 fi
624 name=$(module_name "$sm_path") || exit
625 url=$(git config submodule."$name".url)
626 + branch=$(get_submodule_config "$name" branch master)
627 if ! test -z "$update"
628 then
629 update_module=$update
@@ -653,6 +658,20 @@ Maybe you want to use 'update --init'?")"
658 die "$(eval_gettext "Unable to find current revision in submodule path '\$sm_path'")"
659 fi
660
661 + if test -n "$remote"
662 + then
663 + if test -z "$nofetch"
664 + then
665 + # Fetch remote before determining tracking $sha1
666 + (clear_local_git_env; cd "$sm_path" && git-fetch) ||
667 + die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
668 + fi
669 + remote_name=$(clear_local_git_env; cd "$sm_path" && get_default_remote)
670 + sha1=$(clear_local_git_env; cd "$sm_path" &&
671 + git rev-parse --verify "${remote_name}/${branch}") ||
672 + die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")"
673 + fi
674 +
675 if test "$subsha1" != "$sha1" -o -n "$force"
676 then
677 subforce=$force
t/t7406-submodule-update.sh
+31
@@ -135,6 +135,37 @@ test_expect_success 'submodule update --force forcibly checks out submodules' '
135 )
136 '
137
138 +test_expect_success 'submodule update --remote should fetch upstream changes' '
139 + (cd submodule &&
140 + echo line4 >> file &&
141 + git add file &&
142 + test_tick &&
143 + git commit -m "upstream line4"
144 + ) &&
145 + (cd super &&
146 + git submodule update --remote --force submodule &&
147 + cd submodule &&
148 + test "$(git log -1 --oneline)" = "$(GIT_DIR=../../submodule/.git git log -1 --oneline)"
149 + )
150 +'
151 +
152 +test_expect_success 'local config should override .gitmodules branch' '
153 + (cd submodule &&
154 + git checkout -b test-branch &&
155 + echo line5 >> file &&
156 + git add file &&
157 + test_tick &&
158 + git commit -m "upstream line5" &&
159 + git checkout master
160 + ) &&
161 + (cd super &&
162 + git config submodule.submodule.branch test-branch &&
163 + git submodule update --remote --force submodule &&
164 + cd submodule &&
165 + test "$(git log -1 --oneline)" = "$(GIT_DIR=../../submodule/.git git log -1 --oneline test-branch)"
166 + )
167 +'
168 +
169 test_expect_success 'submodule update --rebase staying on master' '
170 (cd super/submodule &&
171 git checkout master