Skip to content

Commit 5bdc32d

Browse files
npitrespearce
authored andcommitted
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 <[email protected]> Signed-off-by: Shawn O. Pearce <[email protected]>
1 parent fb3650e commit 5bdc32d

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

builtin-clone.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -329,24 +329,28 @@ static void remove_junk_on_signal(int signo)
329329
raise(signo);
330330
}
331331

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)
334334
{
335335
struct ref *local_refs = NULL;
336336
struct ref **tail = &local_refs;
337-
struct ref *r;
338337

339338
get_fetch_map(refs, refspec, &tail, 0);
340339
if (!option_mirror)
341340
get_fetch_map(refs, tag_refspec, &tail, 0);
342341

342+
return local_refs;
343+
}
344+
345+
static void write_remote_refs(const struct ref *local_refs)
346+
{
347+
const struct ref *r;
348+
343349
for (r = local_refs; r; r = r->next)
344350
add_extra_ref(r->peer_ref->name, r->old_sha1, 0);
345351

346352
pack_refs(PACK_REFS_ALL);
347353
clear_extra_refs();
348-
349-
return local_refs;
350354
}
351355

352356
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)
495499

496500
strbuf_reset(&value);
497501

498-
if (path && !is_bundle)
502+
if (path && !is_bundle) {
499503
refs = clone_local(path, git_dir);
500-
else {
504+
mapped_refs = wanted_peer_refs(refs, refspec);
505+
} else {
501506
struct remote *remote = remote_get(argv[0]);
502507
transport = transport_get(remote, remote->url[0]);
503508

@@ -520,14 +525,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
520525
option_upload_pack);
521526

522527
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+
}
525532
}
526533

527534
if (refs) {
528535
clear_extra_refs();
529536

530-
mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
537+
write_remote_refs(mapped_refs);
531538

532539
remote_head = find_ref_by_name(refs, "HEAD");
533540
remote_head_points_at =

0 commit comments

Comments
 (0)