linkgit:git-clone[1] or (if it begins with ./ or ../) a location
relative to the superproject's origin repository.
+In addition, there are a number of optional keys:
+
submodule.<name>.update::
Defines what to do when the submodule is updated by the superproject.
If 'checkout' (the default), the new commit specified in the
A remote branch name for tracking updates in the upstream submodule.
If the option is not specified, it defaults to 'master'. See the
`--remote` documentation in linkgit:git-submodule[1] for details.
+ +
+ This branch name is also used for the local branch created by
+ non-checkout cloning updates. See the `update` documentation in
+ linkgit:git-submodule[1] for details.
submodule.<name>.fetchRecurseSubmodules::
This option can be used to control recursive fetching of this
git ls-files -z --error-unmatch --stage -- "$@" ||
echo "unmatched pathspec exists"
) |
- perl -e '
+ @@PERL@@ -e '
my %unmerged = ();
my ($null_sha1) = ("0" x 40);
my @out = ();
#
# Clone a submodule
#
+ # $1 = submodule path
+ # $2 = submodule name
+ # $3 = URL to clone
+ # $4 = reference repository to reuse (empty for independent)
+ # $5 = depth argument for shallow clones (empty for deep)
+ # $6 = (remote-tracking) starting point for the local branch (empty for HEAD)
+ # $7 = local branch to create (empty for a detached HEAD, unless $6 is
+ # also empty, in which case the local branch is left unchanged)
+ #
# Prior to calling, cmd_update checks that a possibly existing
# path is not a git repository.
# Likewise, cmd_add checks that path does not exist at all,
url=$3
reference="$4"
depth="$5"
+ start_point="$6"
+ local_branch="$7"
quiet=
if test -n "$GIT_QUIET"
then
echo "gitdir: $rel/$a" >"$sm_path/.git"
rel=$(echo $a | sed -e 's|[^/][^/]*|..|g')
- (clear_local_git_env; cd "$sm_path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b")
+ (
+ clear_local_git_env
+ cd "$sm_path" &&
+ GIT_WORK_TREE=. git config core.worktree "$rel/$b" &&
+ # ash fails to wordsplit ${local_branch:+-B "$local_branch"...}
+ case "$local_branch" in
+ '') git checkout -f -q ${start_point:+"$start_point"} ;;
+ ?*) git checkout -f -q -B "$local_branch" ${start_point:+"$start_point"} ;;
+ esac
+ ) || die "$(eval_gettext "Unable to setup cloned submodule '\$sm_path'")"
}
isnumber()
echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
fi
fi
- module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" || exit
- (
- clear_local_git_env
- cd "$sm_path" &&
- # ash fails to wordsplit ${branch:+-b "$branch"...}
- case "$branch" in
- '') git checkout -f -q ;;
- ?*) git checkout -f -q -B "$branch" "origin/$branch" ;;
- esac
- ) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")"
+ if test -n "$branch"
+ then
+ start_point="origin/$branch"
+ local_branch="$branch"
+ else
+ start_point=""
+ local_branch=""
+ fi
+ module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" "$start_point" "$local_branch" || exit
fi
git config submodule."$sm_name".url "$realrepo"
sm_path=$(relative_path "$sm_path") &&
# we make $path available to scripts ...
path=$sm_path &&
- eval "$@" &&
+ if test $# -eq 1
+ then
+ eval "$1"
+ else
+ "$@"
+ fi &&
if test -n "$recursive"
then
cmd_foreach "--recursive" "$@"
cmd_update()
{
# parse $args after "submodule ... update".
- orig_flags=
while test $# -ne 0
do
case "$1" in
--reference)
case "$2" in '') usage ;; esac
reference="--reference=$2"
- orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
shift
;;
--reference=*)
break
;;
esac
- orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
shift
done
fi
name=$(module_name "$sm_path") || exit
url=$(git config submodule."$name".url)
- branch=$(get_submodule_config "$name" branch master)
+ config_branch=$(get_submodule_config "$name" branch)
+ branch="${config_branch:-master}"
+ local_branch="$branch"
if ! test -z "$update"
then
update_module=$update
else
update_module=$(git config submodule."$name".update)
- case "$update_module" in
- '')
- ;; # Unset update mode
- checkout | rebase | merge | none)
- ;; # Known update modes
- !*)
- ;; # Custom update command
- *)
- die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
- ;;
- esac
+ if test -z "$update_module"
+ then
+ update_module="checkout"
+ fi
fi
displaypath=$(relative_path "$prefix$sm_path")
- if test "$update_module" = "none"
- then
+ case "$update_module" in
+ none)
echo "Skipping submodule '$displaypath'"
continue
- fi
+ ;;
+ checkout)
+ local_branch=""
+ ;;
+ rebase | merge | !*)
+ ;;
+ *)
+ die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
+ esac
if test -z "$url"
then
if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
then
- module_clone "$sm_path" "$name" "$url" "$reference" "$depth" || exit
+ start_point="origin/${branch}"
+ module_clone "$sm_path" "$name" "$url" "$reference" "$depth" "$start_point" "$local_branch" || exit
cloned_modules="$cloned_modules;$name"
subsha1=
else
case ";$cloned_modules;" in
*";$name;"*)
# then there is no local change to integrate
- update_module= ;;
+ update_module='!git reset --hard -q'
esac
must_die_on_failure=
case "$update_module" in
+ checkout)
+ command="git checkout $subforce -q"
+ die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")"
+ say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")"
+ ;;
rebase)
command="git rebase"
die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$displaypath'")"
must_die_on_failure=yes
;;
*)
- command="git checkout $subforce -q"
- die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")"
- say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")"
- ;;
+ die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
esac
if (clear_local_git_env; cd "$sm_path" && $command "$sha1")
prefix="$prefix$sm_path/"
clear_local_git_env
cd "$sm_path" &&
- eval cmd_update "$orig_flags"
+ eval cmd_update
)
res=$?
if test $res -gt 0
git submodule add ../none none &&
test_tick &&
git commit -m "none"
+ ) &&
+ (cd super &&
+ git tag initial-setup
)
'
git clone super_update_r super_update_r2 &&
(cd super_update_r2 &&
git submodule update --init --recursive >actual &&
- test_i18ngrep "Submodule path .submodule/subsubmodule.: checked out" actual &&
+ test_i18ngrep "Submodule path .submodule/subsubmodule.: .git reset --hard -q" actual &&
(cd submodule/subsubmodule &&
git log > ../../expected
) &&
(cd submodule &&
test 1 = $(git log --oneline | wc -l)
)
+)
+'
+
+test_expect_success 'submodule update --recursive drops module name before recursing' '
+ (cd super2 &&
+ (cd deeper/submodule/subsubmodule &&
+ git checkout HEAD^
+ ) &&
+ git submodule update --recursive deeper/submodule >actual &&
+ test_i18ngrep "Submodule path .deeper/submodule/subsubmodule.: checked out" actual
)
'
+ test_expect_success 'submodule update --checkout clones detached HEAD' '
+ git clone super super4 &&
+ echo "detached HEAD" >expected &&
+ (cd super4 &&
+ git reset --hard initial-setup &&
+ git submodule init submodule &&
+ git submodule update >> /tmp/log 2>&1 &&
+ (cd submodule &&
+ git symbolic-ref HEAD > ../../actual ||
+ echo "detached HEAD" > ../../actual
+ )
+ ) &&
+ test_cmp actual expected &&
+ rm -rf super4
+ '
+
+ test_expect_success 'submodule update --merge clones attached HEAD' '
+ git clone super super4 &&
+ echo "refs/heads/master" >expected &&
+ (cd super4 &&
+ git reset --hard initial-setup &&
+ git submodule init submodule &&
+ git config submodule.submodule.update merge &&
+ git submodule update --merge &&
+ (cd submodule &&
+ git symbolic-ref HEAD > ../../actual ||
+ echo "detached HEAD" > ../../actual
+ )
+ ) &&
+ test_cmp actual expected &&
+ rm -rf super4
+ '
+
test_done