make 'git clone' ask the remote only for objects it cares about
Current behavior of 'git clone' when not using --mirror is to fetch everything from the peer, and then filter out unwanted refs just before writing them out to the cloned repository. This may become highly inefficient if the peer has an unusual ref namespace, or if it simply has "remotes" refs of its own, and those locally unwanted refs are connecting to a large set of objects which becomes unreferenced as soon as they are fetched. Let's filter out those unwanted refs from the peer _before_ asking it what refs we want to fetch instead, which is the most logical thing to do anyway. Signed-off-by: Nicolas Pitre <nico@fluxnic.net> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Nicolas Pitre committed
Sep 25, 2009 at 23:54 UTC
5bdc32d3e50d8335c65e136e6b5234c5dd92a7a9
1 file changed
+17
-10
builtin-clone.c
+17
-10
@@ -329,24 +329,28 @@ static void remove_junk_on_signal(int signo)
329
raise(signo);
330
}
331
332
-static struct ref *write_remote_refs(const struct ref *refs,
333
- struct refspec *refspec, const char *reflog)
332
+static struct ref *wanted_peer_refs(const struct ref *refs,
333
+ struct refspec *refspec)
334
{
335
struct ref *local_refs = NULL;
336
struct ref **tail = &local_refs;
337
- struct ref *r;
337
338
get_fetch_map(refs, refspec, &tail, 0);
339
if (!option_mirror)
340
get_fetch_map(refs, tag_refspec, &tail, 0);
341
342
+ return local_refs;
343
+}
344
+
345
+static void write_remote_refs(const struct ref *local_refs)
346
+{
347
+ const struct ref *r;
348
+
349
for (r = local_refs; r; r = r->next)
350
add_extra_ref(r->peer_ref->name, r->old_sha1, 0);
351
352
pack_refs(PACK_REFS_ALL);
353
clear_extra_refs();
348
-
349
- return local_refs;
354
}
355
356
int cmd_clone(int argc, const char **argv, const char *prefix)
@@ -495,9 +499,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
499
500
strbuf_reset(&value);
501
498
- if (path && !is_bundle)
502
+ if (path && !is_bundle) {
503
refs = clone_local(path, git_dir);
500
- else {
504
+ mapped_refs = wanted_peer_refs(refs, refspec);
505
+ } else {
506
struct remote *remote = remote_get(argv[0]);
507
transport = transport_get(remote, remote->url[0]);
508
@@ -520,14 +525,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
525
option_upload_pack);
526
527
refs = transport_get_remote_refs(transport);
523
- if (refs)
524
- transport_fetch_refs(transport, refs);
528
+ if (refs) {
529
+ mapped_refs = wanted_peer_refs(refs, refspec);
530
+ transport_fetch_refs(transport, mapped_refs);
531
+ }
532
}
533
534
if (refs) {
535
clear_extra_refs();
536
530
- mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
537
+ write_remote_refs(mapped_refs);
538
539
remote_head = find_ref_by_name(refs, "HEAD");
540
remote_head_points_at =