Show changes to builtin-checkout.c +89 −83
diff --git a/builtin-checkout.c b/builtin-checkout.c
index d88fce2..9c45c49 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -352,6 +352,87 @@ static int reset_tree(struct tree *tree, int quiet, int worktree, int *wt_error)
}
}
+static int switch_trees(int merge, int quiet, int *wt_error,
+ struct commit *old_commit, const char *old_label,
+ struct commit *new_commit, const char *new_label)
+{
+ int ret;
+ 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;
+
+ topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches.";
+
+ refresh_cache(REFRESH_QUIET);
+
+ if (unmerged_cache()) {
+ error("you need to resolve your current index first");
+ return 1;
+ }
+
+ /* 2-way merge to the new branch */
+ topts.initial_checkout = is_cache_unborn();
+ topts.update = 1;
+ topts.merge = 1;
+ topts.gently = merge;
+ topts.verbose_update = !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);
+ if (ret == -1) {
+ /*
+ * Unpack couldn't do a trivial merge; either give up
+ * or do a real merge, depending on whether the merge
+ * flag was used.
+ */
+ struct tree *result;
+ struct tree *work;
+ struct merge_options o;
+ if (!merge)
+ return 1;
+ parse_commit(old_commit);
+
+ /* Do more real merge */
+
+ /*
+ * We update the index fully, then write the tree from
+ * the index, then merge the new branch with the
+ * current tree, with the old branch as the base. Then
+ * we reset the index (but not the working tree) to
+ * the new branch, leaving the working tree as the
+ * merged version, but skipping unmerged entries in
+ * the index.
+ */
+
+ add_files_to_cache(NULL, NULL, 0);
+ init_merge_options(&o);
+ o.verbosity = 0;
+ work = write_tree_from_memory(&o);
+
+ ret = reset_tree(new_commit->tree, quiet, 1, wt_error);
+ if (ret)
+ return ret;
+ o.branch1 = new_label;
+ o.branch2 = old_label;
+ merge_trees(&o, new_commit->tree, work,
+ old_commit->tree, &result);
+ ret = reset_tree(new_commit->tree, quiet, 0, wt_error);
+ }
+ return ret;
+}
+
struct branch_info {
const char *name; /* The short name used */
const char *path; /* The full name of a real branch */
@@ -376,91 +457,16 @@ static int merge_working_tree(struct checkout_opts *opts,
if (read_cache() < 0)
return error("corrupt index file");
- if (opts->force) {
+ if (opts->force)
ret = reset_tree(new->commit->tree, opts->quiet, 1,
&opts->writeout_error);
- if (ret)
- return ret;
- } else {
- 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;
-
- topts.msgs.not_uptodate_file = "You have local changes to '%s'; cannot switch branches.";
-
- refresh_cache(REFRESH_QUIET);
-
- if (unmerged_cache()) {
- error("you need to resolve your current index first");
- return 1;
- }
-
- /* 2-way merge to the new branch */
- topts.initial_checkout = is_cache_unborn();
- 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);
- if (ret == -1) {
- /*
- * Unpack couldn't do a trivial merge; either
- * give up or do a real merge, depending on
- * whether the merge flag was used.
- */
- struct tree *result;
- struct tree *work;
- struct merge_options o;
- if (!opts->merge)
- return 1;
- parse_commit(old->commit);
-
- /* Do more real merge */
-
- /*
- * We update the index fully, then write the
- * tree from the index, then merge the new
- * branch with the current tree, with the old
- * branch as the base. Then we reset the index
- * (but not the working tree) to the new
- * branch, leaving the working tree as the
- * merged version, but skipping unmerged
- * entries in the index.
- */
-
- add_files_to_cache(NULL, NULL, 0);
- init_merge_options(&o);
- o.verbosity = 0;
- work = write_tree_from_memory(&o);
-
- ret = reset_tree(new->commit->tree, opts->quiet, 1,
- &opts->writeout_error);
- if (ret)
- return ret;
- o.branch1 = new->name;
- o.branch2 = "local";
- merge_trees(&o, new->commit->tree, work,
- old->commit->tree, &result);
- ret = reset_tree(new->commit->tree, opts->quiet, 0,
- &opts->writeout_error);
- if (ret)
- return ret;
- }
- }
+ else
+ ret = switch_trees(opts->merge, opts->quiet,
+ &opts->writeout_error,
+ old->commit, "local",
+ new->commit, new->name);
+ if (ret)
+ return ret;
if (write_cache(newfd, active_cache, active_nr) ||
commit_locked_index(lock_file))