summaryrefslogtreecommitdiff
path: root/git-submodule.sh
diff options
context:
space:
mode:
Diffstat (limited to 'git-submodule.sh')
-rwxr-xr-xgit-submodule.sh293
1 files changed, 77 insertions, 216 deletions
diff --git a/git-submodule.sh b/git-submodule.sh
index d56207ea05..7fe8a511b3 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -46,114 +46,6 @@ prefix=
custom_name=
depth=
-# The function takes at most 2 arguments. The first argument is the
-# URL that navigates to the submodule origin repo. When relative, this URL
-# is relative to the superproject origin URL repo. The second up_path
-# argument, if specified, is the relative path that navigates
-# from the submodule working tree to the superproject working tree.
-#
-# The output of the function is the origin URL of the submodule.
-#
-# The output will either be an absolute URL or filesystem path (if the
-# superproject origin URL is an absolute URL or filesystem path,
-# respectively) or a relative file system path (if the superproject
-# origin URL is a relative file system path).
-#
-# When the output is a relative file system path, the path is either
-# relative to the submodule working tree, if up_path is specified, or to
-# the superproject working tree otherwise.
-resolve_relative_url ()
-{
- remote=$(get_default_remote)
- remoteurl=$(git config "remote.$remote.url") ||
- remoteurl=$(pwd) # the repository is its own authoritative upstream
- url="$1"
- remoteurl=${remoteurl%/}
- sep=/
- up_path="$2"
-
- case "$remoteurl" in
- *:*|/*)
- is_relative=
- ;;
- ./*|../*)
- is_relative=t
- ;;
- *)
- is_relative=t
- remoteurl="./$remoteurl"
- ;;
- esac
-
- while test -n "$url"
- do
- case "$url" in
- ../*)
- url="${url#../}"
- case "$remoteurl" in
- */*)
- remoteurl="${remoteurl%/*}"
- ;;
- *:*)
- remoteurl="${remoteurl%:*}"
- sep=:
- ;;
- *)
- if test -z "$is_relative" || test "." = "$remoteurl"
- then
- die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
- else
- remoteurl=.
- fi
- ;;
- esac
- ;;
- ./*)
- url="${url#./}"
- ;;
- *)
- break;;
- esac
- done
- remoteurl="$remoteurl$sep${url%/}"
- echo "${is_relative:+${up_path}}${remoteurl#./}"
-}
-
-# Resolve a path to be relative to another path. This is intended for
-# converting submodule paths when git-submodule is run in a subdirectory
-# and only handles paths where the directory separator is '/'.
-#
-# The output is the first argument as a path relative to the second argument,
-# which defaults to $wt_prefix if it is omitted.
-relative_path ()
-{
- local target curdir result
- target=$1
- curdir=${2-$wt_prefix}
- curdir=${curdir%/}
- result=
-
- while test -n "$curdir"
- do
- case "$target" in
- "$curdir/"*)
- target=${target#"$curdir"/}
- break
- ;;
- esac
-
- result="${result}../"
- if test "$curdir" = "${curdir%/*}"
- then
- curdir=
- else
- curdir="${curdir%/*}"
- fi
- done
-
- echo "$result$target"
-}
-
die_if_unmatched ()
{
if test "$1" = "#unmatched"
@@ -192,6 +84,17 @@ isnumber()
n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
}
+# Sanitize the local git environment for use within a submodule. We
+# can't simply use clear_local_git_env since we want to preserve some
+# of the settings from GIT_CONFIG_PARAMETERS.
+sanitize_submodule_env()
+{
+ save_config=$GIT_CONFIG_PARAMETERS
+ clear_local_git_env
+ GIT_CONFIG_PARAMETERS=$save_config
+ export GIT_CONFIG_PARAMETERS
+}
+
#
# Add a new submodule to the working tree, .gitmodules and the index
#
@@ -281,7 +184,7 @@ cmd_add()
die "$(gettext "Relative path can only be used from the toplevel of the working tree")"
# dereference source url relative to parent's url
- realrepo=$(resolve_relative_url "$repo") || exit
+ realrepo=$(git submodule--helper resolve-relative-url "$repo") || exit
;;
*:*|/*)
# absolute url
@@ -347,9 +250,9 @@ Use -f if you really want to add it." >&2
echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
fi
fi
- git submodule--helper clone ${GIT_QUIET:+--quiet} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" "$reference" "$depth" || exit
+ git submodule--helper clone ${GIT_QUIET:+--quiet} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" ${reference:+"$reference"} ${depth:+"$depth"} || exit
(
- clear_local_git_env
+ sanitize_submodule_env
cd "$sm_path" &&
# ash fails to wordsplit ${branch:+-b "$branch"...}
case "$branch" in
@@ -407,20 +310,23 @@ cmd_foreach()
# command in the subshell (and a recursive call to this function)
exec 3<&0
- git submodule--helper list --prefix "$wt_prefix"|
+ {
+ git submodule--helper list --prefix "$wt_prefix" ||
+ echo "#unmatched"
+ } |
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
if test -e "$sm_path"/.git
then
- displaypath=$(relative_path "$prefix$sm_path")
+ displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
say "$(eval_gettext "Entering '\$displaypath'")"
name=$(git submodule--helper name "$sm_path")
(
prefix="$prefix$sm_path/"
- clear_local_git_env
+ sanitize_submodule_env
cd "$sm_path" &&
- sm_path=$(relative_path "$sm_path") &&
+ sm_path=$(git submodule--helper relative-path "$sm_path" "$wt_prefix") &&
# we make $path available to scripts ...
path=$sm_path &&
if test $# -eq 1
@@ -467,50 +373,7 @@ cmd_init()
shift
done
- git submodule--helper list --prefix "$wt_prefix" "$@" |
- while read mode sha1 stage sm_path
- do
- die_if_unmatched "$mode"
- name=$(git submodule--helper name "$sm_path") || exit
-
- displaypath=$(relative_path "$prefix$sm_path")
-
- # Copy url setting when it is not set yet
- if test -z "$(git config "submodule.$name.url")"
- then
- url=$(git config -f .gitmodules submodule."$name".url)
- test -z "$url" &&
- die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")"
-
- # Possibly a url relative to parent
- case "$url" in
- ./*|../*)
- url=$(resolve_relative_url "$url") || exit
- ;;
- esac
- git config submodule."$name".url "$url" ||
- die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")"
-
- say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")"
- fi
-
- # Copy "update" setting when it is not set yet
- if upd="$(git config -f .gitmodules submodule."$name".update)" &&
- test -n "$upd" &&
- test -z "$(git config submodule."$name".update)"
- then
- case "$upd" in
- checkout | rebase | merge | none)
- ;; # known modes of updating
- *)
- echo >&2 "warning: unknown update mode '$upd' suggested for submodule '$name'"
- upd=none
- ;;
- esac
- git config submodule."$name".update "$upd" ||
- die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
- fi
- done
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init ${GIT_QUIET:+--quiet} ${prefix:+--prefix "$prefix"} "$@"
}
#
@@ -558,13 +421,16 @@ cmd_deinit()
die "$(eval_gettext "Use '--all' if you really want to deinitialize all submodules")"
fi
- git submodule--helper list --prefix "$wt_prefix" "$@" |
+ {
+ git submodule--helper list --prefix "$wt_prefix" "$@" ||
+ echo "#unmatched"
+ } |
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
name=$(git submodule--helper name "$sm_path") || exit
- displaypath=$(relative_path "$sm_path")
+ displaypath=$(git submodule--helper relative-path "$sm_path" "$wt_prefix")
# Remove the submodule work tree (unless the user already did it)
if test -d "$sm_path"
@@ -601,14 +467,14 @@ cmd_deinit()
}
is_tip_reachable () (
- clear_local_git_env
+ sanitize_submodule_env &&
cd "$1" &&
rev=$(git rev-list -n 1 "$2" --not --all 2>/dev/null) &&
test -z "$rev"
)
fetch_in_submodule () (
- clear_local_git_env
+ sanitize_submodule_env &&
cd "$1" &&
case "$2" in
'')
@@ -672,6 +538,14 @@ cmd_update()
--depth=*)
depth=$1
;;
+ -j|--jobs)
+ case "$2" in '') usage ;; esac
+ jobs="--jobs=$2"
+ shift
+ ;;
+ --jobs=*)
+ jobs=$1
+ ;;
--)
shift
break
@@ -691,17 +565,21 @@ cmd_update()
cmd_init "--" "$@" || return
fi
- cloned_modules=
- git submodule--helper list --prefix "$wt_prefix" "$@" | {
+ {
+ git submodule--helper update-clone ${GIT_QUIET:+--quiet} \
+ ${wt_prefix:+--prefix "$wt_prefix"} \
+ ${prefix:+--recursive-prefix "$prefix"} \
+ ${update:+--update "$update"} \
+ ${reference:+--reference "$reference"} \
+ ${depth:+--depth "$depth"} \
+ ${jobs:+$jobs} \
+ "$@" || echo "#unmatched"
+ } | {
err=
- while read mode sha1 stage sm_path
+ while read mode sha1 stage just_cloned sm_path
do
die_if_unmatched "$mode"
- if test "$stage" = U
- then
- echo >&2 "Skipping unmerged submodule $prefix$sm_path"
- continue
- fi
+
name=$(git submodule--helper name "$sm_path") || exit
url=$(git config submodule."$name".url)
branch=$(get_submodule_config "$name" branch master)
@@ -716,31 +594,14 @@ cmd_update()
fi
fi
- displaypath=$(relative_path "$prefix$sm_path")
-
- if test "$update_module" = "none"
- then
- echo "Skipping submodule '$displaypath'"
- continue
- fi
-
- if test -z "$url"
- then
- # Only mention uninitialized submodules when its
- # path have been specified
- test "$#" != "0" &&
- say "$(eval_gettext "Submodule path '\$displaypath' not initialized
-Maybe you want to use 'update --init'?")"
- continue
- fi
+ displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
- if ! test -d "$sm_path"/.git && ! test -f "$sm_path"/.git
+ if test $just_cloned -eq 1
then
- git submodule--helper clone ${GIT_QUIET:+--quiet} --prefix "$prefix" --path "$sm_path" --name "$name" --url "$url" "$reference" "$depth" || exit
- cloned_modules="$cloned_modules;$name"
subsha1=
+ update_module=checkout
else
- subsha1=$(clear_local_git_env; cd "$sm_path" &&
+ subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
git rev-parse --verify HEAD) ||
die "$(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")"
fi
@@ -750,11 +611,11 @@ Maybe you want to use 'update --init'?")"
if test -z "$nofetch"
then
# Fetch remote before determining tracking $sha1
- (clear_local_git_env; cd "$sm_path" && git-fetch) ||
+ (sanitize_submodule_env; cd "$sm_path" && git-fetch) ||
die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
fi
- remote_name=$(clear_local_git_env; cd "$sm_path" && get_default_remote)
- sha1=$(clear_local_git_env; cd "$sm_path" &&
+ remote_name=$(sanitize_submodule_env; cd "$sm_path" && get_default_remote)
+ sha1=$(sanitize_submodule_env; cd "$sm_path" &&
git rev-parse --verify "${remote_name}/${branch}") ||
die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")"
fi
@@ -783,13 +644,6 @@ Maybe you want to use 'update --init'?")"
die "$(eval_gettext "Fetched in submodule path '\$displaypath', but it did not contain $sha1. Direct fetching of that commit failed.")"
fi
- # Is this something we just cloned?
- case ";$cloned_modules;" in
- *";$name;"*)
- # then there is no local change to integrate
- update_module=checkout ;;
- esac
-
must_die_on_failure=
case "$update_module" in
checkout)
@@ -819,7 +673,7 @@ Maybe you want to use 'update --init'?")"
die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
esac
- if (clear_local_git_env; cd "$sm_path" && $command "$sha1")
+ if (sanitize_submodule_env; cd "$sm_path" && $command "$sha1")
then
say "$say_msg"
elif test -n "$must_die_on_failure"
@@ -834,8 +688,9 @@ Maybe you want to use 'update --init'?")"
if test -n "$recursive"
then
(
- prefix="$prefix$sm_path/"
- clear_local_git_env
+ prefix=$(git submodule--helper relative-path "$prefix$sm_path/" "$wt_prefix")
+ wt_prefix=
+ sanitize_submodule_env
cd "$sm_path" &&
eval cmd_update
)
@@ -873,7 +728,7 @@ Maybe you want to use 'update --init'?")"
set_name_rev () {
revname=$( (
- clear_local_git_env
+ sanitize_submodule_env
cd "$1" && {
git describe "$2" 2>/dev/null ||
git describe --tags "$2" 2>/dev/null ||
@@ -1017,7 +872,7 @@ cmd_summary() {
! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
missing_dst=t
- display_name=$(relative_path "$name")
+ display_name=$(git submodule--helper relative-path "$name" "$wt_prefix")
total_commits=
case "$missing_src,$missing_dst" in
@@ -1129,13 +984,16 @@ cmd_status()
shift
done
- git submodule--helper list --prefix "$wt_prefix" "$@" |
+ {
+ git submodule--helper list --prefix "$wt_prefix" "$@" ||
+ echo "#unmatched"
+ } |
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
name=$(git submodule--helper name "$sm_path") || exit
url=$(git config submodule."$name".url)
- displaypath=$(relative_path "$prefix$sm_path")
+ displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
if test "$stage" = U
then
say "U$sha1 $displaypath"
@@ -1157,7 +1015,7 @@ cmd_status()
else
if test -z "$cached"
then
- sha1=$(clear_local_git_env; cd "$sm_path" && git rev-parse --verify HEAD)
+ sha1=$(sanitize_submodule_env; cd "$sm_path" && git rev-parse --verify HEAD)
fi
set_name_rev "$sm_path" "$sha1"
say "+$sha1 $displaypath$revname"
@@ -1167,7 +1025,7 @@ cmd_status()
then
(
prefix="$displaypath/"
- clear_local_git_env
+ sanitize_submodule_env
wt_prefix=
cd "$sm_path" &&
eval cmd_status
@@ -1207,7 +1065,10 @@ cmd_sync()
esac
done
cd_to_toplevel
- git submodule--helper list --prefix "$wt_prefix" "$@" |
+ {
+ git submodule--helper list --prefix "$wt_prefix" "$@" ||
+ echo "#unmatched"
+ } |
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
@@ -1223,9 +1084,9 @@ cmd_sync()
# guarantee a trailing /
up_path=${up_path%/}/ &&
# path from submodule work tree to submodule origin repo
- sub_origin_url=$(resolve_relative_url "$url" "$up_path") &&
+ sub_origin_url=$(git submodule--helper resolve-relative-url "$url" "$up_path") &&
# path from superproject work tree to submodule origin repo
- super_config_url=$(resolve_relative_url "$url") || exit
+ super_config_url=$(git submodule--helper resolve-relative-url "$url") || exit
;;
*)
sub_origin_url="$url"
@@ -1235,14 +1096,14 @@ cmd_sync()
if git config "submodule.$name.url" >/dev/null 2>/dev/null
then
- displaypath=$(relative_path "$prefix$sm_path")
+ displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
say "$(eval_gettext "Synchronizing submodule url for '\$displaypath'")"
git config submodule."$name".url "$super_config_url"
if test -e "$sm_path"/.git
then
(
- clear_local_git_env
+ sanitize_submodule_env
cd "$sm_path"
remote=$(get_default_remote)
git config remote."$remote".url "$sub_origin_url"