diff options
Diffstat (limited to 'git-submodule.sh')
-rwxr-xr-x | git-submodule.sh | 232 |
1 files changed, 165 insertions, 67 deletions
diff --git a/git-submodule.sh b/git-submodule.sh index 79bfaac9d4..2677f2e8b3 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -14,10 +14,13 @@ USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <re or: $dashless [--quiet] foreach [--recursive] <command> or: $dashless [--quiet] sync [--recursive] [--] [<path>...]" OPTIONS_SPEC= +SUBDIRECTORY_OK=Yes . git-sh-setup . git-sh-i18n . git-parse-remote require_work_tree +wt_prefix=$(git rev-parse --show-prefix) +cd_to_toplevel command= branch= @@ -32,6 +35,7 @@ nofetch= update= 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 @@ -106,21 +110,58 @@ resolve_relative_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" +} + # # 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 --error-unmatch --stage -- "$@" || + 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 = (); my $unmatched = 0; + $/ = "\0"; while (<STDIN>) { if (/^unmatched pathspec/) { $unmatched = 1; @@ -211,6 +252,7 @@ module_clone() name=$2 url=$3 reference="$4" + depth="$5" quiet= if test -n "$GIT_QUIET" then @@ -233,7 +275,7 @@ module_clone() mkdir -p "$gitdir_base" ( clear_local_git_env - git clone $quiet -n ${reference:+"$reference"} \ + 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")" @@ -282,6 +324,7 @@ isnumber() cmd_add() { # parse $args after "submodule ... add". + reference_path= while test $# -ne 0 do case "$1" in @@ -298,17 +341,25 @@ cmd_add() ;; --reference) case "$2" in '') usage ;; esac - reference="--reference=$2" + reference_path=$2 shift ;; --reference=*) - reference="$1" + reference_path="${1#--reference=}" ;; --name) case "$2" in '') usage ;; esac custom_name=$2 shift ;; + --depth) + case "$2" in '') usage ;; esac + depth="--depth=$2" + shift + ;; + --depth=*) + depth=$1 + ;; --) shift break @@ -323,6 +374,14 @@ cmd_add() shift done + if test -n "$reference_path" + then + is_absolute_path "$reference_path" || + reference_path="$wt_prefix$reference_path" + + reference="--reference=$reference_path" + fi + repo=$1 sm_path=$2 @@ -335,9 +394,14 @@ cmd_add() usage fi + is_absolute_path "$sm_path" || sm_path="$wt_prefix$sm_path" + # assure repo is absolute or relative to parent case "$repo" in ./*|../*) + test -z "$wt_prefix" || + 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 ;; @@ -405,7 +469,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" || exit + module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" || exit ( clear_local_git_env cd "$sm_path" && @@ -471,21 +535,28 @@ cmd_foreach() die_if_unmatched "$mode" if test -e "$sm_path"/.git then - say "$(eval_gettext "Entering '\$prefix\$sm_path'")" + displaypath=$(relative_path "$sm_path") + say "$(eval_gettext "Entering '\$prefix\$displaypath'")" name=$(module_name "$sm_path") ( prefix="$prefix$sm_path/" clear_local_git_env - # we make $path available to scripts ... - path=$sm_path cd "$sm_path" && - eval "$@" && + sm_path=$(relative_path "$sm_path") && + # we make $path available to scripts ... + path=$sm_path && + if test $# -eq 1 + then + eval "$1" + else + "$@" + fi && if test -n "$recursive" then cmd_foreach "--recursive" "$@" fi ) <&3 3<&- || - die "$(eval_gettext "Stopping at '\$sm_path'; script returned non-zero status.")" + die "$(eval_gettext "Stopping at '\$prefix\$displaypath'; script returned non-zero status.")" fi done } @@ -524,12 +595,14 @@ cmd_init() die_if_unmatched "$mode" name=$(module_name "$sm_path") || exit + displaypath=$(relative_path "$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 '\$sm_path' in .gitmodules")" + die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")" # Possibly a url relative to parent case "$url" in @@ -538,17 +611,27 @@ cmd_init() ;; esac git config submodule."$name".url "$url" || - die "$(eval_gettext "Failed to register url for submodule path '\$sm_path'")" + die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")" - say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$sm_path'")" + say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")" fi # Copy "update" setting when it is not set yet - upd="$(git config -f .gitmodules submodule."$name".update)" - test -z "$upd" || - test -n "$(git config submodule."$name".update)" || - git config submodule."$name".update "$upd" || - die "$(eval_gettext "Failed to register update mode for submodule path '\$sm_path'")" + if upd="$(git config -f .gitmodules submodule."$name".update)" && + test -n "$upd" && + test -z "$(git config submodule."$name".update)" + then + case "$upd" in + 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 } @@ -594,27 +677,29 @@ cmd_deinit() die_if_unmatched "$mode" name=$(module_name "$sm_path") || exit + displaypath=$(relative_path "$sm_path") + # Remove the submodule work tree (unless the user already did it) if test -d "$sm_path" then # Protect submodules containing a .git directory if test -d "$sm_path/.git" then - echo >&2 "$(eval_gettext "Submodule work tree '\$sm_path' contains a .git directory")" + echo >&2 "$(eval_gettext "Submodule work tree '\$displaypath' contains a .git directory")" die "$(eval_gettext "(use 'rm -rf' if you really want to remove it including all of its history)")" fi if test -z "$force" then git rm -qn "$sm_path" || - die "$(eval_gettext "Submodule work tree '\$sm_path' contains local modifications; use '-f' to discard them")" + die "$(eval_gettext "Submodule work tree '\$displaypath' contains local modifications; use '-f' to discard them")" fi rm -rf "$sm_path" && - say "$(eval_gettext "Cleared directory '\$sm_path'")" || - say "$(eval_gettext "Could not remove submodule work tree '\$sm_path'")" + say "$(eval_gettext "Cleared directory '\$displaypath'")" || + say "$(eval_gettext "Could not remove submodule work tree '\$displaypath'")" fi - mkdir "$sm_path" || say "$(eval_gettext "Could not create empty submodule directory '\$sm_path'")" + mkdir "$sm_path" || say "$(eval_gettext "Could not create empty submodule directory '\$displaypath'")" # Remove the .git/config entries (unless the user already did it) if test -n "$(git config --get-regexp submodule."$name\.")" @@ -623,7 +708,7 @@ cmd_deinit() # the user later decides to init this submodule again url=$(git config submodule."$name".url) git config --remove-section submodule."$name" 2>/dev/null && - say "$(eval_gettext "Submodule '\$name' (\$url) unregistered for path '\$sm_path'")" + say "$(eval_gettext "Submodule '\$name' (\$url) unregistered for path '\$displaypath'")" fi done } @@ -636,7 +721,6 @@ cmd_deinit() cmd_update() { # parse $args after "submodule ... update". - orig_flags= while test $# -ne 0 do case "$1" in @@ -661,7 +745,6 @@ cmd_update() --reference) case "$2" in '') usage ;; esac reference="--reference=$2" - orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")" shift ;; --reference=*) @@ -676,6 +759,14 @@ cmd_update() --checkout) update="checkout" ;; + --depth) + case "$2" in '') usage ;; esac + depth="--depth=$2" + shift + ;; + --depth=*) + depth=$1 + ;; --) shift break @@ -687,7 +778,6 @@ cmd_update() break ;; esac - orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")" shift done @@ -717,9 +807,11 @@ cmd_update() update_module=$(git config submodule."$name".update) fi + displaypath=$(relative_path "$prefix$sm_path") + if test "$update_module" = "none" then - echo "Skipping submodule '$prefix$sm_path'" + echo "Skipping submodule '$displaypath'" continue fi @@ -728,20 +820,20 @@ cmd_update() # Only mention uninitialized submodules when its # path have been specified test "$#" != "0" && - say "$(eval_gettext "Submodule path '\$prefix\$sm_path' not initialized + say "$(eval_gettext "Submodule path '\$displaypath' not initialized Maybe you want to use 'update --init'?")" continue fi if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git then - module_clone "$sm_path" "$name" "$url" "$reference" || exit + module_clone "$sm_path" "$name" "$url" "$reference" "$depth" || exit cloned_modules="$cloned_modules;$name" subsha1= else subsha1=$(clear_local_git_env; cd "$sm_path" && git rev-parse --verify HEAD) || - die "$(eval_gettext "Unable to find current revision in submodule path '\$prefix\$sm_path'")" + die "$(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")" fi if test -n "$remote" @@ -774,7 +866,7 @@ Maybe you want to use 'update --init'?")" (clear_local_git_env; cd "$sm_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 '\$prefix\$sm_path'")" + die "$(eval_gettext "Unable to fetch in submodule path '\$displaypath'")" fi # Is this something we just cloned? @@ -788,20 +880,26 @@ Maybe you want to use 'update --init'?")" case "$update_module" in rebase) command="git rebase" - die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$prefix\$sm_path'")" - say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': rebased into '\$sha1'")" + die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$displaypath'")" + say_msg="$(eval_gettext "Submodule path '\$displaypath': rebased into '\$sha1'")" must_die_on_failure=yes ;; merge) command="git merge" - die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$prefix\$sm_path'")" - say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': merged in '\$sha1'")" + die_msg="$(eval_gettext "Unable to merge '\$sha1' in submodule path '\$displaypath'")" + say_msg="$(eval_gettext "Submodule path '\$displaypath': merged in '\$sha1'")" + must_die_on_failure=yes + ;; + !*) + 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'")" must_die_on_failure=yes ;; *) command="git checkout $subforce -q" - die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$prefix\$sm_path'")" - say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': checked out '\$sha1'")" + die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")" + say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")" ;; esac @@ -823,12 +921,12 @@ Maybe you want to use 'update --init'?")" 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 then - die_msg="$(eval_gettext "Failed to recurse into submodule path '\$prefix\$sm_path'")" + die_msg="$(eval_gettext "Failed to recurse into submodule path '\$displaypath'")" if test $res -eq 1 then err="${err};$die_msg" @@ -942,16 +1040,24 @@ cmd_summary() { fi cd_to_toplevel + eval "set $(git rev-parse --sq --prefix "$wt_prefix" -- "$@")" # Get modified modules cared by user modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" | sane_egrep '^:([0-7]* )?160000' | - while read mod_src mod_dst sha1_src sha1_dst status name + while read mod_src mod_dst sha1_src sha1_dst status sm_path do # Always show modules deleted or type-changed (blob<->module) - test $status = D -o $status = T && echo "$name" && continue + test $status = D -o $status = T && echo "$sm_path" && continue + # Respect the ignore setting for --for-status. + if test -n "$for_status" + then + name=$(module_name "$sm_path") + ignore_config=$(get_submodule_config "$name" ignore none) + test $status != A -a $ignore_config = all && continue + fi # Also show added or modified modules which are checked out - GIT_DIR="$name/.git" git-rev-parse --git-dir >/dev/null 2>&1 && - echo "$name" + GIT_DIR="$sm_path/.git" git-rev-parse --git-dir >/dev/null 2>&1 && + echo "$sm_path" done ) @@ -991,16 +1097,18 @@ cmd_summary() { ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null && missing_dst=t + display_name=$(relative_path "$name") + total_commits= case "$missing_src,$missing_dst" in t,) - errmsg="$(eval_gettext " Warn: \$name doesn't contain commit \$sha1_src")" + errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commit \$sha1_src")" ;; ,t) - errmsg="$(eval_gettext " Warn: \$name doesn't contain commit \$sha1_dst")" + errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commit \$sha1_dst")" ;; t,t) - errmsg="$(eval_gettext " Warn: \$name doesn't contain commits \$sha1_src and \$sha1_dst")" + errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commits \$sha1_src and \$sha1_dst")" ;; *) errmsg= @@ -1029,12 +1137,12 @@ cmd_summary() { submodule="$(gettext "submodule")" if test $mod_dst = 160000 then - echo "* $name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:" + echo "* $display_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 "* $display_name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:" fi else - echo "* $name $sha1_abbr_src...$sha1_abbr_dst$total_commits:" + echo "* $display_name $sha1_abbr_src...$sha1_abbr_dst$total_commits:" fi if test -n "$errmsg" then @@ -1060,18 +1168,7 @@ cmd_summary() { echo fi echo - done | - if test -n "$for_status"; then - if [ -n "$files" ]; then - gettextln "Submodules changed but not updated:" | git stripspace -c - else - gettextln "Submodule changes to be committed:" | git stripspace -c - fi - printf "\n" | git stripspace -c - git stripspace -c - else - cat - fi + done } # # List all submodules, prefixed with: @@ -1118,7 +1215,7 @@ cmd_status() die_if_unmatched "$mode" name=$(module_name "$sm_path") || exit url=$(git config submodule."$name".url) - displaypath="$prefix$sm_path" + displaypath=$(relative_path "$prefix$sm_path") if test "$stage" = U then say "U$sha1 $displaypath" @@ -1129,16 +1226,16 @@ cmd_status() say "-$sha1 $displaypath" continue; fi - set_name_rev "$sm_path" "$sha1" if git diff-files --ignore-submodules=dirty --quiet -- "$sm_path" then + set_name_rev "$sm_path" "$sha1" say " $sha1 $displaypath$revname" else if test -z "$cached" then sha1=$(clear_local_git_env; cd "$sm_path" && git rev-parse --verify HEAD) - set_name_rev "$sm_path" "$sha1" fi + set_name_rev "$sm_path" "$sha1" say "+$sha1 $displaypath$revname" fi @@ -1213,7 +1310,8 @@ cmd_sync() if git config "submodule.$name.url" >/dev/null 2>/dev/null then - say "$(eval_gettext "Synchronizing submodule url for '\$prefix\$sm_path'")" + displaypath=$(relative_path "$prefix$sm_path") + say "$(eval_gettext "Synchronizing submodule url for '\$displaypath'")" git config submodule."$name".url "$super_config_url" if test -e "$sm_path"/.git |