99unset CDPATH
1010
1111usage () {
12- echo >&2 " Usage: $0 [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
12+ echo >&2 " Usage: $0 [--reference <reference-repo>] [-- bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
1313 exit 1
1414}
1515
@@ -40,22 +40,72 @@ Perhaps git-update-server-info needs to be run there?"
4040 do
4141 name=` expr " $refname " : ' refs/\(.*\)' ` &&
4242 case " $name " in
43- * ^* ) ;;
44- * )
45- git-http-fetch -v -a -w " $name " " $name " " $1 /" || exit 1
43+ * ^* ) continue ;;
4644 esac
45+ if test -n " $use_separate_remote " &&
46+ branch_name=` expr " $name " : ' heads/\(.*\)' `
47+ then
48+ tname=" remotes/$branch_name "
49+ else
50+ tname=$name
51+ fi
52+ git-http-fetch -v -a -w " $tname " " $name " " $1 /" || exit 1
4753 done < " $clone_tmp /refs"
4854 rm -fr " $clone_tmp "
55+ http_fetch " $1 /HEAD" " $GIT_DIR /REMOTE_HEAD"
56+ }
57+
58+ # Read git-fetch-pack -k output and store the remote branches.
59+ copy_refs='
60+ use File::Path qw(mkpath);
61+ use File::Basename qw(dirname);
62+ my $git_dir = $ARGV[0];
63+ my $use_separate_remote = $ARGV[1];
64+
65+ my $branch_top = ($use_separate_remote ? "remotes" : "heads");
66+ my $tag_top = "tags";
67+
68+ sub store {
69+ my ($sha1, $name, $top) = @_;
70+ $name = "$git_dir/refs/$top/$name";
71+ mkpath(dirname($name));
72+ open O, ">", "$name";
73+ print O "$sha1\n";
74+ close O;
4975}
5076
77+ open FH, "<", "$git_dir/CLONE_HEAD";
78+ while (<FH>) {
79+ my ($sha1, $name) = /^([0-9a-f]{40})\s(.*)$/;
80+ next if ($name =~ /\^\173/);
81+ if ($name eq "HEAD") {
82+ open O, ">", "$git_dir/REMOTE_HEAD";
83+ print O "$sha1\n";
84+ close O;
85+ next;
86+ }
87+ if ($name =~ s/^refs\/heads\///) {
88+ store($sha1, $name, $branch_top);
89+ next;
90+ }
91+ if ($name =~ s/^refs\/tags\///) {
92+ store($sha1, $name, $tag_top);
93+ next;
94+ }
95+ }
96+ close FH;
97+ '
98+
5199quiet=
52100use_local=no
53101local_shared=no
54102no_checkout=
55103upload_pack=
56104bare=
57- origin=origin
105+ reference=
106+ origin=
58107origin_override=
108+ use_separate_remote=
59109while
60110 case " $# ,$1 " in
61111 0,* ) break ;;
@@ -68,7 +118,14 @@ while
68118 * ,-s|* ,--s|* ,--sh|* ,--sha|* ,--shar|* ,--share|* ,--shared)
69119 local_shared=yes; use_local=yes ;;
70120 * ,-q|* ,--quiet) quiet=-q ;;
121+ * ,--use-separate-remote)
122+ use_separate_remote=t ;;
71123 1,-o) usage;;
124+ 1,--reference) usage ;;
125+ * ,--reference)
126+ shift ; reference=" $1 " ;;
127+ * ,--reference=* )
128+ reference=` expr " $1 " : ' --reference=\(.*\)' ` ;;
72129 * ,-o)
73130 git-check-ref-format " $2 " || {
74131 echo >&2 " '$2 ' is not suitable for a branch name"
@@ -100,9 +157,24 @@ then
100157 echo >&2 ' --bare and -o $origin options are incompatible.'
101158 exit 1
102159 fi
160+ if test t = " $use_separate_remote "
161+ then
162+ echo >&2 ' --bare and --use-separate-remote options are incompatible.'
163+ exit 1
164+ fi
103165 no_checkout=yes
104166fi
105167
168+ if test -z " $origin_override$origin "
169+ then
170+ if test -n " $use_separate_remote "
171+ then
172+ origin=remotes/master
173+ else
174+ origin=heads/origin
175+ fi
176+ fi
177+
106178# Turn the source into an absolute path if
107179# it is local
108180repo=" $1 "
@@ -130,6 +202,28 @@ yes)
130202 GIT_DIR=" $D /.git" ;;
131203esac
132204
205+ if test -n " $reference "
206+ then
207+ if test -d " $reference "
208+ then
209+ if test -d " $reference /.git/objects"
210+ then
211+ reference=" $reference /.git"
212+ fi
213+ reference=$( cd " $reference " && pwd)
214+ echo " $reference /objects" > " $GIT_DIR /objects/info/alternates"
215+ (cd " $reference " && tar cf - refs) |
216+ (cd " $GIT_DIR /refs" &&
217+ mkdir reference-tmp &&
218+ cd reference-tmp &&
219+ tar xf -)
220+ else
221+ echo >&2 " $reference : not a local directory." && usage
222+ fi
223+ fi
224+
225+ rm -f " $GIT_DIR /CLONE_HEAD"
226+
133227# We do local magic only when the user tells us to.
134228case " $local ,$use_local " in
135229yes,yes)
@@ -165,24 +259,14 @@ yes,yes)
165259 } > " $GIT_DIR /objects/info/alternates"
166260 ;;
167261 esac
168-
169- # Make a duplicate of refs and HEAD pointer
170- HEAD=
171- if test -f " $repo /HEAD"
172- then
173- HEAD=HEAD
174- fi
175- (cd " $repo " && tar cf - refs $HEAD ) |
176- (cd " $GIT_DIR " && tar xf -) || exit 1
262+ git-ls-remote " $repo " > " $GIT_DIR /CLONE_HEAD"
177263 ;;
178264* )
179265 case " $repo " in
180266 rsync://* )
181267 rsync $quiet -av --ignore-existing \
182- --exclude info " $repo /objects/" " $GIT_DIR /objects/" &&
183- rsync $quiet -av --ignore-existing \
184- --exclude info " $repo /refs/" " $GIT_DIR /refs/" || exit
185-
268+ --exclude info " $repo /objects/" " $GIT_DIR /objects/" ||
269+ exit
186270 # Look at objects/info/alternates for rsync -- http will
187271 # support it natively and git native ones will do it on the
188272 # remote end. Not having that file is not a crime.
@@ -205,6 +289,7 @@ yes,yes)
205289 done
206290 rm -f " $GIT_DIR /TMP_ALT"
207291 fi
292+ git-ls-remote " $repo " > " $GIT_DIR /CLONE_HEAD"
208293 ;;
209294 http://* )
210295 if test -z " @@NO_CURL@@"
@@ -217,37 +302,71 @@ yes,yes)
217302 ;;
218303 * )
219304 cd " $D " && case " $upload_pack " in
220- ' ' ) git-clone -pack $quiet " $repo " ;;
221- * ) git-clone -pack $quiet " $upload_pack " " $repo " ;;
222- esac || {
223- echo >&2 " clone -pack from '$repo ' failed."
305+ ' ' ) git-fetch -pack --all -k $quiet " $repo " ;;
306+ * ) git-fetch -pack --all -k $quiet " $upload_pack " " $repo " ;;
307+ esac > " $GIT_DIR /CLONE_HEAD " || {
308+ echo >&2 " fetch -pack from '$repo ' failed."
224309 exit 1
225310 }
226311 ;;
227312 esac
228313 ;;
229314esac
315+ test -d " $GIT_DIR /refs/reference-tmp" && rm -fr " $GIT_DIR /refs/reference-tmp"
316+
317+ if test -f " $GIT_DIR /CLONE_HEAD"
318+ then
319+ # Figure out where the remote HEAD points at.
320+ perl -e " $copy_refs " " $GIT_DIR " " $use_separate_remote "
321+ fi
230322
231323cd " $D " || exit
232324
233- if test -f " $GIT_DIR /HEAD " && test -z " $bare "
325+ if test -z " $bare " && test -f " $GIT_DIR /REMOTE_HEAD "
234326then
235- head_points_at=` git-symbolic-ref HEAD`
327+ head_sha1=` cat " $GIT_DIR /REMOTE_HEAD" `
328+ # Figure out which remote branch HEAD points at.
329+ case " $use_separate_remote " in
330+ ' ' ) remote_top=refs/heads ;;
331+ * ) remote_top=refs/remotes ;;
332+ esac
333+ head_points_at=$(
334+ (
335+ echo " master"
336+ cd " $GIT_DIR /$remote_top " &&
337+ find . -type f -print | sed -e ' s/^\.\///'
338+ ) | (
339+ done=f
340+ while read name
341+ do
342+ test t = $done && continue
343+ branch_tip=` cat " $GIT_DIR /$remote_top /$name " `
344+ if test " $head_sha1 " = " $branch_tip "
345+ then
346+ echo " $name "
347+ done=t
348+ fi
349+ done
350+ )
351+ )
236352 case " $head_points_at " in
237- refs/heads/* )
238- head_points_at=` expr " $head_points_at " : ' refs/heads/\(.*\)' `
353+ ?* )
239354 mkdir -p " $GIT_DIR /remotes" &&
240355 echo > " $GIT_DIR /remotes/origin" \
241356 " URL: $repo
242- Pull: $head_points_at :$origin " &&
243- git-update-ref " refs/heads/$origin " $( git-rev-parse HEAD) &&
244- (cd " $GIT_DIR " && find " refs/heads" -type f -print) |
357+ Pull: refs/heads/$head_points_at :refs/$origin " &&
358+ case " $use_separate_remote " in
359+ t) git-update-ref HEAD " $head_sha1 " ;;
360+ * ) git-update-ref " refs/$origin " $( git-rev-parse HEAD)
361+ esac &&
362+ (cd " $GIT_DIR " && find " $remote_top " -type f -print) |
245363 while read ref
246364 do
247- head=` expr " $ref " : ' refs/heads/\(.*\)' ` &&
248- test " $head_points_at " = " $head " ||
365+ head=` expr " $ref " : ' refs/\(.*\)' ` &&
366+ name=` expr " $ref " : ' refs/[^\/]*/\(.*\)' ` &&
367+ test " $head_points_at " = " $name " ||
249368 test " $origin " = " $head " ||
250- echo " Pull: ${head } :${head } "
369+ echo " Pull: refs/heads/ ${name } :$remote_top / ${name }"
251370 done >> " $GIT_DIR /remotes/origin"
252371 esac
253372
@@ -256,6 +375,7 @@ Pull: $head_points_at:$origin" &&
256375 git-read-tree -m -u -v HEAD HEAD
257376 esac
258377fi
378+ rm -f " $GIT_DIR /CLONE_HEAD" " $GIT_DIR /REMOTE_HEAD"
259379
260380trap - exit
261381
0 commit comments