Replace a pair of patches with updated ones for subproject support.
[gitweb.git] / git-fetch.sh
index ffbd44f0e1ab841e6f6a38295860220b01bb26ea..b04bd553f86213478a36f8ec2f19476f02ccf09f 100755 (executable)
@@ -4,11 +4,9 @@
 USAGE='<fetch-options> <repository> <refspec>...'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
-TOP=$(git-rev-parse --show-cdup)
-if test ! -z "$TOP"
-then
-       cd "$TOP"
-fi
+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"
@@ -17,7 +15,6 @@ LF='
 '
 IFS="$LF"
 
-rloga=fetch
 no_tags=
 tags=
 append=
@@ -25,8 +22,11 @@ force=
 verbose=
 update_head_ok=
 exec=
-upload_pack=
 keep=
+shallow_depth=
+no_progress=
+test -t 1 || no_progress=--no-progress
+quiet=
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
@@ -36,8 +36,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
@@ -53,14 +57,21 @@ do
        --update-head-o|--update-head-ok)
                update_head_ok=t
                ;;
+       -q|--q|--qu|--qui|--quie|--quiet)
+               quiet=--quiet
+               ;;
        -v|--verbose)
                verbose=Yes
                ;;
        -k|--k|--ke|--kee|--keep)
                keep='-k -k'
                ;;
-       --reflog-action=*)
-               rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+       --depth=*)
+               shallow_depth="--depth=`expr "z$1" : 'z-[^=]*=\(.*\)'`"
+               ;;
+       --depth)
+               shift
+               shallow_depth="--depth=$1"
                ;;
        -*)
                usage
