object name: introduce ':/<oneline prefix>' notation
[gitweb.git] / git-fetch.sh
index 0b1e6d1071350af34e95a402d7ef53f00d03d8a4..d230995f6e3033456b670fa60b8a392dbc8dd08f 100755 (executable)
@@ -2,7 +2,11 @@
 #
 
 USAGE='<fetch-options> <repository> <refspec>...'
+SUBDIRECTORY_OK=Yes
 . git-sh-setup
+set_reflog_action "fetch $*"
+cd_to_toplevel ;# probably unnecessary...
+
 . git-parse-remote
 _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"
@@ -11,7 +15,6 @@ LF='
 '
 IFS="$LF"
 
-rloga=fetch
 no_tags=
 tags=
 append=
@@ -19,7 +22,6 @@ force=
 verbose=
 update_head_ok=
 exec=
-upload_pack=
 keep=
 shallow_depth=
 while case "$#" in 0) break ;; esac
@@ -31,8 +33,12 @@ do
        --upl|--uplo|--uploa|--upload|--upload-|--upload-p|\
        --upload-pa|--upload-pac|--upload-pack)
                shift
-               exec="--exec=$1" 
-               upload_pack="-u $1"
+               exec="--upload-pack=$1"
+               ;;
+       --upl=*|--uplo=*|--uploa=*|--upload=*|\
+       --upload-=*|--upload-p=*|--upload-pa=*|--upload-pac=*|--upload-pack=*)
+               exec=--upload-pack=$(expr "z$1" : 'z-[^=]*=\(.*\)')
+               shift
                ;;
        -f|--f|--fo|--for|--forc|--force)
                force=t
@@ -54,9 +60,6 @@ do
        -k|--k|--ke|--kee|--keep)
                keep='-k -k'
                ;;
-       --reflog-action=*)
-               rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-               ;;
        --depth=*)
                shallow_depth="--depth=`expr "z$1" : 'z-[^=]*=\(.*\)'`"
                ;;
@@ -82,20 +85,27 @@ case "$#" in
        set x $origin ; shift ;;
 esac
 
+if test -z "$exec"
+then
+       # No command line override and we have configuration for the remote.
+       exec="--upload-pack=$(get_uploadpack $1)"
+fi
+
 remote_nick="$1"
 remote=$(get_remote_url "$@")
 refs=
 rref=
 rsync_slurped_objects=
 
-rloga="$rloga $remote_nick"
-test "$remote_nick" = "$remote" || rloga="$rloga $remote"
-
 if test "" = "$append"
 then
        : >"$GIT_DIR/FETCH_HEAD"
 fi
 
+# Global that is reused later
+ls_remote_result=$(git ls-remote $exec "$remote") ||
+       die "Cannot get the repository state from $remote"
+
 append_fetch_head () {
     head_="$1"
     remote_="$2"
@@ -170,12 +180,12 @@ update_local_ref () {
                else
                        echo >&2 "* $1: updating with $3"
                        echo >&2 "  $label_: $newshort_"
-                       git-update-ref -m "$rloga: updating tag" "$1" "$2"
+                       git-update-ref -m "$GIT_REFLOG_ACTION: updating tag" "$1" "$2"
                fi
        else
                echo >&2 "* $1: storing $3"
                echo >&2 "  $label_: $newshort_"
-               git-update-ref -m "$rloga: storing tag" "$1" "$2"
+               git-update-ref -m "$GIT_REFLOG_ACTION: storing tag" "$1" "$2"
        fi
        ;;
 
@@ -198,7 +208,7 @@ update_local_ref () {
            *,$local)
                echo >&2 "* $1: fast forward to $3"
                echo >&2 "  old..new: $oldshort_..$newshort_"
-               git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local"
+               git-update-ref -m "$GIT_REFLOG_ACTION: fast-forward" "$1" "$2" "$local"
                ;;
            *)
                false
@@ -208,7 +218,7 @@ update_local_ref () {
                *,t,*)
                        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"
+                       git-update-ref -m "$GIT_REFLOG_ACTION: forced-update" "$1" "$2" "$local"
                        ;;
                *)
                        echo >&2 "* $1: not updating to non-fast forward $3"
@@ -220,16 +230,26 @@ update_local_ref () {
        else
            echo >&2 "* $1: storing $3"
            echo >&2 "  $label_: $newshort_"
-           git-update-ref -m "$rloga: storing head" "$1" "$2"
+           git-update-ref -m "$GIT_REFLOG_ACTION: storing head" "$1" "$2"
        fi
        ;;
     esac
 }
 
-case "$update_head_ok" in
-'')
+# updating the current HEAD with git-fetch in a bare
+# repository is always fine.
+if test -z "$update_head_ok" && test $(is_bare_repository) = false
+then
        orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
