strbuf: always return a non-NULL value from strbuf_detach
[gitweb.git] / git-submodule.sh
index 3daa0c834cad1ed402376adf535c73e1c06172e4..3d94a14079ccf745b3cf3d5d5a4e471f9b5542bc 100755 (executable)
@@ -35,7 +35,7 @@ resolve_relative_url ()
 {
        remote=$(get_default_remote)
        remoteurl=$(git config "remote.$remote.url") ||
-               die "$(eval_gettext "remote (\$remote) does not have a url defined in .git/config")"
+               remoteurl=$(pwd) # the repository is its own authoritative upstream
        url="$1"
        remoteurl=${remoteurl%/}
        sep=/
@@ -104,9 +104,9 @@ module_name()
        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" &&
-       die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
-       echo "$name"
+       test -z "$name" &&
+       die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")"
+       echo "$name"
 }
 
 #
@@ -122,14 +122,57 @@ module_clone()
        path=$1
        url=$2
        reference="$3"
+       quiet=
+       if test -n "$GIT_QUIET"
+       then
+               quiet=-q
+       fi
+
+       gitdir=
+       gitdir_base=
+       name=$(module_name "$path" 2>/dev/null)
+       test -n "$name" || name="$path"
+       base_name=$(dirname "$name")
 
-       if test -n "$reference"
+       gitdir=$(git rev-parse --git-dir)
+       gitdir_base="$gitdir/modules/$base_name"
+       gitdir="$gitdir/modules/$name"
+
+       if test -d "$gitdir"
        then
-               git-clone "$reference" -n "$url" "$path"
+               mkdir -p "$path"
+               rm -f "$gitdir/index"
        else
-               git-clone -n "$url" "$path"
-       fi ||
-       die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+               mkdir -p "$gitdir_base"
+               git clone $quiet -n ${reference:+"$reference"} \
+                       --separate-git-dir "$gitdir" "$url" "$path" ||
+               die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+       fi
+
+       a=$(cd "$gitdir" && pwd)/
+       b=$(cd "$path" && pwd)/
+       # normalize Windows-style absolute paths to POSIX-style absolute paths
+       case $a in [a-zA-Z]:/*) a=/${a%%:*}${a#*:} ;; esac
+       case $b in [a-zA-Z]:/*) b=/${b%%:*}${b#*:} ;; esac
+       # Remove all common leading directories after a sanity check
+       if test "${a#$b}" != "$a" || test "${b#$a}" != "$b"; then
+               die "$(eval_gettext "Gitdir '\$a' is part of the submodule path '\$b' or vice versa")"
+       fi
+       while test "${a%%/*}" = "${b%%/*}"
+       do
+               a=${a#*/}
+               b=${b#*/}
+       done
+       # Now chop off the trailing '/'s that were added in the beginning
+       a=${a%/}
+       b=${b%/}
+
+       # Turn each leading "*/" component into "../"
+       rel=$(echo $b | sed -e 's|[^/][^/]*|..|g')
+       echo "gitdir: $rel/$a" >"$path/.git"
+
+       rel=$(echo $a | sed -e 's|[^/][^/]*|..|g')
+       (clear_local_git_env; cd "$path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b")
 }
 
 #
@@ -223,12 +266,9 @@ cmd_add()
 
        if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1
        then
-               (
-                       eval_gettext "The following path is ignored by one of your .gitignore files:
+               eval_gettextln "The following path is ignored by one of your .gitignore files:
 \$path
-Use -f if you really want to add it." &&
-                       echo
-               ) >&2
+Use -f if you really want to add it." >&2
                exit 1
        fi
 
@@ -237,19 +277,11 @@ Use -f if you really want to add it." &&
        then
                if test -d "$path"/.git -o -f "$path"/.git
                then
-                       eval_gettext "Adding existing repo at '\$path' to the index"; echo
+                       eval_gettextln "Adding existing repo at '\$path' to the index"
                else
                        die "$(eval_gettext "'\$path' already exists and is not a valid git repo")"
                fi
 
-               case "$repo" in
-               ./*|../*)
-                       url=$(resolve_relative_url "$repo") || exit
-                   ;;
-               *)
-                       url="$repo"
-                       ;;
-               esac
        else
 
                module_clone "$path" "$realrepo" "$reference" || exit
@@ -263,7 +295,7 @@ Use -f if you really want to add it." &&
                        esac
                ) || die "$(eval_gettext "Unable to checkout submodule '\$path'")"
        fi
-       git config submodule."$path".url "$url"
+       git config submodule."$path".url "$realrepo"
 
        git add $force "$path" ||
        die "$(eval_gettext "Failed to add submodule '\$path'")"
@@ -432,6 +464,9 @@ cmd_update()
                --recursive)
                        recursive=1
                        ;;
+               --checkout)
+                       update="checkout"
+                       ;;
                --)
                        shift
                        break
@@ -464,7 +499,19 @@ cmd_update()
                fi
                name=$(module_name "$path") || exit
                url=$(git config submodule."$name".url)
-               update_module=$(git config submodule."$name".update)
+               if ! test -z "$update"
+               then
+                       update_module=$update
+               else
+                       update_module=$(git config submodule."$name".update)
+               fi
+
+               if test "$update_module" = "none"
+               then
+                       echo "Skipping submodule '$path'"
+                       continue
+               fi
+
                if test -z "$url"
                then
                        # Only mention uninitialized submodules when its
@@ -486,11 +533,6 @@ Maybe you want to use 'update --init'?")"
                        die "$(eval_gettext "Unable to find current revision in submodule path '\$path'")"
                fi
 
-               if ! test -z "$update"
-               then
-                       update_module=$update
-               fi
-
                if test "$subsha1" != "$sha1"
                then
                        subforce=$force
@@ -704,10 +746,7 @@ cmd_summary() {
                                ;; # removed
                        *)
                                # unexpected type
-                               (
-                                       eval_gettext "unexpected mode \$mod_dst" &&
-                                       echo
-                               ) >&2
+                               eval_gettextln "unexpected mode \$mod_dst" >&2
                                continue ;;
                        esac
                fi
@@ -794,9 +833,9 @@ cmd_summary() {
        done |
        if test -n "$for_status"; then
                if [ -n "$files" ]; then
-                       gettext "# Submodules changed but not updated:"; echo
+                       gettextln "# Submodules changed but not updated:"
                else
-                       gettext "# Submodule changes to be committed:"; echo
+                       gettextln "# Submodule changes to be committed:"
                fi
                echo "#"
                sed -e 's|^|# |' -e 's|^# $|#|'