X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-submodule.sh;h=3daa0c834cad1ed402376adf535c73e1c06172e4;hb=0591c0a5be7d58dfe2c69c8a81b2cebbb0337320;hp=ec6178ee996ed72143fbcea88516b6b7e489a720;hpb=2cd9de3e18183422cd7ec3cd81cebc656068ea42;p=git.git diff --git a/git-submodule.sh b/git-submodule.sh index ec6178ee9..3daa0c834 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -8,12 +8,13 @@ dashless=$(basename "$0" | sed -e 's/-/ /') USAGE="[--quiet] add [-b branch] [-f|--force] [--reference ] [--] [] or: $dashless [--quiet] status [--cached] [--recursive] [--] [...] or: $dashless [--quiet] init [--] [...] - or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] + or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] or: $dashless [--quiet] summary [--cached|--files] [--summary-limit ] [commit] [--] [...] or: $dashless [--quiet] foreach [--recursive] or: $dashless [--quiet] sync [--] [...]" OPTIONS_SPEC= . git-sh-setup +. git-sh-i18n . git-parse-remote require_work_tree @@ -34,15 +35,27 @@ resolve_relative_url () { remote=$(get_default_remote) remoteurl=$(git config "remote.$remote.url") || - die "remote ($remote) does not have a url defined in .git/config" + die "$(eval_gettext "remote (\$remote) does not have a url defined in .git/config")" url="$1" remoteurl=${remoteurl%/} + sep=/ while test -n "$url" do case "$url" in ../*) url="${url#../}" - remoteurl="${remoteurl%/*}" + case "$remoteurl" in + */*) + remoteurl="${remoteurl%/*}" + ;; + *:*) + remoteurl="${remoteurl%:*}" + sep=: + ;; + *) + die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")" + ;; + esac ;; ./*) url="${url#./}" @@ -51,7 +64,7 @@ resolve_relative_url () break;; esac done - echo "$remoteurl/${url%/}" + echo "$remoteurl$sep${url%/}" } # @@ -60,7 +73,24 @@ resolve_relative_url () # module_list() { - git ls-files --error-unmatch --stage -- "$@" | sane_grep '^160000 ' + git ls-files --error-unmatch --stage -- "$@" | + perl -e ' + my %unmerged = (); + my ($null_sha1) = ("0" x 40); + while () { + 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}++) { + print "$mode $null_sha1 U\t$path\n"; + } + next; + } + print "$_\n"; + } + ' } # @@ -75,7 +105,7 @@ module_name() name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' | sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' ) test -z "$name" && - die "No submodule mapping found in .gitmodules for path '$path'" + die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")" echo "$name" } @@ -93,27 +123,13 @@ module_clone() url=$2 reference="$3" - # If there already is a directory at the submodule path, - # expect it to be empty (since that is the default checkout - # action) and try to remove it. - # Note: if $path is a symlink to a directory the test will - # succeed but the rmdir will fail. We might want to fix this. - if test -d "$path" - then - rmdir "$path" 2>/dev/null || - die "Directory '$path' exists, but is neither empty nor a git repository" - fi - - test -e "$path" && - die "A file already exist at path '$path'" - if test -n "$reference" then git-clone "$reference" -n "$url" "$path" else git-clone -n "$url" "$path" fi || - die "Clone of '$url' into submodule path '$path' failed" + die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")" } # @@ -186,7 +202,7 @@ cmd_add() realrepo=$repo ;; *) - die "repo URL: '$repo' must be absolute or begin with ./|../" + die "$(eval_gettext "repo URL: '\$repo' must be absolute or begin with ./|../")" ;; esac @@ -203,13 +219,16 @@ cmd_add() s|/*$|| ') git ls-files --error-unmatch "$path" > /dev/null 2>&1 && - die "'$path' already exists in the index" + die "$(eval_gettext "'\$path' already exists in the index")" if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1 then - echo >&2 "The following path is ignored by one of your .gitignore files:" && - echo >&2 $path && - echo >&2 "Use -f if you really want to add it." + ( + eval_gettext "The following path is ignored by one of your .gitignore files: +\$path +Use -f if you really want to add it." && + echo + ) >&2 exit 1 fi @@ -218,9 +237,9 @@ cmd_add() then if test -d "$path"/.git -o -f "$path"/.git then - echo "Adding existing repo at '$path' to the index" + eval_gettext "Adding existing repo at '\$path' to the index"; echo else - die "'$path' already exists and is not a valid git repo" + die "$(eval_gettext "'\$path' already exists and is not a valid git repo")" fi case "$repo" in @@ -240,19 +259,19 @@ cmd_add() # ash fails to wordsplit ${branch:+-b "$branch"...} case "$branch" in '') git checkout -f -q ;; - ?*) git checkout -f -q -b "$branch" "origin/$branch" ;; + ?*) git checkout -f -q -B "$branch" "origin/$branch" ;; esac - ) || die "Unable to checkout submodule '$path'" + ) || die "$(eval_gettext "Unable to checkout submodule '\$path'")" fi git config submodule."$path".url "$url" git add $force "$path" || - die "Failed to add submodule '$path'" + die "$(eval_gettext "Failed to add submodule '\$path'")" git config -f .gitmodules submodule."$path".path "$path" && git config -f .gitmodules submodule."$path".url "$repo" && git add --force .gitmodules || - die "Failed to register submodule '$path'" + die "$(eval_gettext "Failed to register submodule '\$path'")" } # @@ -285,12 +304,16 @@ cmd_foreach() toplevel=$(pwd) + # dup stdin so that it can be restored when running the external + # command in the subshell (and a recursive call to this function) + exec 3<&0 + module_list | while read mode sha1 stage path do if test -e "$path"/.git then - say "Entering '$prefix$path'" + say "$(eval_gettext "Entering '\$prefix\$path'")" name=$(module_name "$path") ( prefix="$prefix$path/" @@ -301,8 +324,8 @@ cmd_foreach() then cmd_foreach "--recursive" "$@" fi - ) || - die "Stopping at '$path'; script returned non-zero status." + ) <&3 3<&- || + die "$(eval_gettext "Stopping at '\$path'; script returned non-zero status.")" fi done } @@ -344,7 +367,7 @@ cmd_init() then url=$(git config -f .gitmodules submodule."$name".url) test -z "$url" && - die "No url found for submodule path '$path' in .gitmodules" + die "$(eval_gettext "No url found for submodule path '\$path' in .gitmodules")" # Possibly a url relative to parent case "$url" in @@ -353,7 +376,7 @@ cmd_init() ;; esac git config submodule."$name".url "$url" || - die "Failed to register url for submodule path '$path'" + die "$(eval_gettext "Failed to register url for submodule path '\$path'")" fi # Copy "update" setting when it is not set yet @@ -361,9 +384,9 @@ cmd_init() test -z "$upd" || test -n "$(git config submodule."$name".update)" || git config submodule."$name".update "$upd" || - die "Failed to register update mode for submodule path '$path'" + die "$(eval_gettext "Failed to register update mode for submodule path '\$path'")" - say "Submodule '$name' ($url) registered for path '$path'" + say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$path'")" done } @@ -375,41 +398,38 @@ cmd_init() cmd_update() { # parse $args after "submodule ... update". - orig_args="$@" + orig_flags= while test $# -ne 0 do case "$1" in -q|--quiet) - shift GIT_QUIET=1 ;; -i|--init) init=1 - shift ;; -N|--no-fetch) - shift nofetch=1 ;; + -f|--force) + force=$1 + ;; -r|--rebase) - shift update="rebase" ;; --reference) case "$2" in '') usage ;; esac reference="--reference=$2" - shift 2 + orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")" + shift ;; --reference=*) reference="$1" - shift ;; -m|--merge) - shift update="merge" ;; --recursive) - shift recursive=1 ;; --) @@ -423,6 +443,8 @@ cmd_update() break ;; esac + orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")" + shift done if test -n "$init" @@ -430,9 +452,16 @@ cmd_update() cmd_init "--" "$@" || return fi - module_list "$@" | + cloned_modules= + module_list "$@" | { + err= while read mode sha1 stage path do + if test "$stage" = U + then + echo >&2 "Skipping unmerged submodule $path" + continue + fi name=$(module_name "$path") || exit url=$(git config submodule."$name".url) update_module=$(git config submodule."$name".update) @@ -441,19 +470,20 @@ cmd_update() # Only mention uninitialized submodules when its # path have been specified test "$#" != "0" && - say "Submodule path '$path' not initialized" && - say "Maybe you want to use 'update --init'?" + say "$(eval_gettext "Submodule path '\$path' not initialized +Maybe you want to use 'update --init'?")" continue fi if ! test -d "$path"/.git -o -f "$path"/.git then module_clone "$path" "$url" "$reference"|| exit + cloned_modules="$cloned_modules;$name" subsha1= else subsha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD) || - die "Unable to find current revision in submodule path '$path'" + die "$(eval_gettext "Unable to find current revision in submodule path '\$path'")" fi if ! test -z "$update" @@ -463,48 +493,96 @@ cmd_update() if test "$subsha1" != "$sha1" then - force= - if test -z "$subsha1" + subforce=$force + # If we don't already have a -f flag and the submodule has never been checked out + if test -z "$subsha1" -a -z "$force" then - force="-f" + subforce="-f" fi 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" && - git-fetch) || - die "Unable to fetch in submodule path '$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 + # Is this something we just cloned? + case ";$cloned_modules;" in + *";$name;"*) + # then there is no local change to integrate + update_module= ;; + esac + + must_die_on_failure= case "$update_module" in rebase) command="git rebase" - action="rebase" - msg="rebased onto" + die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$path'")" + say_msg="$(eval_gettext "Submodule path '\$path': rebased into '\$sha1'")" + must_die_on_failure=yes ;; merge) command="git merge" - action="merge" - msg="merged in" + die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$path'")" + say_msg="$(eval_gettext "Submodule path '\$path': merged in '\$sha1'")" + must_die_on_failure=yes ;; *) - command="git checkout $force -q" - action="checkout" - msg="checked out" + command="git checkout $subforce -q" + die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$path'")" + say_msg="$(eval_gettext "Submodule path '\$path': checked out '\$sha1'")" ;; esac - (clear_local_git_env; cd "$path" && $command "$sha1") || - die "Unable to $action '$sha1' in submodule path '$path'" - say "Submodule path '$path': $msg '$sha1'" + if (clear_local_git_env; cd "$path" && $command "$sha1") + then + say "$say_msg" + elif test -n "$must_die_on_failure" + then + die_with_status 2 "$die_msg" + else + err="${err};$die_msg" + continue + fi fi if test -n "$recursive" then - (clear_local_git_env; cd "$path" && cmd_update $orig_args) || - die "Failed to recurse into submodule path '$path'" + (clear_local_git_env; cd "$path" && eval cmd_update "$orig_flags") + res=$? + if test $res -gt 0 + then + die_msg="$(eval_gettext "Failed to recurse into submodule path '\$path'")" + if test $res -eq 1 + then + err="${err};$die_msg" + continue + else + die_with_status $res "$die_msg" + fi + fi fi done + + if test -n "$err" + then + OIFS=$IFS + IFS=';' + for e in $err + do + if test -n "$e" + then + echo >&2 "$e" + fi + done + IFS=$OIFS + exit 1 + fi + } } set_name_rev () { @@ -586,7 +664,7 @@ cmd_summary() { if [ -n "$files" ] then test -n "$cached" && - die "--cached cannot be used with --files" + die "$(gettext -- "--cached cannot be used with --files")" diff_cmd=diff-files head= fi @@ -626,7 +704,10 @@ cmd_summary() { ;; # removed *) # unexpected type - echo >&2 "unexpected mode $mod_dst" + ( + eval_gettext "unexpected mode \$mod_dst" && + echo + ) >&2 continue ;; esac fi @@ -644,13 +725,13 @@ cmd_summary() { total_commits= case "$missing_src,$missing_dst" in t,) - errmsg=" Warn: $name doesn't contain commit $sha1_src" + errmsg="$(eval_gettext " Warn: \$name doesn't contain commit \$sha1_src")" ;; ,t) - errmsg=" Warn: $name doesn't contain commit $sha1_dst" + errmsg="$(eval_gettext " Warn: \$name doesn't contain commit \$sha1_dst")" ;; t,t) - errmsg=" Warn: $name doesn't contain commits $sha1_src and $sha1_dst" + errmsg="$(eval_gettext " Warn: \$name doesn't contain commits \$sha1_src and \$sha1_dst")" ;; *) errmsg= @@ -675,11 +756,13 @@ cmd_summary() { sha1_abbr_dst=$(echo $sha1_dst | cut -c1-7) if test $status = T then + blob="$(gettext "blob")" + submodule="$(gettext "submodule")" if test $mod_dst = 160000 then - echo "* $name $sha1_abbr_src(blob)->$sha1_abbr_dst(submodule)$total_commits:" + echo "* $name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:" else - echo "* $name $sha1_abbr_src(submodule)->$sha1_abbr_dst(blob)$total_commits:" + echo "* $name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:" fi else echo "* $name $sha1_abbr_src...$sha1_abbr_dst$total_commits:" @@ -711,9 +794,9 @@ cmd_summary() { done | if test -n "$for_status"; then if [ -n "$files" ]; then - echo "# Submodules changed but not updated:" + gettext "# Submodules changed but not updated:"; echo else - echo "# Submodule changes to be committed:" + gettext "# Submodule changes to be committed:"; echo fi echo "#" sed -e 's|^|# |' -e 's|^# $|#|' @@ -734,7 +817,7 @@ cmd_summary() { cmd_status() { # parse $args after "submodule ... status". - orig_args="$@" + orig_flags= while test $# -ne 0 do case "$1" in @@ -758,6 +841,7 @@ cmd_status() break ;; esac + orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")" shift done @@ -767,6 +851,11 @@ cmd_status() name=$(module_name "$path") || exit url=$(git config submodule."$name".url) displaypath="$prefix$path" + if test "$stage" = U + then + say "U$sha1 $displaypath" + continue + fi if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git then say "-$sha1 $displaypath" @@ -791,9 +880,9 @@ cmd_status() prefix="$displaypath/" clear_local_git_env cd "$path" && - cmd_status $orig_args + eval cmd_status "$orig_args" ) || - die "Failed to recurse into submodule path '$path'" + die "$(eval_gettext "Failed to recurse into submodule path '\$path'")" fi done } @@ -839,7 +928,7 @@ cmd_sync() if git config "submodule.$name.url" >/dev/null 2>/dev/null then - say "Synchronizing submodule url for '$name'" + say "$(eval_gettext "Synchronizing submodule url for '\$name'")" git config submodule."$name".url "$url" if test -e "$path"/.git