Merge branch 'rs/path-name-safety-cleanup'
[gitweb.git] / builtin / clone.c
index 404c5e80226c81a8f051e63fa8e40286fea95a18..b4c929bb8afbf94967949279a1cc3b9b21dae100 100644 (file)
@@ -41,9 +41,11 @@ static const char * const builtin_clone_usage[] = {
 static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
 static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;
 static int option_shallow_submodules;
-static char *option_template, *option_depth;
+static int deepen;
+static char *option_template, *option_depth, *option_since;
 static char *option_origin = NULL;
 static char *option_branch = NULL;
+static struct string_list option_not = STRING_LIST_INIT_NODUP;
 static const char *real_git_dir;
 static char *option_upload_pack = "git-upload-pack";
 static int option_verbosity;
@@ -94,6 +96,10 @@ static struct option builtin_clone_options[] = {
                   N_("path to git-upload-pack on the remote")),
        OPT_STRING(0, "depth", &option_depth, N_("depth"),
                    N_("create a shallow clone of that depth")),
+       OPT_STRING(0, "shallow-since", &option_since, N_("time"),
+                   N_("create a shallow clone since a specific time")),
+       OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("revision"),
+                       N_("deepen history of shallow clone, excluding rev")),
        OPT_BOOL(0, "single-branch", &option_single_branch,
                    N_("clone only one branch, HEAD or --branch")),
        OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
@@ -164,7 +170,7 @@ static char *get_repo_path(const char *repo, int *is_bundle)
 
        strbuf_addstr(&path, repo);
        raw = get_repo_path_1(&path, is_bundle);
-       canon = raw ? xstrdup(absolute_path(raw)) : NULL;
+       canon = raw ? absolute_pathdup(raw) : NULL;
        strbuf_release(&path);
        return canon;
 }
@@ -345,8 +351,11 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,
                        continue;
                }
                abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf);
-               normalize_path_copy(abs_path, abs_path);
-               add_to_alternates_file(abs_path);
+               if (!normalize_path_copy(abs_path, abs_path))
+                       add_to_alternates_file(abs_path);
+               else
+                       warning("skipping invalid relative alternate: %s/%s",
+                               src_repo, line.buf);
                free(abs_path);
        }
        strbuf_release(&line);
@@ -670,9 +679,9 @@ static void update_head(const struct ref *our, const struct ref *remote,
        }
 }
 
-static int checkout(void)
+static int checkout(int submodule_progress)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        char *head;
        struct lock_file *lock_file;
        struct unpack_trees_options opts;
@@ -683,7 +692,7 @@ static int checkout(void)
        if (option_no_checkout)
                return 0;
 
-       head = resolve_refdup("HEAD", RESOLVE_REF_READING, sha1, NULL);
+       head = resolve_refdup("HEAD", RESOLVE_REF_READING, oid.hash, NULL);
        if (!head) {
                warning(_("remote HEAD refers to nonexistent ref, "
                          "unable to checkout.\n"));
@@ -691,7 +700,7 @@ static int checkout(void)
        }
        if (!strcmp(head, "HEAD")) {
                if (advice_detached_head)
-                       detach_advice(sha1_to_hex(sha1));
+                       detach_advice(oid_to_hex(&oid));
        } else {
                if (!starts_with(head, "refs/heads/"))
                        die(_("HEAD not found below refs/heads!"));
@@ -702,7 +711,7 @@ static int checkout(void)
        setup_work_tree();
 
        lock_file = xcalloc(1, sizeof(struct lock_file));
-       hold_locked_index(lock_file, 1);
+       hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
 
        memset(&opts, 0, sizeof opts);
        opts.update = 1;
@@ -712,7 +721,7 @@ static int checkout(void)
        opts.src_index = &the_index;
        opts.dst_index = &the_index;
 
-       tree = parse_tree_indirect(sha1);
+       tree = parse_tree_indirect(oid.hash);
        parse_tree(tree);
        init_tree_desc(&t, tree->buffer, tree->size);
        if (unpack_trees(1, &t, &opts) < 0)
@@ -722,7 +731,7 @@ static int checkout(void)
                die(_("unable to write new index file"));
 
        err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
-                          sha1_to_hex(sha1), "1", NULL);
+                          oid_to_hex(&oid), "1", NULL);
 
        if (!err && option_recursive) {
                struct argv_array args = ARGV_ARRAY_INIT;
@@ -734,6 +743,9 @@ static int checkout(void)
                if (max_jobs != -1)
                        argv_array_pushf(&args, "--jobs=%d", max_jobs);
 
+               if (submodule_progress)
+                       argv_array_push(&args, "--progress");
+
                err = run_command_v_opt(args.argv, RUN_GIT_CMD);
                argv_array_clear(&args);
        }
