@matheusbsbs / matheus-bagliano / commits / 5bdc32d3e5
Fork 0

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 =