implement fetching of moved submodules
[gitweb.git] / builtin / checkout.c
index b3609434550a5521b63327eeb909b32797215496..fc4f8fd2ea29c7c23d3b1c7ca0ba78824c255a91 100644 (file)
@@ -1,4 +1,5 @@
 #include "builtin.h"
+#include "config.h"
 #include "lockfile.h"
 #include "parse-options.h"
 #include "refs.h"
 #include "submodule-config.h"
 #include "submodule.h"
 
-static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
-
 static const char * const checkout_usage[] = {
        N_("git checkout [<options>] <branch>"),
        N_("git checkout [<options>] [<branch>] -- <file>..."),
        NULL,
 };
 
-static int option_parse_recurse_submodules(const struct option *opt,
-                                          const char *arg, int unset)
-{
-       if (unset) {
-               recurse_submodules = RECURSE_SUBMODULES_OFF;
-               return 0;
-       }
-       if (arg)
-               recurse_submodules =
-                       parse_update_recurse_submodules_arg(opt->long_name,
-                                                           arg);
-       else
-               recurse_submodules = RECURSE_SUBMODULES_ON;
-
-       return 0;
-}
-
 struct checkout_opts {
        int patch_mode;
        int quiet;
@@ -376,6 +358,8 @@ static int checkout_paths(const struct checkout_opts *opts,
        state.force = 1;
        state.refresh_cache = 1;
        state.istate = &the_index;
+
+       enable_delayed_checkout(&state);
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
                if (ce->ce_flags & CE_MATCHED) {
@@ -390,12 +374,13 @@ static int checkout_paths(const struct checkout_opts *opts,
                        pos = skip_same_name(ce, pos) - 1;
                }
        }
+       errs |= finish_delayed_checkout(&state);
 
        if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
 
        read_ref_full("HEAD", 0, rev.hash, NULL);
-       head = lookup_commit_reference_gently(rev.hash, 1);
+       head = lookup_commit_reference_gently(&rev, 1);
 
        errs |= post_checkout_hook(head, head, 0);
        return errs;
@@ -451,6 +436,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
                 * update paths in the work tree, and we cannot revert
                 * them.
                 */
+               /* fallthrough */
        case 0:
                return 0;
        default:
@@ -529,10 +515,10 @@ static int merge_working_tree(const struct checkout_opts *opts,
                        setup_standard_excludes(topts.dir);
                }
                tree = parse_tree_indirect(old->commit ?
-                                          old->commit->object.oid.hash :
-                                          EMPTY_TREE_SHA1_BIN);
+                                          &old->commit->object.oid :
+                                          &empty_tree_oid);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
-               tree = parse_tree_indirect(new->commit->object.oid.hash);
+               tree = parse_tree_indirect(&new->commit->object.oid);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
 
                ret = unpack_trees(2, trees, &topts);
@@ -723,7 +709,7 @@ static int add_pending_uninteresting_ref(const char *refname,
                                         const struct object_id *oid,
                                         int flags, void *cb_data)
 {
-       add_pending_sha1(cb_data, refname, oid->hash, UNINTERESTING);
+       add_pending_oid(cb_data, refname, oid, UNINTERESTING);
        return 0;
 }
 
@@ -809,11 +795,16 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
        add_pending_object(&revs, object, oid_to_hex(&object->oid));
 
        for_each_ref(add_pending_uninteresting_ref, &revs);
-       add_pending_sha1(&revs, "HEAD", new->object.oid.hash, UNINTERESTING);
+       add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING);
 
+       /* Save pending objects, so they can be cleaned up later. */
        refs = revs.pending;
        revs.leak_pending = 1;
 
+       /*
+        * prepare_revision_walk (together with .leak_pending = 1) makes us
+        * the sole owner of the list of pending objects.
+        */
        if (prepare_revision_walk(&revs))
                die(_("internal error in revision walk"));
        if (!(old->object.flags & UNINTERESTING))
@@ -821,8 +812,10 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
        else
                describe_detached_head(_("Previous HEAD position was"), old);
 
+       /* Clean up objects used, as they will be reused. */
        clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
-       free(refs.objects);
+
+       object_array_clear(&refs);
 }
 
 static int switch_branches(const struct checkout_opts *opts,
@@ -836,7 +829,7 @@ static int switch_branches(const struct checkout_opts *opts,
        memset(&old, 0, sizeof(old));
        old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag);
        if (old.path)
-               old.commit = lookup_commit_reference_gently(rev.hash, 1);
+               old.commit = lookup_commit_reference_gently(&rev, 1);
        if (!(flag & REF_ISSYMREF))
                old.path = NULL;
 
@@ -876,7 +869,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
        }
 
        if (starts_with(var, "submodule."))
-               return parse_submodule_config_option(var, value);
+               return git_default_submodule_config(var, value, NULL);
 
        return git_xmerge_config(var, value, NULL);
 }
@@ -1050,10 +1043,10 @@ static int parse_branchname_arg(int argc, const char **argv,
        else
                new->path = NULL; /* not an existing branch */
 
-       new->commit = lookup_commit_reference_gently(rev->hash, 1);
+       new->commit = lookup_commit_reference_gently(rev, 1);
        if (!new->commit) {
                /* not a commit */
-               *source_tree = parse_tree_indirect(rev->hash);
+               *source_tree = parse_tree_indirect(rev);
        } else {
                parse_commit_or_die(new->commit);
                *source_tree = new->commit->tree;
@@ -1131,9 +1124,8 @@ static int checkout_branch(struct checkout_opts *opts,
 
        if (new->path && !opts->force_detach && !opts->new_branch &&
            !opts->ignore_other_worktrees) {
-               struct object_id oid;
                int flag;
-               char *head_ref = resolve_refdup("HEAD", 0, oid.hash, &flag);
+               char *head_ref = resolve_refdup("HEAD", 0, NULL, &flag);
                if (head_ref &&
                    (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
                        die_if_checked_out(new->path, 1);
@@ -1184,9 +1176,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                                N_("second guess 'git checkout <no-such-branch>'")),
                OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
                         N_("do not check if another worktree is holding the given ref")),
-               { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
+               { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
                            "checkout", "control recursive updating of submodules",
-                           PARSE_OPT_OPTARG, option_parse_recurse_submodules },
+                           PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
                OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")),
                OPT_END(),
        };
@@ -1197,7 +1189,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        opts.prefix = prefix;
        opts.show_progress = -1;
 
-       gitmodules_config();
        git_config(git_checkout_config, &opts);
 
        opts.track = BRANCH_TRACK_UNSPECIFIED;
@@ -1217,12 +1208,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
        }
 
-       if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
-               git_config(submodule_config, NULL);
-               if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)
-                       set_config_update_recurse_submodules(recurse_submodules);
-       }
-
        if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
                die(_("-b, -B and --orphan are mutually exclusive"));
 
@@ -1312,6 +1297,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                strbuf_release(&buf);
        }
 
+       UNLEAK(opts);
        if (opts.patch_mode || opts.pathspec.nr)
                return checkout_paths(&opts, new.name);
        else