@@ -841,6 +853,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        const char *src_ref_prefix = "refs/heads/";
        struct remote *remote;
        int err = 0, complete_refs_before_fetch = 1;
+       int submodule_progress;
 
        struct refspec *refspec;
        const char *fetch_pattern;
@@ -857,8 +870,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                usage_msg_opt(_("You must specify a repository to clone."),
                        builtin_clone_usage, builtin_clone_options);
 
+       if (option_depth || option_since || option_not.nr)
+               deepen = 1;
        if (option_single_branch == -1)
-               option_single_branch = option_depth ? 1 : 0;
+               option_single_branch = deepen ? 1 : 0;
 
        if (option_mirror)
                option_bare = 1;
@@ -879,7 +894,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
        path = get_repo_path(repo_name, &is_bundle);
        if (path)
-               repo = xstrdup(absolute_path(repo_name));
+               repo = absolute_pathdup(repo_name);
        else if (!strchr(repo_name, ':'))
                die(_("repository '%s' does not exist"), repo_name);
        else
@@ -931,16 +946,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                set_git_work_tree(work_tree);
        }
 
-       junk_git_dir = git_dir;
+       junk_git_dir = real_git_dir ? real_git_dir : git_dir;
        if (safe_create_leading_directories_const(git_dir) < 0)
                die(_("could not create leading directories of '%s'"), git_dir);
 
-       set_git_dir_init(git_dir, real_git_dir, 0);
-       if (real_git_dir) {
-               git_dir = real_git_dir;
-               junk_git_dir = real_git_dir;
-       }
-
        if (0 <= option_verbosity) {
                if (option_bare)
                        fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
@@ -966,7 +975,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                }
        }
 
-       init_db(option_template, INIT_DB_QUIET);
+       init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET);
+
+       if (real_git_dir)
+               git_dir = real_git_dir;
+
        write_config(&option_config);
 
        git_config(git_default_config, NULL);
@@ -1004,6 +1017,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (is_local) {
                if (option_depth)
                        warning(_("--depth is ignored in local clones; use file:// instead."));
+               if (option_since)
+                       warning(_("--shallow-since is ignored in local clones; use file:// instead."));
+               if (option_not.nr)
+                       warning(_("--shallow-exclude is ignored in local clones; use file:// instead."));
                if (!access(mkpath("%s/shallow", path), F_OK)) {
                        if (option_local > 0)
                                warning(_("source repository is shallow, ignoring --local"));
@@ -1022,6 +1039,12 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (option_depth)
                transport_set_option(transport, TRANS_OPT_DEPTH,
                                     option_depth);
+       if (option_since)
+               transport_set_option(transport, TRANS_OPT_DEEPEN_SINCE,
+                                    option_since);
+       if (option_not.nr)
+               transport_set_option(transport, TRANS_OPT_DEEPEN_NOT,
+                                    (const char *)&option_not);
        if (option_single_branch)
                transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
 
@@ -1029,7 +1052,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                transport_set_option(transport, TRANS_OPT_UPLOADPACK,
                                     option_upload_pack);
 
-       if (transport->smart_options && !option_depth)
+       if (transport->smart_options && !deepen)
                transport->smart_options->check_self_contained_and_connected = 1;
 
        refs = transport_get_remote_refs(transport);
@@ -1099,6 +1122,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
        update_head(our_head_points_at, remote_head, reflog_msg.buf);
 
+       /*
+        * We want to show progress for recursive submodule clones iff
+        * we did so for the main clone. But only the transport knows
+        * the final decision for this flag, so we need to rescue the value
+        * before we free the transport.
+        */
+       submodule_progress = transport->progress;
+
        transport_unlock_pack(transport);
        transport_disconnect(transport);
 
@@ -1108,7 +1139,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        }
 
        junk_mode = JUNK_LEAVE_REPO;
-       err = checkout();
+       err = checkout(submodule_progress);
 
        strbuf_release(&reflog_msg);
        strbuf_release(&branch_top);