X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-submodule.sh;h=1c39b593a628cc94d24d227cc5d92e00ac5e71ed;hb=9047ebbc229bf5b99d6c7522293b8cbd1100b747;hp=100737210de3c76682ab3803626a36328fb27ca1;hpb=e5e9714a106ab668ac982cf73f31919eb4e354fd;p=git.git diff --git a/git-submodule.sh b/git-submodule.sh index 100737210..1c39b593a 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -5,10 +5,11 @@ # Copyright (c) 2007 Lars Hjemli USAGE="[--quiet] [--cached] \ -[add [-b branch]|status|init|update [-i|--init]|summary [-n|--summary-limit ] []] \ -[--] [...]" +[add [-b branch] ]|[status|init|update [-i|--init]|summary [-n|--summary-limit ] []] \ +[--] [...]|[foreach ]|[sync [--] [...]]" OPTIONS_SPEC= . git-sh-setup +. git-parse-remote require_work_tree command= @@ -27,27 +28,14 @@ say() fi } -# NEEDSWORK: identical function exists in get_repo_base in clone.sh -get_repo_base() { - ( - cd "`/bin/pwd`" && - cd "$1" || cd "$1.git" && - { - cd .git - pwd - } - ) 2>/dev/null -} - # 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}" - remoteurl="$(git config remote.$remote.url)" || - die "remote ($remote) does not have a url in .git/config" + 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 @@ -62,7 +50,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 --stage -- "$@" | grep '^160000 ' } # @@ -73,7 +70,7 @@ resolve_relative_url () module_name() { # Do we have "submodule..path = $1" defined in .gitmodules file? - re=$(printf '%s' "$1" | sed -e 's/[].[^$\\*]/\\&/g') + 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" && @@ -115,7 +112,7 @@ module_clone() # # Add a new submodule to the working tree, .gitmodules and the index # -# $@ = repo [path] +# $@ = repo path # # optional branch is stored in global branch variable # @@ -150,16 +147,27 @@ cmd_add() repo=$1 path=$2 - if test -z "$repo"; then + if test -z "$repo" -o -z "$path"; then usage fi - # Guess path from repo if not specified or strip trailing slashes - if test -z "$path"; then - path=$(echo "$repo" | sed -e 's|/*$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g') - else - path=$(echo "$path" | sed -e 's|/*$||') - fi + # assure repo is absolute or relative to parent + case "$repo" in + ./*|../*) + # dereference source url relative to parent's url + realrepo=$(resolve_relative_url "$repo") || exit + ;; + *:*|/*) + # absolute url + realrepo=$repo + ;; + *) + die "repo URL: '$repo' must be absolute or begin with ./|../" + ;; + esac + + # strip trailing slashes from path + path=$(echo "$path" | sed -e 's|/*$||') git ls-files --error-unmatch "$path" > /dev/null 2>&1 && die "'$path' already exists in the index" @@ -167,27 +175,23 @@ cmd_add() # perhaps the path exists and is already a git repo, else clone it if test -e "$path" then - if test -d "$path/.git" && - test "$(unset GIT_DIR; cd $path; git rev-parse --git-dir)" = ".git" + if test -d "$path"/.git -o -f "$path"/.git then echo "Adding existing repo at '$path' to the index" else die "'$path' already exists and is not a valid git repo" fi - else + case "$repo" in ./*|../*) - # dereference source url relative to parent's url - realrepo="$(resolve_relative_url $repo)" ;; + url=$(resolve_relative_url "$repo") || exit + ;; *) - # Turn the source into an absolute path if - # it is local - if base=$(get_repo_base "$repo"); then - repo="$base" - fi - realrepo=$repo + url="$repo" ;; esac + git config submodule."$path".url "$url" + else module_clone "$path" "$realrepo" || exit (unset GIT_DIR; cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) || @@ -203,6 +207,26 @@ cmd_add() die "Failed to register submodule '$path'" } +# +# 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 # @@ -231,7 +255,7 @@ cmd_init() shift done - git ls-files --stage -- "$@" | grep '^160000 ' | + module_list "$@" | while read mode sha1 stage path do # Skip already registered paths @@ -246,7 +270,7 @@ cmd_init() # Possibly a url relative to parent case "$url" in ./*|../*) - url="$(resolve_relative_url "$url")" + url=$(resolve_relative_url "$url") || exit ;; esac @@ -269,6 +293,7 @@ cmd_update() do case "$1" in -q|--quiet) + shift quiet=1 ;; -i|--init) @@ -286,10 +311,9 @@ cmd_update() break ;; esac - shift done - git ls-files --stage -- "$@" | grep '^160000 ' | + module_list "$@" | while read mode sha1 stage path do name=$(module_name "$path") || exit @@ -554,7 +578,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 +602,50 @@ 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) + 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 +656,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)