#!/bin/sh # 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" LF=' ' IFS="$LF" no_tags= tags= append= force= verbose= update_head_ok= exec= keep= shallow_depth= no_progress= test -t 1 || no_progress=--no-progress quiet= while test $# != 0 do case "$1" in -a|--a|--ap|--app|--appe|--appen|--append) append=t ;; --upl|--uplo|--uploa|--upload|--upload-|--upload-p|\ --upload-pa|--upload-pac|--upload-pack) shift 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 ;; -t|--t|--ta|--tag|--tags) tags=t ;; -n|--n|--no|--no-|--no-t|--no-ta|--no-tag|--no-tags) no_tags=t ;; -u|--u|--up|--upd|--upda|--updat|--update|--update-|--update-h|\ --update-he|--update-hea|--update-head|--update-head-|\ --update-head-o|--update-head-ok) update_head_ok=t ;; -q|--q|--qu|--qui|--quie|--quiet) quiet=--quiet ;; -v|--verbose) verbose="$verbose"Yes ;; -k|--k|--ke|--kee|--keep) keep='-k -k' ;; --depth=*) shallow_depth="--depth=`expr "z$1" : 'z-[^=]*=\(.*\)'`" ;; --depth) shift shallow_depth="--depth=$1" ;; -*) usage ;; *) break ;; esac shift done case "$#" in 0) origin=$(get_default_remote) test -n "$(get_remote_url ${origin})" || die "Where do you want to fetch from today?" 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= 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 () { 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 "$@" } # 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 --tags/--notags from remote.$1.tagopt case "$tags$no_tags" in '') case "$(git config --get "remote.$1.tagopt")" in --tags) tags=t ;; --no-tags) no_tags=t ;; esac esac # If --tags (and later --heads or --all) is specified, then we are # not talking about defaults stored in Pull: line of remotes or # branches file, and just fetch those and refspecs explicitly given. # Otherwise we do what we always did. reflist=$(get_remote_refs_for_fetch "$@") if test "$tags" then taglist=`IFS=' ' && echo "$ls_remote_result" | git show-ref --exclude-existing=refs/tags/ | while read sha1 name do echo ".${name}:${name}" done` || exit if test "$#" -gt 1 then # remote URL plus explicit refspecs; we need to merge them. reflist="$reflist$LF$taglist" else # No explicit refspecs; fetch tags only. reflist=$taglist fi fi 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 if test -d "$remote" && # The remote might be our alternate. With # this optimization we will bypass fetch-pack # altogether, which means we cannot be doing # the shallow stuff at all. test ! -f "$GIT_DIR/shallow" && test -z "$shallow_depth" && # See if all of what we are going to fetch are # connected to our repository's tips, in which # case we do not have to do any fetch. theirs=$(echo "$ls_remote_result" | \ git fetch--tool -s pick-rref "$rref" "-") && # This will barf when $theirs reach an object that # we do not have in our repository. Otherwise, # we already have everything the fetch would bring in. git rev-list --objects $theirs --not --all \ >/dev/null 2>/dev/null then echo "$ls_remote_result" | \ git fetch--tool pick-rref "$rref" "-" else flags= case $verbose in YesYes*) flags="-v" ;; esac git-fetch-pack --thin $exec $keep $shallow_depth \ $quiet $no_progress $flags "$remote" $rref || echo failed "$remote" fi 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= for ref in $reflist do refs="$refs$LF$ref" # These are relative path from $GIT_DIR, typically starting at refs/ # but may be HEAD if expr "z$ref" : 'z\.' >/dev/null then not_for_merge=t ref=$(expr "z$ref" : 'z\.\(.*\)') else not_for_merge= fi if expr "z$ref" : 'z+' >/dev/null then single_force=t ref=$(expr "z$ref" : 'z+\(.*\)') else single_force= fi remote_name=$(expr "z$ref" : 'z\([^:]*\):') local_name=$(expr "z$ref" : 'z[^:]*:\(.*\)') rref="$rref$LF$remote_name" # 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 config --bool http.noEPSV`" = true ]; then noepsv_opt="--disable-epsv" fi # Find $remote_name from ls-remote output. head=$(echo "$ls_remote_result" | \ git fetch--tool -s pick-rref "$remote_name" "-") expr "z$head" : "z$_x40\$" >/dev/null || die "No such ref $remote_name at $remote" echo >&2 "Fetching $remote_name from $remote using $proto" 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 -a $v --ignore-existing --exclude info \ "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit # Look at objects/info/alternates for rsync -- http will # support it natively and git native ones will do it on # the remote end. Not having that file is not a crime. rsync -q "$remote/objects/info/alternates" \ "$GIT_DIR/TMP_ALT" 2>/dev/null || rm -f "$GIT_DIR/TMP_ALT" if test -f "$GIT_DIR/TMP_ALT" then resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" | while read alt do case "$alt" in 'bad alternate: '*) die "$alt";; esac echo >&2 "Getting alternate: $alt" rsync -av --ignore-existing --exclude info \ "$alt" "$GIT_OBJECT_DIRECTORY/" || exit done rm -f "$GIT_DIR/TMP_ALT" fi rsync_slurped_objects=t } ;; esac append_fetch_head "$head" "$remote" \ "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" || exit done } fetch_main () { case "$remote" in http://* | https://* | ftp://* | rsync://* ) fetch_per_ref "$@" ;; *) fetch_all_at_once "$@" ;; esac } fetch_main "$reflist" || exit # automated tag following case "$no_tags$tags" in '') case "$reflist" in *:refs/*) # effective only when we are following remote branch # using local tracking branch. taglist=$(IFS=' ' && echo "$ls_remote_result" | git show-ref --exclude-existing=refs/tags/ | while read sha1 name do git cat-file -t "$sha1" >/dev/null 2>&1 || continue echo >&2 "Auto-following $name" echo ".${name}:${name}" done) esac case "$taglist" in '') ;; ?*) # do not deepen a shallow tree when following tags shallow_depth= 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 "$orig_head" in '') ;; ?*) curr_head=$(git rev-parse --verify HEAD 2>/dev/null) if test "$curr_head" != "$orig_head" then git update-ref \ -m "$GIT_REFLOG_ACTION: Undoing incorrectly fetched HEAD." \ HEAD "$orig_head" die "Cannot fetch into the current branch." fi ;; esac