Skip to content

Commit

Permalink
make 'git clone' ask the remote only for objects it cares about
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Nicolas Pitre authored and Shawn O. Pearce committed Sep 26, 2009
1 parent fb3650e commit 5bdc32d
Showing 1 changed file with 17 additions and 10 deletions.
27 changes: 17 additions & 10 deletions builtin-clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,24 +329,28 @@ static void remove_junk_on_signal(int signo)
raise(signo);
}

static struct ref *write_remote_refs(const struct ref *refs,
struct refspec *refspec, const char *reflog)
static struct ref *wanted_peer_refs(const struct ref *refs,
struct refspec *refspec)
{
struct ref *local_refs = NULL;
struct ref **tail = &local_refs;
struct ref *r;

get_fetch_map(refs, refspec, &tail, 0);
if (!option_mirror)
get_fetch_map(refs, tag_refspec, &tail, 0);

return local_refs;
}

static void write_remote_refs(const struct ref *local_refs)
{
const struct ref *r;

for (r = local_refs; r; r = r->next)
add_extra_ref(r->peer_ref->name, r->old_sha1, 0);

pack_refs(PACK_REFS_ALL);
clear_extra_refs();

return local_refs;
}

int cmd_clone(int argc, const char **argv, const char *prefix)
Expand Down Expand Up @@ -495,9 +499,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)

strbuf_reset(&value);

if (path && !is_bundle)
if (path && !is_bundle) {
refs = clone_local(path, git_dir);
else {
mapped_refs = wanted_peer_refs(refs, refspec);
} else {
struct remote *remote = remote_get(argv[0]);
transport = transport_get(remote, remote->url[0]);

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

refs = transport_get_remote_refs(transport);
if (refs)
transport_fetch_refs(transport, refs);
if (refs) {
mapped_refs = wanted_peer_refs(refs, refspec);
transport_fetch_refs(transport, mapped_refs);
}
}

if (refs) {
clear_extra_refs();

mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
write_remote_refs(mapped_refs);

remote_head = find_ref_by_name(refs, "HEAD");
remote_head_points_at =
Expand Down

0 comments on commit 5bdc32d

Please sign in to comment.