builtin-merge: show user-friendly error messages for fast-forward too.
[gitweb.git] / builtin-clone.c
index 9d79301b8e373baa0cadccf8dc4ee3f4ed39e8b6..4992c2597c903d86ce1d0c209828aeb962fef23a 100644 (file)
@@ -38,7 +38,7 @@ static const char * const builtin_clone_usage[] = {
 };
 
 static int option_quiet, option_no_checkout, option_bare, option_mirror;
-static int option_local, option_no_hardlinks, option_shared;
+static int option_local, option_no_hardlinks, option_shared, option_recursive;
 static char *option_template, *option_reference, *option_depth;
 static char *option_origin = NULL;
 static char *option_branch = NULL;
@@ -60,6 +60,8 @@ static struct option builtin_clone_options[] = {
                    "don't use local hardlinks, always copy"),
        OPT_BOOLEAN('s', "shared", &option_shared,
                    "setup as shared repository"),
+       OPT_BOOLEAN(0, "recursive", &option_recursive,
+                   "setup as shared repository"),
        OPT_STRING(0, "template", &option_template, "path",
                   "path the template repository"),
        OPT_STRING(0, "reference", &option_reference, "repo",
@@ -76,6 +78,10 @@ static struct option builtin_clone_options[] = {
        OPT_END()
 };
 
+static const char *argv_submodule[] = {
+       "submodule", "update", "--init", "--recursive", NULL
+};
+
 static char *get_repo_path(const char *repo, int *is_bundle)
 {
        static char *suffix[] = { "/.git", ".git", "" };
@@ -263,7 +269,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
                                die_errno("failed to create link '%s'", dest->buf);
                        option_no_hardlinks = 1;
                }
-               if (copy_file(dest->buf, src->buf, 0666))
+               if (copy_file_with_time(dest->buf, src->buf, 0666))
                        die_errno("failed to copy file to '%s'", dest->buf);
        }
        closedir(dir);
@@ -323,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)
@@ -489,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]);
 
@@ -514,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 =
@@ -593,8 +606,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                option_no_checkout = 1;
        }
 
-       if (transport)
+       if (transport) {
                transport_unlock_pack(transport);
+               transport_disconnect(transport);
+       }
 
        if (!option_no_checkout) {
                struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
@@ -627,6 +642,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
                err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
                                sha1_to_hex(remote_head->old_sha1), "1", NULL);
+
+               if (!err && option_recursive)
+                       err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
        }
 
        strbuf_release(&reflog_msg);