diff mbox series

[7/7] checkout: allow "checkout -m path" to unmerge removed paths

Message ID 20230731224409.4181277-8-gitster@pobox.com (mailing list archive)
State Accepted
Commit 5bdedac3c7b0894643256304cd5f0dd29cf8eec9
Headers show
Series unresolve removal | expand

Commit Message

Junio C Hamano July 31, 2023, 10:44 p.m. UTC
"git checkout -m -- path" uses the unmerge_marked_index() API, whose
implementation is incapable of unresolving a path that was resolved
as removed.  Extend the unmerge_index() API function so that we can
mark the ce_flags member of the cache entries we add to the index as
unmerged, and replace use of unmerge_marked_index() with it.

Now, together with its unmerge_index_entry_at() helper function,
unmerge_marked_index() function is no longer called by anybody, and
can safely be removed.

This makes two known test failures in t2070 and t7201 to succeed.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/checkout.c     |  6 ++--
 builtin/update-index.c |  2 +-
 rerere.c               |  2 +-
 resolve-undo.c         | 75 +++---------------------------------------
 resolve-undo.h         |  6 ++--
 t/t2070-restore.sh     |  2 +-
 t/t7201-co.sh          |  2 +-
 7 files changed, 13 insertions(+), 82 deletions(-)
diff mbox series

Patch

diff --git a/builtin/checkout.c b/builtin/checkout.c
index b8dfba57c6..98fcf1220a 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -566,6 +566,8 @@  static int checkout_paths(const struct checkout_opts *opts,
 
 	if (opts->source_tree)
 		read_tree_some(opts->source_tree, &opts->pathspec);
+	if (opts->merge)
+		unmerge_index(&the_index, &opts->pathspec, CE_MATCHED);
 
 	ps_matched = xcalloc(opts->pathspec.nr, 1);
 
@@ -589,10 +591,6 @@  static int checkout_paths(const struct checkout_opts *opts,
 	}
 	free(ps_matched);
 
-	/* "checkout -m path" to recreate conflicted state */
-	if (opts->merge)
-		unmerge_marked_index(&the_index);
-
 	/* Any unmerged paths? */
 	for (pos = 0; pos < the_index.cache_nr; pos++) {
 		const struct cache_entry *ce = the_index.cache[pos];
diff --git a/builtin/update-index.c b/builtin/update-index.c
index def7f98504..69fe9c8fcb 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -646,7 +646,7 @@  static int unresolve_one(const char *path)
 	item = string_list_lookup(the_index.resolve_undo, path);
 	if (!item)
 		return res; /* no resolve-undo record for the path */
-	res = unmerge_index_entry(&the_index, path, item->util);
+	res = unmerge_index_entry(&the_index, path, item->util, 0);
 	FREE_AND_NULL(item->util);
 	return res;
 }
diff --git a/rerere.c b/rerere.c
index e968d413d6..b525dd9230 100644
--- a/rerere.c
+++ b/rerere.c
@@ -1112,7 +1112,7 @@  int rerere_forget(struct repository *r, struct pathspec *pathspec)
 	 * recover the original conflicted state and then
 	 * find the conflicted paths.
 	 */
-	unmerge_index(r->index, pathspec);
+	unmerge_index(r->index, pathspec, 0);
 	find_conflict(r, &conflict);
 	for (i = 0; i < conflict.nr; i++) {
 		struct string_list_item *it = &conflict.items[i];
diff --git a/resolve-undo.c b/resolve-undo.c
index 3b0244e210..8e5a8072ed 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -115,75 +115,8 @@  void resolve_undo_clear_index(struct index_state *istate)
 	istate->cache_changed |= RESOLVE_UNDO_CHANGED;
 }
 
-int unmerge_index_entry_at(struct index_state *istate, int pos)
-{
-	const struct cache_entry *ce;
-	struct string_list_item *item;
-	struct resolve_undo_info *ru;
-	int i, err = 0, matched;
-	char *name;
-
-	if (!istate->resolve_undo)
-		return pos;
-
-	ce = istate->cache[pos];
-	if (ce_stage(ce)) {
-		/* already unmerged */
-		while ((pos < istate->cache_nr) &&
-		       ! strcmp(istate->cache[pos]->name, ce->name))
-			pos++;
-		return pos - 1; /* return the last entry processed */
-	}
-	item = string_list_lookup(istate->resolve_undo, ce->name);
-	if (!item)
-		return pos;
-	ru = item->util;
-	if (!ru)
-		return pos;
-	matched = ce->ce_flags & CE_MATCHED;
-	name = xstrdup(ce->name);
-	remove_index_entry_at(istate, pos);
-	for (i = 0; i < 3; i++) {
-		struct cache_entry *nce;
-		if (!ru->mode[i])
-			continue;
-		nce = make_cache_entry(istate,
-				       ru->mode[i],
-				       &ru->oid[i],
-				       name, i + 1, 0);
-		if (matched)
-			nce->ce_flags |= CE_MATCHED;
-		if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
-			err = 1;
-			error("cannot unmerge '%s'", name);
-		}
-	}
-	free(name);
-	if (err)
-		return pos;
-	free(ru);
-	item->util = NULL;
-	return unmerge_index_entry_at(istate, pos);
-}
-
-void unmerge_marked_index(struct index_state *istate)
-{
-	int i;
-
-	if (!istate->resolve_undo)
-		return;
-
-	/* TODO: audit for interaction with sparse-index. */
-	ensure_full_index(istate);
-	for (i = 0; i < istate->cache_nr; i++) {
-		const struct cache_entry *ce = istate->cache[i];
-		if (ce->ce_flags & CE_MATCHED)
-			i = unmerge_index_entry_at(istate, i);
-	}
-}
-
 int unmerge_index_entry(struct index_state *istate, const char *path,
-			struct resolve_undo_info *ru)
+			struct resolve_undo_info *ru, unsigned ce_flags)
 {
 	int i = index_name_pos(istate, path, strlen(path));
 
@@ -206,13 +139,15 @@  int unmerge_index_entry(struct index_state *istate, const char *path,
 			continue;
 		ce = make_cache_entry(istate, ru->mode[i], &ru->oid[i],
 				      path, i + 1, 0);
+		ce->ce_flags |= ce_flags;
 		if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD))
 			return error("cannot unmerge '%s'", path);
 	}
 	return 0;
 }
 
