diff options
Diffstat (limited to 'git-submodule.sh')
-rwxr-xr-x | git-submodule.sh | 143 |
1 files changed, 123 insertions, 20 deletions
diff --git a/git-submodule.sh b/git-submodule.sh index 97e4d9a1ef..7c2e060ae7 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -5,16 +5,18 @@ # Copyright (c) 2007 Lars Hjemli USAGE="[--quiet] [--cached] \ -[add <repo> [-b branch] <path>]|[status|init|update [-i|--init]|summary [-n|--summary-limit <n>] [<commit>]] \ -[--] [<path>...]" +[add [-b branch] <repo> <path>]|[status|init|update [-i|--init] [-N|--no-fetch]|summary [-n|--summary-limit <n>] [<commit>]] \ +[--] [<path>...]|[foreach <command>]|[sync [--] [<path>...]]" OPTIONS_SPEC= . git-sh-setup +. git-parse-remote require_work_tree command= branch= quiet= cached= +nofetch= # # print stuff on stdout unless -q was specified @@ -30,12 +32,11 @@ say() # Resolve relative url by appending to parent's url resolve_relative_url () { - branch="$(git symbolic-ref HEAD 2>/dev/null)" - remote="$(git config branch.${branch#refs/heads/}.remote)" - remote="${remote:-origin}" + remote=$(get_default_remote) remoteurl=$(git config "remote.$remote.url") || die "remote ($remote) does not have a url defined in .git/config" url="$1" + remoteurl=${remoteurl%/} while test -n "$url" do case "$url" in @@ -50,7 +51,16 @@ resolve_relative_url () break;; esac done - echo "$remoteurl/$url" + echo "$remoteurl/${url%/}" +} + +# +# Get submodule info for registered submodules +# $@ = path to limit submodule list +# +module_list() +{ + git ls-files --error-unmatch --stage -- "$@" | grep '^160000 ' } # @@ -157,9 +167,18 @@ cmd_add() ;; esac - # strip trailing slashes from path - path=$(echo "$path" | sed -e 's|/*$||') - + # normalize path: + # multiple //; leading ./; /./; /../; trailing / + path=$(printf '%s/\n' "$path" | + sed -e ' + s|//*|/|g + s|^\(\./\)*|| + s|/\./|/|g + :start + s|\([^/]*\)/\.\./|| + tstart + s|/*$|| + ') git ls-files --error-unmatch "$path" > /dev/null 2>&1 && die "'$path' already exists in the index" @@ -199,6 +218,26 @@ cmd_add() } # +# Execute an arbitrary command sequence in each checked out +# submodule +# +# $@ = command to execute +# +cmd_foreach() +{ + module_list | + while read mode sha1 stage path + do + if test -e "$path"/.git + then + say "Entering '$path'" + (cd "$path" && eval "$@") || + die "Stopping at '$path'; script returned non-zero status." + fi + done +} + +# # Register submodules in .git/config # # $@ = requested paths (default to all) @@ -226,7 +265,7 @@ cmd_init() shift done - git ls-files --stage -- "$@" | grep '^160000 ' | + module_list "$@" | while read mode sha1 stage path do # Skip already registered paths @@ -271,6 +310,10 @@ cmd_update() shift cmd_init "$@" || return ;; + -N|--no-fetch) + shift + nofetch=1 + ;; --) shift break @@ -284,7 +327,7 @@ cmd_update() esac done - git ls-files --stage -- "$@" | grep '^160000 ' | + module_list "$@" | while read mode sha1 stage path do name=$(module_name "$path") || exit @@ -316,8 +359,16 @@ cmd_update() then force="-f" fi - (unset GIT_DIR; cd "$path" && git-fetch && - git-checkout $force -q "$sha1") || + + if test -z "$nofetch" + then + (unset GIT_DIR; cd "$path" && + git-fetch) || + die "Unable to fetch in submodule path '$path'" + fi + + (unset GIT_DIR; cd "$path" && + git-checkout $force -q "$sha1") || die "Unable to checkout '$sha1' in submodule path '$path'" say "Submodule path '$path': checked out '$sha1'" @@ -384,7 +435,7 @@ cmd_summary() { test $summary_limit = 0 && return - if rev=$(git rev-parse --verify "$1^0" 2>/dev/null) + if rev=$(git rev-parse -q --verify "$1^0") then head=$rev shift @@ -395,7 +446,7 @@ cmd_summary() { cd_to_toplevel # Get modified modules cared by user modules=$(git diff-index $cached --raw $head -- "$@" | - grep -e '^:160000' -e '^:[0-7]* 160000' | + egrep '^:([0-7]* )?160000' | while read mod_src mod_dst sha1_src sha1_dst status name do # Always show modules deleted or type-changed (blob<->module) @@ -409,7 +460,7 @@ cmd_summary() { test -z "$modules" && return git diff-index $cached --raw $head -- $modules | - grep -e '^:160000' -e '^:[0-7]* 160000' | + egrep '^:([0-7]* )?160000' | cut -c2- | while read mod_src mod_dst sha1_src sha1_dst status name do @@ -435,11 +486,11 @@ cmd_summary() { missing_dst= test $mod_src = 160000 && - ! GIT_DIR="$name/.git" git-rev-parse --verify $sha1_src^0 >/dev/null 2>&1 && + ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null && missing_src=t test $mod_dst = 160000 && - ! GIT_DIR="$name/.git" git-rev-parse --verify $sha1_dst^0 >/dev/null 2>&1 && + ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null && missing_dst=t total_commits= @@ -554,7 +605,7 @@ cmd_status() shift done - git ls-files --stage -- "$@" | grep '^160000 ' | + module_list "$@" | while read mode sha1 stage path do name=$(module_name "$path") || exit @@ -578,6 +629,58 @@ cmd_status() fi done } +# +# Sync remote urls for submodules +# This makes the value for remote.$remote.url match the value +# specified in .gitmodules. +# +cmd_sync() +{ + while test $# -ne 0 + do + case "$1" in + -q|--quiet) + quiet=1 + shift + ;; + --) + shift + break + ;; + -*) + usage + ;; + *) + break + ;; + esac + done + cd_to_toplevel + module_list "$@" | + while read mode sha1 stage path + do + name=$(module_name "$path") + url=$(git config -f .gitmodules --get submodule."$name".url) + + # Possibly a url relative to parent + case "$url" in + ./*|../*) + url=$(resolve_relative_url "$url") || exit + ;; + esac + + if test -e "$path"/.git + then + ( + unset GIT_DIR + cd "$path" + remote=$(get_default_remote) + say "Synchronizing submodule url for '$name'" + git config remote."$remote".url "$url" + ) + fi + done +} # This loop parses the command line arguments to find the # subcommand name to dispatch. Parsing of the subcommand specific @@ -588,7 +691,7 @@ cmd_status() while test $# != 0 && test -z "$command" do case "$1" in - add | init | update | status | summary) + add | foreach | init | update | status | summary | sync) command=$1 ;; -q|--quiet) |