git/t/t1000-read-tree-m-3way.sh

515 lines
16 KiB
Bash
Raw Normal View History

#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
test_description='Three way merge with read-tree -m
This test tries three-way merge with read-tree -m
There is one ancestor (called O for Original) and two branches A
and B derived from it. We want to do a 3-way merge between A and
B, using O as the common ancestor.
merge A O B
Decisions are made by comparing contents of O, A and B pathname
by pathname. The result is determined by the following guiding
principle:
- If only A does something to it and B does not touch it, take
whatever A does.
- If only B does something to it and A does not touch it, take
whatever B does.
- If both A and B does something but in the same way, take
whatever they do.
- If A and B does something but different things, we need a
3-way merge:
- We cannot do anything about the following cases:
* O does not have it. A and B both must be adding to the
same path independently.
* A deletes it. B must be modifying.
- Otherwise, A and B are modifying. Run 3-way merge.
First, the case matrix.
- Vertical axis is for A'\''s actions.
- Horizontal axis is for B'\''s actions.
.----------------------------------------------------------------.
| A B | No Action | Delete | Modify | Add |
|------------+------------+------------+------------+------------|
| No Action | | | | |
| | select O | delete | select B | select B |
| | | | | |
|------------+------------+------------+------------+------------|
| Delete | | | ********** | can |
| | delete | delete | merge | not |
| | | | | happen |
|------------+------------+------------+------------+------------|
| Modify | | ********** | ?????????? | can |
| | select A | merge | select A=B | not |
| | | | merge | happen |
|------------+------------+------------+------------+------------|
| Add | | can | can | ?????????? |
| | select A | not | not | select A=B |
| | | happen | happen | merge |
.----------------------------------------------------------------.
In addition:
SS: a special case of MM, where A and B makes the same modification.
LL: a special case of AA, where A and B creates the same file.
TT: a special case of MM, where A and B makes mergeable changes.
DF: a special case, where A makes a directory and B makes a file.
'
. ./test-lib.sh
. ../lib-read-tree-m-3way.sh
################################################################
# Trivial "majority when 3 stages exist" merge plus #2ALT, #3ALT
# and #5ALT trivial merges.
cat >expected <<\EOF
100644 X 2 AA
100644 X 3 AA
100644 X 0 AN
100644 X 1 DD
100644 X 3 DF
100644 X 2 DF/DF
100644 X 1 DM
100644 X 3 DM
100644 X 1 DN
100644 X 3 DN
[PATCH] read-tree: fix too strong index requirement #5ALT This fixes too strong index requirement 3-way merge enforces in one case: the same file is added in both branches. In this case, the original code insisted that if the index file has that path, it must match our branch and be up-to-date. However in this particular case, it only has to match it, and can be dirty. We just need to make sure that we keep the work-tree copy instead of checking out the merge result. The resolution of such a path, however, cannot be left to outside script, because we will not keep the original stage0 entries for unmerged paths when read-tree finishes, and at that point, the knowledge of "if we resolve it to match the new file added in both branches, the merge succeeds and the work tree would not lose information, but we should _not_ update the work tree from the resulting index file" is lost. For this reason, the now code needs to resolve this case (#5ALT) internally. This affects some existing tests in the test suite, but all in positive ways. In t1000 (3-way test), this #5ALT case now gets one stage0 entry, instead of an identical stage2 and stage3 entry pair, for such a path, and one test that checked for merge failure (because the test assumed the "stricter-than-necessary" behaviour) does not have to fail anymore. In t1005 (emu23 test), two tests that involves a case where the work tree already had a change introduced in the upstream (aka "merged head"), the merge succeeds instead of failing. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-11 01:37:47 +00:00
100644 X 0 LL
100644 X 1 MD
100644 X 2 MD
100644 X 1 MM
100644 X 2 MM
100644 X 3 MM
100644 X 0 MN
100644 X 0 NA
100644 X 1 ND
100644 X 2 ND
100644 X 0 NM
100644 X 0 NN
100644 X 0 SS
100644 X 1 TT
100644 X 2 TT
100644 X 3 TT
100644 X 2 Z/AA
100644 X 3 Z/AA
100644 X 0 Z/AN
100644 X 1 Z/DD
100644 X 1 Z/DM
100644 X 3 Z/DM
100644 X 1 Z/DN
100644 X 3 Z/DN
100644 X 1 Z/MD
100644 X 2 Z/MD
100644 X 1 Z/MM
100644 X 2 Z/MM
100644 X 3 Z/MM
100644 X 0 Z/MN
100644 X 0 Z/NA
100644 X 1 Z/ND
100644 X 2 Z/ND
100644 X 0 Z/NM
100644 X 0 Z/NN
EOF
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
check_result () {
git-ls-files --stage | sed -e 's/ '"$_x40"' / X /' >current &&
diff -u expected current
}
# This is done on an empty work directory, which is the normal
# merge person behaviour.
test_expect_success \
'3-way merge with git-read-tree -m, empty cache' \
"rm -fr [NDMALTS][NDMALTSF] Z &&
rm .git/index &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
# This starts out with the first head, which is the normal
# patch submitter behaviour.
test_expect_success \
'3-way merge with git-read-tree -m, match H' \
"rm -fr [NDMALTS][NDMALTSF] Z &&
rm .git/index &&
git-read-tree $tree_A &&
git-checkout-index -f -u -a &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
: <<\END_OF_CASE_TABLE
We have so far tested only empty index and clean-and-matching-A index
case which are trivial. Make sure index requirements are also
checked.
"git-read-tree -m O A B"
O A B result index requirements
-------------------------------------------------------------------
1 missing missing missing - must not exist.
------------------------------------------------------------------
2 missing missing exists take B* must match B, if exists.
------------------------------------------------------------------
3 missing exists missing take A* must match A, if exists.
------------------------------------------------------------------
4 missing exists A!=B no merge must match A and be
up-to-date, if exists.
------------------------------------------------------------------
5 missing exists A==B take A must match A, if exists.
------------------------------------------------------------------
6 exists missing missing remove must not exist.
------------------------------------------------------------------
7 exists missing O!=B no merge must not exist.
------------------------------------------------------------------
8 exists missing O==B remove must not exist.
------------------------------------------------------------------
9 exists O!=A missing no merge must match A and be
up-to-date, if exists.
------------------------------------------------------------------
10 exists O==A missing remove ditto
------------------------------------------------------------------
11 exists O!=A O!=B no merge must match A and be
A!=B up-to-date, if exists.
------------------------------------------------------------------
12 exists O!=A O!=B take A must match A, if exists.
A==B
------------------------------------------------------------------
13 exists O!=A O==B take A must match A, if exists.
------------------------------------------------------------------
14 exists O==A O!=B take B if exists, must either (1)
match A and be up-to-date,
or (2) match B.
------------------------------------------------------------------
15 exists O==A O==B take B must match A if exists.
------------------------------------------------------------------
16 exists O==A O==B barf must match A if exists.
*multi* in one in another
-------------------------------------------------------------------
Note: we need to be careful in case 2 and 3. The tree A may contain
DF (file) when tree B require DF to be a directory by having DF/DF
(file).
END_OF_CASE_TABLE
test_expect_failure \
'1 - must not have an entry not in A.' \
"rm -f .git/index XX &&
echo XX >XX &&
git-update-index --add XX &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'2 - must match B in !O && !A && B case.' \
"rm -f .git/index NA &&
cp .orig-B/NA NA &&
git-update-index --add NA &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'2 - matching B alone is OK in !O && !A && B case.' \
"rm -f .git/index NA &&
cp .orig-B/NA NA &&
git-update-index --add NA &&
echo extra >>NA &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'3 - must match A in !O && A && !B case.' \
"rm -f .git/index AN &&
cp .orig-A/AN AN &&
git-update-index --add AN &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
'3 - matching A alone is OK in !O && A && !B case.' \
"rm -f .git/index AN &&
cp .orig-A/AN AN &&
git-update-index --add AN &&
echo extra >>AN &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_failure \
'3 (fail) - must match A in !O && A && !B case.' \
"rm -f .git/index AN &&
cp .orig-A/AN AN &&
echo extra >>AN &&
git-update-index --add AN &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'4 - must match and be up-to-date in !O && A && B && A!=B case.' \
"rm -f .git/index AA &&
cp .orig-A/AA AA &&
git-update-index --add AA &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_failure \
'4 (fail) - must match and be up-to-date in !O && A && B && A!=B case.' \
"rm -f .git/index AA &&
cp .orig-A/AA AA &&
git-update-index --add AA &&
echo extra >>AA &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_failure \
'4 (fail) - must match and be up-to-date in !O && A && B && A!=B case.' \
"rm -f .git/index AA &&
cp .orig-A/AA AA &&
echo extra >>AA &&
git-update-index --add AA &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
[PATCH] read-tree: fix too strong index requirement #5ALT This fixes too strong index requirement 3-way merge enforces in one case: the same file is added in both branches. In this case, the original code insisted that if the index file has that path, it must match our branch and be up-to-date. However in this particular case, it only has to match it, and can be dirty. We just need to make sure that we keep the work-tree copy instead of checking out the merge result. The resolution of such a path, however, cannot be left to outside script, because we will not keep the original stage0 entries for unmerged paths when read-tree finishes, and at that point, the knowledge of "if we resolve it to match the new file added in both branches, the merge succeeds and the work tree would not lose information, but we should _not_ update the work tree from the resulting index file" is lost. For this reason, the now code needs to resolve this case (#5ALT) internally. This affects some existing tests in the test suite, but all in positive ways. In t1000 (3-way test), this #5ALT case now gets one stage0 entry, instead of an identical stage2 and stage3 entry pair, for such a path, and one test that checked for merge failure (because the test assumed the "stricter-than-necessary" behaviour) does not have to fail anymore. In t1005 (emu23 test), two tests that involves a case where the work tree already had a change introduced in the upstream (aka "merged head"), the merge succeeds instead of failing. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-11 01:37:47 +00:00
'5 - must match in !O && A && B && A==B case.' \
"rm -f .git/index LL &&
cp .orig-A/LL LL &&
git-update-index --add LL &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
[PATCH] read-tree: fix too strong index requirement #5ALT This fixes too strong index requirement 3-way merge enforces in one case: the same file is added in both branches. In this case, the original code insisted that if the index file has that path, it must match our branch and be up-to-date. However in this particular case, it only has to match it, and can be dirty. We just need to make sure that we keep the work-tree copy instead of checking out the merge result. The resolution of such a path, however, cannot be left to outside script, because we will not keep the original stage0 entries for unmerged paths when read-tree finishes, and at that point, the knowledge of "if we resolve it to match the new file added in both branches, the merge succeeds and the work tree would not lose information, but we should _not_ update the work tree from the resulting index file" is lost. For this reason, the now code needs to resolve this case (#5ALT) internally. This affects some existing tests in the test suite, but all in positive ways. In t1000 (3-way test), this #5ALT case now gets one stage0 entry, instead of an identical stage2 and stage3 entry pair, for such a path, and one test that checked for merge failure (because the test assumed the "stricter-than-necessary" behaviour) does not have to fail anymore. In t1005 (emu23 test), two tests that involves a case where the work tree already had a change introduced in the upstream (aka "merged head"), the merge succeeds instead of failing. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-11 01:37:47 +00:00
test_expect_success \
'5 - must match in !O && A && B && A==B case.' \
"rm -f .git/index LL &&
cp .orig-A/LL LL &&
git-update-index --add LL &&
echo extra >>LL &&
[PATCH] read-tree: fix too strong index requirement #5ALT This fixes too strong index requirement 3-way merge enforces in one case: the same file is added in both branches. In this case, the original code insisted that if the index file has that path, it must match our branch and be up-to-date. However in this particular case, it only has to match it, and can be dirty. We just need to make sure that we keep the work-tree copy instead of checking out the merge result. The resolution of such a path, however, cannot be left to outside script, because we will not keep the original stage0 entries for unmerged paths when read-tree finishes, and at that point, the knowledge of "if we resolve it to match the new file added in both branches, the merge succeeds and the work tree would not lose information, but we should _not_ update the work tree from the resulting index file" is lost. For this reason, the now code needs to resolve this case (#5ALT) internally. This affects some existing tests in the test suite, but all in positive ways. In t1000 (3-way test), this #5ALT case now gets one stage0 entry, instead of an identical stage2 and stage3 entry pair, for such a path, and one test that checked for merge failure (because the test assumed the "stricter-than-necessary" behaviour) does not have to fail anymore. In t1005 (emu23 test), two tests that involves a case where the work tree already had a change introduced in the upstream (aka "merged head"), the merge succeeds instead of failing. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-11 01:37:47 +00:00
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_failure \
[PATCH] read-tree: fix too strong index requirement #5ALT This fixes too strong index requirement 3-way merge enforces in one case: the same file is added in both branches. In this case, the original code insisted that if the index file has that path, it must match our branch and be up-to-date. However in this particular case, it only has to match it, and can be dirty. We just need to make sure that we keep the work-tree copy instead of checking out the merge result. The resolution of such a path, however, cannot be left to outside script, because we will not keep the original stage0 entries for unmerged paths when read-tree finishes, and at that point, the knowledge of "if we resolve it to match the new file added in both branches, the merge succeeds and the work tree would not lose information, but we should _not_ update the work tree from the resulting index file" is lost. For this reason, the now code needs to resolve this case (#5ALT) internally. This affects some existing tests in the test suite, but all in positive ways. In t1000 (3-way test), this #5ALT case now gets one stage0 entry, instead of an identical stage2 and stage3 entry pair, for such a path, and one test that checked for merge failure (because the test assumed the "stricter-than-necessary" behaviour) does not have to fail anymore. In t1005 (emu23 test), two tests that involves a case where the work tree already had a change introduced in the upstream (aka "merged head"), the merge succeeds instead of failing. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-11 01:37:47 +00:00
'5 (fail) - must match A in !O && A && B && A==B case.' \
"rm -f .git/index LL &&
cp .orig-A/LL LL &&
echo extra >>LL &&
git-update-index --add LL &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_failure \
'6 - must not exist in O && !A && !B case' \
"rm -f .git/index DD &&
echo DD >DD
git-update-index --add DD &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_failure \
'7 - must not exist in O && !A && B && O!=B case' \
"rm -f .git/index DM &&
cp .orig-B/DM DM &&
git-update-index --add DM &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_failure \
'8 - must not exist in O && !A && B && O==B case' \
"rm -f .git/index DN &&
cp .orig-B/DN DN &&
git-update-index --add DN &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'9 - must match and be up-to-date in O && A && !B && O!=A case' \
"rm -f .git/index MD &&
cp .orig-A/MD MD &&
git-update-index --add MD &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_failure \
'9 (fail) - must match and be up-to-date in O && A && !B && O!=A case' \
"rm -f .git/index MD &&
cp .orig-A/MD MD &&
git-update-index --add MD &&
echo extra >>MD &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_failure \
'9 (fail) - must match and be up-to-date in O && A && !B && O!=A case' \
"rm -f .git/index MD &&
cp .orig-A/MD MD &&
echo extra >>MD &&
git-update-index --add MD &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'10 - must match and be up-to-date in O && A && !B && O==A case' \
"rm -f .git/index ND &&
cp .orig-A/ND ND &&
git-update-index --add ND &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_failure \
'10 (fail) - must match and be up-to-date in O && A && !B && O==A case' \
"rm -f .git/index ND &&
cp .orig-A/ND ND &&
git-update-index --add ND &&
echo extra >>ND &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_failure \
'10 (fail) - must match and be up-to-date in O && A && !B && O==A case' \
"rm -f .git/index ND &&
cp .orig-A/ND ND &&
echo extra >>ND &&
git-update-index --add ND &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'11 - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' \
"rm -f .git/index MM &&
cp .orig-A/MM MM &&
git-update-index --add MM &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_failure \
'11 (fail) - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' \
"rm -f .git/index MM &&
cp .orig-A/MM MM &&
git-update-index --add MM &&
echo extra >>MM &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_failure \
'11 (fail) - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' \
"rm -f .git/index MM &&
cp .orig-A/MM MM &&
echo extra >>MM &&
git-update-index --add MM &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'12 - must match A in O && A && B && O!=A && A==B case' \
"rm -f .git/index SS &&
cp .orig-A/SS SS &&
git-update-index --add SS &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
'12 - must match A in O && A && B && O!=A && A==B case' \
"rm -f .git/index SS &&
cp .orig-A/SS SS &&
git-update-index --add SS &&
echo extra >>SS &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_failure \
'12 (fail) - must match A in O && A && B && O!=A && A==B case' \
"rm -f .git/index SS &&
cp .orig-A/SS SS &&
echo extra >>SS &&
git-update-index --add SS &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'13 - must match A in O && A && B && O!=A && O==B case' \
"rm -f .git/index MN &&
cp .orig-A/MN MN &&
git-update-index --add MN &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
'13 - must match A in O && A && B && O!=A && O==B case' \
"rm -f .git/index MN &&
cp .orig-A/MN MN &&
git-update-index --add MN &&
echo extra >>MN &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
'14 - must match and be up-to-date in O && A && B && O==A && O!=B case' \
"rm -f .git/index NM &&
cp .orig-A/NM NM &&
git-update-index --add NM &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
'14 - may match B in O && A && B && O==A && O!=B case' \
"rm -f .git/index NM &&
cp .orig-B/NM NM &&
git-update-index --add NM &&
echo extra >>NM &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_failure \
'14 (fail) - must match and be up-to-date in O && A && B && O==A && O!=B case' \
"rm -f .git/index NM &&
cp .orig-A/NM NM &&
git-update-index --add NM &&
echo extra >>NM &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_failure \
'14 (fail) - must match and be up-to-date in O && A && B && O==A && O!=B case' \
"rm -f .git/index NM &&
cp .orig-A/NM NM &&
echo extra >>NM &&
git-update-index --add NM &&
git-read-tree -m $tree_O $tree_A $tree_B"
test_expect_success \
'15 - must match A in O && A && B && O==A && O==B case' \
"rm -f .git/index NN &&
cp .orig-A/NN NN &&
git-update-index --add NN &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_success \
'15 - must match A in O && A && B && O==A && O==B case' \
"rm -f .git/index NN &&
cp .orig-A/NN NN &&
git-update-index --add NN &&
echo extra >>NN &&
git-read-tree -m $tree_O $tree_A $tree_B &&
check_result"
test_expect_failure \
'15 (fail) - must match A in O && A && B && O==A && O==B case' \
"rm -f .git/index NN &&
cp .orig-A/NN NN &&
echo extra >>NN &&
git-update-index --add NN &&
git-read-tree -m $tree_O $tree_A $tree_B"
# #16
test_expect_success \
'16 - A matches in one and B matches in another.' \
'rm -f .git/index F16 &&
echo F16 >F16 &&
git-update-index --add F16 &&
tree0=`git-write-tree` &&
echo E16 >F16 &&
git-update-index F16 &&
tree1=`git-write-tree` &&
git-read-tree -m $tree0 $tree1 $tree1 $tree0 &&
git-ls-files --stage'
test_done