4447badcd2
For local operations and downloading and uploading via git aware protocols, use of $GIT_OBJECT_DIRECTORY/info/alternates is recommended on the server side for big projects that are derived from another one (like Linux kernel). However, dumb protocols and rsync transport needs to resolve this on the client end, which we did not bother doing until this week. I noticed we use "rsync -z" but most of our payload is already compressed, which was not quite right. This commit also fixes it. Signed-off-by: Junio C Hamano <junkio@cox.net>
177 lines
3.5 KiB
Bash
Executable File
177 lines
3.5 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
. git-sh-setup || die "Not a git archive"
|
|
|
|
get_data_source () {
|
|
case "$1" in
|
|
*/*)
|
|
# Not so fast. This could be the partial URL shorthand...
|
|
token=$(expr "$1" : '\([^/]*\)/')
|
|
remainder=$(expr "$1" : '[^/]*/\(.*\)')
|
|
if test -f "$GIT_DIR/branches/$token"
|
|
then
|
|
echo branches-partial
|
|
else
|
|
echo ''
|
|
fi
|
|
;;
|
|
*)
|
|
if test -f "$GIT_DIR/remotes/$1"
|
|
then
|
|
echo remotes
|
|
elif test -f "$GIT_DIR/branches/$1"
|
|
then
|
|
echo branches
|
|
else
|
|
echo ''
|
|
fi ;;
|
|
esac
|
|
}
|
|
|
|
get_remote_url () {
|
|
data_source=$(get_data_source "$1")
|
|
case "$data_source" in
|
|
'')
|
|
echo "$1" ;;
|
|
remotes)
|
|
sed -ne '/^URL: */{
|
|
s///p
|
|
q
|
|
}' "$GIT_DIR/remotes/$1" ;;
|
|
branches)
|
|
sed -e 's/#.*//' "$GIT_DIR/branches/$1" ;;
|
|
branches-partial)
|
|
token=$(expr "$1" : '\([^/]*\)/')
|
|
remainder=$(expr "$1" : '[^/]*/\(.*\)')
|
|
url=$(sed -e 's/#.*//' "$GIT_DIR/branches/$token")
|
|
echo "$url/$remainder"
|
|
;;
|
|
*)
|
|
die "internal error: get-remote-url $1" ;;
|
|
esac
|
|
}
|
|
|
|
get_remote_default_refs_for_push () {
|
|
data_source=$(get_data_source "$1")
|
|
case "$data_source" in
|
|
'' | branches | branches-partial)
|
|
;; # no default push mapping, just send matching refs.
|
|
remotes)
|
|
sed -ne '/^Push: */{
|
|
s///p
|
|
}' "$GIT_DIR/remotes/$1" ;;
|
|
*)
|
|
die "internal error: get-remote-default-ref-for-push $1" ;;
|
|
esac
|
|
}
|
|
|
|
# Subroutine to canonicalize remote:local notation
|
|
canon_refs_list_for_fetch () {
|
|
for ref
|
|
do
|
|
force=
|
|
case "$ref" in
|
|
+*)
|
|
ref=$(expr "$ref" : '\+\(.*\)')
|
|
force=+
|
|
;;
|
|
esac
|
|
expr "$ref" : '.*:' >/dev/null || ref="${ref}:"
|
|
remote=$(expr "$ref" : '\([^:]*\):')
|
|
local=$(expr "$ref" : '[^:]*:\(.*\)')
|
|
case "$remote" in
|
|
'') remote=HEAD ;;
|
|
refs/heads/* | refs/tags/*) ;;
|
|
heads/* | tags/* ) remote="refs/$remote" ;;
|
|
*) remote="refs/heads/$remote" ;;
|
|
esac
|
|
case "$local" in
|
|
'') local= ;;
|
|
refs/heads/* | refs/tags/*) ;;
|
|
heads/* | tags/* ) local="refs/$local" ;;
|
|
*) local="refs/heads/$local" ;;
|
|
esac
|
|
echo "${force}${remote}:${local}"
|
|
done
|
|
}
|
|
|
|
# Returns list of src: (no store), or src:dst (store)
|
|
get_remote_default_refs_for_fetch () {
|
|
data_source=$(get_data_source "$1")
|
|
case "$data_source" in
|
|
'' | branches-partial)
|
|
echo "HEAD:" ;;
|
|
branches)
|
|
remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
|
|
case "$remote_branch" in '') remote_branch=master ;; esac
|
|
echo "refs/heads/${remote_branch}:refs/heads/$1"
|
|
;;
|
|
remotes)
|
|
canon_refs_list_for_fetch $(sed -ne '/^Pull: */{
|
|
s///p
|
|
}' "$GIT_DIR/remotes/$1")
|
|
;;
|
|
*)
|
|
die "internal error: get-remote-default-ref-for-push $1" ;;
|
|
esac
|
|
}
|
|
|
|
get_remote_refs_for_push () {
|
|
case "$#" in
|
|
0) die "internal error: get-remote-refs-for-push." ;;
|
|
1) get_remote_default_refs_for_push "$@" ;;
|
|
*) shift; echo "$@" ;;
|
|
esac
|
|
}
|
|
|
|
get_remote_refs_for_fetch () {
|
|
case "$#" in
|
|
0)
|
|
die "internal error: get-remote-refs-for-fetch." ;;
|
|
1)
|
|
get_remote_default_refs_for_fetch "$@" ;;
|
|
*)
|
|
shift
|
|
tag_just_seen=
|
|
for ref
|
|
do
|
|
if test "$tag_just_seen"
|
|
then
|
|
echo "refs/tags/${ref}:refs/tags/${ref}"
|
|
tag_just_seen=
|
|
continue
|
|
else
|
|
case "$ref" in
|
|
tag)
|
|
tag_just_seen=yes
|
|
continue
|
|
;;
|
|
esac
|
|
fi
|
|
canon_refs_list_for_fetch "$ref"
|
|
done
|
|
;;
|
|
esac
|
|
}
|
|
|
|
resolve_alternates () {
|
|
# original URL (xxx.git)
|
|
top_=`expr "$1" : '\([^:]*:/*[^/]*\)/'`
|
|
while read path
|
|
do
|
|
case "$path" in
|
|
\#* | '')
|
|
continue ;;
|
|
/*)
|
|
echo "$top_$path/" ;;
|
|
../*)
|
|
# relative -- ugly but seems to work.
|
|
echo "$1/objects/$path/" ;;
|
|
*)
|
|
# exit code may not be caught by the reader.
|
|
echo "bad alternate: $path"
|
|
exit 1 ;;
|
|
esac
|
|
done
|
|
}
|