Skip to content

Commit ab5af82

Browse files
pcloudsgitster
authored andcommitted
unpack-trees: fix oneway_merge accidentally carry over stage index
Phillip found out that 'git checkout -f <branch>' does not restore conflict/unmerged files correctly. All tracked files should be taken from <branch> and all non-zero stages removed. Most of this is true, except that the final file could be in stage one instead of zero. "checkout -f" (among other commands) does this with one-way merge, which is supposed to take stat info from the index and everything else from the given tree. The add_entry(.., old, ...) call in oneway_merge() though will keep stage index from the index. This is normally not a problem if the entry from the index is normal (stage #0). But if there is a conflict, stage #0 does not exist and we'll get stage #1 entry as "old" variable, which gets recorded in the final index. Fix it by clearing stage mask. This bug probably comes from b5b4250 (git-read-tree: make one-way merge also honor the "update" flag, 2005-06-07). Before this commit, we may create the final ("dst") index entry from the one in index, but we do clear CE_STAGEMASK. I briefly checked two- and three-way merge functions. I think we don't have the same problem in those. Reported-by: Phillip Wood <[email protected]> Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0e94f7a commit ab5af82

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

t/t2023-checkout-m.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,28 @@ test_expect_success '-m restores 3-way conflicted+resolved file' '
4646
test_cmp both.txt.conflicted.cleaned both.txt.cleaned
4747
'
4848

49+
test_expect_success 'force checkout a conflict file creates stage zero entry' '
50+
git init co-force &&
51+
(
52+
cd co-force &&
53+
echo a >a &&
54+
git add a &&
55+
git commit -ama &&
56+
A_OBJ=$(git rev-parse :a) &&
57+
git branch topic &&
58+
echo b >a &&
59+
git commit -amb &&
60+
B_OBJ=$(git rev-parse :a) &&
61+
git checkout topic &&
62+
echo c >a &&
63+
C_OBJ=$(git hash-object a) &&
64+
git checkout -m master &&
65+
test_cmp_rev :1:a $A_OBJ &&
66+
test_cmp_rev :2:a $B_OBJ &&
67+
test_cmp_rev :3:a $C_OBJ &&
68+
git checkout -f topic &&
69+
test_cmp_rev :0:a $A_OBJ
70+
)
71+
'
72+
4973
test_done

unpack-trees.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2386,7 +2386,7 @@ int oneway_merge(const struct cache_entry * const *src,
23862386
if (o->update && S_ISGITLINK(old->ce_mode) &&
23872387
should_update_submodules() && !verify_uptodate(old, o))
23882388
update |= CE_UPDATE;
2389-
add_entry(o, old, update, 0);
2389+
add_entry(o, old, update, CE_STAGEMASK);
23902390
return 0;
23912391
}
23922392
return merged_entry(a, old, o);

0 commit comments

Comments
 (0)