git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] reset --hard/read-tree --reset -u: remove unmerged new paths

From
Junio C Hamano <gitster@pobox.com>
Date
Oct 15, 2008, 23:00 UTC
Message-ID
<7vy70ppiq1.fsf_-_@gitster.siamese.dyndns.org>
In-Reply-To
<7v3aixqzrn.fsf@gitster.siamese.dyndns.org>

When aborting a failed merge that has brought in a new path using "git reset --hard" or "git read-tree --reset -u", we used to first forget about the new path (via read_cache_unmerged) and then matched the working tree to what is recorded in the index, thus ending up leaving the new path in the work tree.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Junio C Hamano <gitster@pobox.com> writes:
 > Linus Torvalds <torvalds@linux-foundation.org> writes:
 >
 >> On Wed, 15 Oct 2008, Linus Torvalds wrote:
 >>> 
 >> It's quite possible that we should remove unmerged entries. Except that's 
 >> not how our internal 'read_cache_unmerged()' function works. It really 
 >> just ignores them, and throws them on the floor. We _could_ try to just 
 >> turn them into a (since) stage-0 entry.
 >>
 >> Junio?
 >
 > I am not sure what should happen when we can't drop the unmerged entry
 > down to stage-0 due to D/F conflicts, though.  IIRC, read-tree proper
 > would not touch the work tree in such a case, but merge-recursive creates
 > our and their versions with funny suffixes, which will not be known to the
 > index and will be left in the working tree.
 I am still unsure what we should do when we hit D/F conflicts; this one
 simply replaces but it may be safer to drop ADD_CACHE_OK_TO_REPLACE from
 the options to trigger an error in such a case.  I dunno.
 read-cache.c               |   32 +++++++++++++++++++-------------
 t/t1005-read-tree-reset.sh |   30 ++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+), 13 deletions(-)
diff --git a/read-cache.c b/read-cache.c
index c229fd4..efbab6a 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1489,25 +1489,31 @@ int write_index(const struct index_state *istate, int newfd)
 int read_index_unmerged(struct index_state *istate)
 {
 	int i;
-	struct cache_entry **dst;
-	struct cache_entry *last = NULL;
+	int unmerged = 0;
 
 	read_index(istate);
-	dst = istate->cache;
 	for (i = 0; i < istate->cache_nr; i++) {
 		struct cache_entry *ce = istate->cache[i];
-		if (ce_stage(ce)) {
-			remove_name_hash(ce);
-			if (last && !strcmp(ce->name, last->name))
-				continue;
-			cache_tree_invalidate_path(istate->cache_tree, ce->name);
-			last = ce;
+		struct cache_entry *new_ce;
+		int size, len, option;
+
+		if (!ce_stage(ce))
 			continue;
-		}
-		*dst++ = ce;
+		unmerged = 1;
+		len = strlen(ce->name);
+		size = cache_entry_size(len);
+		new_ce = xcalloc(1, size);
+		hashcpy(new_ce->sha1, ce->sha1);
+		memcpy(new_ce->name, ce->name, len);
+		new_ce->ce_flags = create_ce_flags(len, 0);
+		new_ce->ce_mode = ce->ce_mode;
+		option = ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE;
+		if (add_index_entry(istate, new_ce, option))
+			return error("%s: cannot drop to stage #0",
+				     ce->name);
+		i = index_name_pos(istate, new_ce->name, len);
 	}
-	istate->cache_nr = dst - istate->cache;
-	return !!last;
+	return unmerged;
 }
 
 struct update_callback_data
diff --git a/t/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh
index b0d31f5..0cd519c 100755
--- a/t/t1005-read-tree-reset.sh
+++ b/t/t1005-read-tree-reset.sh
@@ -27,4 +27,34 @@ test_expect_success 'reset should work' '
   test_cmp expect actual
 '
 
+test_expect_success 'reset should remove remnants from a failed merge' '
+  git read-tree --reset -u HEAD &&
+  git ls-files -s >expect &&
+  sha1=$(git rev-parse :new) &&
+  (
+	echo "100644 $sha1 1	old"
+	echo "100644 $sha1 3	old"
+  ) | git update-index --index-info &&
+  >old &&
+  git ls-files -s &&
+  git read-tree --reset -u HEAD &&
+  git ls-files -s >actual &&
+  ! test -f old
+'
+
+test_expect_success 'Porcelain reset should remove remnants too' '
+  git read-tree --reset -u HEAD &&
+  git ls-files -s >expect &&
+  sha1=$(git rev-parse :new) &&
+  (
+	echo "100644 $sha1 1	old"
+	echo "100644 $sha1 3	old"
+  ) | git update-index --index-info &&
+  >old &&
+  git ls-files -s &&
+  git reset --hard &&
+  git ls-files -s >actual &&
+  ! test -f old
+'
+
 test_done
-- 
1.6.0.2.717.gc6f0a
Previous: Junio C HamanoNext: Linus Torvalds
Message 20 of 24 in “Untracked working tree files”
  1. Andrew MortonOct 15, 2008
  2. david@lang.hmOct 15, 2008
  3. david@lang.hmOct 15, 2008
  4. Andrew MortonOct 15, 2008
  5. Andrew MortonOct 15, 2008
  6. Nicolas PitreOct 15, 2008
  7. Nicolas PitreOct 15, 2008
  8. Linus TorvaldsOct 15, 2008
  9. david@lang.hmOct 15, 2008
  10. Linus TorvaldsOct 15, 2008
  11. david@lang.hmOct 15, 2008
  12. Andrew MortonOct 15, 2008
  13. Linus TorvaldsOct 15, 2008
  14. Andrew MortonOct 15, 2008
  15. Paolo CiarrocchiOct 16, 2008
  16. Andrew MortonOct 16, 2008
  17. Linus TorvaldsOct 15, 2008
  18. Andrew MortonOct 15, 2008
  19. Junio C HamanoOct 15, 2008
  20. reset --hard/read-tree --reset -u: remove unmerged new pathsJunio C Hamano, Oct 15, 2008
  21. Linus TorvaldsOct 15, 2008
  22. Junio C HamanoOct 16, 2008
  23. Ingo MolnarOct 16, 2008
  24. Junio C HamanoOct 16, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.