clone: delay cloning until after remote HEAD checking
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Mon, 16 Jan 2012 09:46:12 +0000 (16:46 +0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 17 Jan 2012 00:26:25 +0000 (16:26 -0800)
This gives us an opportunity to abort the command during remote HEAD
check without wasting much bandwidth.

Cloning with remote-helper remains before the check because the remote
helper updates mapped_refs, which is necessary for remote ref checks.
foreign_vcs field is used to indicate the transport is handled by
remote helper.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/clone.c
transport.c

index 2733fa47ef32034ac5d4d1435837abddf06e9e3c..a1fbb3b90c0091084c657fc520f6adf6d8cd51f5 100644 (file)
@@ -364,13 +364,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
        closedir(dir);
 }
 
-static const struct ref *clone_local(const char *src_repo,
-                                    const char *dest_repo)
+static void clone_local(const char *src_repo, const char *dest_repo)
 {
-       const struct ref *ret;
-       struct remote *remote;
-       struct transport *transport;
-
        if (option_shared) {
                struct strbuf alt = STRBUF_INIT;
                strbuf_addf(&alt, "%s/objects", src_repo);
@@ -386,13 +381,8 @@ static const struct ref *clone_local(const char *src_repo,
                strbuf_release(&dest);
        }
 
-       remote = remote_get(src_repo);
-       transport = transport_get(remote, src_repo);
-       ret = transport_get_remote_refs(transport);
-       transport_disconnect(transport);
        if (0 <= option_verbosity)
                printf(_("done.\n"));
-       return ret;
 }
 
 static const char *junk_work_tree;
@@ -619,6 +609,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
        struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
        struct transport *transport = NULL;
+       struct remote *remote;
        int err = 0;
 
        struct refspec *refspec;
@@ -773,13 +764,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
        strbuf_reset(&value);
 
-       if (is_local) {
-               refs = clone_local(path, git_dir);
-               mapped_refs = wanted_peer_refs(refs, refspec);
-       } else {
-               struct remote *remote = remote_get(option_origin);
-               transport = transport_get(remote, remote->url[0]);
+       remote = remote_get(option_origin);
+       transport = transport_get(remote, remote->url[0]);
 
+       if (!is_local) {
                if (!transport->get_refs_list || !transport->fetch)
                        die(_("Don't know how to clone %s"), transport->url);
 
@@ -796,14 +784,23 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                if (option_upload_pack)
                        transport_set_option(transport, TRANS_OPT_UPLOADPACK,
                                             option_upload_pack);
-
-               refs = transport_get_remote_refs(transport);
-               if (refs) {
-                       mapped_refs = wanted_peer_refs(refs, refspec);
-                       transport_fetch_refs(transport, mapped_refs);
-               }
        }
 
+       refs = transport_get_remote_refs(transport);
+       mapped_refs = refs ? wanted_peer_refs(refs, refspec) : NULL;
+
+       /*
+        * mapped_refs may be updated if transport-helper is used so
+        * we need fetch it early because remote_head code below
+        * relies on it.
+        *
+        * for normal clones, transport_get_remote_refs() should
+        * return reliable ref set, we can delay cloning until after
+        * remote HEAD check.
+        */
+       if (!is_local && remote->foreign_vcs && refs)
+               transport_fetch_refs(transport, mapped_refs);
+
        if (refs) {
                remote_head = find_ref_by_name(refs, "HEAD");
                remote_head_points_at =
@@ -838,15 +835,18 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                                              "refs/heads/master");
        }
 
+       if (is_local)
+               clone_local(path, git_dir);
+       else if (refs && !remote->foreign_vcs)
+               transport_fetch_refs(transport, mapped_refs);
+
        update_remote_refs(refs, mapped_refs, remote_head_points_at,
                           branch_top.buf, reflog_msg.buf);
 
        update_head(our_head_points_at, remote_head, reflog_msg.buf);
 
-       if (transport) {
-               transport_unlock_pack(transport);
-               transport_disconnect(transport);
-       }
+       transport_unlock_pack(transport);
+       transport_disconnect(transport);
 
        err = checkout();
 
index a99b7c9c457c4ac3b76dc6859507711f847e5f62..43666394df3627a3d066f84ae529101d6e9a9f92 100644 (file)
@@ -895,8 +895,10 @@ struct transport *transport_get(struct remote *remote, const char *url)
 
                while (is_urlschemechar(p == url, *p))
                        p++;
-               if (!prefixcmp(p, "::"))
+               if (!prefixcmp(p, "::")) {
                        helper = xstrndup(url, p - url);
+                       remote->foreign_vcs = helper;
+               }
        }
 
        if (helper) {
@@ -938,6 +940,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
                char *handler = xmalloc(len + 1);
                handler[len] = 0;
                strncpy(handler, url, len);
+               remote->foreign_vcs = handler;
                transport_helper_init(ret, handler);
        }