git-fetch.shon commit git-svn: exit with status 1 for test failures (d25c26e)
   1#!/bin/sh
   2#
   3
   4USAGE='<fetch-options> <repository> <refspec>...'
   5. git-sh-setup
   6. git-parse-remote
   7_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
   8_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
   9
  10LF='
  11'
  12IFS="$LF"
  13
  14rloga=fetch
  15no_tags=
  16tags=
  17append=
  18force=
  19verbose=
  20update_head_ok=
  21exec=
  22upload_pack=
  23keep=
  24while case "$#" in 0) break ;; esac
  25do
  26        case "$1" in
  27        -a|--a|--ap|--app|--appe|--appen|--append)
  28                append=t
  29                ;;
  30        --upl|--uplo|--uploa|--upload|--upload-|--upload-p|\
  31        --upload-pa|--upload-pac|--upload-pack)
  32                shift
  33                exec="--exec=$1" 
  34                upload_pack="-u $1"
  35                ;;
  36        -f|--f|--fo|--for|--forc|--force)
  37                force=t
  38                ;;
  39        -t|--t|--ta|--tag|--tags)
  40                tags=t
  41                ;;
  42        -n|--n|--no|--no-|--no-t|--no-ta|--no-tag|--no-tags)
  43                no_tags=t
  44                ;;
  45        -u|--u|--up|--upd|--upda|--updat|--update|--update-|--update-h|\
  46        --update-he|--update-hea|--update-head|--update-head-|\
  47        --update-head-o|--update-head-ok)
  48                update_head_ok=t
  49                ;;
  50        -v|--verbose)
  51                verbose=Yes
  52                ;;
  53        -k|--k|--ke|--kee|--keep)
  54                keep='-k -k'
  55                ;;
  56        --reflog-action=*)
  57                rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
  58                ;;
  59        -*)
  60                usage
  61                ;;
  62        *)
  63                break
  64                ;;
  65        esac
  66        shift
  67done
  68
  69case "$#" in
  700)
  71        origin=$(get_default_remote)
  72        test -n "$(get_remote_url ${origin})" ||
  73                die "Where do you want to fetch from today?"
  74        set x $origin ; shift ;;
  75esac
  76
  77remote_nick="$1"
  78remote=$(get_remote_url "$@")
  79refs=
  80rref=
  81rsync_slurped_objects=
  82
  83rloga="$rloga $remote_nick"
  84test "$remote_nick" = "$remote" || rloga="$rloga $remote"
  85
  86if test "" = "$append"
  87then
  88        : >"$GIT_DIR/FETCH_HEAD"
  89fi
  90
  91append_fetch_head () {
  92    head_="$1"
  93    remote_="$2"
  94    remote_name_="$3"
  95    remote_nick_="$4"
  96    local_name_="$5"
  97    case "$6" in
  98    t) not_for_merge_='not-for-merge' ;;
  99    '') not_for_merge_= ;;
 100    esac
 101
 102    # remote-nick is the URL given on the command line (or a shorthand)
 103    # remote-name is the $GIT_DIR relative refs/ path we computed
 104    # for this refspec.
 105
 106    # the $note_ variable will be fed to git-fmt-merge-msg for further
 107    # processing.
 108    case "$remote_name_" in
 109    HEAD)
 110        note_= ;;
 111    refs/heads/*)
 112        note_="$(expr "$remote_name_" : 'refs/heads/\(.*\)')"
 113        note_="branch '$note_' of " ;;
 114    refs/tags/*)
 115        note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')"
 116        note_="tag '$note_' of " ;;
 117    refs/remotes/*)
 118        note_="$(expr "$remote_name_" : 'refs/remotes/\(.*\)')"
 119        note_="remote branch '$note_' of " ;;
 120    *)
 121        note_="$remote_name of " ;;
 122    esac
 123    remote_1_=$(expr "z$remote_" : 'z\(.*\)\.git/*$') &&
 124        remote_="$remote_1_"
 125    note_="$note_$remote_"
 126
 127    # 2.6.11-tree tag would not be happy to be fed to resolve.
 128    if git-cat-file commit "$head_" >/dev/null 2>&1
 129    then
 130        headc_=$(git-rev-parse --verify "$head_^0") || exit
 131        echo "$headc_   $not_for_merge_ $note_" >>"$GIT_DIR/FETCH_HEAD"
 132    else
 133        echo "$head_    not-for-merge   $note_" >>"$GIT_DIR/FETCH_HEAD"
 134    fi
 135
 136    update_local_ref "$local_name_" "$head_" "$note_"
 137}
 138
 139update_local_ref () {
 140    # If we are storing the head locally make sure that it is
 141    # a fast forward (aka "reverse push").
 142
 143    label_=$(git-cat-file -t $2)
 144    newshort_=$(git-rev-parse --short $2)
 145    if test -z "$1" ; then
 146        [ "$verbose" ] && echo >&2 "* fetched $3"
 147        [ "$verbose" ] && echo >&2 "  $label_: $newshort_"
 148        return 0
 149    fi
 150    oldshort_=$(git show-ref --hash --abbrev "$1" 2>/dev/null)
 151
 152    case "$1" in
 153    refs/tags/*)
 154        # Tags need not be pointing at commits so there
 155        # is no way to guarantee "fast-forward" anyway.
 156        if test -n "$oldshort_"
 157        then
 158                if now_=$(git show-ref --hash "$1") && test "$now_" = "$2"
 159                then
 160                        [ "$verbose" ] && echo >&2 "* $1: same as $3"
 161                        [ "$verbose" ] && echo >&2 "  $label_: $newshort_" ||:
 162                else
 163                        echo >&2 "* $1: updating with $3"
 164                        echo >&2 "  $label_: $newshort_"
 165                        git-update-ref -m "$rloga: updating tag" "$1" "$2"
 166                fi
 167        else
 168                echo >&2 "* $1: storing $3"
 169                echo >&2 "  $label_: $newshort_"
 170                git-update-ref -m "$rloga: storing tag" "$1" "$2"
 171        fi
 172        ;;
 173
 174    refs/heads/* | refs/remotes/*)
 175        # $1 is the ref being updated.
 176        # $2 is the new value for the ref.
 177        local=$(git-rev-parse --verify "$1^0" 2>/dev/null)
 178        if test "$local"
 179        then
 180            # Require fast-forward.
 181            mb=$(git-merge-base "$local" "$2") &&
 182            case "$2,$mb" in
 183            $local,*)
 184                if test -n "$verbose"
 185                then
 186                        echo >&2 "* $1: same as $3"
 187                        echo >&2 "  $label_: $newshort_"
 188                fi
 189                ;;
 190            *,$local)
 191                echo >&2 "* $1: fast forward to $3"
 192                echo >&2 "  old..new: $oldshort_..$newshort_"
 193                git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local"
 194                ;;
 195            *)
 196                false
 197                ;;
 198            esac || {
 199                case ",$force,$single_force," in
 200                *,t,*)
 201                        echo >&2 "* $1: forcing update to non-fast forward $3"
 202                        echo >&2 "  old...new: $oldshort_...$newshort_"
 203                        git-update-ref -m "$rloga: forced-update" "$1" "$2" "$local"
 204                        ;;
 205                *)
 206                        echo >&2 "* $1: not updating to non-fast forward $3"
 207                        echo >&2 "  old...new: $oldshort_...$newshort_"
 208                        exit 1
 209                        ;;
 210                esac
 211            }
 212        else
 213            echo >&2 "* $1: storing $3"
 214            echo >&2 "  $label_: $newshort_"
 215            git-update-ref -m "$rloga: storing head" "$1" "$2"
 216        fi
 217        ;;
 218    esac
 219}
 220
 221case "$update_head_ok" in
 222'')
 223        orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
 224        ;;
 225esac
 226
 227# If --tags (and later --heads or --all) is specified, then we are
 228# not talking about defaults stored in Pull: line of remotes or
 229# branches file, and just fetch those and refspecs explicitly given.
 230# Otherwise we do what we always did.
 231
 232reflist=$(get_remote_refs_for_fetch "$@")
 233if test "$tags"
 234then
 235        taglist=`IFS="  " &&
 236                  (
 237                        git-ls-remote $upload_pack --tags "$remote" ||
 238                        echo fail ouch
 239                  ) |
 240                  while read sha1 name
 241                  do
 242                        case "$sha1" in
 243                        fail)
 244                                exit 1
 245                        esac
 246                        case "$name" in
 247                        *^*) continue ;;
 248                        esac
 249                        if git-check-ref-format "$name"
 250                        then
 251                            echo ".${name}:${name}"
 252                        else
 253                            echo >&2 "warning: tag ${name} ignored"
 254                        fi
 255                  done` || exit
 256        if test "$#" -gt 1
 257        then
 258                # remote URL plus explicit refspecs; we need to merge them.
 259                reflist="$reflist$LF$taglist"
 260        else
 261                # No explicit refspecs; fetch tags only.
 262                reflist=$taglist
 263        fi
 264fi
 265
 266fetch_main () {
 267  reflist="$1"
 268  refs=
 269  rref=
 270
 271  for ref in $reflist
 272  do
 273      refs="$refs$LF$ref"
 274
 275      # These are relative path from $GIT_DIR, typically starting at refs/
 276      # but may be HEAD
 277      if expr "z$ref" : 'z\.' >/dev/null
 278      then
 279          not_for_merge=t
 280          ref=$(expr "z$ref" : 'z\.\(.*\)')
 281      else
 282          not_for_merge=
 283      fi
 284      if expr "z$ref" : 'z+' >/dev/null
 285      then
 286          single_force=t
 287          ref=$(expr "z$ref" : 'z+\(.*\)')
 288      else
 289          single_force=
 290      fi
 291      remote_name=$(expr "z$ref" : 'z\([^:]*\):')
 292      local_name=$(expr "z$ref" : 'z[^:]*:\(.*\)')
 293
 294      rref="$rref$LF$remote_name"
 295
 296      # There are transports that can fetch only one head at a time...
 297      case "$remote" in
 298      http://* | https://* | ftp://*)
 299          proto=`expr "$remote" : '\([^:]*\):'`
 300          if [ -n "$GIT_SSL_NO_VERIFY" ]; then
 301              curl_extra_args="-k"
 302          fi
 303          if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
 304                "`git-repo-config --bool http.noEPSV`" = true ]; then
 305              noepsv_opt="--disable-epsv"
 306          fi
 307          max_depth=5
 308          depth=0
 309          head="ref: $remote_name"
 310          while (expr "z$head" : "zref:" && expr $depth \< $max_depth) >/dev/null
 311          do
 312            remote_name_quoted=$(@@PERL@@ -e '
 313              my $u = $ARGV[0];
 314              $u =~ s/^ref:\s*//;
 315              $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
 316              print "$u";
 317          ' "$head")
 318            head=$(curl -nsfL $curl_extra_args $noepsv_opt "$remote/$remote_name_quoted")
 319            depth=$( expr \( $depth + 1 \) )
 320          done
 321          expr "z$head" : "z$_x40\$" >/dev/null ||
 322              die "Failed to fetch $remote_name from $remote"
 323          echo >&2 "Fetching $remote_name from $remote using $proto"
 324          git-http-fetch -v -a "$head" "$remote/" || exit
 325          ;;
 326      rsync://*)
 327          TMP_HEAD="$GIT_DIR/TMP_HEAD"
 328          rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
 329          head=$(git-rev-parse --verify TMP_HEAD)
 330          rm -f "$TMP_HEAD"
 331          test "$rsync_slurped_objects" || {
 332              rsync -av --ignore-existing --exclude info \
 333                  "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
 334
 335              # Look at objects/info/alternates for rsync -- http will
 336              # support it natively and git native ones will do it on
 337              # the remote end.  Not having that file is not a crime.
 338              rsync -q "$remote/objects/info/alternates" \
 339                  "$GIT_DIR/TMP_ALT" 2>/dev/null ||
 340                  rm -f "$GIT_DIR/TMP_ALT"
 341              if test -f "$GIT_DIR/TMP_ALT"
 342              then
 343                  resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
 344                  while read alt
 345                  do
 346                      case "$alt" in 'bad alternate: '*) die "$alt";; esac
 347                      echo >&2 "Getting alternate: $alt"
 348                      rsync -av --ignore-existing --exclude info \
 349                      "$alt" "$GIT_OBJECT_DIRECTORY/" || exit
 350                  done
 351                  rm -f "$GIT_DIR/TMP_ALT"
 352              fi
 353              rsync_slurped_objects=t
 354          }
 355          ;;
 356      *)
 357          # We will do git native transport with just one call later.
 358          continue ;;
 359      esac
 360
 361      append_fetch_head "$head" "$remote" \
 362          "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
 363
 364  done
 365
 366  case "$remote" in
 367  http://* | https://* | ftp://* | rsync://* )
 368      ;; # we are already done.
 369  *)
 370    ( : subshell because we muck with IFS
 371      pack_lockfile=
 372      IFS="     $LF"
 373      (
 374          git-fetch-pack --thin $exec $keep "$remote" $rref || echo failed "$remote"
 375      ) |
 376      while read sha1 remote_name
 377      do
 378          case "$sha1" in
 379          failed)
 380                  echo >&2 "Fetch failure: $remote"
 381                  exit 1 ;;
 382          # special line coming from index-pack with the pack name
 383          pack)
 384                  continue ;;
 385          keep)
 386                  pack_lockfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
 387                  continue ;;
 388          esac
 389          found=
 390          single_force=
 391          for ref in $refs
 392          do
 393              case "$ref" in
 394              +$remote_name:*)
 395                  single_force=t
 396                  not_for_merge=
 397                  found="$ref"
 398                  break ;;
 399              .+$remote_name:*)
 400                  single_force=t
 401                  not_for_merge=t
 402                  found="$ref"
 403                  break ;;
 404              .$remote_name:*)
 405                  not_for_merge=t
 406                  found="$ref"
 407                  break ;;
 408              $remote_name:*)
 409                  not_for_merge=
 410                  found="$ref"
 411                  break ;;
 412              esac
 413          done
 414          local_name=$(expr "z$found" : 'z[^:]*:\(.*\)')
 415          append_fetch_head "$sha1" "$remote" \
 416                  "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
 417      done
 418      if [ "$pack_lockfile" ]; then rm -f "$pack_lockfile"; fi
 419    ) || exit ;;
 420  esac
 421
 422}
 423
 424fetch_main "$reflist"
 425
 426# automated tag following
 427case "$no_tags$tags" in
 428'')
 429        case "$reflist" in
 430        *:refs/*)
 431                # effective only when we are following remote branch
 432                # using local tracking branch.
 433                taglist=$(IFS=" " &&
 434                git-ls-remote $upload_pack --tags "$remote" |
 435                sed -n  -e 's|^\('"$_x40"'\)    \(refs/tags/.*\)^{}$|\1 \2|p' \
 436                        -e 's|^\('"$_x40"'\)    \(refs/tags/.*\)$|\1 \2|p' |
 437                while read sha1 name
 438                do
 439                        git-show-ref --verify --quiet -- "$name" && continue
 440                        git-check-ref-format "$name" || {
 441                                echo >&2 "warning: tag ${name} ignored"
 442                                continue
 443                        }
 444                        git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
 445                        echo >&2 "Auto-following $name"
 446                        echo ".${name}:${name}"
 447                done)
 448        esac
 449        case "$taglist" in
 450        '') ;;
 451        ?*)
 452                fetch_main "$taglist" ;;
 453        esac
 454esac
 455
 456# If the original head was empty (i.e. no "master" yet), or
 457# if we were told not to worry, we do not have to check.
 458case "$orig_head" in
 459'')
 460        ;;
 461?*)
 462        curr_head=$(git-rev-parse --verify HEAD 2>/dev/null)
 463        if test "$curr_head" != "$orig_head"
 464        then
 465            git-update-ref \
 466                        -m "$rloga: Undoing incorrectly fetched HEAD." \
 467                        HEAD "$orig_head"
 468                die "Cannot fetch into the current branch."
 469        fi
 470        ;;
 471esac