Merge branch 'maint'
[gitweb.git] / git-submodule.sh
index 673aa27a452b11af62d89986bf21c8a4f10e0c41..82ac28fa27dc41b821905f1a83155994d56c4f3b 100755 (executable)
@@ -5,6 +5,7 @@
 # Copyright (c) 2007 Lars Hjemli
 
 USAGE='[--quiet] [--cached] [add <repo> [-b branch]|status|init|update] [--] [<path>...]'
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 
@@ -39,6 +40,32 @@ get_repo_base() {
        ) 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"
+       url="$1"
+       while test -n "$url"
+       do
+               case "$url" in
+               ../*)
+                       url="${url#../}"
+                       remoteurl="${remoteurl%/*}"
+                       ;;
+               ./*)
+                       url="${url#./}"
+                       ;;
+               *)
+                       break;;
+               esac
+       done
+       echo "$remoteurl/$url"
+}
+
 #
 # Map submodule path to submodule name
 #
@@ -47,7 +74,7 @@ get_repo_base() {
 module_name()
 {
        # Do we have "submodule.<something>.path = $1" defined in .gitmodules file?
-       re=$(printf '%s' "$1" | sed -e 's/\([^a-zA-Z0-9_]\)/\\\1/g')
+       re=$(printf '%s' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
        name=$( GIT_CONFIG=.gitmodules \
                git config --get-regexp '^submodule\..*\.path$' |
                sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
@@ -103,11 +130,19 @@ module_add()
                usage
        fi
 
-       # Turn the source into an absolute path if
-       # it is local
-       if base=$(get_repo_base "$repo"); then
-               repo="$base"
-       fi
+       case "$repo" in
+       ./*|../*)
+               # dereference source url relative to parent's url
+               realrepo="$(resolve_relative_url $repo)" ;;
+       *)
+               # Turn the source into an absolute path if
+               # it is local
+               if base=$(get_repo_base "$repo"); then
+                       repo="$base"
+               fi
+               realrepo=$repo
+               ;;
+       esac
 
        # Guess path from repo if not specified or strip trailing slashes
        if test -z "$path"; then
@@ -122,7 +157,7 @@ module_add()
        git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
        die "'$path' already exists in the index"
 
-       module_clone "$path" "$repo" || exit
+       module_clone "$path" "$realrepo" || exit
        (unset GIT_DIR && cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) ||
        die "Unable to checkout submodule '$path'"
        git add "$path" ||
@@ -153,6 +188,13 @@ modules_init()
                test -z "$url" &&
                die "No url found for submodule path '$path' in .gitmodules"
 
+               # Possibly a url relative to parent
+               case "$url" in
+               ./*|../*)
+                       url="$(resolve_relative_url "$url")"
+                       ;;
+               esac
+
                git config submodule."$name".url "$url" ||
                die "Failed to register url for submodule path '$path'"