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