Merge branch 'nd/no-more-check-racy'
[gitweb.git] / merge-recursive.c
index acc2f64a4e9d03f49165e3c46396ce00a09dc6bd..6c40c61c4728d9224006768599d7bf2ded744bb1 100644 (file)
@@ -146,7 +146,8 @@ static int err(struct merge_options *o, const char *err, ...)
        return -1;
 }
 
-static struct tree *shift_tree_object(struct tree *one, struct tree *two,
+static struct tree *shift_tree_object(struct repository *repo,
+                                     struct tree *one, struct tree *two,
                                      const char *subtree_shift)
 {
        struct object_id shifted;
@@ -159,12 +160,14 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
        }
        if (oideq(&two->object.oid, &shifted))
                return two;
-       return lookup_tree(the_repository, &shifted);
+       return lookup_tree(repo, &shifted);
 }
 
-static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
+static struct commit *make_virtual_commit(struct repository *repo,
+                                         struct tree *tree,
+                                         const char *comment)
 {
-       struct commit *commit = alloc_commit_node(the_repository);
+       struct commit *commit = alloc_commit_node(repo);
 
        set_merge_remote_desc(commit, comment, (struct object *)commit);
        commit->maybe_tree = tree;
@@ -186,6 +189,7 @@ static int oid_eq(const struct object_id *a, const struct object_id *b)
 enum rename_type {
        RENAME_NORMAL = 0,
        RENAME_VIA_DIR,
+       RENAME_ADD,
        RENAME_DELETE,
        RENAME_ONE_FILE_TO_ONE,
        RENAME_ONE_FILE_TO_TWO,
@@ -228,6 +232,7 @@ static inline void setup_rename_conflict_info(enum rename_type rename_type,
                                              struct stage_data *src_entry1,
                                              struct stage_data *src_entry2)
 {
+       int ostage1 = 0, ostage2;
        struct rename_conflict_info *ci;
 
        /*
@@ -264,18 +269,22 @@ static inline void setup_rename_conflict_info(enum rename_type rename_type,
                dst_entry2->rename_conflict_info = ci;
        }
 
-       if (rename_type == RENAME_TWO_FILES_TO_ONE) {
-               /*
-                * For each rename, there could have been
-                * modifications on the side of history where that
-                * file was not renamed.
-                */
-               int ostage1 = o->branch1 == branch1 ? 3 : 2;
-               int ostage2 = ostage1 ^ 1;
+       /*
+        * For each rename, there could have been
+        * modifications on the side of history where that
+        * file was not renamed.
+        */
+       if (rename_type == RENAME_ADD ||
+           rename_type == RENAME_TWO_FILES_TO_ONE) {
+               ostage1 = o->branch1 == branch1 ? 3 : 2;
 
                ci->ren1_other.path = pair1->one->path;
                oidcpy(&ci->ren1_other.oid, &src_entry1->stages[ostage1].oid);
                ci->ren1_other.mode = src_entry1->stages[ostage1].mode;
+       }
+
+       if (rename_type == RENAME_TWO_FILES_TO_ONE) {
+               ostage2 = ostage1 ^ 1;
 
                ci->ren2_other.path = pair2->one->path;
                oidcpy(&ci->ren2_other.oid, &src_entry2->stages[ostage2].oid);
@@ -337,22 +346,24 @@ static int add_cacheinfo(struct merge_options *o,
                         unsigned int mode, const struct object_id *oid,
                         const char *path, int stage, int refresh, int options)
 {
+       struct index_state *istate = o->repo->index;
        struct cache_entry *ce;
        int ret;
 
-       ce = make_cache_entry(&the_index, mode, oid ? oid : &null_oid, path, stage, 0);
+       ce = make_cache_entry(istate, mode, oid ? oid : &null_oid, path, stage, 0);
        if (!ce)
                return err(o, _("add_cacheinfo failed for path '%s'; merge aborting."), path);
 
-       ret = add_cache_entry(ce, options);
+       ret = add_index_entry(istate, ce, options);
        if (refresh) {
                struct cache_entry *nce;
 
-               nce = refresh_cache_entry(&the_index, ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
+               nce = refresh_cache_entry(istate, ce,
+                                         CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
                if (!nce)
                        return err(o, _("add_cacheinfo failed to refresh for path '%s'; merge aborting."), path);
                if (nce != ce)
-                       ret = add_cache_entry(nce, options);
+                       ret = add_index_entry(istate, nce, options);
        }
        return ret;
 }
@@ -380,7 +391,7 @@ static int unpack_trees_start(struct merge_options *o,
        o->unpack_opts.merge = 1;
        o->unpack_opts.head_idx = 2;
        o->unpack_opts.fn = threeway_merge;
-       o->unpack_opts.src_index = &the_index;
+       o->unpack_opts.src_index = o->repo->index;
        o->unpack_opts.dst_index = &tmp_index;
        o->unpack_opts.aggressive = !merge_detect_rename(o);
        setup_unpack_trees_porcelain(&o->unpack_opts, "merge");
@@ -390,16 +401,16 @@ static int unpack_trees_start(struct merge_options *o,
        init_tree_desc_from_tree(t+2, merge);
 
        rc = unpack_trees(3, t, &o->unpack_opts);
-       cache_tree_free(&active_cache_tree);
+       cache_tree_free(&o->repo->index->cache_tree);
 
        /*
-        * Update the_index to match the new results, AFTER saving a copy
+        * Update o->repo->index to match the new results, AFTER saving a copy
         * in o->orig_index.  Update src_index to point to the saved copy.
         * (verify_uptodate() checks src_index, and the original index is
         * the one that had the necessary modification timestamps.)
         */
-       o->orig_index = the_index;
-       the_index = tmp_index;
+       o->orig_index = *o->repo->index;
+       *o->repo->index = tmp_index;
        o->unpack_opts.src_index = &o->orig_index;
 
        return rc;
@@ -414,12 +425,13 @@ static void unpack_trees_finish(struct merge_options *o)
 struct tree *write_tree_from_memory(struct merge_options *o)
 {
        struct tree *result = NULL;
+       struct index_state *istate = o->repo->index;
 
-       if (unmerged_cache()) {
+       if (unmerged_index(istate)) {
                int i;
                fprintf(stderr, "BUG: There are unmerged index entries:\n");
-               for (i = 0; i < active_nr; i++) {
-                       const struct cache_entry *ce = active_cache[i];
+               for (i = 0; i < istate->cache_nr; i++) {
+                       const struct cache_entry *ce = istate->cache[i];
                        if (ce_stage(ce))
                                fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce),
                                        (int)ce_namelen(ce), ce->name);
@@ -427,16 +439,16 @@ struct tree *write_tree_from_memory(struct merge_options *o)
                BUG("unmerged index entries in merge-recursive.c");
        }
 
-       if (!active_cache_tree)
-               active_cache_tree = cache_tree();
+       if (!istate->cache_tree)
+               istate->cache_tree = cache_tree();
 
-       if (!cache_tree_fully_valid(active_cache_tree) &&
-           cache_tree_update(&the_index, 0) < 0) {
+       if (!cache_tree_fully_valid(istate->cache_tree) &&
+           cache_tree_update(istate, 0) < 0) {
                err(o, _("error building trees"));
                return NULL;
        }
 
-       result = lookup_tree(the_repository, &active_cache_tree->oid);
+       result = lookup_tree(o->repo, &istate->cache_tree->oid);
 
        return result;
 }
@@ -463,7 +475,8 @@ static void get_files_dirs(struct merge_options *o, struct tree *tree)
 {
        struct pathspec match_all;
        memset(&match_all, 0, sizeof(match_all));
-       read_tree_recursive(tree, "", 0, 0, &match_all, save_files_dirs, o);
+       read_tree_recursive(the_repository, tree, "", 0, 0,
+                           &match_all, save_files_dirs, o);
 }
 
 static int get_tree_entry_if_blob(const struct object_id *tree,
@@ -506,17 +519,17 @@ static struct stage_data *insert_stage_data(const char *path,
  * Create a dictionary mapping file names to stage_data objects. The
  * dictionary contains one entry for every path with a non-zero stage entry.
  */
-static struct string_list *get_unmerged(void)
+static struct string_list *get_unmerged(struct index_state *istate)
 {
        struct string_list *unmerged = xcalloc(1, sizeof(struct string_list));
        int i;
 
        unmerged->strdup_strings = 1;
 
-       for (i = 0; i < active_nr; i++) {
+       for (i = 0; i < istate->cache_nr; i++) {
                struct string_list_item *item;
                struct stage_data *e;
-               const struct cache_entry *ce = active_cache[i];
+               const struct cache_entry *ce = istate->cache[i];
                if (!ce_stage(ce))
                        continue;
 
@@ -676,7 +689,7 @@ static int update_stages(struct merge_options *opt, const char *path,
        int clear = 1;
        int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK;
        if (clear)
-               if (remove_file_from_cache(path))
+               if (remove_file_from_index(opt->repo->index, path))
                        return -1;
        if (o)
                if (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options))
@@ -690,27 +703,6 @@ static int update_stages(struct merge_options *opt, const char *path,
        return 0;
 }
 
-static int update_stages_for_stage_data(struct merge_options *opt,
-                                       const char *path,
-                                       const struct stage_data *stage_data)
-{
-       struct diff_filespec o, a, b;
-
-       o.mode = stage_data->stages[1].mode;
-       oidcpy(&o.oid, &stage_data->stages[1].oid);
-
-       a.mode = stage_data->stages[2].mode;
-       oidcpy(&a.oid, &stage_data->stages[2].oid);
-
-       b.mode = stage_data->stages[3].mode;
-       oidcpy(&b.oid, &stage_data->stages[3].oid);
-
-       return update_stages(opt, path,
-                            is_null_oid(&o.oid) ? NULL : &o,
-                            is_null_oid(&a.oid) ? NULL : &a,
-                            is_null_oid(&b.oid) ? NULL : &b);
-}
-
 static void update_entry(struct stage_data *entry,
                         struct diff_filespec *o,
                         struct diff_filespec *a,
@@ -732,13 +724,14 @@ static int remove_file(struct merge_options *o, int clean,
        int update_working_directory = !o->call_depth && !no_wd;
 
        if (update_cache) {
-               if (remove_file_from_cache(path))
+               if (remove_file_from_index(o->repo->index, path))
                        return -1;
        }
        if (update_working_directory) {
                if (ignore_case) {
                        struct cache_entry *ce;
-                       ce = cache_file_exists(path, strlen(path), ignore_case);
+                       ce = index_file_exists(o->repo->index, path, strlen(path),
+                                              ignore_case);
                        if (ce && ce_stage(ce) == 0 && strcmp(path, ce->name))
                                return 0;
                }
@@ -788,7 +781,8 @@ static char *unique_path(struct merge_options *o, const char *path, const char *
  * check the working directory.  If empty_ok is non-zero, also return
  * 0 in the case where the working-tree dir exists but is empty.
  */
-static int dir_in_way(const char *path, int check_working_copy, int empty_ok)
+static int dir_in_way(struct index_state *istate, const char *path,
+                     int check_working_copy, int empty_ok)
 {
        int pos;
        struct strbuf dirpath = STRBUF_INIT;
@@ -797,12 +791,12 @@ static int dir_in_way(const char *path, int check_working_copy, int empty_ok)
        strbuf_addstr(&dirpath, path);
        strbuf_addch(&dirpath, '/');
 
-       pos = cache_name_pos(dirpath.buf, dirpath.len);
+       pos = index_name_pos(istate, dirpath.buf, dirpath.len);
 
        if (pos < 0)
                pos = -1 - pos;
-       if (pos < active_nr &&
-           !strncmp(dirpath.buf, active_cache[pos]->name, dirpath.len)) {
+       if (pos < istate->cache_nr &&
+           !strncmp(dirpath.buf, istate->cache[pos]->name, dirpath.len)) {
                strbuf_release(&dirpath);
                return 1;
        }
@@ -845,8 +839,10 @@ static int was_tracked(struct merge_options *o, const char *path)
        return 0;
 }
 
-static int would_lose_untracked(const char *path)
+static int would_lose_untracked(struct merge_options *o, const char *path)
 {
+       struct index_state *istate = o->repo->index;
+
        /*
         * This may look like it can be simplified to:
         *   return !was_tracked(o, path) && file_exists(path)
@@ -864,19 +860,19 @@ static int would_lose_untracked(const char *path)
         * update_file()/would_lose_untracked(); see every comment in this
         * file which mentions "update_stages".
         */
-       int pos = cache_name_pos(path, strlen(path));
+       int pos = index_name_pos(istate, path, strlen(path));
 
        if (pos < 0)
                pos = -1 - pos;
-       while (pos < active_nr &&
-              !strcmp(path, active_cache[pos]->name)) {
+       while (pos < istate->cache_nr &&
+              !strcmp(path, istate->cache[pos]->name)) {
                /*
                 * If stage #0, it is definitely tracked.
                 * If it has stage #2 then it was tracked
                 * before this merge started.  All other
                 * cases the path was not tracked.
                 */
-               switch (ce_stage(active_cache[pos])) {
+               switch (ce_stage(istate->cache[pos])) {
                case 0:
                case 2:
                        return 0;
@@ -936,7 +932,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
         * Do not unlink a file in the work tree if we are not
         * tracking it.
         */
-       if (would_lose_untracked(path))
+       if (would_lose_untracked(o, path))
                return err(o, _("refusing to lose untracked file at '%s'"),
                           path);
 
@@ -986,7 +982,7 @@ static int update_file_flags(struct merge_options *o,
                }
                if (S_ISREG(mode)) {
                        struct strbuf strbuf = STRBUF_INIT;
-                       if (convert_to_working_tree(&the_index, path, buf, size, &strbuf)) {
+                       if (convert_to_working_tree(o->repo->index, path, buf, size, &strbuf)) {
                                free(buf);
                                size = strbuf.len;
                                buf = strbuf_detach(&strbuf, NULL);
@@ -1058,7 +1054,8 @@ static int merge_3way(struct merge_options *o,
                      const struct diff_filespec *a,
                      const struct diff_filespec *b,
                      const char *branch1,
-                     const char *branch2)
+                     const char *branch2,
+                     const int extra_marker_size)
 {
        mmfile_t orig, src1, src2;
        struct ll_merge_options ll_opts = {0};
@@ -1066,6 +1063,7 @@ static int merge_3way(struct merge_options *o,
        int merge_status;
 
        ll_opts.renormalize = o->renormalize;
+       ll_opts.extra_marker_size = extra_marker_size;
        ll_opts.xdl_opts = o->xdl_opts;
 
        if (o->call_depth) {
@@ -1104,7 +1102,7 @@ static int merge_3way(struct merge_options *o,
 
        merge_status = ll_merge(result_buf, a->path, &orig, base_name,
                                &src1, name1, &src2, name2,
-                               &the_index, &ll_opts);
+                               o->repo->index, &ll_opts);
 
        free(base_name);
        free(name1);
@@ -1115,7 +1113,8 @@ static int merge_3way(struct merge_options *o,
        return merge_status;
 }
 
-static int find_first_merges(struct object_array *result, const char *path,
+static int find_first_merges(struct repository *repo,
+                            struct object_array *result, const char *path,
                             struct commit *a, struct commit *b)
 {
        int i, j;
@@ -1135,7 +1134,7 @@ static int find_first_merges(struct object_array *result, const char *path,
        /* get all revisions that merge commit a */
        xsnprintf(merged_revision, sizeof(merged_revision), "^%s",
                  oid_to_hex(&a->object.oid));
-       repo_init_revisions(the_repository, &revs, NULL);
+       repo_init_revisions(repo, &revs, NULL);
        rev_opts.submodule = path;
        /* FIXME: can't handle linked worktrees in submodules yet */
        revs.single_worktree = path != NULL;
@@ -1213,9 +1212,9 @@ static int merge_submodule(struct merge_options *o,
                return 0;
        }
 
-       if (!(commit_base = lookup_commit_reference(the_repository, base)) ||
-           !(commit_a = lookup_commit_reference(the_repository, a)) ||
-           !(commit_b = lookup_commit_reference(the_repository, b))) {
+       if (!(commit_base = lookup_commit_reference(o->repo, base)) ||
+           !(commit_a = lookup_commit_reference(o->repo, a)) ||
+           !(commit_b = lookup_commit_reference(o->repo, b))) {
                output(o, 1, _("Failed to merge submodule %s (commits not present)"), path);
                return 0;
        }
@@ -1265,7 +1264,8 @@ static int merge_submodule(struct merge_options *o,
                return 0;
 
        /* find commit which merges them */
-       parent_count = find_first_merges(&merges, path, commit_a, commit_b);
+       parent_count = find_first_merges(o->repo, &merges, path,
+                                        commit_a, commit_b);
        switch (parent_count) {
        case 0:
                output(o, 1, _("Failed to merge submodule %s (merge following commits not found)"), path);
@@ -1301,6 +1301,7 @@ static int merge_mode_and_contents(struct merge_options *o,
                                   const char *filename,
                                   const char *branch1,
                                   const char *branch2,
+                                  const int extra_marker_size,
                                   struct merge_file_info *result)
 {
        if (o->branch1 != branch1) {
@@ -1311,7 +1312,8 @@ static int merge_mode_and_contents(struct merge_options *o,
                 */
                return merge_mode_and_contents(o, one, b, a,
                                               filename,
-                                              branch2, branch1, result);
+                                              branch2, branch1,
+                                              extra_marker_size, result);
        }
 
        result->merge = 0;
@@ -1352,7 +1354,8 @@ static int merge_mode_and_contents(struct merge_options *o,
                        int ret = 0, merge_status;
 
                        merge_status = merge_3way(o, &result_buf, one, a, b,
-                                                 branch1, branch2);
+                                                 branch1, branch2,
+                                                 extra_marker_size);
 
                        if ((merge_status < 0) || !result_buf.ptr)
                                ret = err(o, _("Failed to execute internal merge"));
@@ -1399,8 +1402,7 @@ static int merge_mode_and_contents(struct merge_options *o,
 
 static int handle_rename_via_dir(struct merge_options *o,
                                 struct diff_filepair *pair,
-                                const char *rename_branch,
-                                const char *other_branch)
+                                const char *rename_branch)
 {
        /*
         * Handle file adds that need to be renamed due to directory rename
@@ -1410,7 +1412,7 @@ static int handle_rename_via_dir(struct merge_options *o,
         */
        const struct diff_filespec *dest = pair->two;
 
-       if (!o->call_depth && would_lose_untracked(dest->path)) {
+       if (!o->call_depth && would_lose_untracked(o, dest->path)) {
                char *alt_path = unique_path(o, dest->path, rename_branch);
 
                output(o, 1, _("Error: Refusing to lose untracked file at %s; "
@@ -1448,8 +1450,8 @@ static int handle_change_delete(struct merge_options *o,
        const char *update_path = path;
        int ret = 0;
 
-       if (dir_in_way(path, !o->call_depth, 0) ||
-           (!o->call_depth && would_lose_untracked(path))) {
+       if (dir_in_way(o->repo->index, path, !o->call_depth, 0) ||
+           (!o->call_depth && would_lose_untracked(o, path))) {
                update_path = alt_path = unique_path(o, path, change_branch);
        }
 
@@ -1459,7 +1461,7 @@ static int handle_change_delete(struct merge_options *o,
                 * correct; since there is no true "middle point" between
                 * them, simply reuse the base version for virtual merge base.
                 */
-               ret = remove_file_from_cache(path);
+               ret = remove_file_from_index(o->repo->index, path);
                if (!ret)
                        ret = update_file(o, 0, o_oid, o_mode, update_path);
        } else {
@@ -1535,7 +1537,7 @@ static int handle_rename_delete(struct merge_options *o,
                return -1;
 
        if (o->call_depth)
-               return remove_file_from_cache(dest->path);
+               return remove_file_from_index(o->repo->index, dest->path);
        else
                return update_stages(o, dest->path, NULL,
                                     rename_branch == o->branch1 ? dest : NULL,
@@ -1555,80 +1557,203 @@ static struct diff_filespec *filespec_from_entry(struct diff_filespec *target,
        return target;
 }
 
-static int handle_file(struct merge_options *o,
-                       struct diff_filespec *rename,
-                       int stage,
-                       struct rename_conflict_info *ci)
+static int handle_file_collision(struct merge_options *o,
+                                const char *collide_path,
+                                const char *prev_path1,
+                                const char *prev_path2,
+                                const char *branch1, const char *branch2,
+                                const struct object_id *a_oid,
+                                unsigned int a_mode,
+                                const struct object_id *b_oid,
+                                unsigned int b_mode)
 {
-       char *dst_name = rename->path;
-       struct stage_data *dst_entry;
-       const char *cur_branch, *other_branch;
-       struct diff_filespec other;
-       struct diff_filespec *add;
-       int ret;
+       struct merge_file_info mfi;
+       struct diff_filespec null, a, b;
+       char *alt_path = NULL;
+       const char *update_path = collide_path;
 
-       if (stage == 2) {
-               dst_entry = ci->dst_entry1;
-               cur_branch = ci->branch1;
-               other_branch = ci->branch2;
-       } else {
-               dst_entry = ci->dst_entry2;
-               cur_branch = ci->branch2;
-               other_branch = ci->branch1;
+       /*
+        * It's easiest to get the correct things into stage 2 and 3, and
+        * to make sure that the content merge puts HEAD before the other
+        * branch if we just ensure that branch1 == o->branch1.  So, simply
+        * flip arguments around if we don't have that.
+        */
+       if (branch1 != o->branch1) {
+               return handle_file_collision(o, collide_path,
+                                            prev_path2, prev_path1,
+                                            branch2, branch1,
+                                            b_oid, b_mode,
+                                            a_oid, a_mode);
        }
 
-       add = filespec_from_entry(&other, dst_entry, stage ^ 1);
-       if (add) {
-               int ren_src_was_dirty = was_dirty(o, rename->path);
-               char *add_name = unique_path(o, rename->path, other_branch);
-               if (update_file(o, 0, &add->oid, add->mode, add_name))
-                       return -1;
+       /*
+        * In the recursive case, we just opt to undo renames
+        */
+       if (o->call_depth && (prev_path1 || prev_path2)) {
+               /* Put first file (a_oid, a_mode) in its original spot */
+               if (prev_path1) {
+                       if (update_file(o, 1, a_oid, a_mode, prev_path1))
+                               return -1;
+               } else {
+                       if (update_file(o, 1, a_oid, a_mode, collide_path))
+                               return -1;
+               }
 
-               if (ren_src_was_dirty) {
-                       output(o, 1, _("Refusing to lose dirty file at %s"),
-                              rename->path);
+               /* Put second file (b_oid, b_mode) in its original spot */
+               if (prev_path2) {
+                       if (update_file(o, 1, b_oid, b_mode, prev_path2))
+                               return -1;
+               } else {
+                       if (update_file(o, 1, b_oid, b_mode, collide_path))
+                               return -1;
                }
+
+               /* Don't leave something at collision path if unrenaming both */
+               if (prev_path1 && prev_path2)
+                       remove_file(o, 1, collide_path, 0);
+
+               return 0;
+       }
+
+       /* Remove rename sources if rename/add or rename/rename(2to1) */
+       if (prev_path1)
+               remove_file(o, 1, prev_path1,
+                           o->call_depth || would_lose_untracked(o, prev_path1));
+       if (prev_path2)
+               remove_file(o, 1, prev_path2,
+                           o->call_depth || would_lose_untracked(o, prev_path2));
+
+       /*
+        * Remove the collision path, if it wouldn't cause dirty contents
+        * or an untracked file to get lost.  We'll either overwrite with
+        * merged contents, or just write out to differently named files.
+        */
+       if (was_dirty(o, collide_path)) {
+               output(o, 1, _("Refusing to lose dirty file at %s"),
+                      collide_path);
+               update_path = alt_path = unique_path(o, collide_path, "merged");
+       } else if (would_lose_untracked(o, collide_path)) {
                /*
-                * Because the double negatives somehow keep confusing me...
-                *    1) update_wd iff !ren_src_was_dirty.
-                *    2) no_wd iff !update_wd
-                *    3) so, no_wd == !!ren_src_was_dirty == ren_src_was_dirty
+                * Only way we get here is if both renames were from
+                * a directory rename AND user had an untracked file
+                * at the location where both files end up after the
+                * two directory renames.  See testcase 10d of t6043.
                 */
-               remove_file(o, 0, rename->path, ren_src_was_dirty);
-               dst_name = unique_path(o, rename->path, cur_branch);
+               output(o, 1, _("Refusing to lose untracked file at "
+                              "%s, even though it's in the way."),
+                      collide_path);
+               update_path = alt_path = unique_path(o, collide_path, "merged");
        } else {
-               if (dir_in_way(rename->path, !o->call_depth, 0)) {
-                       dst_name = unique_path(o, rename->path, cur_branch);
-                       output(o, 1, _("%s is a directory in %s adding as %s instead"),
-                              rename->path, other_branch, dst_name);
-               } else if (!o->call_depth &&
-                          would_lose_untracked(rename->path)) {
-                       dst_name = unique_path(o, rename->path, cur_branch);
-                       output(o, 1, _("Refusing to lose untracked file at %s; "
-                                      "adding as %s instead"),
-                              rename->path, dst_name);
-               }
+               /*
+                * FIXME: It's possible that the two files are identical
+                * and that the current working copy happens to match, in
+                * which case we are unnecessarily touching the working
+                * tree file.  It's not a likely enough scenario that I
+                * want to code up the checks for it and a better fix is
+                * available if we restructure how unpack_trees() and
+                * merge-recursive interoperate anyway, so punting for
+                * now...
+                */
+               remove_file(o, 0, collide_path, 0);
        }
-       if ((ret = update_file(o, 0, &rename->oid, rename->mode, dst_name)))
-               ; /* fall through, do allow dst_name to be released */
-       else if (stage == 2)
-               ret = update_stages(o, rename->path, NULL, rename, add);
-       else
-               ret = update_stages(o, rename->path, NULL, add, rename);
 
-       if (dst_name != rename->path)
-               free(dst_name);
+       /* Store things in diff_filespecs for functions that need it */
+       memset(&a, 0, sizeof(struct diff_filespec));
+       memset(&b, 0, sizeof(struct diff_filespec));
+       null.path = a.path = b.path = (char *)collide_path;
+       oidcpy(&null.oid, &null_oid);
+       null.mode = 0;
+       oidcpy(&a.oid, a_oid);
+       a.mode = a_mode;
+       a.oid_valid = 1;
+       oidcpy(&b.oid, b_oid);
+       b.mode = b_mode;
+       b.oid_valid = 1;
 
-       return ret;
+       if (merge_mode_and_contents(o, &null, &a, &b, collide_path,
+                                   branch1, branch2, o->call_depth * 2, &mfi))
+               return -1;
+       mfi.clean &= !alt_path;
+       if (update_file(o, mfi.clean, &mfi.oid, mfi.mode, update_path))
+               return -1;
+       if (!mfi.clean && !o->call_depth &&
+           update_stages(o, collide_path, NULL, &a, &b))
+               return -1;
+       free(alt_path);
+       /*
+        * FIXME: If both a & b both started with conflicts (only possible
+        * if they came from a rename/rename(2to1)), but had IDENTICAL
+        * contents including those conflicts, then in the next line we claim
+        * it was clean.  If someone cares about this case, we should have the
+        * caller notify us if we started with conflicts.
+        */
+       return mfi.clean;
+}
+
+static int handle_rename_add(struct merge_options *o,
+                            struct rename_conflict_info *ci)
+{
+       /* a was renamed to c, and a separate c was added. */
+       struct diff_filespec *a = ci->pair1->one;
+       struct diff_filespec *c = ci->pair1->two;
+       char *path = c->path;
+       char *prev_path_desc;
+       struct merge_file_info mfi;
+
+       int other_stage = (ci->branch1 == o->branch1 ? 3 : 2);
+
+       output(o, 1, _("CONFLICT (rename/add): "
+              "Rename %s->%s in %s.  Added %s in %s"),
+              a->path, c->path, ci->branch1,
+              c->path, ci->branch2);
+
+       prev_path_desc = xstrfmt("version of %s from %s", path, a->path);
+       if (merge_mode_and_contents(o, a, c, &ci->ren1_other, prev_path_desc,
+                                   o->branch1, o->branch2,
+                                   1 + o->call_depth * 2, &mfi))
+               return -1;
+       free(prev_path_desc);
+
+       return handle_file_collision(o,
+                                    c->path, a->path, NULL,
+                                    ci->branch1, ci->branch2,
+                                    &mfi.oid, mfi.mode,
+                                    &ci->dst_entry1->stages[other_stage].oid,
+                                    ci->dst_entry1->stages[other_stage].mode);
+}
+
+static char *find_path_for_conflict(struct merge_options *o,
+                                   const char *path,
+                                   const char *branch1,
+                                   const char *branch2)
+{
+       char *new_path = NULL;
+       if (dir_in_way(o->repo->index, path, !o->call_depth, 0)) {
+               new_path = unique_path(o, path, branch1);
+               output(o, 1, _("%s is a directory in %s adding "
+                              "as %s instead"),
+                      path, branch2, new_path);
+       } else if (would_lose_untracked(o, path)) {
+               new_path = unique_path(o, path, branch1);
+               output(o, 1, _("Refusing to lose untracked file"
+                              " at %s; adding as %s instead"),
+                      path, new_path);
+       }
+
+       return new_path;
 }
 
 static int handle_rename_rename_1to2(struct merge_options *o,
                                     struct rename_conflict_info *ci)
 {
        /* One file was renamed in both branches, but to different names. */
+       struct merge_file_info mfi;
+       struct diff_filespec other;
+       struct diff_filespec *add;
        struct diff_filespec *one = ci->pair1->one;
        struct diff_filespec *a = ci->pair1->two;
        struct diff_filespec *b = ci->pair2->two;
+       char *path_desc;
 
        output(o, 1, _("CONFLICT (rename/rename): "
               "Rename \"%s\"->\"%s\" in branch \"%s\" "
@@ -1636,14 +1761,16 @@ static int handle_rename_rename_1to2(struct merge_options *o,
               one->path, a->path, ci->branch1,
               one->path, b->path, ci->branch2,
               o->call_depth ? _(" (left unresolved)") : "");
-       if (o->call_depth) {
-               struct merge_file_info mfi;
-               struct diff_filespec other;
-               struct diff_filespec *add;
-               if (merge_mode_and_contents(o, one, a, b, one->path,
-                                           ci->branch1, ci->branch2, &mfi))
-                       return -1;
 
+       path_desc = xstrfmt("%s and %s, both renamed from %s",
+                           a->path, b->path, one->path);
+       if (merge_mode_and_contents(o, one, a, b, path_desc,
+                                   ci->branch1, ci->branch2,
+                                   o->call_depth * 2, &mfi))
+               return -1;
+       free(path_desc);
+
+       if (o->call_depth) {
                /*
                 * FIXME: For rename/add-source conflicts (if we could detect
                 * such), this is wrong.  We should instead find a unique
@@ -1667,16 +1794,58 @@ static int handle_rename_rename_1to2(struct merge_options *o,
                                return -1;
                }
                else
-                       remove_file_from_cache(a->path);
+                       remove_file_from_index(o->repo->index, a->path);
                add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1);
                if (add) {
                        if (update_file(o, 0, &add->oid, add->mode, b->path))
                                return -1;
                }
                else
-                       remove_file_from_cache(b->path);
-       } else if (handle_file(o, a, 2, ci) || handle_file(o, b, 3, ci))
-               return -1;
+                       remove_file_from_index(o->repo->index, b->path);
+       } else {
+               /*
+                * For each destination path, we need to see if there is a
+                * rename/add collision.  If not, we can write the file out
+                * to the specified location.
+                */
+               add = filespec_from_entry(&other, ci->dst_entry1, 2 ^ 1);
+               if (add) {
+                       if (handle_file_collision(o, a->path,
+                                                 NULL, NULL,
+                                                 ci->branch1, ci->branch2,
+                                                 &mfi.oid, mfi.mode,
+                                                 &add->oid, add->mode) < 0)
+                               return -1;
+               } else {
+                       char *new_path = find_path_for_conflict(o, a->path,
+                                                               ci->branch1,
+                                                               ci->branch2);
+                       if (update_file(o, 0, &mfi.oid, mfi.mode, new_path ? new_path : a->path))
+                               return -1;
+                       free(new_path);
+                       if (update_stages(o, a->path, NULL, a, NULL))
+                               return -1;
+               }
+
+               add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1);
+               if (add) {
+                       if (handle_file_collision(o, b->path,
+                                                 NULL, NULL,
+                                                 ci->branch1, ci->branch2,
+                                                 &add->oid, add->mode,
+                                                 &mfi.oid, mfi.mode) < 0)
+                               return -1;
+               } else {
+                       char *new_path = find_path_for_conflict(o, b->path,
+                                                               ci->branch2,
+                                                               ci->branch1);
+                       if (update_file(o, 0, &mfi.oid, mfi.mode, new_path ? new_path : b->path))
+                               return -1;
+                       free(new_path);
+                       if (update_stages(o, b->path, NULL, NULL, b))
+                               return -1;
+               }
+       }
 
        return 0;
 }
@@ -1694,7 +1863,6 @@ static int handle_rename_rename_2to1(struct merge_options *o,
        char *path_side_2_desc;
        struct merge_file_info mfi_c1;
        struct merge_file_info mfi_c2;
-       int ret;
 
        output(o, 1, _("CONFLICT (rename/rename): "
               "Rename %s->%s in %s. "
@@ -1702,79 +1870,22 @@ static int handle_rename_rename_2to1(struct merge_options *o,
               a->path, c1->path, ci->branch1,
               b->path, c2->path, ci->branch2);
 
-       remove_file(o, 1, a->path, o->call_depth || would_lose_untracked(a->path));
-       remove_file(o, 1, b->path, o->call_depth || would_lose_untracked(b->path));
-
        path_side_1_desc = xstrfmt("version of %s from %s", path, a->path);
        path_side_2_desc = xstrfmt("version of %s from %s", path, b->path);
        if (merge_mode_and_contents(o, a, c1, &ci->ren1_other, path_side_1_desc,
-                                   o->branch1, o->branch2, &mfi_c1) ||
+                                   o->branch1, o->branch2,
+                                   1 + o->call_depth * 2, &mfi_c1) ||
            merge_mode_and_contents(o, b, &ci->ren2_other, c2, path_side_2_desc,
-                                   o->branch1, o->branch2, &mfi_c2))
+                                   o->branch1, o->branch2,
+                                   1 + o->call_depth * 2, &mfi_c2))
                return -1;
        free(path_side_1_desc);
        free(path_side_2_desc);
 
-       if (o->call_depth) {
-               /*
-                * If mfi_c1.clean && mfi_c2.clean, then it might make
-                * sense to do a two-way merge of those results.  But, I
-                * think in all cases, it makes sense to have the virtual
-                * merge base just undo the renames; they can be detected
-                * again later for the non-recursive merge.
-                */
-               remove_file(o, 0, path, 0);
-               ret = update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, a->path);
-               if (!ret)
-                       ret = update_file(o, 0, &mfi_c2.oid, mfi_c2.mode,
-                                         b->path);
-       } else {
-               char *new_path1 = unique_path(o, path, ci->branch1);
-               char *new_path2 = unique_path(o, path, ci->branch2);
-               output(o, 1, _("Renaming %s to %s and %s to %s instead"),
-                      a->path, new_path1, b->path, new_path2);
-               if (was_dirty(o, path))
-                       output(o, 1, _("Refusing to lose dirty file at %s"),
-                              path);
-               else if (would_lose_untracked(path))
-                       /*
-                        * Only way we get here is if both renames were from
-                        * a directory rename AND user had an untracked file
-                        * at the location where both files end up after the
-                        * two directory renames.  See testcase 10d of t6043.
-                        */
-                       output(o, 1, _("Refusing to lose untracked file at "
-                                      "%s, even though it's in the way."),
-                              path);
-               else
-                       remove_file(o, 0, path, 0);
-               ret = update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, new_path1);
-               if (!ret)
-                       ret = update_file(o, 0, &mfi_c2.oid, mfi_c2.mode,
-                                         new_path2);
-               /*
-                * unpack_trees() actually populates the index for us for
-                * "normal" rename/rename(2to1) situtations so that the
-                * correct entries are at the higher stages, which would
-                * make the call below to update_stages_for_stage_data
-                * unnecessary.  However, if either of the renames came
-                * from a directory rename, then unpack_trees() will not
-                * have gotten the right data loaded into the index, so we
-                * need to do so now.  (While it'd be tempting to move this
-                * call to update_stages_for_stage_data() to
-                * apply_directory_rename_modifications(), that would break
-                * our intermediate calls to would_lose_untracked() since
-                * those rely on the current in-memory index.  See also the
-                * big "NOTE" in update_stages()).
-                */
-               if (update_stages_for_stage_data(o, path, ci->dst_entry1))
-                       ret = -1;
-
-               free(new_path2);
-               free(new_path1);
-       }
-
-       return ret;
+       return handle_file_collision(o, path, a->path, b->path,
+                                    ci->branch1, ci->branch2,
+                                    &mfi_c1.oid, mfi_c1.mode,
+                                    &mfi_c2.oid, mfi_c2.mode);
 }
 
 /*
@@ -1787,7 +1898,7 @@ static struct diff_queue_struct *get_diffpairs(struct merge_options *o,
        struct diff_queue_struct *ret;
        struct diff_options opts;
 
-       repo_diff_setup(the_repository, &opts);
+       repo_diff_setup(o->repo, &opts);
        opts.flags.recursive = 1;
        opts.flags.rename_empty = 0;
        opts.detect_rename = merge_detect_rename(o);
@@ -2101,8 +2212,7 @@ static void handle_directory_level_conflicts(struct merge_options *o,
        remove_hashmap_entries(dir_re_merge, &remove_from_merge);
 }
 
-static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs,
-                                            struct tree *tree)
+static struct hashmap *get_directory_renames(struct diff_queue_struct *pairs)
 {
        struct hashmap *dir_renames;
        struct hashmap_iter iter;
@@ -2348,8 +2458,7 @@ static void apply_directory_rename_modifications(struct merge_options *o,
                                                 struct tree *o_tree,
                                                 struct tree *a_tree,
                                                 struct tree *b_tree,
-                                                struct string_list *entries,
-                                                int *clean)
+                                                struct string_list *entries)
 {
        struct string_list_item *item;
        int stage = (tree == a_tree ? 2 : 3);
@@ -2520,8 +2629,7 @@ static struct string_list *get_renames(struct merge_options *o,
                        apply_directory_rename_modifications(o, pair, new_path,
                                                             re, tree, o_tree,
                                                             a_tree, b_tree,
-                                                            entries,
-                                                            clean_merge);
+                                                            entries);
        }
 
        hashmap_iter_init(&collisions, &iter);
@@ -2732,47 +2840,23 @@ static int process_renames(struct merge_options *o,
                                                      0  /* update_wd    */))
                                        clean_merge = -1;
                        } else if (!oid_eq(&dst_other.oid, &null_oid)) {
-                               clean_merge = 0;
-                               try_merge = 1;
-                               output(o, 1, _("CONFLICT (rename/add): Rename %s->%s in %s. "
-                                      "%s added in %s"),
-                                      ren1_src, ren1_dst, branch1,
-                                      ren1_dst, branch2);
-                               if (o->call_depth) {
-                                       struct merge_file_info mfi;
-                                       struct diff_filespec one, a, b;
-
-                                       oidcpy(&one.oid, &null_oid);
-                                       one.mode = 0;
-                                       one.path = ren1->pair->two->path;
-
-                                       oidcpy(&a.oid, &ren1->pair->two->oid);
-                                       a.mode = ren1->pair->two->mode;
-                                       a.path = one.path;
-
-                                       oidcpy(&b.oid, &dst_other.oid);
-                                       b.mode = dst_other.mode;
-                                       b.path = one.path;
-
-                                       if (merge_mode_and_contents(o, &one, &a, &b, ren1_dst,
-                                                                   branch1, branch2,
-                                                                   &mfi)) {
-                                               clean_merge = -1;
-                                               goto cleanup_and_return;
-                                       }
-                                       output(o, 1, _("Adding merged %s"), ren1_dst);
-                                       if (update_file(o, 0, &mfi.oid,
-                                                       mfi.mode, ren1_dst))
-                                               clean_merge = -1;
-                                       try_merge = 0;
-                               } else {
-                                       char *new_path = unique_path(o, ren1_dst, branch2);
-                                       output(o, 1, _("Adding as %s instead"), new_path);
-                                       if (update_file(o, 0, &dst_other.oid,
-                                                       dst_other.mode, new_path))
-                                               clean_merge = -1;
-                                       free(new_path);
-                               }
+                               /*
+                                * Probably not a clean merge, but it's
+                                * premature to set clean_merge to 0 here,
+                                * because if the rename merges cleanly and
+                                * the merge exactly matches the newly added
+                                * file, then the merge will be clean.
+                                */
+                               setup_rename_conflict_info(RENAME_ADD,
+                                                          ren1->pair,
+                                                          NULL,
+                                                          branch1,
+                                                          branch2,
+                                                          ren1->dst_entry,
+                                                          NULL,
+                                                          o,
+                                                          ren1->src_entry,
+                                                          NULL);
                        } else
                                try_merge = 1;
 
@@ -2856,8 +2940,8 @@ static int detect_and_process_renames(struct merge_options *o,
        merge_pairs = get_diffpairs(o, common, merge);
 
        if (o->detect_directory_renames) {
-               dir_re_head = get_directory_renames(head_pairs, head);
-               dir_re_merge = get_directory_renames(merge_pairs, merge);
+               dir_re_head = get_directory_renames(head_pairs);
+               dir_re_merge = get_directory_renames(merge_pairs);
 
                handle_directory_level_conflicts(o,
                                                 dir_re_head, head,
@@ -2966,8 +3050,8 @@ static int blob_unchanged(struct merge_options *opt,
         * performed.  Comparison can be skipped if both files are
         * unchanged since their sha1s have already been compared.
         */
-       if (renormalize_buffer(&the_index, path, o.buf, o.len, &o) |
-           renormalize_buffer(&the_index, path, a.buf, a.len, &a))
+       if (renormalize_buffer(opt->repo->index, path, o.buf, o.len, &o) |
+           renormalize_buffer(opt->repo->index, path, a.buf, a.len, &a))
                ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len));
 
 error_return:
@@ -3048,12 +3132,13 @@ static int handle_content_merge(struct merge_options *o,
                a.path = (char *)path1;
                b.path = (char *)path2;
 
-               if (dir_in_way(path, !o->call_depth,
+               if (dir_in_way(o->repo->index, path, !o->call_depth,
                               S_ISGITLINK(pair1->two->mode)))
                        df_conflict_remains = 1;
        }
        if (merge_mode_and_contents(o, &one, &a, &b, path,
-                                   o->branch1, o->branch2, &mfi))
+                                   o->branch1, o->branch2,
+                                   o->call_depth * 2, &mfi))
                return -1;
 
        /*
@@ -3081,8 +3166,8 @@ static int handle_content_merge(struct merge_options *o,
                pos = index_name_pos(&o->orig_index, path, strlen(path));
                ce = o->orig_index.cache[pos];
                if (ce_skip_worktree(ce)) {
-                       pos = index_name_pos(&the_index, path, strlen(path));
-                       ce = the_index.cache[pos];
+                       pos = index_name_pos(o->repo->index, path, strlen(path));
+                       ce = o->repo->index->cache[pos];
                        ce->ce_flags |= CE_SKIP_WORKTREE;
                }
                return mfi.clean;
@@ -3101,7 +3186,7 @@ static int handle_content_merge(struct merge_options *o,
        if (df_conflict_remains || is_dirty) {
                char *new_path;
                if (o->call_depth) {
-                       remove_file_from_cache(path);
+                       remove_file_from_index(o->repo->index, path);
                } else {
                        if (!mfi.clean) {
                                if (update_stages(o, path, &one, &a, &b))
@@ -3179,10 +3264,18 @@ static int process_entry(struct merge_options *o,
                        clean_merge = 1;
                        if (handle_rename_via_dir(o,
                                                  conflict_info->pair1,
-                                                 conflict_info->branch1,
-                                                 conflict_info->branch2))
+                                                 conflict_info->branch1))
                                clean_merge = -1;
                        break;
+               case RENAME_ADD:
+                       /*
+                        * Probably unclean merge, but if the renamed file
+                        * merges cleanly and the result can then be
+                        * two-way merged cleanly with the added file, I
+                        * guess it's a clean merge?
+                        */
+                       clean_merge = handle_rename_add(o, conflict_info);
+                       break;
                case RENAME_DELETE:
                        clean_merge = 0;
                        if (handle_rename_delete(o,
@@ -3197,9 +3290,14 @@ static int process_entry(struct merge_options *o,
                                clean_merge = -1;
                        break;
                case RENAME_TWO_FILES_TO_ONE:
-                       clean_merge = 0;
-                       if (handle_rename_rename_2to1(o, conflict_info))
-                               clean_merge = -1;
+                       /*
+                        * Probably unclean merge, but if the two renamed
+                        * files merge cleanly and the two resulting files
+                        * can then be two-way merged cleanly, I guess it's
+                        * a clean merge?
+                        */
+                       clean_merge = handle_rename_rename_2to1(o,
+                                                               conflict_info);
                        break;
                default:
                        entry->processed = 0;
@@ -3247,7 +3345,7 @@ static int process_entry(struct merge_options *o,
                        oid = b_oid;
                        conf = _("directory/file");
                }
-               if (dir_in_way(path,
+               if (dir_in_way(o->repo->index, path,
                               !o->call_depth && !S_ISGITLINK(a_mode),
                               0)) {
                        char *new_path = unique_path(o, path, add_branch);
@@ -3258,7 +3356,7 @@ static int process_entry(struct merge_options *o,
                        if (update_file(o, 0, oid, mode, new_path))
                                clean_merge = -1;
                        else if (o->call_depth)
-                               remove_file_from_cache(path);
+                               remove_file_from_index(o->repo->index, path);
                        free(new_path);
                } else {
                        output(o, 2, _("Adding %s"), path);
@@ -3267,14 +3365,27 @@ static int process_entry(struct merge_options *o,
                                clean_merge = -1;
                }
        } else if (a_oid && b_oid) {
-               /* Case C: Added in both (check for same permissions) and */
-               /* case D: Modified in both, but differently. */
-               int is_dirty = 0; /* unpack_trees would have bailed if dirty */
-               clean_merge = handle_content_merge(o, path, is_dirty,
-                                                  o_oid, o_mode,
-                                                  a_oid, a_mode,
-                                                  b_oid, b_mode,
-                                                  NULL);
+               if (!o_oid) {
+                       /* Case C: Added in both (check for same permissions) */
+                       output(o, 1,
+                              _("CONFLICT (add/add): Merge conflict in %s"),
+                              path);
+                       clean_merge = handle_file_collision(o,
+                                                           path, NULL, NULL,
+                                                           o->branch1,
+                                                           o->branch2,
+                                                           a_oid, a_mode,
+                                                           b_oid, b_mode);
+               } else {
+                       /* case D: Modified in both, but differently. */
+                       int is_dirty = 0; /* unpack_trees would have bailed if dirty */
+                       clean_merge = handle_content_merge(o, path,
+                                                          is_dirty,
+                                                          o_oid, o_mode,
+                                                          a_oid, a_mode,
+                                                          b_oid, b_mode,
+                                                          NULL);
+               }
        } else if (!o_oid && !a_oid && !b_oid) {
                /*
                 * this entry was deleted altogether. a_mode == 0 means
@@ -3293,18 +3404,19 @@ int merge_trees(struct merge_options *o,
                struct tree *common,
                struct tree **result)
 {
+       struct index_state *istate = o->repo->index;
        int code, clean;
        struct strbuf sb = STRBUF_INIT;
 
-       if (!o->call_depth && index_has_changes(&the_index, head, &sb)) {
+       if (!o->call_depth && repo_index_has_changes(o->repo, head, &sb)) {
                err(o, _("Your local changes to the following files would be overwritten by merge:\n  %s"),
                    sb.buf);
                return -1;
        }
 
        if (o->subtree_shift) {
-               merge = shift_tree_object(head, merge, o->subtree_shift);
-               common = shift_tree_object(head, common, o->subtree_shift);
+               merge = shift_tree_object(o->repo, head, merge, o->subtree_shift);
+               common = shift_tree_object(o->repo, head, common, o->subtree_shift);
        }
 
        if (oid_eq(&common->object.oid, &merge->object.oid)) {
@@ -3324,7 +3436,7 @@ int merge_trees(struct merge_options *o,
                return -1;
        }
 
-       if (unmerged_cache()) {
+       if (unmerged_index(istate)) {
                struct string_list *entries;
                struct rename_info re_info;
                int i;
@@ -3339,7 +3451,7 @@ int merge_trees(struct merge_options *o,
                get_files_dirs(o, head);
                get_files_dirs(o, merge);
 
-               entries = get_unmerged();
+               entries = get_unmerged(o->repo->index);
                clean = detect_and_process_renames(o, common, head, merge,
                                                   entries, &re_info);
                record_df_conflict_files(o, entries);
@@ -3440,8 +3552,8 @@ int merge_recursive(struct merge_options *o,
                /* if there is no common ancestor, use an empty tree */
                struct tree *tree;
 
-               tree = lookup_tree(the_repository, the_repository->hash_algo->empty_tree);
-               merged_common_ancestors = make_virtual_commit(tree, "ancestor");
+               tree = lookup_tree(o->repo, o->repo->hash_algo->empty_tree);
+               merged_common_ancestors = make_virtual_commit(o->repo, tree, "ancestor");
        }
 
        for (iter = ca; iter; iter = iter->next) {
@@ -3455,7 +3567,7 @@ int merge_recursive(struct merge_options *o,
                 * overwritten it: the committed "conflicts" were
                 * already resolved.
                 */
-               discard_cache();
+               discard_index(o->repo->index);
                saved_b1 = o->branch1;
                saved_b2 = o->branch2;
                o->branch1 = "Temporary merge branch 1";
@@ -3471,9 +3583,9 @@ int merge_recursive(struct merge_options *o,
                        return err(o, _("merge returned no commit"));
        }
 
-       discard_cache();
+       discard_index(o->repo->index);
        if (!o->call_depth)
-               read_cache();
+               repo_read_index(o->repo);
 
        o->ancestor = "merged common ancestors";
        clean = merge_trees(o, get_commit_tree(h1), get_commit_tree(h2),
@@ -3485,7 +3597,7 @@ int merge_recursive(struct merge_options *o,
        }
 
        if (o->call_depth) {
-               *result = make_virtual_commit(mrtree, "merged tree");
+               *result = make_virtual_commit(o->repo, mrtree, "merged tree");
                commit_list_insert(h1, &(*result)->parents);
                commit_list_insert(h2, &(*result)->parents->next);
        }
@@ -3498,17 +3610,17 @@ int merge_recursive(struct merge_options *o,
        return clean;
 }
 
-static struct commit *get_ref(const struct object_id *oid, const char *name)
+static struct commit *get_ref(struct repository *repo, const struct object_id *oid,
+                             const char *name)
 {
        struct object *object;
 
-       object = deref_tag(the_repository, parse_object(the_repository, oid),
-                          name,
-                          strlen(name));
+       object = deref_tag(repo, parse_object(repo, oid),
+                          name, strlen(name));
        if (!object)
                return NULL;
        if (object->type == OBJ_TREE)
-               return make_virtual_commit((struct tree*)object, name);
+               return make_virtual_commit(repo, (struct tree*)object, name);
        if (object->type != OBJ_COMMIT)
                return NULL;
        if (parse_commit((struct commit *)object))
@@ -3525,22 +3637,22 @@ int merge_recursive_generic(struct merge_options *o,
 {
        int clean;
        struct lock_file lock = LOCK_INIT;
-       struct commit *head_commit = get_ref(head, o->branch1);
-       struct commit *next_commit = get_ref(merge, o->branch2);
+       struct commit *head_commit = get_ref(o->repo, head, o->branch1);
+       struct commit *next_commit = get_ref(o->repo, merge, o->branch2);
        struct commit_list *ca = NULL;
 
        if (base_list) {
                int i;
                for (i = 0; i < num_base_list; ++i) {
                        struct commit *base;
-                       if (!(base = get_ref(base_list[i], oid_to_hex(base_list[i]))))
+                       if (!(base = get_ref(o->repo, base_list[i], oid_to_hex(base_list[i]))))
                                return err(o, _("Could not parse object '%s'"),
                                           oid_to_hex(base_list[i]));
                        commit_list_insert(base, &ca);
                }
        }
 
-       hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
+       repo_hold_locked_index(o->repo, &lock, LOCK_DIE_ON_ERROR);
        clean = merge_recursive(o, head_commit, next_commit, ca,
                                result);
        if (clean < 0) {
@@ -3548,7 +3660,7 @@ int merge_recursive_generic(struct merge_options *o,
                return clean;
        }
 
-       if (write_locked_index(&the_index, &lock,
+       if (write_locked_index(o->repo->index, &lock,
                               COMMIT_LOCK | SKIP_IF_UNCHANGED))
                return err(o, _("Unable to write index."));
 
@@ -3572,10 +3684,12 @@ static void merge_recursive_config(struct merge_options *o)
        git_config(git_xmerge_config, NULL);
 }
 
-void init_merge_options(struct merge_options *o)
+void init_merge_options(struct merge_options *o,
+                       struct repository *repo)
 {
        const char *merge_verbosity;
        memset(o, 0, sizeof(struct merge_options));
+       o->repo = repo;
        o->verbosity = 2;
        o->buffer_output = 1;
        o->diff_rename_limit = -1;
@@ -3645,6 +3759,10 @@ int parse_merge_opt(struct merge_options *o, const char *s)
                        return -1;
                o->merge_detect_rename = 1;
        }
+       /*
+        * Please update $__git_merge_strategy_options in
+        * git-completion.bash when you add new options
+        */
        else
                return -1;
        return 0;