@@ -80,158 +91,49 @@ 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 $upload_pack "$remote") ||
+ls_remote_result=$(git ls-remote $exec "$remote") ||
        die "Cannot get the repository state from $remote"
 
 append_fetch_head () {
-    head_="$1"
-    remote_="$2"
-    remote_name_="$3"
-    remote_nick_="$4"
-    local_name_="$5"
-    case "$6" in
-    t) not_for_merge_='not-for-merge' ;;
-    '') not_for_merge_= ;;
-    esac
-
-    # remote-nick is the URL given on the command line (or a shorthand)
-    # remote-name is the $GIT_DIR relative refs/ path we computed
-    # for this refspec.
-
-    # the $note_ variable will be fed to git-fmt-merge-msg for further
-    # processing.
-    case "$remote_name_" in
-    HEAD)
-       note_= ;;
-    refs/heads/*)
-       note_="$(expr "$remote_name_" : 'refs/heads/\(.*\)')"
-       note_="branch '$note_' of " ;;
-    refs/tags/*)
-       note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')"
-       note_="tag '$note_' of " ;;
-    refs/remotes/*)
-       note_="$(expr "$remote_name_" : 'refs/remotes/\(.*\)')"
-       note_="remote branch '$note_' of " ;;
-    *)
-       note_="$remote_name of " ;;
-    esac
-    remote_1_=$(expr "z$remote_" : 'z\(.*\)\.git/*$') &&
-       remote_="$remote_1_"
-    note_="$note_$remote_"
-
-    # 2.6.11-tree tag would not be happy to be fed to resolve.
-    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"
-    else
-       echo "$head_    not-for-merge   $note_" >>"$GIT_DIR/FETCH_HEAD"
-    fi
-
-    update_local_ref "$local_name_" "$head_" "$note_"
+       flags=
+       test -n "$verbose" && flags="$flags$LF-v"
+       test -n "$force$single_force" && flags="$flags$LF-f"
+       GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \
+               git-fetch--tool $flags append-fetch-head "$@"
 }
 
-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 -n "$oldshort_"
-       then
-               if now_=$(git show-ref --hash "$1") && test "$now_" = "$2"
-               then
-                       [ "$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
-       ;;
-
-    refs/heads/* | refs/remotes/*)
-       # $1 is the ref being updated.
-       # $2 is the new value for the ref.
-       local=$(git-rev-parse --verify "$1^0" 2>/dev/null)
-       if test "$local"
-       then
-           # Require fast-forward.
-           mb=$(git-merge-base "$local" "$2") &&
-           case "$2,$mb" in
-           $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 "  old..new: $oldshort_..$newshort_"
-               git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local"
-               ;;
-           *)
-               false
-               ;;
-           esac || {
-               case ",$force,$single_force," in
-               *,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"
-                       ;;
-               *)
-                       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
-       ;;
-    esac
-}
+# 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
 
-case "$update_head_ok" in
+# Allow --notags from remote.$1.tagopt
+case "$tags$no_tags" in
 '')
-       orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
-       ;;
+       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
@@ -244,23 +146,10 @@ if test "$tags"
 then
        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 ;;
-                       refs/tags/*) ;;
-                       *) 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
@@ -272,7 +161,40 @@ then
        fi
 fi
 
-fetch_main () {
+fetch_all_at_once () {
+
+  eval=$(echo "$1" | git-fetch--tool parse-reflist "-")
+  eval "$eval"
+
+    ( : subshell because we muck with IFS
+      IFS="    $LF"
+      (
+       if test "$remote" = . ; then
+           git-show-ref $rref || echo failed "$remote"
+       elif test -f "$remote" ; then
+           test -n "$shallow_depth" &&
+               die "shallow clone with bundle is not supported"
+           git-bundle unbundle "$remote" $rref ||
+           echo failed "$remote"
+       else
+         git-fetch-pack --thin $exec $keep $shallow_depth \
+             $quiet $no_progress "$remote" $rref ||
+         echo failed "$remote"
+       fi
+      ) |
+      (
+       flags=
+       test -n "$verbose" && flags="$flags -v"
+       test -n "$force" && flags="$flags -f"
+       GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \
+               git-fetch--tool $flags native-store \
+                       "$remote" "$remote_nick" "$refs"
+      )
+    ) || exit
+
+}
+
+fetch_per_ref () {
   reflist="$1"
   refs=
   rref=
@@ -305,12 +227,14 @@ fetch_main () {
       # There are transports that can fetch only one head at a time...
       case "$remote" in
       http://* | https://* | ftp://*)
+         test -n "$shallow_depth" &&
+               die "shallow clone with http not supported"
          proto=`expr "$remote" : '\([^:]*\):'`
          if [ -n "$GIT_SSL_NO_VERIFY" ]; then
              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
 
@@ -328,15 +252,19 @@ fetch_main () {
          expr "z$head" : "z$_x40\$" >/dev/null ||
                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
+         case "$quiet" in '') v=-v ;; *) v= ;; esac
+         git-http-fetch $v -a "$head" "$remote" || exit
          ;;
       rsync://*)
+         test -n "$shallow_depth" &&
+               die "shallow clone with rsync not supported"
          TMP_HEAD="$GIT_DIR/TMP_HEAD"
          rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
          head=$(git-rev-parse --verify TMP_HEAD)
          rm -f "$TMP_HEAD"
+         case "$quiet" in '') v=-v ;; *) v= ;; esac
          test "$rsync_slurped_objects" || {
-             rsync -av --ignore-existing --exclude info \
+             rsync -a $v --ignore-existing --exclude info \
                  "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
 
              # Look at objects/info/alternates for rsync -- http will
@@ -360,9 +288,6 @@ fetch_main () {
              rsync_slurped_objects=t
          }
          ;;
-      *)
-         # We will do git native transport with just one call later.
-         continue ;;
       esac
 
       append_fetch_head "$head" "$remote" \
@@ -370,63 +295,17 @@ fetch_main () {
 
   done
 
-  case "$remote" in
-  http://* | https://* | ftp://* | rsync://* )
-      ;; # we are already done.
-  *)
-    ( : subshell because we muck with IFS
-      pack_lockfile=
-      IFS="    $LF"
-      (
-         git-fetch-pack --thin $exec $keep "$remote" $rref || echo failed "$remote"
-      ) |
-      while read sha1 remote_name
-      do
-         case "$sha1" in
-         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=
-         for ref in $refs
-         do
-             case "$ref" in
-             +$remote_name:*)
-                 single_force=t
-                 not_for_merge=
-                 found="$ref"
-                 break ;;
-             .+$remote_name:*)
-                 single_force=t
-                 not_for_merge=t
-                 found="$ref"
-                 break ;;
-             .$remote_name:*)
-                 not_for_merge=t
-                 found="$ref"
-                 break ;;
-             $remote_name:*)
-                 not_for_merge=
-                 found="$ref"
-                 break ;;
-             esac
-         done
-         local_name=$(expr "z$found" : 'z[^:]*:\(.*\)')
-         append_fetch_head "$sha1" "$remote" \
-                 "$remote_name" "$remote_nick" "$local_name" \
-                 "$not_for_merge" || exit
-      done &&
-      if [ "$pack_lockfile" ]; then rm -f "$pack_lockfile"; fi
-    ) || exit ;;
-  esac
+}
 
+fetch_main () {
+       case "$remote" in
+       http://* | https://* | ftp://* | rsync://* )
+               fetch_per_ref "$@"
+               ;;
+       *)
+               fetch_all_at_once "$@"
+               ;;
+       esac
 }
 
 fetch_main "$reflist" || exit
@@ -451,6 +330,8 @@ case "$no_tags$tags" in
        case "$taglist" in
        '') ;;
        ?*)
+               # do not deepen a shallow tree when following tags
+               shallow_depth=
                fetch_main "$taglist" || exit ;;
        esac
 esac
@@ -465,7 +346,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