diff --git a/builtin/checkout.c b/builtin/checkout.c
index 20e38c5edc..a7b6454061 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -709,6 +709,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
 			 * whether the merge flag was used.
 			 */
 			struct tree *work;
+			struct object_id work_oid;
 			struct tree *old_tree;
 			struct merge_options o;
 			struct strbuf sb = STRBUF_INIT;
@@ -759,7 +760,10 @@ static int merge_working_tree(const struct checkout_opts *opts,
 			 */
 			init_merge_options(&o, the_repository);
 			o.verbosity = 0;
-			work = write_tree_from_memory(&o);
+			if (write_index_as_tree(&work_oid, &the_index, NULL,
+					WRITE_TREE_FROM_MEMORY, NULL) ||
+			    !(work = lookup_tree(the_repository, &work_oid)))
+				die(_("error building trees"));
 
 			ret = reset_tree(new_tree,
 					 opts, 1,
diff --git a/cache-tree.c b/cache-tree.c
index 706ffcf188..99144b1704 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -613,14 +613,19 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
 	int entries, was_valid;
 	struct lock_file lock_file = LOCK_INIT;
 	int ret = 0;
+	int access_disk = !(flags & WRITE_TREE_FROM_MEMORY);
 
-	hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
+	if (access_disk) {
+		hold_lock_file_for_update(&lock_file, index_path,
+					  LOCK_DIE_ON_ERROR);
 
-	entries = read_index_from(index_state, index_path, get_git_dir());
-	if (entries < 0) {
-		ret = WRITE_TREE_UNREADABLE_INDEX;
-		goto out;
+		entries = read_index_from(index_state, index_path, get_git_dir());
+		if (entries < 0) {
+			ret = WRITE_TREE_UNREADABLE_INDEX;
+			goto out;
+		}
 	}
+
 	if (flags & WRITE_TREE_IGNORE_CACHE_TREE)
 		cache_tree_free(&index_state->cache_tree);
 
@@ -633,13 +638,16 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
 			ret = WRITE_TREE_UNMERGED_INDEX;
 			goto out;
 		}
-		write_locked_index(index_state, &lock_file, COMMIT_LOCK);
-		/* Not being able to write is fine -- we are only interested
-		 * in updating the cache-tree part, and if the next caller
-		 * ends up using the old index with unupdated cache-tree part
-		 * it misses the work we did here, but that is just a
-		 * performance penalty and not a big deal.
-		 */
+		if (access_disk) {
+			write_locked_index(index_state, &lock_file, COMMIT_LOCK);
+			/* Not being able to write is fine -- we are only
+			 * interested in updating the cache-tree part, and if
+			 * the next caller ends up using the old index with
+			 * unupdated cache-tree part it misses the work we
+			 * did here, but that is just a performance penalty
+			 * and not a big deal.
+			 */
+		}
 	}
 
 	if (prefix) {
@@ -655,7 +663,9 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
 		oidcpy(oid, &index_state->cache_tree->oid);
 
 out:
-	rollback_lock_file(&lock_file);
+	if (access_disk)
+		rollback_lock_file(&lock_file);
+
 	return ret;
 }
 
diff --git a/cache-tree.h b/cache-tree.h
index 757bbc48bc..481ec45dfa 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -34,12 +34,13 @@ int cache_tree_fully_valid(struct cache_tree *);
 int cache_tree_update(struct index_state *, int);
 void cache_tree_verify(struct repository *, struct index_state *);
 
-/* bitmasks to write_cache_as_tree flags */
+/* bitmasks to write_index_as_tree flags */
 #define WRITE_TREE_MISSING_OK 1
 #define WRITE_TREE_IGNORE_CACHE_TREE 2
 #define WRITE_TREE_DRY_RUN 4
 #define WRITE_TREE_SILENT 8
 #define WRITE_TREE_REPAIR 16
+#define WRITE_TREE_FROM_MEMORY 32
 
 /* error return codes */
 #define WRITE_TREE_UNREADABLE_INDEX (-1)
diff --git a/merge-recursive.c b/merge-recursive.c
index 308e350ff1..6c38c02e3f 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -412,37 +412,6 @@ static void unpack_trees_finish(struct merge_options *opt)
 	clear_unpack_trees_porcelain(&opt->unpack_opts);
 }
 
-struct tree *write_tree_from_memory(struct merge_options *opt)
-{
-	struct tree *result = NULL;
-	struct index_state *istate = opt->repo->index;
-
-	if (unmerged_index(istate)) {
-		int i;
-		fprintf(stderr, "BUG: There are unmerged index entries:\n");
-		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);
-		}
-		BUG("unmerged index entries in merge-recursive.c");
-	}
-
-	if (!istate->cache_tree)
-		istate->cache_tree = cache_tree();
-
-	if (!cache_tree_fully_valid(istate->cache_tree) &&
-	    cache_tree_update(istate, 0) < 0) {
-		err(opt, _("error building trees"));
-		return NULL;
-	}
-
-	result = lookup_tree(opt->repo, &istate->cache_tree->oid);
-
-	return result;
-}
-
 static int save_files_dirs(const struct object_id *oid,
 			   struct strbuf *base, const char *path,
 			   unsigned int mode, int stage, void *context)
@@ -3471,8 +3440,15 @@ static int merge_trees_internal(struct merge_options *opt,
 
 	unpack_trees_finish(opt);
 
-	if (opt->call_depth && !(*result = write_tree_from_memory(opt)))
-		return -1;
+	if (opt->call_depth) {
+		struct object_id tree_id;
+		if (write_index_as_tree(&tree_id, opt->repo->index, NULL,
+					WRITE_TREE_FROM_MEMORY, NULL) ||
+		    !(*result = lookup_tree(opt->repo, &tree_id))) {
+			err(opt, _("error building trees"));
+			return -1;
+		}
+	}
 
 	return clean;
 }
diff --git a/merge-recursive.h b/merge-recursive.h
index 812c456f1b..b3394502c7 100644
--- a/merge-recursive.h
+++ b/merge-recursive.h
@@ -109,7 +109,6 @@ int merge_recursive_generic(struct merge_options *o,
 
 void init_merge_options(struct merge_options *o,
 			struct repository *repo);
-struct tree *write_tree_from_memory(struct merge_options *o);
 
 int parse_merge_opt(struct merge_options *out, const char *s);
 
