git-fetch.shon commit Merge branch 'fixes' (d6179f5)
   1#!/bin/sh
   2#
   3. git-sh-setup || die "Not a git archive"
   4. git-parse-remote
   5_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
   6_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
   7
   8append=
   9force=
  10update_head_ok=
  11while case "$#" in 0) break ;; esac
  12do
  13        case "$1" in
  14        -a|--a|--ap|--app|--appe|--appen|--append)
  15                append=t
  16                ;;
  17        -f|--f|--fo|--for|--forc|--force)
  18                force=t
  19                ;;
  20        -u|--u|--up|--upd|--upda|--updat|--update|--update-|--update-h|\
  21        --update-he|--update-hea|--update-head|--update-head-|\
  22        --update-head-o|--update-head-ok)
  23                update_head_ok=t
  24                ;;
  25        *)
  26                break
  27                ;;
  28        esac
  29        shift
  30done
  31
  32case "$#" in
  330)
  34        test -f "$GIT_DIR/branches/origin" ||
  35                test -f "$GIT_DIR/remotes/origin" ||
  36                        die "Where do you want to fetch from today?"
  37        set origin ;;
  38esac
  39
  40remote_nick="$1"
  41remote=$(get_remote_url "$@")
  42refs=
  43rref=
  44rsync_slurped_objects=
  45
  46if test "" = "$append"
  47then
  48        : >$GIT_DIR/FETCH_HEAD
  49fi
  50
  51append_fetch_head () {
  52    head_="$1"
  53    remote_="$2"
  54    remote_name_="$3"
  55    remote_nick_="$4"
  56    local_name_="$5"
  57
  58    # remote-nick is the URL given on the command line (or a shorthand)
  59    # remote-name is the $GIT_DIR relative refs/ path we computed
  60    # for this refspec.
  61    case "$remote_name_" in
  62    HEAD)
  63        note_= ;;
  64    refs/heads/*)
  65        note_="$(expr "$remote_name_" : 'refs/heads/\(.*\)')"
  66        note_="branch '$note_' of " ;;
  67    refs/tags/*)
  68        note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')"
  69        note_="tag '$note_' of " ;;
  70    *)
  71        note_="$remote_name of " ;;
  72    esac
  73    remote_1_=$(expr "$remote_" : '\(.*\)\.git/*$') &&
  74        remote_="$remote_1_"
  75    note_="$note_$remote_"
  76
  77    # 2.6.11-tree tag would not be happy to be fed to resolve.
  78    if git-cat-file commit "$head_" >/dev/null 2>&1
  79    then
  80        headc_=$(git-rev-parse --verify "$head_^0") || exit
  81        echo "$headc_   $note_" >>$GIT_DIR/FETCH_HEAD
  82        echo >&2 "* committish: $head_"
  83        echo >&2 "  $note_"
  84    else
  85        echo >&2 "* non-commit: $head_"
  86        echo >&2 "  $note_"
  87    fi
  88    if test "$local_name_" != ""
  89    then
  90        # We are storing the head locally.  Make sure that it is
  91        # a fast forward (aka "reverse push").
  92        fast_forward_local "$local_name_" "$head_" "$note_"
  93    fi
  94}
  95
  96fast_forward_local () {
  97    mkdir -p "$(dirname "$GIT_DIR/$1")"
  98    case "$1" in
  99    refs/tags/*)
 100        # Tags need not be pointing at commits so there
 101        # is no way to guarantee "fast-forward" anyway.
 102        if test -f "$GIT_DIR/$1"
 103        then
 104                echo >&2 "* $1: updating with $3"
 105        else
 106                echo >&2 "* $1: storing $3"
 107        fi
 108        echo "$2" >"$GIT_DIR/$1" ;;
 109
 110    refs/heads/*)
 111        # NEEDSWORK: use the same cmpxchg protocol here.
 112        echo "$2" >"$GIT_DIR/$1.lock"
 113        if test -f "$GIT_DIR/$1"
 114        then
 115            local=$(git-rev-parse --verify "$1^0") &&
 116            mb=$(git-merge-base "$local" "$2") &&
 117            case "$2,$mb" in
 118            $local,*)
 119                echo >&2 "* $1: same as $3"
 120                ;;
 121            *,$local)
 122                echo >&2 "* $1: fast forward to $3"
 123                ;;
 124            *)
 125                false
 126                ;;
 127            esac || {
 128                echo >&2 "* $1: does not fast forward to $3;"
 129                case "$force,$single_force" in
 130                t,* | *,t)
 131                        echo >&2 "  forcing update."
 132                        ;;
 133                *)
 134                        mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1.remote"
 135                        echo >&2 "  leaving it in '$1.remote'"
 136                        ;;
 137                esac
 138            }
 139        else
 140                echo >&2 "* $1: storing $3"
 141        fi
 142        test -f "$GIT_DIR/$1.lock" &&
 143            mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1"
 144        ;;
 145    esac
 146}
 147
 148case "$update_head_ok" in
 149'')
 150        orig_head=$(cat "$GIT_DIR/HEAD" 2>/dev/null)
 151        ;;
 152esac
 153
 154for ref in $(get_remote_refs_for_fetch "$@")
 155do
 156    refs="$refs $ref"
 157
 158    # These are relative path from $GIT_DIR, typically starting at refs/
 159    # but may be HEAD
 160    if expr "$ref" : '\+' >/dev/null
 161    then
 162        single_force=t
 163        ref=$(expr "$ref" : '\+\(.*\)')
 164    else
 165        single_force=
 166    fi
 167    remote_name=$(expr "$ref" : '\([^:]*\):')
 168    local_name=$(expr "$ref" : '[^:]*:\(.*\)')
 169
 170    rref="$rref $remote_name"
 171
 172    # There are transports that can fetch only one head at a time...
 173    case "$remote" in
 174    http://* | https://*)
 175        if [ -n "$GIT_SSL_NO_VERIFY" ]; then
 176            curl_extra_args="-k"
 177        fi
 178        head=$(curl -nsf $curl_extra_args "$remote/$remote_name") &&
 179        expr "$head" : "$_x40\$" >/dev/null ||
 180                die "Failed to fetch $remote_name from $remote"
 181        echo Fetching "$remote_name from $remote" using http
 182        git-http-fetch -v -a "$head" "$remote/" || exit
 183        ;;
 184    rsync://*)
 185        TMP_HEAD="$GIT_DIR/TMP_HEAD"
 186        rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
 187        head=$(git-rev-parse TMP_HEAD)
 188        rm -f "$TMP_HEAD"
 189        test "$rsync_slurped_objects" || {
 190            rsync -av --ignore-existing --exclude info \
 191                "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
 192
 193            # Look at objects/info/alternates for rsync -- http will
 194            # support it natively and git native ones will do it on the remote
 195            # end.  Not having that file is not a crime.
 196            rsync -q "$remote/objects/info/alternates" \
 197                "$GIT_DIR/TMP_ALT" 2>/dev/null ||
 198                rm -f "$GIT_DIR/TMP_ALT"
 199            if test -f "$GIT_DIR/TMP_ALT"
 200            then
 201                resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
 202                while read alt
 203                do
 204                    case "$alt" in 'bad alternate: '*) die "$alt";; esac
 205                    echo >&2 "Getting alternate: $alt"
 206                    rsync -av --ignore-existing --exclude info \
 207                    "$alt" "$GIT_OBJECT_DIRECTORY/" || exit
 208                done
 209                rm -f "$GIT_DIR/TMP_ALT"
 210            fi
 211            rsync_slurped_objects=t
 212        }
 213        ;;
 214    *)
 215        # We will do git native transport with just one call later.
 216        continue ;;
 217    esac
 218
 219    append_fetch_head "$head" "$remote" "$remote_name" "$remote_nick" "$local_name"
 220
 221done
 222
 223case "$remote" in
 224http://* | https://* | rsync://* )
 225    ;; # we are already done.
 226*)
 227    (
 228        git-fetch-pack "$remote" $rref || echo failed "$remote"
 229    ) |
 230    while read sha1 remote_name
 231    do
 232        case "$sha1" in
 233        failed)
 234                echo >&2 "Fetch failure: $remote"
 235                exit 1 ;;
 236        esac
 237        found=
 238        single_force=
 239        for ref in $refs
 240        do
 241            case "$ref" in
 242            +$remote_name:*)
 243                single_force=t
 244                found="$ref"
 245                break ;;
 246            $remote_name:*)
 247                found="$ref"
 248                break ;;
 249            esac
 250        done
 251
 252        local_name=$(expr "$found" : '[^:]*:\(.*\)')
 253        append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name"
 254    done || exit
 255    ;;
 256esac
 257
 258# If the original head was empty (i.e. no "master" yet), or
 259# if we were told not to worry, we do not have to check.
 260case ",$update_head_ok,$orig_head," in
 261*,, | t,* )
 262        ;;
 263*)
 264        curr_head=$(cat "$GIT_DIR/HEAD" 2>/dev/null)
 265        if test "$curr_head" != "$orig_head"
 266        then
 267                echo "$orig_head" >$GIT_DIR/HEAD
 268                die "Cannot fetch into the current branch."
 269        fi
 270        ;;
 271esac