You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
4.3 KiB
203 lines
4.3 KiB
#!/bin/sh |
|
# |
|
. git-sh-setup-script || die "Not a git archive" |
|
. git-parse-remote-script |
|
_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= |
|
while case "$#" in 0) break ;; esac |
|
do |
|
case "$1" in |
|
-a|--a|--ap|--app|--appe|--appen|--append) |
|
append=t |
|
shift |
|
;; |
|
-f|--f|--fo|--for|--forc|--force) |
|
force=t |
|
shift |
|
;; |
|
*) |
|
break |
|
;; |
|
esac |
|
done |
|
|
|
case "$#" in |
|
0) |
|
test -f "$GIT_DIR/branches/origin" || |
|
test -f "$GIT_DIR/remotes/origin" || |
|
die "Where do you want to fetch from?" |
|
set origin ;; |
|
esac |
|
|
|
remote_nick="$1" |
|
remote=$(get_remote_url "$@") |
|
refs= |
|
rref= |
|
rsync_slurped_objects= |
|
|
|
if test "" = "$append" |
|
then |
|
: >$GIT_DIR/FETCH_HEAD |
|
fi |
|
|
|
append_fetch_head () { |
|
head_="$1" |
|
remote_="$2" |
|
remote_name_="$3" |
|
remote_nick_="$4" |
|
local_name_="$5" |
|
|
|
# 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 |
|
headc_=$(git-rev-parse --verify "$head_^0") || exit |
|
note_="$headc_ $remote_name_ from $remote_nick_" |
|
echo "$note_" >>$GIT_DIR/FETCH_HEAD |
|
echo >&2 "* committish: $note_" |
|
else |
|
echo >&2 "* non-commit: $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_" |
|
fi |
|
} |
|
|
|
fast_forward_local () { |
|
case "$1" in |
|
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 $4" |
|
echo >&2 " from $3." |
|
else |
|
echo >&2 "* $1: storing $4" |
|
echo >&2 " from $3." |
|
fi |
|
echo "$2" >"$GIT_DIR/$1" ;; |
|
|
|
refs/heads/*) |
|
# NEEDSWORK: use the same cmpxchg protocol here. |
|
echo "$2" >"$GIT_DIR/$1.lock" |
|
if test -f "$GIT_DIR/$1" |
|
then |
|
local=$(git-rev-parse --verify "$1^0") && |
|
mb=$(git-merge-base "$local" "$2") && |
|
case "$2,$mb" in |
|
$local,*) |
|
echo >&2 "* $1: same as $4" |
|
echo >&2 " from $3" |
|
;; |
|
*,$local) |
|
echo >&2 "* $1: fast forward to $4" |
|
echo >&2 " from $3" |
|
;; |
|
*) |
|
false |
|
;; |
|
esac || { |
|
echo >&2 "* $1: does not fast forward to $4" |
|
case "$force,$single_force" in |
|
t,* | *,t) |
|
echo >&2 " from $3; forcing update." |
|
;; |
|
*) |
|
mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1.remote" |
|
echo >&2 " from $3; leaving it in '$1.remote'" |
|
;; |
|
esac |
|
} |
|
else |
|
echo >&2 "* $1: storing $4" |
|
echo >&2 " from $3." |
|
fi |
|
test -f "$GIT_DIR/$1.lock" && |
|
mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1" |
|
;; |
|
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" : '[^:]*:\(.*\)') |
|
|
|
rref="$rref $remote_name" |
|
|
|
# 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 |
|
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 |
|
git-http-pull -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) |
|
rm -f "$TMP_HEAD" |
|
test "$rsync_slurped_objects" || { |
|
rsync -avz --ignore-existing "$remote/objects/" \ |
|
"$GIT_OBJECT_DIRECTORY/" || exit |
|
rsync_slurped_objects=t |
|
} |
|
;; |
|
*) |
|
# We will do git native transport with just one call later. |
|
continue ;; |
|
esac |
|
|
|
append_fetch_head "$head" "$remote" "$remote_name" "$remote_nick" "$local_name" |
|
|
|
done |
|
|
|
case "$remote" in |
|
http://* | https://* | rsync://* ) |
|
;; # we are already done. |
|
*) |
|
git-fetch-pack "$remote" $rref | |
|
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 ;; |
|
esac |
|
done |
|
|
|
local_name=$(expr "$found" : '[^:]*:\(.*\)') |
|
append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name" |
|
done |
|
;; |
|
esac
|
|
|