Skip to content

Commit 1656313

Browse files
author
Junio C Hamano
committed
Merge branch 'jc/clone' into next
* jc/clone: revamp git-clone.
2 parents b7986ce + dfeff66 commit 1656313

File tree

2 files changed

+166
-36
lines changed

2 files changed

+166
-36
lines changed

fetch-pack.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
static int keep_pack;
88
static int quiet;
99
static int verbose;
10+
static int fetch_all;
1011
static const char fetch_pack_usage[] =
11-
"git-fetch-pack [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...";
12+
"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...";
1213
static const char *exec = "git-upload-pack";
1314

1415
#define COMPLETE (1U << 0)
@@ -266,8 +267,9 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
266267
for (prev = NULL, current = *refs; current; current = next) {
267268
next = current->next;
268269
if ((!memcmp(current->name, "refs/", 5) &&
269-
check_ref_format(current->name + 5)) ||
270-
!path_match(current->name, nr_match, match)) {
270+
check_ref_format(current->name + 5)) ||
271+
(!fetch_all &&
272+
!path_match(current->name, nr_match, match))) {
271273
if (prev == NULL)
272274
*refs = next;
273275
else
@@ -376,7 +378,11 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
376378
goto all_done;
377379
}
378380
if (find_common(fd, sha1, ref) < 0)
379-
fprintf(stderr, "warning: no common commits\n");
381+
if (!keep_pack)
382+
/* When cloning, it is not unusual to have
383+
* no common commit.
384+
*/
385+
fprintf(stderr, "warning: no common commits\n");
380386

381387
if (keep_pack)
382388
status = receive_keep_pack(fd, "git-fetch-pack", quiet);
@@ -426,6 +432,10 @@ int main(int argc, char **argv)
426432
use_thin_pack = 1;
427433
continue;
428434
}
435+
if (!strcmp("--all", arg)) {
436+
fetch_all = 1;
437+
continue;
438+
}
429439
if (!strcmp("-v", arg)) {
430440
verbose = 1;
431441
continue;

git-clone.sh

Lines changed: 152 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
unset CDPATH
1010

1111
usage() {
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+
5199
quiet=
52100
use_local=no
53101
local_shared=no
54102
no_checkout=
55103
upload_pack=
56104
bare=
57-
origin=origin
105+
reference=
106+
origin=
58107
origin_override=
108+
use_separate_remote=
59109
while
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
104166
fi
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
108180
repo="$1"
@@ -130,6 +202,28 @@ yes)
130202
GIT_DIR="$D/.git" ;;
131203
esac
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.
134228
case "$local,$use_local" in
135229
yes,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
;;
229314
esac
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

231323
cd "$D" || exit
232324

233-
if test -f "$GIT_DIR/HEAD" && test -z "$bare"
325+
if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD"
234326
then
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
258377
fi
378+
rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD"
259379

260380
trap - exit
261381

0 commit comments

Comments
 (0)