X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=git-fetch-script;h=f9f90b6db15d9e178bf7cea586f0fd41c75ca032;hb=0516de30e8bdd26086e2a3edd3375981fd0c34d6;hp=a70909e4ff15035d135eed061de8b4ea70ac5060;hpb=92c533ef0ea2cb43f0d7d493f006f5b4dfa7cda1;p=git.git diff --git a/git-fetch-script b/git-fetch-script index a70909e4..f9f90b6d 100755 --- a/git-fetch-script +++ b/git-fetch-script @@ -6,19 +6,37 @@ _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" append= +force= +update_head_ok= +while case "$#" in 0) break ;; esac +do + case "$1" in + -a|--a|--ap|--app|--appe|--appen|--append) + append=t + ;; + -f|--f|--fo|--for|--forc|--force) + force=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 + ;; + *) + break + ;; + esac + shift +done + case "$#" in 0) test -f "$GIT_DIR/branches/origin" || test -f "$GIT_DIR/remotes/origin" || - die "Where do you want to fetch from?" + die "Where do you want to fetch from today?" set origin ;; -*) - case "$1" in - -a|--a|--ap|--app|--appe|--appen|--append) - append=t - shift ;; - esac esac + remote_nick="$1" remote=$(get_remote_url "$@") refs= @@ -37,21 +55,41 @@ append_fetch_head () { remote_nick_="$4" local_name_="$5" + # 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. + 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 " ;; + *) + note_="$remote_name of " ;; + esac + remote_1_=$(expr "$remote_" : '\(.*\)\.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 - head_=$(git-rev-parse --verify "$head_^0") || exit - note_="$head_ $remote_name_ from $remote_nick_" - echo "$note_" >>$GIT_DIR/FETCH_HEAD - echo >&2 "* committish: $note_" + headc_=$(git-rev-parse --verify "$head_^0") || exit + echo "$headc_ $note_" >>$GIT_DIR/FETCH_HEAD + echo >&2 "* committish: $head_" + echo >&2 " $note_" else - echo >&2 "* non-commit: $note_" + echo >&2 "* non-commit: $head_" + echo >&2 " $note_" fi if test "$local_name_" != "" then # We are storing the head locally. Make sure that it is # a fast forward (aka "reverse push"). - fast_forward_local "$local_name_" "$head_" "$remote_" "$remote_name_" + fast_forward_local "$local_name_" "$head_" "$note_" fi } @@ -60,7 +98,14 @@ fast_forward_local () { refs/tags/*) # Tags need not be pointing at commits so there # is no way to guarantee "fast-forward" anyway. + if test -f "$GIT_DIR/$1" + then + echo >&2 "* $1: updating with $3" + else + echo >&2 "* $1: storing $3" + fi echo "$2" >"$GIT_DIR/$1" ;; + refs/heads/*) # NEEDSWORK: use the same cmpxchg protocol here. echo "$2" >"$GIT_DIR/$1.lock" @@ -70,24 +115,28 @@ fast_forward_local () { mb=$(git-merge-base "$local" "$2") && case "$2,$mb" in $local,*) - echo >&2 "* $1: same as $4" - echo >&2 " from $3" + echo >&2 "* $1: same as $3" ;; *,$local) - echo >&2 "* $1: fast forward to $4" - echo >&2 " from $3" + echo >&2 "* $1: fast forward to $3" ;; *) false ;; esac || { - mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1.remote" - echo >&2 "* $1: does not fast forward to $4" - echo >&2 " from $3; leaving it in '$1.remote'" + echo >&2 "* $1: does not fast forward to $3;" + case "$force,$single_force" in + t,* | *,t) + echo >&2 " forcing update." + ;; + *) + mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1.remote" + echo >&2 " leaving it in '$1.remote'" + ;; + esac } else - echo >&2 "* $1: storing $4" - echo >&2 " from $3." + echo >&2 "* $1: storing $3" fi test -f "$GIT_DIR/$1.lock" && mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1" @@ -95,12 +144,25 @@ fast_forward_local () { esac } +case "$update_head_ok" in +'') + orig_head=$(cat "$GIT_DIR/HEAD" 2>/dev/null) + ;; +esac + for ref in $(get_remote_refs_for_fetch "$@") do refs="$refs $ref" # These are relative path from $GIT_DIR, typically starting at refs/ # but may be HEAD + if expr "$ref" : '\+' >/dev/null + then + single_force=t + ref=$(expr "$ref" : '\+\(.*\)') + else + single_force= + fi remote_name=$(expr "$ref" : '\([^:]*\):') local_name=$(expr "$ref" : '[^:]*:\(.*\)') @@ -114,7 +176,7 @@ do fi head=$(curl -nsf $curl_extra_args "$remote/$remote_name") && expr "$head" : "$_x40\$" >/dev/null || - die "Failed to fetch $remote_name from $remote" + die "Failed to fetch $remote_name from $remote" echo Fetching "$remote_name from $remote" using http git-http-pull -v -a "$head" "$remote/" || exit ;; @@ -146,9 +208,14 @@ http://* | https://* | rsync://* ) while read sha1 remote_name do found= + single_force= for ref in $refs do case "$ref" in + +$remote_name:*) + single_force=t + found="$ref" + break ;; $remote_name:*) found="$ref" break ;; @@ -156,7 +223,22 @@ http://* | https://* | rsync://* ) done local_name=$(expr "$found" : '[^:]*:\(.*\)') - append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name" + append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name" done ;; 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 ",$update_head_ok,$orig_head," in +*,, | t,* ) + ;; +*) + curr_head=$(cat "$GIT_DIR/HEAD" 2>/dev/null) + if test "$curr_head" != "$orig_head" + then + echo "$orig_head" >$GIT_DIR/HEAD + die "Cannot fetch into the current branch." + fi + ;; +esac