Introduce core.sharedrepository
[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 usage() {
12         echo >&2 "Usage: $0 [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
13         exit 1
14 }
15
16 get_repo_base() {
17         (cd "$1" && (cd .git ; pwd)) 2> /dev/null
18 }
19
20 if [ -n "$GIT_SSL_NO_VERIFY" ]; then
21     curl_extra_args="-k"
22 fi
23
24 http_fetch () {
25         # $1 = Remote, $2 = Local
26         curl -nsfL $curl_extra_args "$1" >"$2"
27 }
28
29 clone_dumb_http () {
30         # $1 - remote, $2 - local
31         cd "$2" &&
32         clone_tmp='.git/clone-tmp' &&
33         mkdir -p "$clone_tmp" || exit 1
34         http_fetch "$1/info/refs" "$clone_tmp/refs" || {
35                 echo >&2 "Cannot get remote repository information.
36 Perhaps git-update-server-info needs to be run there?"
37                 exit 1;
38         }
39         while read sha1 refname
40         do
41                 name=`expr "$refname" : 'refs/\(.*\)'` &&
42                 case "$name" in
43                 *^*)    ;;
44                 *)
45                         git-http-fetch -v -a -w "$name" "$name" "$1/" || exit 1
46                 esac
47         done <"$clone_tmp/refs"
48         rm -fr "$clone_tmp"
49 }
50
51 quiet=
52 use_local=no
53 local_shared=no
54 no_checkout=
55 upload_pack=
56 origin=origin
57 while
58         case "$#,$1" in
59         0,*) break ;;
60         *,-n) no_checkout=yes ;;
61         *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;;
62         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) 
63           local_shared=yes; use_local=yes ;;
64         *,-q|*,--quiet) quiet=-q ;;
65         1,-o) usage;;
66         *,-o)
67                 git-check-ref-format "$2" || {
68                     echo >&2 "'$2' is not suitable for a branch name"
69                     exit 1
70                 }
71                 origin="$2"; shift
72                 ;;
73         1,-u|1,--upload-pack) usage ;;
74         *,-u|*,--upload-pack)
75                 shift
76                 upload_pack="--exec=$1" ;;
77         *,-*) usage ;;
78         *) break ;;
79         esac
80 do
81         shift
82 done
83
84 # Turn the source into an absolute path if
85 # it is local
86 repo="$1"
87 local=no
88 if base=$(get_repo_base "$repo"); then
89         repo="$base"
90         local=yes
91 fi
92
93 dir="$2"
94 # Try using "humanish" part of source repo if user didn't specify one
95 [ -z "$dir" ] && dir=$(echo "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*/||g')
96 [ -e "$dir" ] && echo "$dir already exists." && usage
97 mkdir -p "$dir" &&
98 D=$(
99         (cd "$dir" && git-init-db && pwd)
100 ) &&
101 test -d "$D" || usage
102
103 # We do local magic only when the user tells us to.
104 case "$local,$use_local" in
105 yes,yes)
106         ( cd "$repo/objects" ) || {
107                 echo >&2 "-l flag seen but $repo is not local."
108                 exit 1
109         }
110
111         case "$local_shared" in
112         no)
113             # See if we can hardlink and drop "l" if not.
114             sample_file=$(cd "$repo" && \
115                           find objects -type f -print | sed -e 1q)
116
117             # objects directory should not be empty since we are cloning!
118             test -f "$repo/$sample_file" || exit
119
120             l=
121             if ln "$repo/$sample_file" "$D/.git/objects/sample" 2>/dev/null
122             then
123                     l=l
124             fi &&
125             rm -f "$D/.git/objects/sample" &&
126             cd "$repo" &&
127             find objects -depth -print | cpio -puamd$l "$D/.git/" || exit 1
128             ;;
129         yes)
130             mkdir -p "$D/.git/objects/info"
131             {
132                 test -f "$repo/objects/info/alternates" &&
133                 cat "$repo/objects/info/alternates";
134                 echo "$repo/objects"
135             } >"$D/.git/objects/info/alternates"
136             ;;
137         esac
138
139         # Make a duplicate of refs and HEAD pointer
140         HEAD=
141         if test -f "$repo/HEAD"
142         then
143                 HEAD=HEAD
144         fi
145         (cd "$repo" && tar cf - refs $HEAD) |
146         (cd "$D/.git" && tar xf -) || exit 1
147         ;;
148 *)
149         case "$repo" in
150         rsync://*)
151                 rsync $quiet -av --ignore-existing  \
152                         --exclude info "$repo/objects/" "$D/.git/objects/" &&
153                 rsync $quiet -av --ignore-existing  \
154                         --exclude info "$repo/refs/" "$D/.git/refs/" || exit
155
156                 # Look at objects/info/alternates for rsync -- http will
157                 # support it natively and git native ones will do it on the
158                 # remote end.  Not having that file is not a crime.
159                 rsync -q "$repo/objects/info/alternates" \
160                         "$D/.git/TMP_ALT" 2>/dev/null ||
161                         rm -f "$D/.git/TMP_ALT"
162                 if test -f "$D/.git/TMP_ALT"
163                 then
164                     ( cd "$D" &&
165                       . git-parse-remote &&
166                       resolve_alternates "$repo" <"./.git/TMP_ALT" ) |
167                     while read alt
168                     do
169                         case "$alt" in 'bad alternate: '*) die "$alt";; esac
170                         case "$quiet" in
171                         '')     echo >&2 "Getting alternate: $alt" ;;
172                         esac
173                         rsync $quiet -av --ignore-existing  \
174                             --exclude info "$alt" "$D/.git/objects" || exit
175                     done
176                     rm -f "$D/.git/TMP_ALT"
177                 fi
178                 ;;
179         http://*)
180                 clone_dumb_http "$repo" "$D"
181                 ;;
182         *)
183                 cd "$D" && case "$upload_pack" in
184                 '') git-clone-pack $quiet "$repo" ;;
185                 *) git-clone-pack $quiet "$upload_pack" "$repo" ;;
186                 esac || {
187                         echo >&2 "clone-pack from '$repo' failed."
188                         exit 1
189                 }
190                 ;;
191         esac
192         ;;
193 esac
194
195 cd "$D" || exit
196
197 if test -f ".git/HEAD"
198 then
199         head_points_at=`git-symbolic-ref HEAD`
200         case "$head_points_at" in
201         refs/heads/*)
202                 head_points_at=`expr "$head_points_at" : 'refs/heads/\(.*\)'`
203                 mkdir -p .git/remotes &&
204                 echo >.git/remotes/origin \
205                 "URL: $repo
206 Pull: $head_points_at:$origin" &&
207                 git-update-ref "refs/heads/$origin" $(git-rev-parse HEAD) &&
208                 find .git/refs/heads -type f -print |
209                 while read ref
210                 do
211                         head=`expr "$ref" : '.git/refs/heads/\(.*\)'` &&
212                         test "$head_points_at" = "$head" ||
213                         test "$origin" = "$head" ||
214                         echo "Pull: ${head}:${head}"
215                 done >>.git/remotes/origin
216         esac
217
218         case "$no_checkout" in
219         '')
220                 git checkout
221         esac
222 fi