diff options
author | Junio C Hamano <junkio@cox.net> | 2006-01-07 00:48:04 -0800 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2006-01-07 21:33:51 -0800 |
commit | 03febf99bc77001af6709ee1c17d3dc5e71e8990 (patch) | |
tree | 34eb3db82325927855ac003feedd881799098116 /git-fetch.sh | |
parent | 026351a03507dc3a2e89e068c01234dc55914df2 (diff) | |
download | git-03febf99bc77001af6709ee1c17d3dc5e71e8990.tar.gz git-03febf99bc77001af6709ee1c17d3dc5e71e8990.tar.xz |
git-fetch: auto-following tags.
I added things to ls-remote so that Cogito can auto-follow tags
easily and correctly a while ago, but git-fetch did not use the
facility. Recently added git-describe command relies on
repository keeping up-to-date set of tags, which made it much
more attractive to automatically follow tags, so we do that as
well.
Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'git-fetch.sh')
-rwxr-xr-x | git-fetch.sh | 275 |
1 files changed, 156 insertions, 119 deletions
diff --git a/git-fetch.sh b/git-fetch.sh index b46b3e558..73e57bd78 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -11,6 +11,7 @@ LF=' ' IFS="$LF" +no_tags= tags= append= force= @@ -28,6 +29,9 @@ do -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) @@ -212,133 +216,166 @@ then fi fi -for ref in $reflist -do - refs="$refs$LF$ref" +fetch_main () { + reflist="$1" + refs= - # 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 - ref=$(expr "$ref" : '\+\(.*\)') - else - single_force= - fi - remote_name=$(expr "$ref" : '\([^:]*\):') - local_name=$(expr "$ref" : '[^:]*:\(.*\)') + for ref in $reflist + do + refs="$refs$LF$ref" - rref="$rref$LF$remote_name" + # 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 + ref=$(expr "$ref" : '\+\(.*\)') + else + single_force= + fi + remote_name=$(expr "$ref" : '\([^:]*\):') + local_name=$(expr "$ref" : '[^:]*:\(.*\)') - # There are transports that can fetch only one head at a time... - case "$remote" in - http://* | https://*) - if [ -n "$GIT_SSL_NO_VERIFY" ]; then - curl_extra_args="-k" - fi - remote_name_quoted=$(perl -e ' - my $u = $ARGV[0]; - $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg; - print "$u"; - ' "$remote_name") - head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted") && - expr "$head" : "$_x40\$" >/dev/null || - die "Failed to fetch $remote_name from $remote" - 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 -q "$remote/$remote_name" "$TMP_HEAD" || exit 1 - head=$(git-rev-parse --verify TMP_HEAD) - rm -f "$TMP_HEAD" - test "$rsync_slurped_objects" || { - rsync -av --ignore-existing --exclude info \ - "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit + rref="$rref$LF$remote_name" - # 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 - } - ;; - *) - # We will do git native transport with just one call later. - continue ;; - esac + # There are transports that can fetch only one head at a time... + case "$remote" in + http://* | https://*) + if [ -n "$GIT_SSL_NO_VERIFY" ]; then + curl_extra_args="-k" + fi + remote_name_quoted=$(perl -e ' + my $u = $ARGV[0]; + $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg; + print "$u"; + ' "$remote_name") + head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted") && + expr "$head" : "$_x40\$" >/dev/null || + die "Failed to fetch $remote_name from $remote" + 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 -q "$remote/$remote_name" "$TMP_HEAD" || exit 1 + head=$(git-rev-parse --verify TMP_HEAD) + rm -f "$TMP_HEAD" + test "$rsync_slurped_objects" || { + rsync -av --ignore-existing --exclude info \ + "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit - append_fetch_head "$head" "$remote" \ - "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" + # 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 + } + ;; + *) + # We will do git native transport with just one call later. + continue ;; + esac -done + append_fetch_head "$head" "$remote" \ + "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" -case "$remote" in -http://* | https://* | rsync://* ) - ;; # we are already done. -*) - IFS=" $LF" - ( - 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 + done + + case "$remote" in + http://* | https://* | rsync://* ) + ;; # we are already done. + *) + ( : subshell because we muck with IFS + IFS=" $LF" + ( + 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 + do + 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" "$not_for_merge" + done + ) || exit ;; + esac + +} + +fetch_main "$reflist" + +# automated tag following +case "$no_tags$tags" in +'') + taglist=$(IFS=" " && + git-ls-remote --tags "$remote" | + sed -ne 's|^\([0-9a-f]*\)[ ]\(refs/tags/.*\)^{}$|\1 \2|p' | + while read sha1 name do - 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" "$not_for_merge" - done || exit - ;; + test -f "$GIT_DIR/$name" && continue + git-check-ref-format "$name" || { + echo >&2 "warning: tag ${name} ignored" + continue + } + git-cat-file -t "$sha1" >/dev/null 2>&1 || continue + echo >&2 "Auto-following $name" + echo ".${name}:${name}" + done) + case "$taglist" in + '') ;; + ?*) + fetch_main "$taglist" ;; + esac esac # If the original head was empty (i.e. no "master" yet), or |