Skip to content

Commit 06c2768

Browse files
committed
Merge branch 'wk/submodule-on-branch'
Make sure 'submodule update' modes that do not detach HEADs can be used more pleasantly by checking out a concrete branch when cloning them to prime the well. * wk/submodule-on-branch: Documentation: describe 'submodule update --remote' use case submodule: explicit local branch creation in module_clone submodule: document module_clone arguments in comments submodule: make 'checkout' update_module mode more explicit
2 parents 0434783 + 9937e65 commit 06c2768

File tree

4 files changed

+135
-42
lines changed

4 files changed

+135
-42
lines changed

Documentation/git-submodule.txt

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ SYNOPSIS
1515
'git submodule' [--quiet] init [--] [<path>...]
1616
'git submodule' [--quiet] deinit [-f|--force] [--] <path>...
1717
'git submodule' [--quiet] update [--init] [--remote] [-N|--no-fetch]
18-
[-f|--force] [--rebase] [--reference <repository>] [--depth <depth>]
19-
[--merge] [--recursive] [--] [<path>...]
18+
[-f|--force] [--rebase|--merge|--checkout] [--reference <repository>]
19+
[--depth <depth>] [--recursive] [--] [<path>...]
2020
'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
2121
[commit] [--] [<path>...]
2222
'git submodule' [--quiet] foreach [--recursive] <command>
@@ -155,13 +155,31 @@ it contains local modifications.
155155

