rerere: add clear, diff, and status commands
[gitweb.git] / git-fetch.sh
index 09a5d6ceab7875f2344f84d684ea5cc250786c64..4eecf148ea90c02bfe9f2aa018118ccbd26f8e97 100755 (executable)
@@ -20,7 +20,7 @@ verbose=
 update_head_ok=
 exec=
 upload_pack=
-keep=--thin
+keep=
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
@@ -51,7 +51,7 @@ do
                verbose=Yes
                ;;
        -k|--k|--ke|--kee|--keep)
-               keep=--keep
+               keep='-k -k'
                ;;
        --reflog-action=*)
                rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
@@ -68,11 +68,10 @@ done
 
 case "$#" in
 0)
-       test -f "$GIT_DIR/branches/origin" ||
-               test -f "$GIT_DIR/remotes/origin" ||
-                       git-repo-config --get remote.origin.url >/dev/null ||
-                               die "Where do you want to fetch from today?"
-       set origin ;;
+       origin=$(get_default_remote)
+       test -n "$(get_remote_url ${origin})" ||
+               die "Where do you want to fetch from today?"
+       set x $origin ; shift ;;
 esac
 
 remote_nick="$1"
@@ -89,6 +88,10 @@ then
        : >"$GIT_DIR/FETCH_HEAD"
 fi
 
