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>
This commit is contained in:
parent
026351a035
commit
03febf99bc
@ -10,15 +10,23 @@
|
|||||||
fetches is a descendant of `<lbranch>`. This option
|
fetches is a descendant of `<lbranch>`. This option
|
||||||
overrides that check.
|
overrides that check.
|
||||||
|
|
||||||
|
\--no-tags::
|
||||||
|
By default, `git-fetch` fetches tags that point at
|
||||||
|
objects that are downloaded from the remote repository
|
||||||
|
and stores them locally. This option disables this
|
||||||
|
automatic tag following.
|
||||||
|
|
||||||
-t, \--tags::
|
-t, \--tags::
|
||||||
By default, the git core utilities will not fetch and store
|
Most of the tags are fetched automatically as branch
|
||||||
tags under the same name as the remote repository; ask it
|
heads are downloaded, but tags that do not point at
|
||||||
to do so using `--tags`. Using this option will bound the
|
objects reachable from the branch heads that are being
|
||||||
list of objects pulled to the remote tags. Commits in branches
|
tracked will not be fetched by this mechanism. This
|
||||||
beyond the tags will be ignored.
|
flag lets all tags and their associated objects be
|
||||||
|
downloaded.
|
||||||
|
|
||||||
-u, \--update-head-ok::
|
-u, \--update-head-ok::
|
||||||
By default `git-fetch` refuses to update the head which
|
By default `git-fetch` refuses to update the head which
|
||||||
corresponds to the current branch. This flag disables the
|
corresponds to the current branch. This flag disables the
|
||||||
check. Note that fetching into the current branch will not
|
check. Note that fetching into the current branch will not
|
||||||
update the index and working directory, so use it with care.
|
update the index and working directory, so use it with care.
|
||||||
|
|
||||||
|
275
git-fetch.sh
275
git-fetch.sh
@ -11,6 +11,7 @@ LF='
|
|||||||
'
|
'
|
||||||
IFS="$LF"
|
IFS="$LF"
|
||||||
|
|
||||||
|
no_tags=
|
||||||
tags=
|
tags=
|
||||||
append=
|
append=
|
||||||
force=
|
force=
|
||||||
@ -28,6 +29,9 @@ do
|
|||||||
-t|--t|--ta|--tag|--tags)
|
-t|--t|--ta|--tag|--tags)
|
||||||
tags=t
|
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|\
|
-u|--u|--up|--upd|--upda|--updat|--update|--update-|--update-h|\
|
||||||
--update-he|--update-hea|--update-head|--update-head-|\
|
--update-he|--update-hea|--update-head|--update-head-|\
|
||||||
--update-head-o|--update-head-ok)
|
--update-head-o|--update-head-ok)
|
||||||
@ -212,133 +216,166 @@ then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for ref in $reflist
|
fetch_main () {
|
||||||
do
|
reflist="$1"
|
||||||
refs="$refs$LF$ref"
|
refs=
|
||||||
|
|
||||||
# These are relative path from $GIT_DIR, typically starting at refs/
|
for ref in $reflist
|
||||||
# but may be HEAD
|
do
|
||||||
if expr "$ref" : '\.' >/dev/null
|
refs="$refs$LF$ref"
|
||||||
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" : '[^:]*:\(.*\)')
|
|
||||||
|
|
||||||
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...
|
rref="$rref$LF$remote_name"
|
||||||
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
|
|
||||||
|
|
||||||
# Look at objects/info/alternates for rsync -- http will
|
# There are transports that can fetch only one head at a time...
|
||||||
# support it natively and git native ones will do it on the remote
|
case "$remote" in
|
||||||
# end. Not having that file is not a crime.
|
http://* | https://*)
|
||||||
rsync -q "$remote/objects/info/alternates" \
|
if [ -n "$GIT_SSL_NO_VERIFY" ]; then
|
||||||
"$GIT_DIR/TMP_ALT" 2>/dev/null ||
|
curl_extra_args="-k"
|
||||||
rm -f "$GIT_DIR/TMP_ALT"
|
fi
|
||||||
if test -f "$GIT_DIR/TMP_ALT"
|
remote_name_quoted=$(perl -e '
|
||||||
then
|
my $u = $ARGV[0];
|
||||||
resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
|
$u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
|
||||||
while read alt
|
print "$u";
|
||||||
do
|
' "$remote_name")
|
||||||
case "$alt" in 'bad alternate: '*) die "$alt";; esac
|
head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted") &&
|
||||||
echo >&2 "Getting alternate: $alt"
|
expr "$head" : "$_x40\$" >/dev/null ||
|
||||||
rsync -av --ignore-existing --exclude info \
|
die "Failed to fetch $remote_name from $remote"
|
||||||
"$alt" "$GIT_OBJECT_DIRECTORY/" || exit
|
echo >&2 Fetching "$remote_name from $remote" using http
|
||||||
done
|
git-http-fetch -v -a "$head" "$remote/" || exit
|
||||||
rm -f "$GIT_DIR/TMP_ALT"
|
;;
|
||||||
fi
|
rsync://*)
|
||||||
rsync_slurped_objects=t
|
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"
|
||||||
# We will do git native transport with just one call later.
|
test "$rsync_slurped_objects" || {
|
||||||
continue ;;
|
rsync -av --ignore-existing --exclude info \
|
||||||
esac
|
"$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
|
||||||
|
|
||||||
append_fetch_head "$head" "$remote" \
|
# Look at objects/info/alternates for rsync -- http will
|
||||||
"$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
|
# 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
|
done
|
||||||
http://* | https://* | rsync://* )
|
|
||||||
;; # we are already done.
|
case "$remote" in
|
||||||
*)
|
http://* | https://* | rsync://* )
|
||||||
IFS=" $LF"
|
;; # we are already done.
|
||||||
(
|
*)
|
||||||
git-fetch-pack "$remote" $rref || echo failed "$remote"
|
( : subshell because we muck with IFS
|
||||||
) |
|
IFS=" $LF"
|
||||||
while read sha1 remote_name
|
(
|
||||||
do
|
git-fetch-pack "$remote" $rref || echo failed "$remote"
|
||||||
case "$sha1" in
|
) |
|
||||||
failed)
|
while read sha1 remote_name
|
||||||
echo >&2 "Fetch failure: $remote"
|
do
|
||||||
exit 1 ;;
|
case "$sha1" in
|
||||||
esac
|
failed)
|
||||||
found=
|
echo >&2 "Fetch failure: $remote"
|
||||||
single_force=
|
exit 1 ;;
|
||||||
for ref in $refs
|
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
|
do
|
||||||
case "$ref" in
|
test -f "$GIT_DIR/$name" && continue
|
||||||
+$remote_name:*)
|
git-check-ref-format "$name" || {
|
||||||
single_force=t
|
echo >&2 "warning: tag ${name} ignored"
|
||||||
not_for_merge=
|
continue
|
||||||
found="$ref"
|
}
|
||||||
break ;;
|
git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
|
||||||
.+$remote_name:*)
|
echo >&2 "Auto-following $name"
|
||||||
single_force=t
|
echo ".${name}:${name}"
|
||||||
not_for_merge=t
|
done)
|
||||||
found="$ref"
|
case "$taglist" in
|
||||||
break ;;
|
'') ;;
|
||||||
.$remote_name:*)
|
?*)
|
||||||
not_for_merge=t
|
fetch_main "$taglist" ;;
|
||||||
found="$ref"
|
esac
|
||||||
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
|
esac
|
||||||
|
|
||||||
# If the original head was empty (i.e. no "master" yet), or
|
# If the original head was empty (i.e. no "master" yet), or
|
||||||
|
Loading…
Reference in New Issue
Block a user