X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-submodule.sh;h=3320998c76ba72094755ec60369a6266751889ff;hb=b3abdd9d216c578383b66bb10b95edb3380640e7;hp=486d3b212484b2ac8d33f1fb8a1c65c6fded7dc5;hpb=33aa6fff5d502d8e2806d31bb0916006993c1f24;p=git.git diff --git a/git-submodule.sh b/git-submodule.sh index 486d3b212..3320998c7 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -1,13 +1,15 @@ #!/bin/sh # -# git-submodules.sh: init, update or list git submodules +# git-submodules.sh: add, init, update or list git submodules # # Copyright (c) 2007 Lars Hjemli -USAGE='[--quiet] [--cached] [status|init|update] [--] [...]' +USAGE='[--quiet] [--cached] [add [-b branch]|status|init|update] [--] [...]' . git-sh-setup require_work_tree +add= +branch= init= update= status= @@ -25,10 +27,43 @@ 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 +} + +# +# Map submodule path to submodule name +# +# $1 = path +# +module_name() +{ + # Do we have "submodule..path = $1" defined in .gitmodules file? + re=$(printf '%s' "$1" | sed -e 's/\([^a-zA-Z0-9_]\)/\\\1/g') + name=$( GIT_CONFIG=.gitmodules \ + git config --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'" + echo "$name" +} # # Clone a submodule # +# Prior to calling, modules_update checks that a possibly existing +# path is not a git repository. +# Likewise, module_add checks that path does not exist at all, +# since it is the location of a new submodule. +# module_clone() { path=$1 @@ -49,11 +84,58 @@ module_clone() die "A file already exist at path '$path'" git-clone -n "$url" "$path" || - die "Clone of submodule '$path' failed" + die "Clone of '$url' into submodule path '$path' failed" +} + +# +# Add a new submodule to the working tree, .gitmodules and the index +# +# $@ = repo [path] +# +# optional branch is stored in global branch variable +# +module_add() +{ + repo=$1 + path=$2 + + if test -z "$repo"; then + usage + fi + + # Turn the source into an absolute path if + # it is local + if base=$(get_repo_base "$repo"); then + repo="$base" + 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 + + test -e "$path" && + die "'$path' already exists" + + git ls-files --error-unmatch "$path" > /dev/null 2>&1 && + die "'$path' already exists in the index" + + module_clone "$path" "$repo" || exit + (unset GIT_DIR && cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) || + die "Unable to checkout submodule '$path'" + git add "$path" || + die "Failed to add submodule '$path'" + + GIT_CONFIG=.gitmodules git config submodule."$path".path "$path" && + GIT_CONFIG=.gitmodules git config submodule."$path".url "$repo" && + git add .gitmodules || + die "Failed to register submodule '$path'" } # -# Run clone + checkout on missing submodules +# Register submodules in .git/config # # $@ = requested paths (default to all) # @@ -62,37 +144,24 @@ modules_init() git ls-files --stage -- "$@" | grep -e '^160000 ' | while read mode sha1 stage path do - # Skip submodule paths that already contain a .git directory. - # This will also trigger if $path is a symlink to a git - # repository - test -d "$path"/.git && continue + # Skip already registered paths + name=$(module_name "$path") || exit + url=$(git config submodule."$name".url) + test -z "$url" || continue - url=$(GIT_CONFIG=.gitmodules git-config module."$path".url) + url=$(GIT_CONFIG=.gitmodules git config submodule."$name".url) test -z "$url" && - die "No url found for submodule '$path' in .gitmodules" + die "No url found for submodule path '$path' in .gitmodules" - # MAYBE FIXME: this would be the place to check GIT_CONFIG - # for a preferred url for this submodule, possibly like this: - # - # modname=$(GIT_CONFIG=.gitmodules git-config module."$path".name) - # alturl=$(git-config module."$modname".url) - # - # This would let the versioned .gitmodules file use the submodule - # path as key, while the unversioned GIT_CONFIG would use the - # logical modulename (if present) as key. But this would need - # another fallback mechanism if the module wasn't named. + git config submodule."$name".url "$url" || + die "Failed to register url for submodule path '$path'" - module_clone "$path" "$url" || exit - - (unset GIT_DIR && cd "$path" && git-checkout -q "$sha1") || - die "Checkout of submodule '$path' failed" - - say "Submodule '$path' initialized" + say "Submodule '$name' ($url) registered for path '$path'" done } # -# Checkout correct revision of each initialized submodule +# Update each submodule path to correct revision, using clone and checkout as needed # # $@ = requested paths (default to all) # @@ -101,31 +170,52 @@ modules_update() git ls-files --stage -- "$@" | grep -e '^160000 ' | while read mode sha1 stage path do - if ! test -d "$path"/.git + name=$(module_name "$path") || exit + url=$(git config submodule."$name".url) + if test -z "$url" then # Only mention uninitialized submodules when its # path have been specified test "$#" != "0" && - say "Submodule '$path' not initialized" - continue; + say "Submodule path '$path' not initialized" + continue + fi + + if ! test -d "$path"/.git + then + module_clone "$path" "$url" || exit + subsha1= + else + subsha1=$(unset GIT_DIR && cd "$path" && + git rev-parse --verify HEAD) || + die "Unable to find current revision in submodule path '$path'" fi - subsha1=$(unset GIT_DIR && cd "$path" && - git-rev-parse --verify HEAD) || - die "Unable to find current revision of submodule '$path'" if test "$subsha1" != "$sha1" then (unset GIT_DIR && cd "$path" && git-fetch && git-checkout -q "$sha1") || - die "Unable to checkout '$sha1' in submodule '$path'" + die "Unable to checkout '$sha1' in submodule path '$path'" - say "Submodule '$path': checked out '$sha1'" + say "Submodule path '$path': checked out '$sha1'" fi done } +set_name_rev () { + revname=$( ( + unset GIT_DIR && + cd "$1" && { + git describe "$2" 2>/dev/null || + git describe --tags "$2" 2>/dev/null || + git describe --contains --tags "$2" + } + ) ) + test -z "$revname" || revname=" ($revname)" +} + # -# List all registered submodules, prefixed with: +# List all submodules, prefixed with: # - submodule not initialized # + different revision checked out # @@ -139,22 +229,24 @@ modules_list() git ls-files --stage -- "$@" | grep -e '^160000 ' | while read mode sha1 stage path do - if ! test -d "$path"/.git + name=$(module_name "$path") || exit + url=$(git config submodule."$name".url) + if test -z "url" || ! test -d "$path"/.git then say "-$sha1 $path" continue; fi - revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1) + set_name_rev "$path" "$sha1" if git diff-files --quiet -- "$path" then - say " $sha1 $path ($revname)" + say " $sha1 $path$revname" else if test -z "$cached" then - sha1=$(unset GIT_DIR && cd "$path" && git-rev-parse --verify HEAD) - revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1) + sha1=$(unset GIT_DIR && cd "$path" && git rev-parse --verify HEAD) + set_name_rev "$path" "$sha1" fi - say "+$sha1 $path ($revname)" + say "+$sha1 $path$revname" fi done } @@ -162,6 +254,9 @@ modules_list() while case "$#" in 0) break ;; esac do case "$1" in + add) + add=1 + ;; init) init=1 ;; @@ -174,6 +269,14 @@ do -q|--quiet) quiet=1 ;; + -b|--branch) + case "$2" in + '') + usage + ;; + esac + branch="$2"; shift + ;; --cached) cached=1 ;; @@ -190,14 +293,27 @@ do shift done -case "$init,$update,$status,$cached" in -1,,,) +case "$add,$branch" in +1,*) + ;; +,) + ;; +,*) + usage + ;; +esac + +case "$add,$init,$update,$status,$cached" in +1,,,,) + module_add "$@" + ;; +,1,,,) modules_init "$@" ;; -,1,,) +,,1,,) modules_update "$@" ;; -,,*,*) +,,,*,*) modules_list "$@" ;; *)