#!/bin/sh # setvar USAGE = '' ...'' setvar SUBDIRECTORY_OK = 'Yes' source git-sh-setup set_reflog_action "fetch $[join(ARGV)]" cd_to_toplevel ;# probably unnecessary... source git-parse-remote setvar _x40 = ''[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'' setvar _x40 = ""$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"" setvar LF = '' '' setvar IFS = "$LF" setvar no_tags = '' setvar tags = '' setvar append = '' setvar force = '' setvar verbose = '' setvar update_head_ok = '' setvar exec = '' setvar keep = '' setvar shallow_depth = '' setvar no_progress = '' test -t 1 || setvar no_progress = '--no-progress' setvar quiet = '' while test $# != 0 { case (1) { -a|--a|--ap|--app|--appe|--appen|--append { setvar append = 't' } --upl|--uplo|--uploa|--upload|--upload-|--upload-p|\ --upload-pa|--upload-pac|--upload-pack { shift setvar exec = ""--upload-pack=$1"" } --upl=*|--uplo=*|--uploa=*|--upload=*|\ --upload-=*|--upload-p=*|--upload-pa=*|--upload-pac=*|--upload-pack=* { setvar exec = "--upload-pack=$(expr "z$1" : 'z-[^=]*=\(.*\)')" shift } -f|--f|--fo|--for|--forc|--force { setvar force = 't' } -t|--t|--ta|--tag|--tags { setvar tags = 't' } -n|--n|--no|--no-|--no-t|--no-ta|--no-tag|--no-tags { setvar 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 { setvar update_head_ok = 't' } -q|--q|--qu|--qui|--quie|--quiet { setvar quiet = '--quiet' } -v|--verbose { setvar verbose = ""$verbose"Yes" } -k|--k|--ke|--kee|--keep { setvar keep = ''-k -k'' } --depth=* { setvar shallow_depth = ""--depth=$(expr "z$1" : 'z-[^=]*=\(.*\)')"" } --depth { shift setvar shallow_depth = ""--depth=$1"" } -* { usage } * { break } } shift } case (#) { 0 { setvar origin = $(get_default_remote) test -n $(get_remote_url ${origin}) || die "Where do you want to fetch from today?" set x $origin ; shift } } if test -z $exec { # No command line override and we have configuration for the remote. setvar exec = ""--upload-pack=$(get_uploadpack $1)"" } setvar remote_nick = "$1" setvar remote = $(get_remote_url "$@") setvar refs = '' setvar rref = '' setvar rsync_slurped_objects = '' if test "" = $append { : >"$GIT_DIR/FETCH_HEAD" } # Global that is reused later setvar ls_remote_result = $(git ls-remote $exec "$remote") || die "Cannot get the repository state from $remote" proc append_fetch_head { setvar flags = '' test -n $verbose && setvar flags = ""$flags$LF-v"" test -n "$force$single_force" && setvar flags = ""$flags$LF-f""" GIT_REFLOG_ACTION=$GIT_REFLOG_ACTION" \ git fetch--tool $flags append-fetch-head @ARGV } # 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 { setvar orig_head = $(git rev-parse --verify HEAD 2>/dev/null) } # Allow --tags/--notags from remote.$1.tagopt case{ '' { case{ --tags { setvar tags = 't' } --no-tags { setvar no_tags = 't' } } } } # 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. setvar reflist = $(get_remote_refs_for_fetch "$@") if test $tags { setvar 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 "$Argc" -gt 1 { # remote URL plus explicit refspecs; we need to merge them. setvar reflist = ""$reflist$LF$taglist"" } else { # No explicit refspecs; fetch tags only. setvar reflist = "$taglist" } } proc fetch_all_at_once { setvar eval = $(echo "$1" | git fetch--tool parse-reflist "-") eval $eval shell { : subshell because we muck with IFS setvar IFS = "" $LF"" shell { if test $remote = . { git show-ref $rref || echo failed $remote } elif test -f $remote { 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. setvar 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 { echo $ls_remote_result | \ git fetch--tool pick-rref $rref "-" } else { setvar flags = '' case (verbose) { YesYes* { setvar flags = ""-v"" } } git-fetch-pack --thin $exec $keep $shallow_depth \ $quiet $no_progress $flags $remote $rref || echo failed $remote } } } | shell { setvar flags = '' test -n $verbose && setvar flags = ""$flags -v"" test -n $force && setvar flags = ""$flags -f""" GIT_REFLOG_ACTION=$GIT_REFLOG_ACTION" \ git fetch--tool $flags native-store \ $remote $remote_nick $refs } } || exit } proc fetch_per_ref { setvar reflist = "$1" setvar refs = '' setvar rref = '' for ref in $reflist { setvar 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 { setvar not_for_merge = 't' setvar ref = $(expr "z$ref" : 'z\.\(.*\)') } else { setvar not_for_merge = '' } if expr "z$ref" : 'z+' >/dev/null { setvar single_force = 't' setvar ref = $(expr "z$ref" : 'z+\(.*\)') } else { setvar single_force = '' } setvar remote_name = $(expr "z$ref" : 'z\([^:]*\):') setvar local_name = $(expr "z$ref" : 'z[^:]*:\(.*\)') setvar rref = ""$rref$LF$remote_name"" # There are transports that can fetch only one head at a time... case (remote) { http://* | https://* | ftp://* { test -n $shallow_depth && die "shallow clone with http not supported" setvar proto = $(expr "$remote" : '\([^:]*\):') if test -n $GIT_SSL_NO_VERIFY { setvar curl_extra_args = ""-k"" } if test -n $GIT_CURL_FTP_NO_EPSV -o \ $(git config --bool http.noEPSV) = true { setvar noepsv_opt = ""--disable-epsv"" } # Find $remote_name from ls-remote output. setvar 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>&2 "Fetching $remote_name from $remote using $proto" case (quiet) { '' { setvar v = '-v' } * { setvar v = '' } } git-http-fetch $v -a $head $remote || exit } rsync://* { test -n $shallow_depth && die "shallow clone with rsync not supported" setvar TMP_HEAD = ""$GIT_DIR/TMP_HEAD"" rsync -L -q "$remote/$remote_name" $TMP_HEAD || exit 1 setvar head = $(git rev-parse --verify TMP_HEAD) rm -f $TMP_HEAD case (quiet) { '' { setvar v = '-v' } * { setvar v = '' } } test $rsync_slurped_objects || do { 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" { resolve_alternates $remote <"$GIT_DIR/TMP_ALT" | while read alt { case (alt) { 'bad alternate: '* { die $alt} } echo >&2 "Getting alternate: $alt>&2 "Getting alternate: $alt" rsync -av --ignore-existing --exclude info \ $alt "$GIT_OBJECT_DIRECTORY/" || exit } rm -f "$GIT_DIR/TMP_ALT" } setvar rsync_slurped_objects = 't' } } } append_fetch_head $head $remote \ $remote_name $remote_nick $local_name $not_for_merge || exit } } proc fetch_main { case (remote) { http://* | https://* | ftp://* | rsync://* { fetch_per_ref @ARGV } * { fetch_all_at_once @ARGV } } } fetch_main $reflist || exit # automated tag following case{ '' { case (reflist) { *:refs/* { # effective only when we are following remote branch # using local tracking branch. setvar 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) } } case (taglist) { '' { } ?* { # do not deepen a shallow tree when following tags setvar shallow_depth = '' fetch_main $taglist || exit } } } } # 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) { '' { } ?* { setvar curr_head = $(git rev-parse --verify HEAD 2>/dev/null) if test $curr_head != $orig_head { git update-ref \ -m "$GIT_REFLOG_ACTION: Undoing incorrectly fetched HEAD." \ HEAD $orig_head die "Cannot fetch into the current branch." } } }