Support receiving server capabilities
[git.git] / git-fetch.sh
index 27407c1..31e5f4c 100755 (executable)
@@ -5,6 +5,11 @@
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
 
+LF='
+'
+IFS="$LF"
+
+tags=
 append=
 force=
 update_head_ok=
@@ -17,6 +22,9 @@ do
        -f|--f|--fo|--for|--forc|--force)
                force=t
                ;;
+       -t|--t|--ta|--tag|--tags)
+               tags=t
+               ;;
        -u|--u|--up|--upd|--upda|--updat|--update|--update-|--update-h|\
        --update-he|--update-hea|--update-head|--update-head-|\
        --update-head-o|--update-head-ok)
@@ -45,7 +53,7 @@ rsync_slurped_objects=
 
 if test "" = "$append"
 then
-       : >$GIT_DIR/FETCH_HEAD
+       : >"$GIT_DIR/FETCH_HEAD"
 fi
 
 append_fetch_head () {
@@ -82,11 +90,11 @@ append_fetch_head () {
     if git-cat-file commit "$head_" >/dev/null 2>&1
     then
        headc_=$(git-rev-parse --verify "$head_^0") || exit
-       echo "$headc_   $not_for_merge_ $note_" >>$GIT_DIR/FETCH_HEAD
+       echo "$headc_   $not_for_merge_ $note_" >>"$GIT_DIR/FETCH_HEAD"
        echo >&2 "* committish: $head_"
        echo >&2 "  $note_"
     else
-       echo "$head_    not-for-merge   $note_" >>$GIT_DIR/FETCH_HEAD
+       echo "$head_    not-for-merge   $note_" >>"$GIT_DIR/FETCH_HEAD"
        echo >&2 "* non-commit: $head_"
        echo >&2 "  $note_"
     fi
@@ -106,7 +114,12 @@ fast_forward_local () {
        # is no way to guarantee "fast-forward" anyway.
        if test -f "$GIT_DIR/$1"
        then
-               echo >&2 "* $1: updating with $3"
+               if now_=$(cat "$GIT_DIR/$1") && test "$now_" = "$2"
+               then
+                       echo >&2 "* $1: same as $3"
+               else
+                       echo >&2 "* $1: updating with $3"
+               fi
        else
                echo >&2 "* $1: storing $3"
        fi
@@ -158,9 +171,32 @@ case "$update_head_ok" in
        ;;
 esac
 
-for ref in $(get_remote_refs_for_fetch "$@")
+# If --tags (and later --heads or --all) is specified, then we are
+# not talking about defaults stored in Pull: line of remotes or
+# branches file, and just fetch those and refspecs explicitly given.
+# Otherwise we do what we always did.
+
+reflist=$(get_remote_refs_for_fetch "$@")
+if test "$tags"
+then
+       taglist=$(git-ls-remote --tags "$remote" |
+               sed -e '
+                       /\^/d
+                       s/^[^   ]*      //
+                       s/.*/&:&/')
+       if test "$#" -gt 1
+       then
+               # remote URL plus explicit refspecs; we need to merge them.
+               reflist="$reflist$LF$taglist"
+       else
+               # No explicit refspecs; fetch tags only.
+               reflist=$taglist
+       fi
+fi
+
+for ref in $reflist
 do
-    refs="$refs $ref"
+    refs="$refs$LF$ref"
 
     # These are relative path from $GIT_DIR, typically starting at refs/
     # but may be HEAD
@@ -181,7 +217,7 @@ do
     remote_name=$(expr "$ref" : '\([^:]*\):')
     local_name=$(expr "$ref" : '[^:]*:\(.*\)')
 
-    rref="$rref $remote_name"
+    rref="$rref$LF$remote_name"
 
     # There are transports that can fetch only one head at a time...
     case "$remote" in
@@ -189,7 +225,12 @@ do
        if [ -n "$GIT_SSL_NO_VERIFY" ]; then
            curl_extra_args="-k"
        fi
-       head=$(curl -nsf $curl_extra_args "$remote/$remote_name") &&
+       remote_name_quoted=$(perl -e '
+           my $u = $ARGV[0];
+           $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
+           print "$u";
+       ' "$remote_name")
+       head=$(curl -nsf $curl_extra_args "$remote/$remote_name_quoted") &&
        expr "$head" : "$_x40\$" >/dev/null ||
                die "Failed to fetch $remote_name from $remote"
        echo >&2 Fetching "$remote_name from $remote" using http
@@ -239,6 +280,7 @@ case "$remote" in
 http://* | https://* | rsync://* )
     ;; # we are already done.
 *)
+    IFS="      $LF"
     (
        git-fetch-pack "$remote" $rref || echo failed "$remote"
     ) |