The logic to bring the index and the working tree from one commit to another is a nontrivial amount of code in this function. Separate it out into its own function, so that other callers can call it. Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx> --- builtin-checkout.c | 172 +++++++++++++++++++++++++++------------------------- 1 files changed, 89 insertions(+), 83 deletions(-) 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)) -- 1.6.1.rc1.72.ga5ce6 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html