-void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
+void unmerge_index(struct index_state *istate, const struct pathspec *pathspec,
+		   unsigned ce_flags)
 {
 	struct string_list_item *item;
 
@@ -231,7 +166,7 @@  void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
 				    item->string, strlen(item->string),
 				    0, NULL, 0))
 			continue;
-		unmerge_index_entry(istate, path, ru);
+		unmerge_index_entry(istate, path, ru, ce_flags);
 		free(ru);
 		item->util = NULL;
 	}
diff --git a/resolve-undo.h b/resolve-undo.h
index 1ae321c88b..f3f8462751 100644
--- a/resolve-undo.h
+++ b/resolve-undo.h
@@ -17,9 +17,7 @@  void record_resolve_undo(struct index_state *, struct cache_entry *);
 void resolve_undo_write(struct strbuf *, struct string_list *);
 struct string_list *resolve_undo_read(const char *, unsigned long);
 void resolve_undo_clear_index(struct index_state *);
-int unmerge_index_entry_at(struct index_state *, int);
-int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *);
-void unmerge_index(struct index_state *, const struct pathspec *);
-void unmerge_marked_index(struct index_state *);
+int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *, unsigned);
+void unmerge_index(struct index_state *, const struct pathspec *, unsigned);
 
 #endif
diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh
index d97ecc2483..16d6348b69 100755
--- a/t/t2070-restore.sh
+++ b/t/t2070-restore.sh
@@ -180,7 +180,7 @@  test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
 	test_cmp expect file
 '
 
-test_expect_failure 'restore --merge to unresolve after (mistaken) resolution' '
+test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
 	O=$(echo original | git hash-object -w --stdin) &&
 	A=$(echo ourside | git hash-object -w --stdin) &&
 	B=$(echo theirside | git hash-object -w --stdin) &&
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 4b07a26c14..df582295df 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -543,7 +543,7 @@  test_expect_success 'checkout -m works after (mistaken) resolution' '
 	test_cmp merged file
 '
 
-test_expect_failure 'checkout -m works after (mistaken) resolution to remove' '
+test_expect_success 'checkout -m works after (mistaken) resolution to remove' '
 	setup_conflicting_index &&
 	echo "none of the above" >sample &&
 	cat sample >fild &&