@matheusbsbs / matheus-bagliano / commits / d1a43f2aa4
Fork 0

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

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 committed Oct 15, 2008 at 16:00 UTC d1a43f2aa4bfb5aef29e9e1fe1fb9bb18c0e8b65
2 files changed +78 -13
read-cache.c
+18 -13
@@ -1460,23 +1460,28 @@ int write_index(const struct index_state *istate, int newfd)
1460 int read_index_unmerged(struct index_state *istate)
1461 {
1462 int i;
1463 - struct cache_entry **dst;
1464 - struct cache_entry *last = NULL;
1463 + int unmerged = 0;
1464
1465 read_index(istate);
1467 - dst = istate->cache;
1466 for (i = 0; i < istate->cache_nr; i++) {
1467 struct cache_entry *ce = istate->cache[i];
1470 - if (ce_stage(ce)) {
1471 - remove_name_hash(ce);
1472 - if (last && !strcmp(ce->name, last->name))
1473 - continue;
1474 - cache_tree_invalidate_path(istate->cache_tree, ce->name);
1475 - last = ce;
1468 + struct cache_entry *new_ce;
1469 + int size, len;
1470 +
1471 + if (!ce_stage(ce))
1472 continue;
1477 - }
1478 - *dst++ = ce;
1473 + unmerged = 1;
1474 + len = strlen(ce->name);
1475 + size = cache_entry_size(len);
1476 + new_ce = xcalloc(1, size);
1477 + hashcpy(new_ce->sha1, ce->sha1);
1478 + memcpy(new_ce->name, ce->name, len);
1479 + new_ce->ce_flags = create_ce_flags(len, 0);
1480 + new_ce->ce_mode = ce->ce_mode;
1481 + if (add_index_entry(istate, new_ce, 0))
1482 + return error("%s: cannot drop to stage #0",
1483 + ce->name);
1484 + i = index_name_pos(istate, new_ce->name, len);
1485 }
1480 - istate->cache_nr = dst - istate->cache;
1481 - return !!last;
1486 + return unmerged;
1487 }
t/t1005-read-tree-reset.sh
+60
@@ -27,4 +27,64 @@ test_expect_success 'reset should work' '
27 test_cmp expect actual
28 '
29
30 +test_expect_success 'reset should remove remnants from a failed merge' '
31 + git read-tree --reset -u HEAD &&
32 + git ls-files -s >expect &&
33 + sha1=$(git rev-parse :new) &&
34 + (
35 + echo "100644 $sha1 1 old"
36 + echo "100644 $sha1 3 old"
37 + ) | git update-index --index-info &&
38 + >old &&
39 + git ls-files -s &&
40 + git read-tree --reset -u HEAD &&
41 + git ls-files -s >actual &&
42 + ! test -f old
43 +'
44 +
45 +test_expect_success 'Porcelain reset should remove remnants too' '
46 + git read-tree --reset -u HEAD &&
47 + git ls-files -s >expect &&
48 + sha1=$(git rev-parse :new) &&
49 + (
50 + echo "100644 $sha1 1 old"
51 + echo "100644 $sha1 3 old"
52 + ) | git update-index --index-info &&
53 + >old &&
54 + git ls-files -s &&
55 + git reset --hard &&
56 + git ls-files -s >actual &&
57 + ! test -f old
58 +'
59 +
60 +test_expect_success 'Porcelain checkout -f should remove remnants too' '
61 + git read-tree --reset -u HEAD &&
62 + git ls-files -s >expect &&
63 + sha1=$(git rev-parse :new) &&
64 + (
65 + echo "100644 $sha1 1 old"
66 + echo "100644 $sha1 3 old"
67 + ) | git update-index --index-info &&
68 + >old &&
69 + git ls-files -s &&
70 + git checkout -f &&
71 + git ls-files -s >actual &&
72 + ! test -f old
73 +'
74 +
75 +test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' '
76 + git read-tree --reset -u HEAD &&
77 + git ls-files -s >expect &&
78 + sha1=$(git rev-parse :new) &&
79 + (
80 + echo "100644 $sha1 1 old"
81 + echo "100644 $sha1 3 old"
82 + ) | git update-index --index-info &&
83 + >old &&
84 + git ls-files -s &&
85 + git checkout -f HEAD &&
86 + git ls-files -s >actual &&
87 + ! test -f old
88 +'
89 +
90 test_done