156156
update::
157157
Update the registered submodules, i.e. clone missing submodules and
158-
checkout the commit specified in the index of the containing repository.
159-
This will make the submodules HEAD be detached unless `--rebase` or
160-
`--merge` is specified or the key `submodule.$name.update` is set to
161-
`rebase`, `merge` or `none`. `none` can be overridden by specifying
162-
`--checkout`. Setting the key `submodule.$name.update` to `!command`
163-
will cause `command` to be run. `command` can be any arbitrary shell
164-
command that takes a single argument, namely the sha1 to update to.
158+
checkout the commit specified in the index of the containing
159+
repository. The update mode defaults to `checkout`, but can be
160+
configured with the `submodule.<name>.update` setting or the
161+
`--rebase`, `--merge`, or `--checkout` options.
162+
+
163+
For updates that clone missing submodules, checkout-mode updates will
164+
create submodules with detached HEADs; all other modes will create
165+
submodules with a local branch named after `submodule.<path>.branch`.
166+
+
167+
For updates that do not clone missing submodules, the submodule's HEAD
168+
is only touched when the remote reference does not match the
169+
submodule's HEAD (for none-mode updates, the submodule is never
170+
touched). The remote reference is usually the gitlinked commit from
171+
the superproject's tree, but with `--remote` it is the upstream
172+
subproject's `submodule.<name>.branch`. This remote reference is
173+
integrated with the submodule's HEAD using the specified update mode.
174+
For checkout-mode updates, that will result in a detached HEAD. For
175+
rebase- and merge-mode updates, the commit referenced by the
176+
submodule's HEAD may change, but the symbolic reference will remain
177+
unchanged (i.e. checked-out branches will still be checked-out
178+
branches, and detached HEADs will still be detached HEADs). If none
179+
of the builtin modes fit your needs, set `submodule.<name>.update` to
180+
`!command` to configure a custom integration command. `command` can
181+
be any arbitrary shell command that takes a single argument, namely
182+
the sha1 to update to.
165183
+
166184
If the submodule is not yet initialized, and you just want to use the
167185
setting as stored in .gitmodules, you can automatically initialize the
@@ -281,6 +299,16 @@ In order to ensure a current tracking branch state, `update --remote`
281299
fetches the submodule's remote repository before calculating the
282300
SHA-1. If you don't want to fetch, you should use `submodule update
283301
--remote --no-fetch`.
302+
+
303+
Use this option to integrate changes from the upstream subproject with
304+
your submodule's current HEAD. Alternatively, you can run `git pull`
305+
from the submodule, which is equivalent except for the remote branch
306+
name: `update --remote` uses the default upstream repository and
307+
`submodule.<name>.branch`, while `git pull` uses the submodule's
308+
`branch.<name>.merge`. Prefer `submodule.<name>.branch` if you want
309+
to distribute the default upstream branch with the superproject and
310+
`branch.<name>.merge` if you want a more native feel while working in
311+
the submodule itself.
284312

285313
-N::
286314
--no-fetch::

Documentation/gitmodules.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ submodule.<name>.branch::
5555
A remote branch name for tracking updates in the upstream submodule.
5656
If the option is not specified, it defaults to 'master'. See the
5757
`--remote` documentation in linkgit:git-submodule[1] for details.
58+
+
59+
This branch name is also used for the local branch created by
60+
non-checkout cloning updates. See the `update` documentation in
61+
linkgit:git-submodule[1] for details.
5862

5963
submodule.<name>.fetchRecurseSubmodules::
6064
This option can be used to control recursive fetching of this

git-submodule.sh

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,15 @@ module_name()
241241
#
242242
# Clone a submodule
243243
#
244+
# $1 = submodule path
245+
# $2 = submodule name
246+
# $3 = URL to clone
247+
# $4 = reference repository to reuse (empty for independent)
248+
# $5 = depth argument for shallow clones (empty for deep)
249+
# $6 = (remote-tracking) starting point for the local branch (empty for HEAD)
250+
# $7 = local branch to create (empty for a detached HEAD, unless $6 is
251+
# also empty, in which case the local branch is left unchanged)
252+
#
244253
# Prior to calling, cmd_update checks that a possibly existing
245254
# path is not a git repository.
246255
# Likewise, cmd_add checks that path does not exist at all,
@@ -253,6 +262,8 @@ module_clone()
253262
url=$3
254263
reference="$4"
255264
depth="$5"
265+
start_point="$6"
266+
local_branch="$7"
256267
quiet=
257268
if test -n "$GIT_QUIET"
258269
then
@@ -306,7 +317,16 @@ module_clone()
306317
echo "gitdir: $rel/$a" >"$sm_path/.git"
307318

308319
rel=$(echo $a | sed -e 's|[^/][^/]*|..|g')
309-
(clear_local_git_env; cd "$sm_path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b")
320+
(
321+
clear_local_git_env
322+
cd "$sm_path" &&
323+
GIT_WORK_TREE=. git config core.worktree "$rel/$b" &&
324+
# ash fails to wordsplit ${local_branch:+-B "$local_branch"...}
325+
case "$local_branch" in
326+
'') git checkout -f -q ${start_point:+"$start_point"} ;;
327+
?*) git checkout -f -q -B "$local_branch" ${start_point:+"$start_point"} ;;
328+
esac
329+
) || die "$(eval_gettext "Unable to setup cloned submodule '\$sm_path'")"
310330
}
311331

312332
isnumber()
@@ -469,16 +489,15 @@ Use -f if you really want to add it." >&2
469489
echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
470490
fi
471491
fi
472-
module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" || exit
473-
(
474-
clear_local_git_env
475-
cd "$sm_path" &&
476-
# ash fails to wordsplit ${branch:+-b "$branch"...}
477-
case "$branch" in
478-
'') git checkout -f -q ;;
479-
?*) git checkout -f -q -B "$branch" "origin/$branch" ;;
480-
esac
481-
) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")"
492+
if test -n "$branch"
493+
then
494+
start_point="origin/$branch"
495+
local_branch="$branch"
496+
else
497+
start_point=""
498+
local_branch=""
499+
fi
500+
module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" "$start_point" "$local_branch" || exit
482501
fi
483502
git config submodule."$sm_name".url "$realrepo"
484503

@@ -799,32 +818,35 @@ cmd_update()
799818
fi
800819
name=$(module_name "$sm_path") || exit
801820
url=$(git config submodule."$name".url)
802-
branch=$(get_submodule_config "$name" branch master)
821+
config_branch=$(get_submodule_config "$name" branch)
822+
branch="${config_branch:-master}"
823+
local_branch="$branch"
803824
if ! test -z "$update"
804825
then
805826
update_module=$update
806827
else
807828
update_module=$(git config submodule."$name".update)
808-
case "$update_module" in
809-
'')
810-
;; # Unset update mode
811-
checkout | rebase | merge | none)
812-
;; # Known update modes
813-
!*)
814-
;; # Custom update command
815-
*)
816-
die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
817-
;;
818-
esac
829+
if test -z "$update_module"
830+
then
831+
update_module="checkout"
832+
fi
819833
fi
820834

821835
displaypath=$(relative_path "$prefix$sm_path")
822836

823-
if test "$update_module" = "none"
824-
then
837+
case "$update_module" in
838+
none)
825839
echo "Skipping submodule '$displaypath'"
826840
continue
827-
fi
841+
;;
842+
checkout)
843+
local_branch=""
844+
;;
845+
rebase | merge | !*)
846+
;;
847+
*)
848+
die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
849+
esac
828850

829851
if test -z "$url"
830852
then
@@ -838,7 +860,8 @@ Maybe you want to use 'update --init'?")"
838860

839861
if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
840862
then
841-
module_clone "$sm_path" "$name" "$url" "$reference" "$depth" || exit
863+
start_point="origin/${branch}"
864+
module_clone "$sm_path" "$name" "$url" "$reference" "$depth" "$start_point" "$local_branch" || exit
842865
cloned_modules="$cloned_modules;$name"
843866
subsha1=
844867
else
@@ -884,11 +907,16 @@ Maybe you want to use 'update --init'?")"
884907
case ";$cloned_modules;" in
885908
*";$name;"*)
886909
# then there is no local change to integrate
887-
update_module= ;;
910+
update_module='!git reset --hard -q'
888911
esac
889912

890913
must_die_on_failure=
891914
case "$update_module" in
915+
checkout)
916+
command="git checkout $subforce -q"
917+
die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")"
918+
say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")"
919+
;;
892920
rebase)
893921
command="git rebase"
894922
die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$displaypath'")"
@@ -908,10 +936,7 @@ Maybe you want to use 'update --init'?")"
908936
must_die_on_failure=yes
909937
;;
910938
*)
911-
command="git checkout $subforce -q"
912-
die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")"
913-
say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")"
914-
;;
939+
die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
915940
esac
916941

917942
if (clear_local_git_env; cd "$sm_path" && $command "$sha1")

t/t7406-submodule-update.sh

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ test_expect_success 'setup a submodule tree' '
6363
git submodule add ../none none &&
6464
test_tick &&
6565
git commit -m "none"
66+
) &&
67+
(cd super &&
68+
git tag initial-setup
6669
)
6770
'
6871

@@ -703,7 +706,7 @@ test_expect_success 'submodule update places git-dir in superprojects git-dir re
703706
git clone super_update_r super_update_r2 &&
704707
(cd super_update_r2 &&
705708
git submodule update --init --recursive >actual &&
706-
test_i18ngrep "Submodule path .submodule/subsubmodule.: checked out" actual &&
709+
test_i18ngrep "Submodule path .submodule/subsubmodule.: .git reset --hard -q" actual &&
707710
(cd submodule/subsubmodule &&
708711
git log > ../../expected
709712
) &&
@@ -775,4 +778,37 @@ test_expect_success 'submodule update --recursive drops module name before recur
775778
)
776779
'
777780

781+
test_expect_success 'submodule update --checkout clones detached HEAD' '
782+
git clone super super4 &&
783+
echo "detached HEAD" >expected &&
784+
(cd super4 &&
785+
git reset --hard initial-setup &&
786+
git submodule init submodule &&
787+
git submodule update >> /tmp/log 2>&1 &&
788+
(cd submodule &&
789+
git symbolic-ref HEAD > ../../actual ||
790+
echo "detached HEAD" > ../../actual
791+
)
792+
) &&
793+
test_cmp actual expected &&
794+
rm -rf super4
795+
'
796+
797+
test_expect_success 'submodule update --merge clones attached HEAD' '
798+
git clone super super4 &&
799+
echo "refs/heads/master" >expected &&
800+
(cd super4 &&
801+
git reset --hard initial-setup &&
802+
git submodule init submodule &&
803+
git config submodule.submodule.update merge &&
804+
git submodule update --merge &&
805+
(cd submodule &&
806+
git symbolic-ref HEAD > ../../actual ||
807+
echo "detached HEAD" > ../../actual
808+
)
809+
) &&
810+
test_cmp actual expected &&
811+
rm -rf super4
812+
'
813+
778814
test_done

0 commit comments

Comments
 (0)