+# Global that is reused later
+ls_remote_result=$(git ls-remote $upload_pack "$remote") ||
+       die "Cannot find the reflist at $remote"
+
 append_fetch_head () {
     head_="$1"
     remote_="$2"
@@ -130,38 +133,44 @@ append_fetch_head () {
     then
        headc_=$(git-rev-parse --verify "$head_^0") || exit
        echo "$headc_   $not_for_merge_ $note_" >>"$GIT_DIR/FETCH_HEAD"
-       [ "$verbose" ] && echo >&2 "* committish: $head_"
-       [ "$verbose" ] && echo >&2 "  $note_"
     else
        echo "$head_    not-for-merge   $note_" >>"$GIT_DIR/FETCH_HEAD"
-       [ "$verbose" ] && echo >&2 "* non-commit: $head_"
-       [ "$verbose" ] && echo >&2 "  $note_"
-    fi
-    if test "$local_name_" != ""
-    then
-       # We are storing the head locally.  Make sure that it is
-       # a fast forward (aka "reverse push").
-       fast_forward_local "$local_name_" "$head_" "$note_"
     fi
+
+    update_local_ref "$local_name_" "$head_" "$note_"
 }
 
-fast_forward_local () {
-    mkdir -p "$(dirname "$GIT_DIR/$1")"
+update_local_ref () {
+    # If we are storing the head locally make sure that it is
+    # a fast forward (aka "reverse push").
+
+    label_=$(git-cat-file -t $2)
+    newshort_=$(git-rev-parse --short $2)
+    if test -z "$1" ; then
+       [ "$verbose" ] && echo >&2 "* fetched $3"
+       [ "$verbose" ] && echo >&2 "  $label_: $newshort_"
+       return 0
+    fi
+    oldshort_=$(git show-ref --hash --abbrev "$1" 2>/dev/null)
+
     case "$1" in
     refs/tags/*)
        # Tags need not be pointing at commits so there
        # is no way to guarantee "fast-forward" anyway.
-       if test -f "$GIT_DIR/$1"
+       if test -n "$oldshort_"
        then
-               if now_=$(cat "$GIT_DIR/$1") && test "$now_" = "$2"
+               if now_=$(git show-ref --hash "$1") && test "$now_" = "$2"
                then
-                       [ "$verbose" ] && echo >&2 "* $1: same as $3" ||:
+                       [ "$verbose" ] && echo >&2 "* $1: same as $3"
+                       [ "$verbose" ] && echo >&2 "  $label_: $newshort_" ||:
                else
                        echo >&2 "* $1: updating with $3"
+                       echo >&2 "  $label_: $newshort_"
                        git-update-ref -m "$rloga: updating tag" "$1" "$2"
                fi
        else
                echo >&2 "* $1: storing $3"
+               echo >&2 "  $label_: $newshort_"
                git-update-ref -m "$rloga: storing tag" "$1" "$2"
        fi
        ;;
@@ -179,31 +188,34 @@ fast_forward_local () {
                if test -n "$verbose"
                then
                        echo >&2 "* $1: same as $3"
+                       echo >&2 "  $label_: $newshort_"
                fi
                ;;
            *,$local)
                echo >&2 "* $1: fast forward to $3"
-               echo >&2 "  from $local to $2"
+               echo >&2 "  old..new: $oldshort_..$newshort_"
                git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local"
                ;;
            *)
                false
                ;;
            esac || {
-               echo >&2 "* $1: does not fast forward to $3;"
                case ",$force,$single_force," in
                *,t,*)
-                       echo >&2 "  forcing update."
+                       echo >&2 "* $1: forcing update to non-fast forward $3"
+                       echo >&2 "  old...new: $oldshort_...$newshort_"
                        git-update-ref -m "$rloga: forced-update" "$1" "$2" "$local"
                        ;;
                *)
-                       echo >&2 "  not updating."
+                       echo >&2 "* $1: not updating to non-fast forward $3"
+                       echo >&2 "  old...new: $oldshort_...$newshort_"
                        exit 1
                        ;;
                esac
            }
        else
            echo >&2 "* $1: storing $3"
+           echo >&2 "  $label_: $newshort_"
            git-update-ref -m "$rloga: storing head" "$1" "$2"
        fi
        ;;
@@ -225,10 +237,7 @@ reflist=$(get_remote_refs_for_fetch "$@")
 if test "$tags"
 then
        taglist=`IFS="  " &&
-                 (
-                       git-ls-remote $upload_pack --tags "$remote" ||
-                       echo fail ouch
-                 ) |
+                 echo "$ls_remote_result" |
                  while read sha1 name
                  do
                        case "$sha1" in
@@ -237,6 +246,8 @@ then
                        esac
                        case "$name" in
                        *^*) continue ;;
+                       refs/tags/*) ;;
+                       *) continue ;;
                        esac
                        if git-check-ref-format "$name"
                        then
@@ -258,6 +269,7 @@ fi
 fetch_main () {
   reflist="$1"
   refs=
+  rref=
 
   for ref in $reflist
   do
@@ -287,26 +299,29 @@ fetch_main () {
       # There are transports that can fetch only one head at a time...
       case "$remote" in
       http://* | https://* | ftp://*)
+         proto=`expr "$remote" : '\([^:]*\):'`
          if [ -n "$GIT_SSL_NO_VERIFY" ]; then
              curl_extra_args="-k"
          fi
-         max_depth=5
-         depth=0
-         head="ref: $remote_name"
-         while (expr "z$head" : "zref:" && expr $depth \< $max_depth) >/dev/null
-         do
-           remote_name_quoted=$(@@PERL@@ -e '
-             my $u = $ARGV[0];
-              $u =~ s/^ref:\s*//;
-             $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
-             print "$u";
-         ' "$head")
-           head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted")
-           depth=$( expr \( $depth + 1 \) )
-         done
+         if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
+               "`git-repo-config --bool http.noEPSV`" = true ]; then
+             noepsv_opt="--disable-epsv"
+         fi
+
+         # Find $remote_name from ls-remote output.
+         head=$(
+               IFS='   '
+               echo "$ls_remote_result" |
+               while read sha1 name
+               do
+                       test "z$name" = "z$remote_name" || continue
+                       echo "$sha1"
+                       break
+               done
+         )
          expr "z$head" : "z$_x40\$" >/dev/null ||
-             die "Failed to fetch $remote_name from $remote"
-         echo >&2 Fetching "$remote_name from $remote" using http
+               die "No such ref $remote_name at $remote"
+         echo >&2 "Fetching $remote_name from $remote using $proto"
          git-http-fetch -v -a "$head" "$remote/" || exit
          ;;
       rsync://*)
@@ -345,7 +360,7 @@ fetch_main () {
       esac
 
       append_fetch_head "$head" "$remote" \
-         "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
+         "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" || exit
 
   done
 
@@ -354,9 +369,10 @@ fetch_main () {
       ;; # we are already done.
   *)
     ( : subshell because we muck with IFS
+      pack_lockfile=
       IFS="    $LF"
       (
-         git-fetch-pack $exec $keep "$remote" $rref || echo failed "$remote"
+         git-fetch-pack --thin $exec $keep "$remote" $rref || echo failed "$remote"
       ) |
       while read sha1 remote_name
       do
@@ -364,6 +380,12 @@ fetch_main () {
          failed)
                  echo >&2 "Fetch failure: $remote"
                  exit 1 ;;
+         # special line coming from index-pack with the pack name
+         pack)
+                 continue ;;
+         keep)
+                 pack_lockfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
+                 continue ;;
          esac
          found=
          single_force=
@@ -392,14 +414,16 @@ fetch_main () {
          done
          local_name=$(expr "z$found" : 'z[^:]*:\(.*\)')
          append_fetch_head "$sha1" "$remote" \
-                 "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
-      done
+                 "$remote_name" "$remote_nick" "$local_name" \
+                 "$not_for_merge" || exit
+      done &&
+      if [ "$pack_lockfile" ]; then rm -f "$pack_lockfile"; fi
     ) || exit ;;
   esac
 
 }
 
-fetch_main "$reflist"
+fetch_main "$reflist" || exit
 
 # automated tag following
 case "$no_tags$tags" in
@@ -409,11 +433,12 @@ case "$no_tags$tags" in
                # effective only when we are following remote branch
                # using local tracking branch.
                taglist=$(IFS=" " &&
-               git-ls-remote $upload_pack --tags "$remote" |
-               sed -ne 's|^\([0-9a-f]*\)[      ]\(refs/tags/.*\)^{}$|\1 \2|p' |
+               echo "$ls_remote_result" |
+               sed -n  -e 's|^\('"$_x40"'\)    \(refs/tags/.*\)^{}$|\1 \2|p' \
+                       -e 's|^\('"$_x40"'\)    \(refs/tags/.*\)$|\1 \2|p' |
                while read sha1 name
                do
-                       test -f "$GIT_DIR/$name" && continue
+                       git-show-ref --verify --quiet -- "$name" && continue
                        git-check-ref-format "$name" || {
                                echo >&2 "warning: tag ${name} ignored"
                                continue
@@ -426,16 +451,16 @@ case "$no_tags$tags" in
        case "$taglist" in
        '') ;;
        ?*)
-               fetch_main "$taglist" ;;
+               fetch_main "$taglist" || exit ;;
        esac
 esac
 
 # If the original head was empty (i.e. no "master" yet), or
 # if we were told not to worry, we do not have to check.
-case ",$update_head_ok,$orig_head," in
-*,, | t,* )
+case "$orig_head" in
+'')
        ;;
-*)
+?*)
        curr_head=$(git-rev-parse --verify HEAD 2>/dev/null)
        if test "$curr_head" != "$orig_head"
        then