-       ;;
+fi
+
+# Allow --notags from remote.$1.tagopt
+case "$tags$no_tags" in
+'')
+       case "$(git-config --get "remote.$1.tagopt")" in
+       --no-tags)
+               no_tags=t ;;
+       esac
 esac
 
 # If --tags (and later --heads or --all) is specified, then we are
@@ -240,26 +260,12 @@ esac
 reflist=$(get_remote_refs_for_fetch "$@")
 if test "$tags"
 then
-       taglist=`IFS="  " &&
-                 (
-                       git-ls-remote $upload_pack --tags "$remote" ||
-                       echo fail ouch
-                 ) |
+       taglist=`IFS='  ' &&
+                 echo "$ls_remote_result" |
+                 git-show-ref --exclude-existing=refs/tags/ |
                  while read sha1 name
                  do
-                       case "$sha1" in
-                       fail)
-                               exit 1
-                       esac
-                       case "$name" in
-                       *^*) continue ;;
-                       esac
-                       if git-check-ref-format "$name"
-                       then
-                           echo ".${name}:${name}"
-                       else
-                           echo >&2 "warning: tag ${name} ignored"
-                       fi
+                       echo ".${name}:${name}"
                  done` || exit
        if test "$#" -gt 1
        then
@@ -311,25 +317,23 @@ fetch_main () {
              curl_extra_args="-k"
          fi
          if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
-               "`git-repo-config --bool http.noEPSV`" = true ]; then
+               "`git-config --bool http.noEPSV`" = true ]; then
              noepsv_opt="--disable-epsv"
          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 $noepsv_opt "$remote/$remote_name_quoted")
-           depth=$( expr \( $depth + 1 \) )
-         done
+
+         # 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"
+               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
          ;;
@@ -371,7 +375,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
 
@@ -380,13 +384,22 @@ fetch_main () {
       ;; # we are already done.
   *)
     ( : subshell because we muck with IFS
-      pack_lockfile=
       IFS="    $LF"
       (
-         git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref || echo failed "$remote"
+         git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref ||
+         echo failed "$remote"
       ) |
-      while read sha1 remote_name
-      do
+      (
+       trap '
+               if test -n "$keepfile" && test -f "$keepfile"
+               then
+                       rm -f "$keepfile"
+               fi
+       ' 0
+
+        keepfile=
+       while read sha1 remote_name
+       do
          case "$sha1" in
          failed)
                  echo >&2 "Fetch failure: $remote"
@@ -395,7 +408,7 @@ fetch_main () {
          pack)
                  continue ;;
          keep)
-                 pack_lockfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
+                 keepfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
                  continue ;;
          esac
          found=
@@ -425,15 +438,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
-      if [ "$pack_lockfile" ]; then rm -f "$pack_lockfile"; fi
+                 "$remote_name" "$remote_nick" "$local_name" \
+                 "$not_for_merge" || exit
+        done
+      )
     ) || exit ;;
   esac
 
 }
 
-fetch_main "$reflist"
+fetch_main "$reflist" || exit
 
 # automated tag following
 case "$no_tags$tags" in
@@ -442,17 +456,11 @@ case "$no_tags$tags" in
        *:refs/*)
                # effective only when we are following remote branch
                # using local tracking branch.
-               taglist=$(IFS=" " &&
-               git-ls-remote $upload_pack --tags "$remote" |
-               sed -n  -e 's|^\('"$_x40"'\)    \(refs/tags/.*\)^{}$|\1 \2|p' \
-                       -e 's|^\('"$_x40"'\)    \(refs/tags/.*\)$|\1 \2|p' |
+               taglist=$(IFS=' ' &&
+               echo "$ls_remote_result" |
+               git-show-ref --exclude-existing=refs/tags/ |
                while read sha1 name
                do
-                       git-show-ref --verify --quiet -- "$name" && continue
-                       git-check-ref-format "$name" || {
-                               echo >&2 "warning: tag ${name} ignored"
-                               continue
-                       }
                        git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
                        echo >&2 "Auto-following $name"
                        echo ".${name}:${name}"
@@ -461,7 +469,9 @@ case "$no_tags$tags" in
        case "$taglist" in
        '') ;;
        ?*)
-               fetch_main "$taglist" ;;
+               # do not deepen a shallow tree when following tags
+               shallow_depth=
+               fetch_main "$taglist" || exit ;;
        esac
 esac
 
@@ -475,7 +485,7 @@ case "$orig_head" in
        if test "$curr_head" != "$orig_head"
        then
            git-update-ref \
-                       -m "$rloga: Undoing incorrectly fetched HEAD." \
+                       -m "$GIT_REFLOG_ACTION: Undoing incorrectly fetched HEAD." \
                        HEAD "$orig_head"
                die "Cannot fetch into the current branch."
        fi