[PATCH] Multi-head fetch.
[git.git] / git-fetch-script
1 #!/bin/sh
2 #
3 . git-sh-setup-script || die "Not a git archive"
4 . git-parse-remote-script
5 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
6 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
7
8 append=
9 case "$#" in
10 0)
11         die "Where do you want to fetch from?" ;;
12 *)
13         case "$1" in
14         -a|--a|--ap|--app|--appe|--appen|--append)
15                 append=t
16                 shift ;;
17         esac
18 esac
19 remote_nick="$1"
20 remote=$(get_remote_url "$@")
21 refs=
22 rref=
23 rsync_slurped_objects=
24
25 if test "" = "$append"
26 then
27         : >$GIT_DIR/FETCH_HEAD
28 fi
29
30 append_fetch_head () {
31     head_="$1"
32     remote_="$2"
33     remote_name_="$3"
34     remote_nick_="$4"
35     local_name_="$5"
36
37     # 2.6.11-tree tag would not be happy to be fed to resolve.
38     if git-cat-file commit "$head_" >/dev/null 2>&1
39     then
40         head_=$(git-rev-parse --verify "$head_^0") || exit
41         note_="$head_   $remote_name_ from $remote_nick_"
42         echo "$note_" >>$GIT_DIR/FETCH_HEAD
43         echo >&2 "* committish: $note_"
44     else
45         echo >&2 "* non-commit: $note_"
46     fi
47     if test "$local_name_" != ""
48     then
49         # We are storing the head locally.  Make sure that it is
50         # a fast forward (aka "reverse push").
51         fast_forward_local "$local_name_" "$head_" "$remote_" "$remote_name_"
52     fi
53 }
54
55 fast_forward_local () {
56     case "$1" in
57     refs/tags/*)
58         # Tags need not be pointing at commits so there
59         # is no way to guarantee "fast-forward" anyway.
60         echo "$2" >"$GIT_DIR/$1" ;;
61     refs/heads/*)
62         # NEEDSWORK: use the same cmpxchg protocol here.
63         echo "$2" >"$GIT_DIR/$1.lock"
64         if test -f "$GIT_DIR/$1"
65         then
66             local=$(git-rev-parse --verify "$1^0") &&
67             mb=$(git-merge-base "$local" "$2") &&
68             case "$2,$mb" in
69             $local,*)
70                 echo >&2 "* $1: same as $4"
71                 echo >&2 "  from $3"
72                 ;;
73             *,$local)
74                 echo >&2 "* $1: fast forward to $4"
75                 echo >&2 "  from $3"
76                 ;;
77             *)
78                 false
79                 ;;
80             esac || {
81                 mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1.remote"
82                 echo >&2 "* $1: does not fast forward to $4"
83                 echo >&2 "  from $3; leaving it in '$1.remote'"
84             }
85         else
86                 echo >&2 "* $1: storing $4"
87                 echo >&2 "  from $3."
88         fi
89         test -f "$GIT_DIR/$1.lock" &&
90             mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1"
91         ;;
92     esac
93 }
94
95 for ref in $(get_remote_refs_for_fetch "$@")
96 do
97     refs="$refs $ref"
98
99     # These are relative path from $GIT_DIR, typically starting at refs/
100     # but may be HEAD
101     remote_name=$(expr "$ref" : '\([^:]*\):')
102     local_name=$(expr "$ref" : '[^:]*:\(.*\)')
103
104     rref="$rref $remote_name"
105
106     # There are transports that can fetch only one head at a time...
107     case "$remote" in
108     http://* | https://*)
109         if [ -n "$GIT_SSL_NO_VERIFY" ]; then
110             curl_extra_args="-k"
111         fi
112         head=$(curl -nsf $curl_extra_args "$remote/$remote_name") &&
113         expr "$head" : "$_x40\$" >/dev/null ||
114             die "Failed to fetch $remote_name from $remote"
115         echo Fetching "$remote_name from $remote" using http
116         git-http-pull -v -a "$head" "$remote/" || exit
117         ;;
118     rsync://*)
119         TMP_HEAD="$GIT_DIR/TMP_HEAD"
120         rsync -L "$remote/$remote_name" "$TMP_HEAD" || exit 1
121         head=$(git-rev-parse TMP_HEAD)
122         rm -f "$TMP_HEAD"
123         test "$rsync_slurped_objects" || {
124             rsync -avz --ignore-existing "$remote/objects/" \
125                 "$GIT_OBJECT_DIRECTORY/" || exit
126             rsync_slurped_objects=t
127         }
128         ;;
129     *)
130         # We will do git native transport with just one call later.
131         continue ;;
132     esac
133
134     append_fetch_head "$head" "$remote" "$remote_name" "$remote_nick" "$local_name"
135
136 done
137
138 case "$remote" in
139 http://* | https://* | rsync://* )
140     ;; # we are already done.
141 *)
142     git-fetch-pack "$remote" $rref |
143     while read sha1 remote_name
144     do
145         found=
146         for ref in $refs
147         do
148             case "$ref" in
149             $remote_name:*)
150                 found="$ref"
151                 break ;;
152             esac
153         done
154
155         local_name=$(expr "$found" : '[^:]*:\(.*\)')
156         append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name"
157     done
158     ;;
159 esac