Code

Make 'unpack_trees()' have a separate source and destination index
[git.git] / builtin-checkout.c
index 283831e8af93ede033bfe8eb27ae609e31638051..7deb504837d252dd43fa9746c5d12342e93a5923 100644 (file)
@@ -67,17 +67,8 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
 
 static int read_tree_some(struct tree *tree, const char **pathspec)
 {
-       int newfd;
-       struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
-       newfd = hold_locked_index(lock_file, 1);
-       read_cache();
-
        read_tree_recursive(tree, "", 0, 0, pathspec, update_some);
 
-       if (write_cache(newfd, active_cache, active_nr) ||
-           commit_locked_index(lock_file))
-               die("unable to write new index file");
-
        /* update the index with the given tree's info
         * for all args, expanding wildcards, and exit
         * with any non-zero return code.
@@ -85,7 +76,7 @@ static int read_tree_some(struct tree *tree, const char **pathspec)
        return 0;
 }
 
-static int checkout_paths(const char **pathspec)
+static int checkout_paths(struct tree *source_tree, const char **pathspec)
 {
        int pos;
        struct checkout state;
@@ -94,6 +85,15 @@ static int checkout_paths(const char **pathspec)
        int flag;
        struct commit *head;
 
+       int newfd;
+       struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+
+       newfd = hold_locked_index(lock_file, 1);
+       read_cache();
+
+       if (source_tree)
+               read_tree_some(source_tree, pathspec);
+
        for (pos = 0; pathspec[pos]; pos++)
                ;
        ps_matched = xcalloc(1, pos);
@@ -116,6 +116,10 @@ static int checkout_paths(const char **pathspec)
                }
        }
 
+       if (write_cache(newfd, active_cache, active_nr) ||
+           commit_locked_index(lock_file))
+               die("unable to write new index file");
+
        resolve_ref("HEAD", rev, 0, &flag);
        head = lookup_commit_reference_gently(rev, 1);
 
@@ -148,6 +152,7 @@ static int reset_to_new(struct tree *tree, int quiet)
 {
        struct unpack_trees_options opts;
        struct tree_desc tree_desc;
+
        memset(&opts, 0, sizeof(opts));
        opts.head_idx = -1;
        opts.update = 1;
@@ -155,6 +160,8 @@ static int reset_to_new(struct tree *tree, int quiet)
        opts.merge = 1;
        opts.fn = oneway_merge;
        opts.verbose_update = !quiet;
+       opts.src_index = &the_index;
+       opts.dst_index = &the_index;
        parse_tree(tree);
        init_tree_desc(&tree_desc, tree->buffer, tree->size);
        if (unpack_trees(1, &tree_desc, &opts))
@@ -166,6 +173,7 @@ static void reset_clean_to_new(struct tree *tree, int quiet)
 {
        struct unpack_trees_options opts;
        struct tree_desc tree_desc;
+
        memset(&opts, 0, sizeof(opts));
        opts.head_idx = -1;
        opts.skip_unmerged = 1;
@@ -173,6 +181,8 @@ static void reset_clean_to_new(struct tree *tree, int quiet)
        opts.merge = 1;
        opts.fn = oneway_merge;
        opts.verbose_update = !quiet;
+       opts.src_index = &the_index;
+       opts.dst_index = &the_index;
        parse_tree(tree);
        init_tree_desc(&tree_desc, tree->buffer, tree->size);
        if (unpack_trees(1, &tree_desc, &opts))
@@ -186,7 +196,7 @@ struct checkout_opts {
 
        char *new_branch;
        int new_branch_log;
-       int track;
+       enum branch_track track;
 };
 
 struct branch_info {
@@ -220,30 +230,34 @@ static int merge_working_tree(struct checkout_opts *opts,
                struct tree_desc trees[2];
                struct tree *tree;
                struct unpack_trees_options topts;
+
                memset(&topts, 0, sizeof(topts));
                topts.head_idx = -1;
+               topts.src_index = &the_index;
+               topts.dst_index = &the_index;
 
                refresh_cache(REFRESH_QUIET);
 
                if (unmerged_cache()) {
-                       ret = opts->merge ? -1 :
-                               error("you need to resolve your current index first");
-               } else {
-                       topts.update = 1;
-                       topts.merge = 1;
-                       topts.gently = opts->merge;
-                       topts.verbose_update = !opts->quiet;
-                       topts.fn = twoway_merge;
-                       topts.dir = xcalloc(1, sizeof(*topts.dir));
-                       topts.dir->show_ignored = 1;
-                       topts.dir->exclude_per_dir = ".gitignore";
-                       tree = parse_tree_indirect(old->commit->object.sha1);
-                       init_tree_desc(&trees[0], tree->buffer, tree->size);
-                       tree = parse_tree_indirect(new->commit->object.sha1);
-                       init_tree_desc(&trees[1], tree->buffer, tree->size);
-                       ret = unpack_trees(2, trees, &topts);
+                       error("you need to resolve your current index first");
+                       return 1;
                }
-               if (ret) {
+
+               /* 2-way merge to the new branch */
+               topts.update = 1;
+               topts.merge = 1;
+               topts.gently = opts->merge;
+               topts.verbose_update = !opts->quiet;
+               topts.fn = twoway_merge;
+               topts.dir = xcalloc(1, sizeof(*topts.dir));
+               topts.dir->show_ignored = 1;
+               topts.dir->exclude_per_dir = ".gitignore";
+               tree = parse_tree_indirect(old->commit->object.sha1);
+               init_tree_desc(&trees[0], tree->buffer, tree->size);
+               tree = parse_tree_indirect(new->commit->object.sha1);
+               init_tree_desc(&trees[1], tree->buffer, tree->size);
+
+               if (unpack_trees(2, trees, &topts)) {
                        /*
                         * Unpack couldn't do a trivial merge; either
                         * give up or do a real merge, depending on
@@ -479,16 +493,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
        return post_checkout_hook(old.commit, new->commit, 1);
 }
 
-static int branch_track = 0;
-
-static int git_checkout_config(const char *var, const char *value)
-{
-       if (!strcmp(var, "branch.autosetupmerge"))
-               branch_track = git_config_bool(var, value);
-
-       return git_default_config(var, value);
-}
-
 int cmd_checkout(int argc, const char **argv, const char *prefix)
 {
        struct checkout_opts opts;
@@ -500,7 +504,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                OPT__QUIET(&opts.quiet),
                OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
                OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
-               OPT_BOOLEAN( 0 , "track", &opts.track, "track"),
+               OPT_SET_INT( 0 , "track",  &opts.track, "track",
+                       BRANCH_TRACK_EXPLICIT),
                OPT_BOOLEAN('f', NULL, &opts.force, "force"),
                OPT_BOOLEAN('m', NULL, &opts.merge, "merge"),
                OPT_END(),
@@ -509,9 +514,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        memset(&opts, 0, sizeof(opts));
        memset(&new, 0, sizeof(new));
 
-       git_config(git_checkout_config);
+       git_config(git_default_config);
 
-       opts.track = branch_track;
+       opts.track = git_branch_track;
 
        argc = parse_options(argc, argv, options, checkout_usage, 0);
        if (argc) {
@@ -540,7 +545,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                argc--;
        }
 
-       if (!opts.new_branch && (opts.track != branch_track))
+       if (!opts.new_branch && (opts.track != git_branch_track))
                die("git checkout: --track and --no-track require -b");
 
        if (opts.force && opts.merge)
@@ -548,6 +553,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 
        if (argc) {
                const char **pathspec = get_pathspec(prefix, argv);
+
+               if (!pathspec)
+                       die("invalid path specification");
+
                /* Checkout paths */
                if (opts.new_branch || opts.force || opts.merge) {
                        if (argc == 1) {
@@ -557,11 +566,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                        }
                }
 
-               if (source_tree)
-                       read_tree_some(source_tree, pathspec);
-               else
-                       read_cache();
-               return checkout_paths(pathspec);
+               return checkout_paths(source_tree, pathspec);
        }
 
        if (new.name && !new.commit) {