diff options
Diffstat (limited to 'git-submodule.sh')
-rwxr-xr-x | git-submodule.sh | 206 |
1 files changed, 48 insertions, 158 deletions
diff --git a/git-submodule.sh b/git-submodule.sh index 78c2740fdb..753a90d307 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -154,48 +154,6 @@ relative_path () echo "$result$target" } -# -# Get submodule info for registered submodules -# $@ = path to limit submodule list -# -module_list() -{ - eval "set $(git rev-parse --sq --prefix "$wt_prefix" -- "$@")" - ( - git ls-files -z --error-unmatch --stage -- "$@" || - echo "unmatched pathspec exists" - ) | - @@PERL@@ -e ' - my %unmerged = (); - my ($null_sha1) = ("0" x 40); - my @out = (); - my $unmatched = 0; - $/ = "\0"; - while (<STDIN>) { - if (/^unmatched pathspec/) { - $unmatched = 1; - next; - } - chomp; - my ($mode, $sha1, $stage, $path) = - /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/; - next unless $mode eq "160000"; - if ($stage ne "0") { - if (!$unmerged{$path}++) { - push @out, "$mode $null_sha1 U\t$path\n"; - } - next; - } - push @out, "$_\n"; - } - if ($unmatched) { - print "#unmatched\n"; - } else { - print for (@out); - } - ' -} - die_if_unmatched () { if test "$1" = "#unmatched" @@ -229,98 +187,6 @@ get_submodule_config () { printf '%s' "${value:-$default}" } - -# -# Map submodule path to submodule name -# -# $1 = path -# -module_name() -{ - # Do we have "submodule.<something>.path = $1" defined in .gitmodules file? - sm_path="$1" - re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g') - name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' | - sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' ) - test -z "$name" && - die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$sm_path'")" - printf '%s\n' "$name" -} - -# -# 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) -# -# 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, -# since it is the location of a new submodule. -# -module_clone() -{ - sm_path=$1 - name=$2 - url=$3 - reference="$4" - depth="$5" - quiet= - if test -n "$GIT_QUIET" - then - quiet=-q - fi - - gitdir= - gitdir_base= - base_name=$(dirname "$name") - - gitdir=$(git rev-parse --git-dir) - gitdir_base="$gitdir/modules/$base_name" - gitdir="$gitdir/modules/$name" - - if test -d "$gitdir" - then - mkdir -p "$sm_path" - rm -f "$gitdir/index" - else - mkdir -p "$gitdir_base" - ( - clear_local_git_env - git clone $quiet ${depth:+"$depth"} -n ${reference:+"$reference"} \ - --separate-git-dir "$gitdir" "$url" "$sm_path" - ) || - die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")" - fi - - # We already are at the root of the work tree but cd_to_toplevel will - # resolve any symlinks that might be present in $PWD - a=$(cd_to_toplevel && cd "$gitdir" && pwd)/ - b=$(cd_to_toplevel && cd "$sm_path" && pwd)/ - # Remove all common leading directories after a sanity check - if test "${a#$b}" != "$a" || test "${b#$a}" != "$b"; then - die "$(eval_gettext "Gitdir '\$a' is part of the submodule path '\$b' or vice versa")" - fi - while test "${a%%/*}" = "${b%%/*}" - do - a=${a#*/} - b=${b#*/} - done - # Now chop off the trailing '/'s that were added in the beginning - a=${a%/} - b=${b%/} - - # Turn each leading "*/" component into "../" - rel=$(printf '%s\n' "$b" | sed -e 's|[^/][^/]*|..|g') - printf '%s\n' "gitdir: $rel/$a" >"$sm_path/.git" - - rel=$(printf '%s\n' "$a" | sed -e 's|[^/][^/]*|..|g') - (clear_local_git_env; cd "$sm_path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b") -} - isnumber() { n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1" @@ -481,7 +347,7 @@ Use -f if you really want to add it." >&2 echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")" fi fi - module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" || exit + git submodule--helper clone ${GIT_QUIET:+--quiet} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" "$reference" "$depth" || exit ( clear_local_git_env cd "$sm_path" && @@ -541,15 +407,15 @@ cmd_foreach() # command in the subshell (and a recursive call to this function) exec 3<&0 - module_list | + git submodule--helper list --prefix "$wt_prefix"| while read mode sha1 stage sm_path do die_if_unmatched "$mode" if test -e "$sm_path"/.git then - displaypath=$(relative_path "$sm_path") - say "$(eval_gettext "Entering '\$prefix\$displaypath'")" - name=$(module_name "$sm_path") + displaypath=$(relative_path "$prefix$sm_path") + say "$(eval_gettext "Entering '\$displaypath'")" + name=$(git submodule--helper name "$sm_path") ( prefix="$prefix$sm_path/" clear_local_git_env @@ -568,7 +434,7 @@ cmd_foreach() cmd_foreach "--recursive" "$@" fi ) <&3 3<&- || - die "$(eval_gettext "Stopping at '\$prefix\$displaypath'; script returned non-zero status.")" + die "$(eval_gettext "Stopping at '\$displaypath'; script returned non-zero status.")" fi done } @@ -601,13 +467,13 @@ cmd_init() shift done - module_list "$@" | + git submodule--helper list --prefix "$wt_prefix" "$@" | while read mode sha1 stage sm_path do die_if_unmatched "$mode" - name=$(module_name "$sm_path") || exit + name=$(git submodule--helper name "$sm_path") || exit - displaypath=$(relative_path "$sm_path") + displaypath=$(relative_path "$prefix$sm_path") # Copy url setting when it is not set yet if test -z "$(git config "submodule.$name.url")" @@ -683,11 +549,11 @@ cmd_deinit() die "$(eval_gettext "Use '.' if you really want to deinitialize all submodules")" fi - module_list "$@" | + git submodule--helper list --prefix "$wt_prefix" "$@" | while read mode sha1 stage sm_path do die_if_unmatched "$mode" - name=$(module_name "$sm_path") || exit + name=$(git submodule--helper name "$sm_path") || exit displaypath=$(relative_path "$sm_path") @@ -725,6 +591,24 @@ cmd_deinit() done } +is_tip_reachable () ( + clear_local_git_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 + cd "$1" && + case "$2" in + '') + git fetch ;; + *) + git fetch $(get_default_remote) "$2" ;; + esac +) + # # Update each submodule path to correct revision, using clone and checkout as needed # @@ -799,7 +683,7 @@ cmd_update() fi cloned_modules= - module_list "$@" | { + git submodule--helper list --prefix "$wt_prefix" "$@" | { err= while read mode sha1 stage sm_path do @@ -809,7 +693,7 @@ cmd_update() echo >&2 "Skipping unmerged submodule $prefix$sm_path" continue fi - name=$(module_name "$sm_path") || exit + name=$(git submodule--helper name "$sm_path") || exit url=$(git config submodule."$name".url) branch=$(get_submodule_config "$name" branch master) if ! test -z "$update" @@ -843,7 +727,7 @@ Maybe you want to use 'update --init'?")" if ! test -d "$sm_path"/.git && ! test -f "$sm_path"/.git then - module_clone "$sm_path" "$name" "$url" "$reference" "$depth" || exit + 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= else @@ -879,10 +763,15 @@ Maybe you want to use 'update --init'?")" then # Run fetch only if $sha1 isn't present or it # is not reachable from a ref. - (clear_local_git_env; cd "$sm_path" && - ( (rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) && - test -z "$rev") || git-fetch)) || + is_tip_reachable "$sm_path" "$sha1" || + fetch_in_submodule "$sm_path" || die "$(eval_gettext "Unable to fetch in submodule path '\$displaypath'")" + + # Now we tried the usual fetch, but $sha1 may + # not be reachable from any of the refs + is_tip_reachable "$sm_path" "$sha1" || + fetch_in_submodule "$sm_path" "$sha1" || + 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? @@ -913,8 +802,8 @@ Maybe you want to use 'update --init'?")" ;; !*) command="${update_module#!}" - die_msg="$(eval_gettext "Execution of '\$command \$sha1' failed in submodule path '\$prefix\$sm_path'")" - say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': '\$command \$sha1'")" + die_msg="$(eval_gettext "Execution of '\$command \$sha1' failed in submodule path '\$displaypath'")" + say_msg="$(eval_gettext "Submodule path '\$displaypath': '\$command \$sha1'")" must_die_on_failure=yes ;; *) @@ -1073,7 +962,7 @@ cmd_summary() { # Respect the ignore setting for --for-status. if test -n "$for_status" then - name=$(module_name "$sm_path") + name=$(git submodule--helper name "$sm_path") ignore_config=$(get_submodule_config "$name" ignore none) test $status != A && test $ignore_config = all && continue fi @@ -1231,11 +1120,11 @@ cmd_status() shift done - module_list "$@" | + git submodule--helper list --prefix "$wt_prefix" "$@" | while read mode sha1 stage sm_path do die_if_unmatched "$mode" - name=$(module_name "$sm_path") || exit + name=$(git submodule--helper name "$sm_path") || exit url=$(git config submodule."$name".url) displaypath=$(relative_path "$prefix$sm_path") if test "$stage" = U @@ -1270,6 +1159,7 @@ cmd_status() ( prefix="$displaypath/" clear_local_git_env + wt_prefix= cd "$sm_path" && eval cmd_status ) || @@ -1308,11 +1198,11 @@ cmd_sync() esac done cd_to_toplevel - module_list "$@" | + git submodule--helper list --prefix "$wt_prefix" "$@" | while read mode sha1 stage sm_path do die_if_unmatched "$mode" - name=$(module_name "$sm_path") + name=$(git submodule--helper name "$sm_path") url=$(git config -f .gitmodules --get submodule."$name".url) # Possibly a url relative to parent |