]> asedeno.scripts.mit.edu Git - git.git/blob - git-clone.sh
clone: correctly report http_fetch errors
[git.git] / git-clone.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2005, Linus Torvalds
4 # Copyright (c) 2005, Junio C Hamano
5 #
6 # Clone a repository into a different directory that does not yet exist.
7
8 # See git-sh-setup why.
9 unset CDPATH
10
11 die() {
12         echo >&2 "$@"
13         exit 1
14 }
15
16 usage() {
17         die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] <repo> [<dir>]"
18 }
19
20 get_repo_base() {
21         (
22                 cd "`/bin/pwd`" &&
23                 cd "$1" || cd "$1.git" &&
24                 {
25                         cd .git
26                         pwd
27                 }
28         ) 2>/dev/null
29 }
30
31 if [ -n "$GIT_SSL_NO_VERIFY" -o \
32         "`git config --bool http.sslVerify`" = false ]; then
33     curl_extra_args="-k"
34 fi
35
36 http_fetch () {
37         # $1 = Remote, $2 = Local
38         curl -nsfL $curl_extra_args "$1" >"$2"
39         curl_exit_status=$?
40         case $curl_exit_status in
41         126|127) exit ;;
42         *)       return $curl_exit_status ;;
43         esac
44 }
45
46 clone_dumb_http () {
47         # $1 - remote, $2 - local
48         cd "$2" &&
49         clone_tmp="$GIT_DIR/clone-tmp" &&
50         mkdir -p "$clone_tmp" || exit 1
51         if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
52                 "`git config --bool http.noEPSV`" = true ]; then
53                 curl_extra_args="${curl_extra_args} --disable-epsv"
54         fi
55         http_fetch "$1/info/refs" "$clone_tmp/refs" ||
56                 die "Cannot get remote repository information.
57 Perhaps git-update-server-info needs to be run there?"
58         test "z$quiet" = z && v=-v || v=
59         while read sha1 refname
60         do
61                 name=`expr "z$refname" : 'zrefs/\(.*\)'` &&
62                 case "$name" in
63                 *^*)    continue;;
64                 esac
65                 case "$bare,$name" in
66                 yes,* | ,heads/* | ,tags/*) ;;
67                 *)      continue ;;
68                 esac
69                 if test -n "$use_separate_remote" &&
70                    branch_name=`expr "z$name" : 'zheads/\(.*\)'`
71                 then
72                         tname="remotes/$origin/$branch_name"
73                 else
74                         tname=$name
75                 fi
76                 git-http-fetch $v -a -w "$tname" "$sha1" "$1" || exit 1
77         done <"$clone_tmp/refs"
78         rm -fr "$clone_tmp"
79         http_fetch "$1/HEAD" "$GIT_DIR/REMOTE_HEAD" ||
80         rm -f "$GIT_DIR/REMOTE_HEAD"
81         if test -f "$GIT_DIR/REMOTE_HEAD"; then
82                 head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
83                 case "$head_sha1" in
84                 'ref: refs/'*)
85                         ;;
86                 *)
87                         git-http-fetch $v -a "$head_sha1" "$1" ||
88                         rm -f "$GIT_DIR/REMOTE_HEAD"
89                         ;;
90                 esac
91         fi
92 }
93
94 quiet=
95 local=no
96 use_local_hardlink=yes
97 local_shared=no
98 unset template
99 no_checkout=
100 upload_pack=
101 bare=
102 reference=
103 origin=
104 origin_override=
105 use_separate_remote=t
106 depth=
107 no_progress=
108 local_explicitly_asked_for=
109 test -t 1 || no_progress=--no-progress
110 while
111         case "$#,$1" in
112         0,*) break ;;
113         *,-n|*,--no|*,--no-|*,--no-c|*,--no-ch|*,--no-che|*,--no-chec|\
114         *,--no-check|*,--no-checko|*,--no-checkou|*,--no-checkout)
115           no_checkout=yes ;;
116         *,--na|*,--nak|*,--nake|*,--naked|\
117         *,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;;
118         *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local)
119           local_explicitly_asked_for=yes
120           use_local_hardlink=yes ;;
121         *,--no-h|*,--no-ha|*,--no-har|*,--no-hard|*,--no-hardl|\
122         *,--no-hardli|*,--no-hardlin|*,--no-hardlink|*,--no-hardlinks)
123           use_local_hardlink=no ;;
124         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
125           local_shared=yes; ;;
126         1,--template) usage ;;
127         *,--template)
128                 shift; template="--template=$1" ;;
129         *,--template=*)
130           template="$1" ;;
131         *,-q|*,--quiet) quiet=-q ;;
132         *,--use-separate-remote) ;;
133         *,--no-separate-remote)
134                 die "clones are always made with separate-remote layout" ;;
135         1,--reference) usage ;;
136         *,--reference)
137                 shift; reference="$1" ;;
138         *,--reference=*)
139                 reference=`expr "z$1" : 'z--reference=\(.*\)'` ;;
140         *,-o|*,--or|*,--ori|*,--orig|*,--origi|*,--origin)
141                 case "$2" in
142                 '')
143                     usage ;;
144                 */*)
145                     die "'$2' is not suitable for an origin name"
146                 esac
147                 git check-ref-format "heads/$2" ||
148                     die "'$2' is not suitable for a branch name"
149                 test -z "$origin_override" ||
150                     die "Do not give more than one --origin options."
151                 origin_override=yes
152                 origin="$2"; shift
153                 ;;
154         1,-u|1,--upload-pack) usage ;;
155         *,-u|*,--upload-pack)
156                 shift
157                 upload_pack="--upload-pack=$1" ;;
158         *,--upload-pack=*)
159                 upload_pack=--upload-pack=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
160         1,--depth) usage;;
161         *,--depth)
162                 shift
163                 depth="--depth=$1";;
164         *,-*) usage ;;
165         *) break ;;
166         esac
167 do
168         shift
169 done
170
171 repo="$1"
172 test -n "$repo" ||
173     die 'you must specify a repository to clone.'
174
175 # --bare implies --no-checkout and --no-separate-remote
176 if test yes = "$bare"
177 then
178         if test yes = "$origin_override"
179         then
180                 die '--bare and --origin $origin options are incompatible.'
181         fi
182         no_checkout=yes
183         use_separate_remote=
184 fi
185
186 if test -z "$origin"
187 then
188         origin=origin
189 fi
190
191 # Turn the source into an absolute path if
192 # it is local
193 if base=$(get_repo_base "$repo"); then
194         repo="$base"
195         local=yes
196 fi
197
198 dir="$2"
199 # Try using "humanish" part of source repo if user didn't specify one
200 [ -z "$dir" ] && dir=$(echo "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
201 [ -e "$dir" ] && die "destination directory '$dir' already exists."
202 [ yes = "$bare" ] && unset GIT_WORK_TREE
203 [ -n "$GIT_WORK_TREE" ] && [ -e "$GIT_WORK_TREE" ] &&
204 die "working tree '$GIT_WORK_TREE' already exists."
205 D=
206 W=
207 cleanup() {
208         err=$?
209         test -z "$D" && rm -rf "$dir"
210         test -z "$W" && test -n "$GIT_WORK_TREE" && rm -rf "$GIT_WORK_TREE"
211         cd ..
212         test -n "$D" && rm -rf "$D"
213         test -n "$W" && rm -rf "$W"
214         exit $err
215 }
216 trap cleanup 0
217 mkdir -p "$dir" && D=$(cd "$dir" && pwd) || usage
218 test -n "$GIT_WORK_TREE" && mkdir -p "$GIT_WORK_TREE" &&
219 W=$(cd "$GIT_WORK_TREE" && pwd) && export GIT_WORK_TREE="$W"
220 if test yes = "$bare" || test -n "$GIT_WORK_TREE"; then
221         GIT_DIR="$D"
222 else
223         GIT_DIR="$D/.git"
224 fi &&
225 export GIT_DIR &&
226 GIT_CONFIG="$GIT_DIR/config" git-init $quiet ${template+"$template"} || usage
227
228 if test -n "$bare"
229 then
230         GIT_CONFIG="$GIT_DIR/config" git config core.bare true
231 fi
232
233 if test -n "$reference"
234 then
235         ref_git=
236         if test -d "$reference"
237         then
238                 if test -d "$reference/.git/objects"
239                 then
240                         ref_git="$reference/.git"
241                 elif test -d "$reference/objects"
242                 then
243                         ref_git="$reference"
244                 fi
245         fi
246         if test -n "$ref_git"
247         then
248                 ref_git=$(cd "$ref_git" && pwd)
249                 echo "$ref_git/objects" >"$GIT_DIR/objects/info/alternates"
250                 (
251                         GIT_DIR="$ref_git" git for-each-ref \
252                                 --format='%(objectname) %(*objectname)'
253                 ) |
254                 while read a b
255                 do
256                         test -z "$a" ||
257                         git update-ref "refs/reference-tmp/$a" "$a"
258                         test -z "$b" ||
259                         git update-ref "refs/reference-tmp/$b" "$b"
260                 done
261         else
262                 die "reference repository '$reference' is not a local directory."
263         fi
264 fi
265
266 rm -f "$GIT_DIR/CLONE_HEAD"
267
268 # We do local magic only when the user tells us to.
269 case "$local" in
270 yes)
271         ( cd "$repo/objects" ) ||
272                 die "cannot chdir to local '$repo/objects'."
273
274         if test "$local_shared" = yes
275         then
276                 mkdir -p "$GIT_DIR/objects/info"
277                 echo "$repo/objects" >>"$GIT_DIR/objects/info/alternates"
278         else
279                 l= &&
280                 if test "$use_local_hardlink" = yes
281                 then
282                         # See if we can hardlink and drop "l" if not.
283                         sample_file=$(cd "$repo" && \
284                                       find objects -type f -print | sed -e 1q)
285                         # objects directory should not be empty because
286                         # we are cloning!
287                         test -f "$repo/$sample_file" || exit
288                         if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
289                         then
290                                 rm -f "$GIT_DIR/objects/sample"
291                                 l=l
292                         elif test -n "$local_explicitly_asked_for"
293                         then
294                                 echo >&2 "Warning: -l asked but cannot hardlink to $repo"
295                         fi
296                 fi &&
297                 cd "$repo" &&
298                 find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1
299         fi
300         git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
301         ;;
302 *)
303         case "$repo" in
304         rsync://*)
305                 case "$depth" in
306                 "") ;;
307                 *) die "shallow over rsync not supported" ;;
308                 esac
309                 rsync $quiet -av --ignore-existing  \
310                         --exclude info "$repo/objects/" "$GIT_DIR/objects/" ||
311                 exit
312                 # Look at objects/info/alternates for rsync -- http will
313                 # support it natively and git native ones will do it on the
314                 # remote end.  Not having that file is not a crime.
315                 rsync -q "$repo/objects/info/alternates" \
316                         "$GIT_DIR/TMP_ALT" 2>/dev/null ||
317                         rm -f "$GIT_DIR/TMP_ALT"
318                 if test -f "$GIT_DIR/TMP_ALT"
319                 then
320                     ( cd "$D" &&
321                       . git-parse-remote &&
322                       resolve_alternates "$repo" <"$GIT_DIR/TMP_ALT" ) |
323                     while read alt
324                     do
325                         case "$alt" in 'bad alternate: '*) die "$alt";; esac
326                         case "$quiet" in
327                         '')     echo >&2 "Getting alternate: $alt" ;;
328                         esac
329                         rsync $quiet -av --ignore-existing  \
330                             --exclude info "$alt" "$GIT_DIR/objects" || exit
331                     done
332                     rm -f "$GIT_DIR/TMP_ALT"
333                 fi
334                 git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
335                 ;;
336         https://*|http://*|ftp://*)
337                 case "$depth" in
338                 "") ;;
339                 *) die "shallow over http or ftp not supported" ;;
340                 esac
341                 if test -z "@@NO_CURL@@"
342                 then
343                         clone_dumb_http "$repo" "$D"
344                 else
345                         die "http transport not supported, rebuild Git with curl support"
346                 fi
347                 ;;
348         *)
349                 case "$upload_pack" in
350                 '') git-fetch-pack --all -k $quiet $depth $no_progress "$repo";;
351                 *) git-fetch-pack --all -k $quiet "$upload_pack" $depth $no_progress "$repo" ;;
352                 esac >"$GIT_DIR/CLONE_HEAD" ||
353                         die "fetch-pack from '$repo' failed."
354                 ;;
355         esac
356         ;;
357 esac
358 test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp"
359
360 if test -f "$GIT_DIR/CLONE_HEAD"
361 then
362         # Read git-fetch-pack -k output and store the remote branches.
363         if [ -n "$use_separate_remote" ]
364         then
365                 branch_top="remotes/$origin"
366         else
367                 branch_top="heads"
368         fi
369         tag_top="tags"
370         while read sha1 name
371         do
372                 case "$name" in
373                 *'^{}')
374                         continue ;;
375                 HEAD)
376                         destname="REMOTE_HEAD" ;;
377                 refs/heads/*)
378                         destname="refs/$branch_top/${name#refs/heads/}" ;;
379                 refs/tags/*)
380                         destname="refs/$tag_top/${name#refs/tags/}" ;;
381                 *)
382                         continue ;;
383                 esac
384                 git update-ref -m "clone: from $repo" "$destname" "$sha1" ""
385         done < "$GIT_DIR/CLONE_HEAD"
386 fi
387
388 if test -n "$W"; then
389         cd "$W" || exit
390 else
391         cd "$D" || exit
392 fi
393
394 if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD"
395 then
396         # a non-bare repository is always in separate-remote layout
397         remote_top="refs/remotes/$origin"
398         head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
399         case "$head_sha1" in
400         'ref: refs/'*)
401                 # Uh-oh, the remote told us (http transport done against
402                 # new style repository with a symref HEAD).
403                 # Ideally we should skip the guesswork but for now
404                 # opt for minimum change.
405                 head_sha1=`expr "z$head_sha1" : 'zref: refs/heads/\(.*\)'`
406                 head_sha1=`cat "$GIT_DIR/$remote_top/$head_sha1"`
407                 ;;
408         esac
409
410         # The name under $remote_top the remote HEAD seems to point at.
411         head_points_at=$(
412                 (
413                         test -f "$GIT_DIR/$remote_top/master" && echo "master"
414                         cd "$GIT_DIR/$remote_top" &&
415                         find . -type f -print | sed -e 's/^\.\///'
416                 ) | (
417                 done=f
418                 while read name
419                 do
420                         test t = $done && continue
421                         branch_tip=`cat "$GIT_DIR/$remote_top/$name"`
422                         if test "$head_sha1" = "$branch_tip"
423                         then
424                                 echo "$name"
425                                 done=t
426                         fi
427                 done
428                 )
429         )
430
431         # Upstream URL
432         git config remote."$origin".url "$repo" &&
433
434         # Set up the mappings to track the remote branches.
435         git config remote."$origin".fetch \
436                 "+refs/heads/*:$remote_top/*" '^$' &&
437
438         # Write out remote.$origin config, and update our "$head_points_at".
439         case "$head_points_at" in
440         ?*)
441                 # Local default branch
442                 git symbolic-ref HEAD "refs/heads/$head_points_at" &&
443
444                 # Tracking branch for the primary branch at the remote.
445                 git update-ref HEAD "$head_sha1" &&
446
447                 rm -f "refs/remotes/$origin/HEAD"
448                 git symbolic-ref "refs/remotes/$origin/HEAD" \
449                         "refs/remotes/$origin/$head_points_at" &&
450
451                 git config branch."$head_points_at".remote "$origin" &&
452                 git config branch."$head_points_at".merge "refs/heads/$head_points_at"
453                 ;;
454         '')
455                 # Source had detached HEAD pointing nowhere
456                 git update-ref --no-deref HEAD "$head_sha1" &&
457                 rm -f "refs/remotes/$origin/HEAD"
458                 ;;
459         esac
460
461         case "$no_checkout" in
462         '')
463                 test "z$quiet" = z -a "z$no_progress" = z && v=-v || v=
464                 git read-tree -m -u $v HEAD HEAD
465         esac
466 fi
467 rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD"
468
469 trap - 0