X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=git-fetch.sh;h=27407c1d357d8bf9d621875b1a773cef671ddc3d;hb=49a0f240f7be05728f97903efd97ad7898ff6d08;hp=4928cd5bed7dd6a5bd4653f51a45c611bf8e9379;hpb=215a7ad1ef790467a4cd3f0dcffbd6e5f04c38f7;p=git.git diff --git a/git-fetch.sh b/git-fetch.sh index 4928cd5b..27407c1d 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -54,6 +54,10 @@ append_fetch_head () { remote_name_="$3" remote_nick_="$4" local_name_="$5" + case "$6" in + t) not_for_merge_='not-for-merge' ;; + '') not_for_merge_= ;; + esac # remote-nick is the URL given on the command line (or a shorthand) # remote-name is the $GIT_DIR relative refs/ path we computed @@ -78,10 +82,11 @@ append_fetch_head () { if git-cat-file commit "$head_" >/dev/null 2>&1 then headc_=$(git-rev-parse --verify "$head_^0") || exit - echo "$headc_ $note_" >>$GIT_DIR/FETCH_HEAD + echo "$headc_ $not_for_merge_ $note_" >>$GIT_DIR/FETCH_HEAD echo >&2 "* committish: $head_" echo >&2 " $note_" else + echo "$head_ not-for-merge $note_" >>$GIT_DIR/FETCH_HEAD echo >&2 "* non-commit: $head_" echo >&2 " $note_" fi @@ -94,6 +99,7 @@ append_fetch_head () { } fast_forward_local () { + mkdir -p "$(dirname "$GIT_DIR/$1")" case "$1" in refs/tags/*) # Tags need not be pointing at commits so there @@ -104,14 +110,16 @@ fast_forward_local () { else echo >&2 "* $1: storing $3" fi - echo "$2" >"$GIT_DIR/$1" ;; + git-update-ref "$1" "$2" + ;; refs/heads/*) - # NEEDSWORK: use the same cmpxchg protocol here. - echo "$2" >"$GIT_DIR/$1.lock" - if test -f "$GIT_DIR/$1" + # $1 is the ref being updated. + # $2 is the new value for the ref. + local=$(git-rev-parse --verify "$1^0" 2>/dev/null) + if test "$local" then - local=$(git-rev-parse --verify "$1^0") && + # Require fast-forward. mb=$(git-merge-base "$local" "$2") && case "$2,$mb" in $local,*) @@ -119,34 +127,34 @@ fast_forward_local () { ;; *,$local) echo >&2 "* $1: fast forward to $3" + git-update-ref "$1" "$2" "$local" ;; *) false ;; esac || { echo >&2 "* $1: does not fast forward to $3;" - case "$force,$single_force" in - t,* | *,t) + case ",$force,$single_force," in + *,t,*) echo >&2 " forcing update." + git-update-ref "$1" "$2" "$local" ;; *) - mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1.remote" - echo >&2 " leaving it in '$1.remote'" + echo >&2 " not updating." ;; esac } else - echo >&2 "* $1: storing $3" + echo >&2 "* $1: storing $3" + git-update-ref "$1" "$2" fi - test -f "$GIT_DIR/$1.lock" && - mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1" ;; esac } case "$update_head_ok" in '') - orig_head=$(cat "$GIT_DIR/HEAD" 2>/dev/null) + orig_head=$(git-rev-parse --verify HEAD 2>/dev/null) ;; esac @@ -156,6 +164,13 @@ do # These are relative path from $GIT_DIR, typically starting at refs/ # but may be HEAD + if expr "$ref" : '\.' >/dev/null + then + not_for_merge=t + ref=$(expr "$ref" : '\.\(.*\)') + else + not_for_merge= + fi if expr "$ref" : '\+' >/dev/null then single_force=t @@ -177,17 +192,36 @@ do head=$(curl -nsf $curl_extra_args "$remote/$remote_name") && expr "$head" : "$_x40\$" >/dev/null || die "Failed to fetch $remote_name from $remote" - echo Fetching "$remote_name from $remote" using http + echo >&2 Fetching "$remote_name from $remote" using http git-http-fetch -v -a "$head" "$remote/" || exit ;; rsync://*) TMP_HEAD="$GIT_DIR/TMP_HEAD" - rsync -L "$remote/$remote_name" "$TMP_HEAD" || exit 1 - head=$(git-rev-parse TMP_HEAD) + rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1 + head=$(git-rev-parse --verify TMP_HEAD) rm -f "$TMP_HEAD" test "$rsync_slurped_objects" || { - rsync -avz --ignore-existing "$remote/objects/" \ - "$GIT_OBJECT_DIRECTORY/" || exit + rsync -av --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 } ;; @@ -196,7 +230,8 @@ do continue ;; esac - append_fetch_head "$head" "$remote" "$remote_name" "$remote_nick" "$local_name" + append_fetch_head "$head" "$remote" \ + "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" done @@ -204,9 +239,16 @@ case "$remote" in http://* | https://* | rsync://* ) ;; # we are already done. *) - git-fetch-pack "$remote" $rref | + ( + git-fetch-pack "$remote" $rref || echo failed "$remote" + ) | while read sha1 remote_name do + case "$sha1" in + failed) + echo >&2 "Fetch failure: $remote" + exit 1 ;; + esac found= single_force= for ref in $refs @@ -214,17 +256,28 @@ http://* | https://* | rsync://* ) case "$ref" in +$remote_name:*) single_force=t + not_for_merge= + found="$ref" + break ;; + .+$remote_name:*) + single_force=t + not_for_merge=t + found="$ref" + break ;; + .$remote_name:*) + not_for_merge=t found="$ref" break ;; $remote_name:*) + not_for_merge= found="$ref" break ;; esac done - local_name=$(expr "$found" : '[^:]*:\(.*\)') - append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name" - done + append_fetch_head "$sha1" "$remote" \ + "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" + done || exit ;; esac @@ -234,10 +287,10 @@ case ",$update_head_ok,$orig_head," in *,, | t,* ) ;; *) - curr_head=$(cat "$GIT_DIR/HEAD" 2>/dev/null) + curr_head=$(git-rev-parse --verify HEAD 2>/dev/null) if test "$curr_head" != "$orig_head" then - echo "$orig_head" >$GIT_DIR/HEAD + git-update-ref HEAD "$orig_head" die "Cannot fetch into the current branch." fi ;;