2007-04-07 14:17:35 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description='merge-recursive backend test'
|
|
|
|
|
|
|
|
. ./test-lib.sh
|
|
|
|
|
|
|
|
test_expect_success 'setup 1' '
|
|
|
|
|
|
|
|
echo hello >a &&
|
|
|
|
o0=$(git hash-object a) &&
|
|
|
|
cp a b &&
|
2007-04-19 04:51:06 +00:00
|
|
|
cp a c &&
|
2007-04-07 14:17:35 +00:00
|
|
|
mkdir d &&
|
|
|
|
cp a d/e &&
|
|
|
|
|
|
|
|
test_tick &&
|
2007-04-19 04:51:06 +00:00
|
|
|
git add a b c d/e &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git commit -m initial &&
|
|
|
|
c0=$(git rev-parse --verify HEAD) &&
|
|
|
|
git branch side &&
|
|
|
|
git branch df-1 &&
|
|
|
|
git branch df-2 &&
|
|
|
|
git branch df-3 &&
|
|
|
|
git branch remove &&
|
2010-06-08 11:34:12 +00:00
|
|
|
git branch submod &&
|
2010-09-01 20:15:32 +00:00
|
|
|
git branch copy &&
|
|
|
|
git branch rename &&
|
2013-06-07 20:53:30 +00:00
|
|
|
git branch rename-ln &&
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
echo hello >>a &&
|
|
|
|
cp a d/e &&
|
|
|
|
o1=$(git hash-object a) &&
|
|
|
|
|
|
|
|
git add a d/e &&
|
|
|
|
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "master modifies a and d/e" &&
|
|
|
|
c1=$(git rev-parse --verify HEAD) &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o1 a" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o1 d/e" &&
|
|
|
|
echo "100644 $o1 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'setup 2' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -rf [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git checkout side &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o0 a" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 $o0 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o0 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
echo goodbye >>a &&
|
|
|
|
o2=$(git hash-object a) &&
|
|
|
|
|
|
|
|
git add a &&
|
|
|
|
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "side modifies a" &&
|
|
|
|
c2=$(git rev-parse --verify HEAD) &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o2 a" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 $o2 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o0 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'setup 3' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -rf [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git checkout df-1 &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o0 a" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 $o0 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o0 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
rm -f b && mkdir b && echo df-1 >b/c && git add b/c &&
|
|
|
|
o3=$(git hash-object b/c) &&
|
|
|
|
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "df-1 makes b/c" &&
|
|
|
|
c3=$(git rev-parse --verify HEAD) &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o0 a" &&
|
|
|
|
echo "100644 blob $o3 b/c" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 $o0 0 a" &&
|
|
|
|
echo "100644 $o3 0 b/c" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o0 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'setup 4' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -rf [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git checkout df-2 &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o0 a" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 $o0 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o0 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
rm -f a && mkdir a && echo df-2 >a/c && git add a/c &&
|
|
|
|
o4=$(git hash-object a/c) &&
|
|
|
|
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "df-2 makes a/c" &&
|
|
|
|
c4=$(git rev-parse --verify HEAD) &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o4 a/c" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 $o4 0 a/c" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o0 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'setup 5' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -rf [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git checkout remove &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o0 a" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 $o0 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o0 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
rm -f b &&
|
|
|
|
echo remove-conflict >a &&
|
|
|
|
|
|
|
|
git add a &&
|
|
|
|
git rm b &&
|
|
|
|
o5=$(git hash-object a) &&
|
|
|
|
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "remove removes b and modifies a" &&
|
|
|
|
c5=$(git rev-parse --verify HEAD) &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o5 a" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 $o5 0 a" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o0 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'setup 6' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -rf [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git checkout df-3 &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o0 a" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 $o0 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o0 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
rm -fr d && echo df-3 >d && git add d &&
|
|
|
|
o6=$(git hash-object d) &&
|
|
|
|
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "df-3 makes d" &&
|
|
|
|
c6=$(git rev-parse --verify HEAD) &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o0 a" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o6 d" &&
|
|
|
|
echo "100644 $o0 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o6 0 d"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
2010-06-08 11:34:12 +00:00
|
|
|
test_expect_success 'setup 7' '
|
|
|
|
|
|
|
|
git checkout submod &&
|
|
|
|
git rm d/e &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "remove d/e" &&
|
|
|
|
git update-index --add --cacheinfo 160000 $c1 d &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "make d/ a submodule"
|
|
|
|
'
|
|
|
|
|
2010-09-01 20:15:32 +00:00
|
|
|
test_expect_success 'setup 8' '
|
|
|
|
git checkout rename &&
|
|
|
|
git mv a e &&
|
|
|
|
git add e &&
|
|
|
|
test_tick &&
|
2010-09-20 08:28:34 +00:00
|
|
|
git commit -m "rename a->e" &&
|
2014-01-27 14:45:06 +00:00
|
|
|
c7=$(git rev-parse --verify HEAD) &&
|
2013-06-07 20:53:30 +00:00
|
|
|
git checkout rename-ln &&
|
|
|
|
git mv a e &&
|
|
|
|
test_ln_s_add e a &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "rename a->e, symlink a->e" &&
|
2015-12-22 15:05:54 +00:00
|
|
|
oln=$(printf e | git hash-object --stdin)
|
2010-09-01 20:15:32 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'setup 9' '
|
|
|
|
git checkout copy &&
|
|
|
|
cp a e &&
|
|
|
|
git add e &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "copy a->e"
|
|
|
|
'
|
|
|
|
|
2007-04-07 14:17:35 +00:00
|
|
|
test_expect_success 'merge-recursive simple' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -fr [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git checkout -f "$c2" &&
|
|
|
|
|
2011-12-08 13:10:13 +00:00
|
|
|
test_expect_code 1 git merge-recursive "$c0" -- "$c2" "$c1"
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive result' '
|
|
|
|
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o0 1 a" &&
|
|
|
|
echo "100644 $o2 2 a" &&
|
|
|
|
echo "100644 $o1 3 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
'
|
|
|
|
|
2011-04-12 23:20:32 +00:00
|
|
|
test_expect_success 'fail if the index has unresolved entries' '
|
merge: fix numerus bugs around "trivial merge" area
The "trivial merge" codepath wants to optimize itself by making an
internal call to the read-tree machinery, but it does not read the index
before doing so, and the codepath is never exercised. Incidentally, this
failure to read the index upfront means that the safety to refuse doing
anything when the index is unmerged does not kick in, either.
These two problem are fixed by using read_cache_unmerged() that does read
the index before checking if it is unmerged at the beginning of
cmd_merge().
The primary logic of the merge, however, assumes that the process never
reads the index in-core, and the call to write_cache_as_tree() it makes
from write_tree_trivial() will always read from the on-disk index that is
prepared the strategy back-ends. This assumption is now broken by the
above fix. To fix this issue, we now call discard_cache() before calling
write_tree_trivial() when it wants to write the on-disk index as a tree.
When multiple strategies are tried, their results are evaluated by reading
the resulting index and inspecting it. The codepath needs to make a call
to read_cache() for each successful strategy, and for that to work, they
need to discard_cache() the one read by the previous round.
Also the "trivial merge" forgot that the current commit is one of the
parents of the resulting commit.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-08-23 19:56:57 +00:00
|
|
|
|
|
|
|
rm -fr [abcd] &&
|
|
|
|
git checkout -f "$c1" &&
|
|
|
|
|
|
|
|
test_must_fail git merge "$c5" &&
|
|
|
|
test_must_fail git merge "$c5" 2> out &&
|
2011-04-12 23:20:32 +00:00
|
|
|
test_i18ngrep "not possible because you have unmerged files" out &&
|
Be more user-friendly when refusing to do something because of conflict.
Various commands refuse to run in the presence of conflicts (commit,
merge, pull, cherry-pick/revert). They all used to provide rough, and
inconsistant error messages.
A new variable advice.resolveconflict is introduced, and allows more
verbose messages, pointing the user to the appropriate solution.
For commit, the error message used to look like this:
$ git commit
foo.txt: needs merge
foo.txt: unmerged (c34a92682e0394bc0d6f4d4a67a8e2d32395c169)
foo.txt: unmerged (3afcd75de8de0bb5076942fcb17446be50451030)
foo.txt: unmerged (c9785d77b76dfe4fb038bf927ee518f6ae45ede4)
error: Error building trees
The "need merge" line is given by refresh_cache. We add the IN_PORCELAIN
option to make the output more consistant with the other porcelain
commands, and catch the error in return, to stop with a clean error
message. The next lines were displayed by a call to cache_tree_update(),
which is not reached anymore if we noticed the conflict.
The new output looks like:
U foo.txt
fatal: 'commit' is not possible because you have unmerged files.
Please, fix them up in the work tree, and then use 'git add/rm <file>' as
appropriate to mark resolution and make a commit, or use 'git commit -a'.
Pull is slightly modified to abort immediately if $GIT_DIR/MERGE_HEAD
exists instead of waiting for merge to complain.
The behavior of merge and the test-case are slightly modified to reflect
the usual flow: start with conflicts, fix them, and afterwards get rid of
MERGE_HEAD, with different error messages at each stage.
Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-12 09:54:44 +00:00
|
|
|
git add -u &&
|
|
|
|
test_must_fail git merge "$c5" 2> out &&
|
2011-04-12 23:20:32 +00:00
|
|
|
test_i18ngrep "You have not concluded your merge" out &&
|
2009-06-01 09:20:56 +00:00
|
|
|
rm -f .git/MERGE_HEAD &&
|
|
|
|
test_must_fail git merge "$c5" 2> out &&
|
2011-04-12 23:20:32 +00:00
|
|
|
test_i18ngrep "Your local changes to the following files would be overwritten by merge:" out
|
merge: fix numerus bugs around "trivial merge" area
The "trivial merge" codepath wants to optimize itself by making an
internal call to the read-tree machinery, but it does not read the index
before doing so, and the codepath is never exercised. Incidentally, this
failure to read the index upfront means that the safety to refuse doing
anything when the index is unmerged does not kick in, either.
These two problem are fixed by using read_cache_unmerged() that does read
the index before checking if it is unmerged at the beginning of
cmd_merge().
The primary logic of the merge, however, assumes that the process never
reads the index in-core, and the call to write_cache_as_tree() it makes
from write_tree_trivial() will always read from the on-disk index that is
prepared the strategy back-ends. This assumption is now broken by the
above fix. To fix this issue, we now call discard_cache() before calling
write_tree_trivial() when it wants to write the on-disk index as a tree.
When multiple strategies are tried, their results are evaluated by reading
the resulting index and inspecting it. The codepath needs to make a call
to read_cache() for each successful strategy, and for that to work, they
need to discard_cache() the one read by the previous round.
Also the "trivial merge" forgot that the current commit is one of the
parents of the resulting commit.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-08-23 19:56:57 +00:00
|
|
|
'
|
|
|
|
|
2007-04-07 14:17:35 +00:00
|
|
|
test_expect_success 'merge-recursive remove conflict' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -fr [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git checkout -f "$c1" &&
|
|
|
|
|
2011-12-08 13:10:13 +00:00
|
|
|
test_expect_code 1 git merge-recursive "$c0" -- "$c1" "$c5"
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive remove conflict' '
|
|
|
|
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o0 1 a" &&
|
|
|
|
echo "100644 $o1 2 a" &&
|
|
|
|
echo "100644 $o5 3 a" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive d/f simple' '
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -fr [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout -f "$c1" &&
|
|
|
|
|
2008-09-03 08:59:27 +00:00
|
|
|
git merge-recursive "$c0" -- "$c1" "$c3"
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive result' '
|
|
|
|
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o1 0 a" &&
|
|
|
|
echo "100644 $o3 0 b/c" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive d/f conflict' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -fr [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout -f "$c1" &&
|
|
|
|
|
2011-12-08 13:10:13 +00:00
|
|
|
test_expect_code 1 git merge-recursive "$c0" -- "$c1" "$c4"
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive d/f conflict result' '
|
|
|
|
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o0 1 a" &&
|
|
|
|
echo "100644 $o1 2 a" &&
|
|
|
|
echo "100644 $o4 0 a/c" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive d/f conflict the other way' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -fr [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout -f "$c4" &&
|
|
|
|
|
2011-12-08 13:10:13 +00:00
|
|
|
test_expect_code 1 git merge-recursive "$c0" -- "$c4" "$c1"
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive d/f conflict result the other way' '
|
|
|
|
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o0 1 a" &&
|
|
|
|
echo "100644 $o1 3 a" &&
|
|
|
|
echo "100644 $o4 0 a/c" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive d/f conflict' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -fr [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout -f "$c1" &&
|
|
|
|
|
2011-12-08 13:10:13 +00:00
|
|
|
test_expect_code 1 git merge-recursive "$c0" -- "$c1" "$c6"
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive d/f conflict result' '
|
|
|
|
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o1 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
|
|
|
echo "100644 $o6 3 d" &&
|
|
|
|
echo "100644 $o0 1 d/e" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 2 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive d/f conflict' '
|
|
|
|
|
2007-04-19 04:51:06 +00:00
|
|
|
rm -fr [abcd] &&
|
2007-04-07 14:17:35 +00:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout -f "$c6" &&
|
|
|
|
|
2011-12-08 13:10:13 +00:00
|
|
|
test_expect_code 1 git merge-recursive "$c0" -- "$c6" "$c1"
|
2007-04-07 14:17:35 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive d/f conflict result' '
|
|
|
|
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o1 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
|
|
|
echo "100644 $o6 2 d" &&
|
|
|
|
echo "100644 $o0 1 d/e" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 3 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
'
|
|
|
|
|
2019-09-18 20:27:38 +00:00
|
|
|
test_expect_success SYMLINKS 'dir in working tree with symlink ancestor does not produce d/f conflict' '
|
|
|
|
git init sym &&
|
|
|
|
(
|
|
|
|
cd sym &&
|
|
|
|
ln -s . foo &&
|
|
|
|
mkdir bar &&
|
|
|
|
>bar/file &&
|
|
|
|
git add foo bar/file &&
|
|
|
|
git commit -m "foo symlink" &&
|
|
|
|
|
|
|
|
git checkout -b branch1 &&
|
|
|
|
git commit --allow-empty -m "empty commit" &&
|
|
|
|
|
|
|
|
git checkout master &&
|
|
|
|
git rm foo &&
|
|
|
|
mkdir foo &&
|
|
|
|
>foo/bar &&
|
|
|
|
git add foo/bar &&
|
|
|
|
git commit -m "replace foo symlink with real foo dir and foo/bar file" &&
|
|
|
|
|
|
|
|
git checkout branch1 &&
|
|
|
|
|
|
|
|
git cherry-pick master &&
|
|
|
|
test_path_is_dir foo &&
|
|
|
|
test_path_is_file foo/bar
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2007-04-07 14:17:35 +00:00
|
|
|
test_expect_success 'reset and 3-way merge' '
|
|
|
|
|
|
|
|
git reset --hard "$c2" &&
|
|
|
|
git read-tree -m "$c0" "$c2" "$c1"
|
|
|
|
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'reset and bind merge' '
|
|
|
|
|
|
|
|
git reset --hard master &&
|
|
|
|
git read-tree --prefix=M/ master &&
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o1 0 M/a" &&
|
|
|
|
echo "100644 $o0 0 M/b" &&
|
|
|
|
echo "100644 $o0 0 M/c" &&
|
|
|
|
echo "100644 $o1 0 M/d/e" &&
|
|
|
|
echo "100644 $o1 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 0 d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
git read-tree --prefix=a1/ master &&
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o1 0 M/a" &&
|
|
|
|
echo "100644 $o0 0 M/b" &&
|
|
|
|
echo "100644 $o0 0 M/c" &&
|
|
|
|
echo "100644 $o1 0 M/d/e" &&
|
|
|
|
echo "100644 $o1 0 a" &&
|
|
|
|
echo "100644 $o1 0 a1/a" &&
|
|
|
|
echo "100644 $o0 0 a1/b" &&
|
|
|
|
echo "100644 $o0 0 a1/c" &&
|
|
|
|
echo "100644 $o1 0 a1/d/e" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 0 d/e"
|
|
|
|
) >expected &&
|
2010-10-31 01:46:54 +00:00
|
|
|
test_cmp expected actual &&
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
git read-tree --prefix=z/ master &&
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o1 0 M/a" &&
|
|
|
|
echo "100644 $o0 0 M/b" &&
|
|
|
|
echo "100644 $o0 0 M/c" &&
|
|
|
|
echo "100644 $o1 0 M/d/e" &&
|
|
|
|
echo "100644 $o1 0 a" &&
|
|
|
|
echo "100644 $o1 0 a1/a" &&
|
|
|
|
echo "100644 $o0 0 a1/b" &&
|
|
|
|
echo "100644 $o0 0 a1/c" &&
|
|
|
|
echo "100644 $o1 0 a1/d/e" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
|
|
|
echo "100644 $o1 0 d/e" &&
|
|
|
|
echo "100644 $o1 0 z/a" &&
|
|
|
|
echo "100644 $o0 0 z/b" &&
|
|
|
|
echo "100644 $o0 0 z/c" &&
|
2007-04-07 14:17:35 +00:00
|
|
|
echo "100644 $o1 0 z/d/e"
|
|
|
|
) >expected &&
|
2008-05-24 05:28:56 +00:00
|
|
|
test_cmp expected actual
|
2007-04-07 14:17:35 +00:00
|
|
|
|
|
|
|
'
|
|
|
|
|
2014-01-27 14:45:09 +00:00
|
|
|
test_expect_success 'merge-recursive w/ empty work tree - ours has rename' '
|
2014-01-27 14:45:06 +00:00
|
|
|
(
|
|
|
|
GIT_WORK_TREE="$PWD/ours-has-rename-work" &&
|
|
|
|
export GIT_WORK_TREE &&
|
|
|
|
GIT_INDEX_FILE="$PWD/ours-has-rename-index" &&
|
|
|
|
export GIT_INDEX_FILE &&
|
|
|
|
mkdir "$GIT_WORK_TREE" &&
|
2018-02-23 23:39:44 +00:00
|
|
|
git read-tree -i -m $c7 2>actual-err &&
|
|
|
|
test_must_be_empty actual-err &&
|
|
|
|
git update-index --ignore-missing --refresh 2>actual-err &&
|
|
|
|
test_must_be_empty actual-err &&
|
|
|
|
git merge-recursive $c0 -- $c7 $c3 2>actual-err &&
|
|
|
|
test_must_be_empty actual-err &&
|
|
|
|
git ls-files -s >actual-files 2>actual-err &&
|
|
|
|
test_must_be_empty actual-err
|
|
|
|
) &&
|
2014-01-27 14:45:06 +00:00
|
|
|
cat >expected-files <<-EOF &&
|
|
|
|
100644 $o3 0 b/c
|
|
|
|
100644 $o0 0 c
|
|
|
|
100644 $o0 0 d/e
|
|
|
|
100644 $o0 0 e
|
|
|
|
EOF
|
2018-02-23 23:39:44 +00:00
|
|
|
test_cmp expected-files actual-files
|
2014-01-27 14:45:06 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'merge-recursive w/ empty work tree - theirs has rename' '
|
|
|
|
(
|
|
|
|
GIT_WORK_TREE="$PWD/theirs-has-rename-work" &&
|
|
|
|
export GIT_WORK_TREE &&
|
|
|
|
GIT_INDEX_FILE="$PWD/theirs-has-rename-index" &&
|
|
|
|
export GIT_INDEX_FILE &&
|
|
|
|
mkdir "$GIT_WORK_TREE" &&
|
2018-02-23 23:39:44 +00:00
|
|
|
git read-tree -i -m $c3 2>actual-err &&
|
|
|
|
test_must_be_empty actual-err &&
|
|
|
|
git update-index --ignore-missing --refresh 2>actual-err &&
|
|
|
|
test_must_be_empty actual-err &&
|
|
|
|
git merge-recursive $c0 -- $c3 $c7 2>actual-err &&
|
|
|
|
test_must_be_empty actual-err &&
|
|
|
|
git ls-files -s >actual-files 2>actual-err &&
|
|
|
|
test_must_be_empty actual-err
|
|
|
|
) &&
|
2014-01-27 14:45:06 +00:00
|
|
|
cat >expected-files <<-EOF &&
|
|
|
|
100644 $o3 0 b/c
|
|
|
|
100644 $o0 0 c
|
|
|
|
100644 $o0 0 d/e
|
|
|
|
100644 $o0 0 e
|
|
|
|
EOF
|
2018-02-23 23:39:44 +00:00
|
|
|
test_cmp expected-files actual-files
|
2014-01-27 14:45:06 +00:00
|
|
|
'
|
|
|
|
|
2008-09-25 20:12:45 +00:00
|
|
|
test_expect_success 'merge removes empty directories' '
|
|
|
|
|
|
|
|
git reset --hard master &&
|
|
|
|
git checkout -b rm &&
|
|
|
|
git rm d/e &&
|
|
|
|
git commit -mremoved-d/e &&
|
|
|
|
git checkout master &&
|
|
|
|
git merge -s recursive rm &&
|
2020-01-07 04:53:05 +00:00
|
|
|
test_path_is_missing d
|
2008-09-25 20:12:45 +00:00
|
|
|
'
|
|
|
|
|
2016-11-07 18:31:31 +00:00
|
|
|
test_expect_success 'merge-recursive simple w/submodule' '
|
2010-06-08 11:34:12 +00:00
|
|
|
|
|
|
|
git checkout submod &&
|
|
|
|
git merge remove
|
|
|
|
'
|
|
|
|
|
2016-11-07 18:31:31 +00:00
|
|
|
test_expect_success 'merge-recursive simple w/submodule result' '
|
2010-06-08 11:34:12 +00:00
|
|
|
|
|
|
|
git ls-files -s >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 $o5 0 a" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
2010-06-08 11:34:12 +00:00
|
|
|
echo "160000 $c1 0 d"
|
|
|
|
) >expected &&
|
|
|
|
test_cmp expected actual
|
|
|
|
'
|
|
|
|
|
2010-09-01 20:15:32 +00:00
|
|
|
test_expect_success 'merge-recursive copy vs. rename' '
|
|
|
|
git checkout -f copy &&
|
|
|
|
git merge rename &&
|
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 blob $o0 e" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
|
|
|
echo "100644 $o0 0 d/e" &&
|
2010-09-01 20:15:32 +00:00
|
|
|
echo "100644 $o0 0 e"
|
|
|
|
) >expected &&
|
|
|
|
test_cmp expected actual
|
|
|
|
'
|
|
|
|
|
2013-06-07 20:53:30 +00:00
|
|
|
test_expect_failure 'merge-recursive rename vs. rename/symlink' '
|
|
|
|
|
|
|
|
git checkout -f rename &&
|
|
|
|
git merge rename-ln &&
|
2018-07-02 00:23:59 +00:00
|
|
|
( git ls-tree -r HEAD && git ls-files -s ) >actual &&
|
2013-06-07 20:53:30 +00:00
|
|
|
(
|
2018-07-02 00:23:59 +00:00
|
|
|
echo "120000 blob $oln a" &&
|
|
|
|
echo "100644 blob $o0 b" &&
|
|
|
|
echo "100644 blob $o0 c" &&
|
|
|
|
echo "100644 blob $o0 d/e" &&
|
|
|
|
echo "100644 blob $o0 e" &&
|
|
|
|
echo "120000 $oln 0 a" &&
|
|
|
|
echo "100644 $o0 0 b" &&
|
|
|
|
echo "100644 $o0 0 c" &&
|
|
|
|
echo "100644 $o0 0 d/e" &&
|
2013-06-07 20:53:30 +00:00
|
|
|
echo "100644 $o0 0 e"
|
|
|
|
) >expected &&
|
|
|
|
test_cmp expected actual
|
|
|
|
'
|
2010-09-20 08:28:34 +00:00
|
|
|
|
2015-10-26 21:36:18 +00:00
|
|
|
test_expect_success 'merging with triple rename across D/F conflict' '
|
|
|
|
git reset --hard HEAD &&
|
|
|
|
git checkout -b main &&
|
|
|
|
git rm -rf . &&
|
|
|
|
|
|
|
|
echo "just a file" >sub1 &&
|
|
|
|
mkdir -p sub2 &&
|
|
|
|
echo content1 >sub2/file1 &&
|
|
|
|
echo content2 >sub2/file2 &&
|
|
|
|
echo content3 >sub2/file3 &&
|
|
|
|
mkdir simple &&
|
|
|
|
echo base >simple/bar &&
|
|
|
|
git add -A &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m base &&
|
|
|
|
|
|
|
|
git checkout -b other &&
|
|
|
|
echo more >>simple/bar &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -a -m changesimplefile &&
|
|
|
|
|
|
|
|
git checkout main &&
|
|
|
|
git rm sub1 &&
|
|
|
|
git mv sub2 sub1 &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m changefiletodir &&
|
|
|
|
|
|
|
|
test_tick &&
|
|
|
|
git merge other
|
|
|
|
'
|
2010-09-20 08:28:34 +00:00
|
|
|
|
2016-08-13 12:16:04 +00:00
|
|
|
test_expect_success 'merge-recursive remembers the names of all base trees' '
|
|
|
|
git reset --hard HEAD &&
|
|
|
|
|
Ensure index matches head before invoking merge machinery, round N
This is the bug that just won't die; there always seems to be another
form of it somewhere. See the commit message of 55f39cf7551b ("merge:
fix misleading pre-merge check documentation", 2018-06-30) for a more
detailed explanation), but in short:
<quick summary>
builtin/merge.c contains this important requirement for merge
strategies:
...the index must be in sync with the head commit. The strategies are
responsible to ensure this.
This condition is important to enforce because there are two likely
failure cases when the index isn't in sync with the head commit:
* we silently throw away changes the user had staged before the merge
* we accidentally (and silently) include changes in the merge that
were not part of either of the branches/trees being merged
Discarding users' work and mis-merging are both bad outcomes, especially
when done silently, so naturally this rule was stated sternly -- but,
unfortunately totally ignored in practice unless and until actual bugs
were found. But, fear not: the bugs from this were fixed in commit
ee6566e8d70d ("[PATCH] Rewrite read-tree", 2005-09-05)
through a rewrite of read-tree (again, commit 55f39cf7551b has a more
detailed explanation of how this affected merge). And it was fixed
again in commit
160252f81626 ("git-merge-ours: make sure our index matches HEAD", 2005-11-03)
...and it was fixed again in commit
3ec62ad9ffba ("merge-octopus: abort if index does not match HEAD", 2016-04-09)
...and again in commit
65170c07d466 ("merge-recursive: avoid incorporating uncommitted changes in a merge", 2017-12-21)
...and again in commit
eddd1a411d93 ("merge-recursive: enforce rule that index matches head before merging", 2018-06-30)
...with multiple testcases added to the testsuite that could be
enumerated in even more commits.
Then, finally, in a patch in the same series as the last fix above, the
documentation about this requirement was fixed in commit 55f39cf7551b
("merge: fix misleading pre-merge check documentation", 2018-06-30), and
we all lived happily ever after...
</quick summary>
Unfortunately, "ever after" apparently denotes a limited time and it
expired today. The merge-recursive rule to enforce that index matches
head was at the beginning of merge_trees() and would only trigger when
opt->call_depth was 0. Since merge_recursive() doesn't call
merge_trees() until after returning from recursing, this meant that the
check wasn't triggered by merge_recursive() until it had first finished
all the intermediate merges to create virtual merge bases. That is a
potentially HUGE amount of computation (and writing of intermediate
merge results into the .git/objects directory) before it errors out and
says, in effect, "Sorry, I can't do any merging because you have some
local changes that would be overwritten."
Trying to enforce that all of merge_trees(), merge_recursive(), and
merge_recursive_generic() checked the index == head condition earlier
resulted in a bunch of broken tests. It turns out that
merge_recursive() has code to drop and reload the cache while recursing
to create intermediate virtual merge bases, but unfortunately that code
runs even when no recursion is necessary. This unconditional dropping
and reloading of the cache masked a few bugs:
* builtin/merge-recursive.c: didn't even bother loading the index.
* builtin/stash.c: feels like a fake 'builtin' because it repeatedly
invokes git subprocesses all over the place, mixed with other
operations. In particular, invoking "git reset" will reset the
index on disk, but the parent process that invoked it won't
automatically have its in-memory index updated.
* t3030-merge-recursive.h: this test has always been broken in that it
didn't make sure to make index match head before running. But, it
didn't care about the index or even the merge result, just the
verbose output while running. While commit eddd1a411d93
("merge-recursive: enforce rule that index matches head before
merging", 2018-06-30) should have uncovered this broken test, it
used a test_must_fail wrapper around the merge-recursive call
because it was known that the merge resulted in a rename/rename
conflict. Thus, that fix only made this test fail for a different
reason, and since the index == head check didn't happen until after
coming all the way back out of the recursion, the testcase had
enough information to pass the one check that it did perform.
So, load the index in builtin/merge-recursive.c, reload the in-memory
index in builtin/stash.c, and modify the t3030 testcase to correctly
setup the index and make sure that the test fails in the expected way
(meaning it reports a rename/rename conflict). This makes sure that
all callers actually make the index match head. The next commit will
then enforce the condition that index matches head earlier so this
problem doesn't return in the future.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-17 18:41:28 +00:00
|
|
|
# make the index match $c1 so that merge-recursive below does not
|
|
|
|
# fail early
|
|
|
|
git diff --binary HEAD $c1 -- | git apply --cached &&
|
|
|
|
|
2016-08-13 12:16:04 +00:00
|
|
|
# more trees than static slots used by oid_to_hex()
|
|
|
|
for commit in $c0 $c2 $c4 $c5 $c6 $c7
|
|
|
|
do
|
|
|
|
git rev-parse "$commit^{tree}"
|
|
|
|
done >trees &&
|
|
|
|
|
Ensure index matches head before invoking merge machinery, round N
This is the bug that just won't die; there always seems to be another
form of it somewhere. See the commit message of 55f39cf7551b ("merge:
fix misleading pre-merge check documentation", 2018-06-30) for a more
detailed explanation), but in short:
<quick summary>
builtin/merge.c contains this important requirement for merge
strategies:
...the index must be in sync with the head commit. The strategies are
responsible to ensure this.
This condition is important to enforce because there are two likely
failure cases when the index isn't in sync with the head commit:
* we silently throw away changes the user had staged before the merge
* we accidentally (and silently) include changes in the merge that
were not part of either of the branches/trees being merged
Discarding users' work and mis-merging are both bad outcomes, especially
when done silently, so naturally this rule was stated sternly -- but,
unfortunately totally ignored in practice unless and until actual bugs
were found. But, fear not: the bugs from this were fixed in commit
ee6566e8d70d ("[PATCH] Rewrite read-tree", 2005-09-05)
through a rewrite of read-tree (again, commit 55f39cf7551b has a more
detailed explanation of how this affected merge). And it was fixed
again in commit
160252f81626 ("git-merge-ours: make sure our index matches HEAD", 2005-11-03)
...and it was fixed again in commit
3ec62ad9ffba ("merge-octopus: abort if index does not match HEAD", 2016-04-09)
...and again in commit
65170c07d466 ("merge-recursive: avoid incorporating uncommitted changes in a merge", 2017-12-21)
...and again in commit
eddd1a411d93 ("merge-recursive: enforce rule that index matches head before merging", 2018-06-30)
...with multiple testcases added to the testsuite that could be
enumerated in even more commits.
Then, finally, in a patch in the same series as the last fix above, the
documentation about this requirement was fixed in commit 55f39cf7551b
("merge: fix misleading pre-merge check documentation", 2018-06-30), and
we all lived happily ever after...
</quick summary>
Unfortunately, "ever after" apparently denotes a limited time and it
expired today. The merge-recursive rule to enforce that index matches
head was at the beginning of merge_trees() and would only trigger when
opt->call_depth was 0. Since merge_recursive() doesn't call
merge_trees() until after returning from recursing, this meant that the
check wasn't triggered by merge_recursive() until it had first finished
all the intermediate merges to create virtual merge bases. That is a
potentially HUGE amount of computation (and writing of intermediate
merge results into the .git/objects directory) before it errors out and
says, in effect, "Sorry, I can't do any merging because you have some
local changes that would be overwritten."
Trying to enforce that all of merge_trees(), merge_recursive(), and
merge_recursive_generic() checked the index == head condition earlier
resulted in a bunch of broken tests. It turns out that
merge_recursive() has code to drop and reload the cache while recursing
to create intermediate virtual merge bases, but unfortunately that code
runs even when no recursion is necessary. This unconditional dropping
and reloading of the cache masked a few bugs:
* builtin/merge-recursive.c: didn't even bother loading the index.
* builtin/stash.c: feels like a fake 'builtin' because it repeatedly
invokes git subprocesses all over the place, mixed with other
operations. In particular, invoking "git reset" will reset the
index on disk, but the parent process that invoked it won't
automatically have its in-memory index updated.
* t3030-merge-recursive.h: this test has always been broken in that it
didn't make sure to make index match head before running. But, it
didn't care about the index or even the merge result, just the
verbose output while running. While commit eddd1a411d93
("merge-recursive: enforce rule that index matches head before
merging", 2018-06-30) should have uncovered this broken test, it
used a test_must_fail wrapper around the merge-recursive call
because it was known that the merge resulted in a rename/rename
conflict. Thus, that fix only made this test fail for a different
reason, and since the index == head check didn't happen until after
coming all the way back out of the recursion, the testcase had
enough information to pass the one check that it did perform.
So, load the index in builtin/merge-recursive.c, reload the in-memory
index in builtin/stash.c, and modify the t3030 testcase to correctly
setup the index and make sure that the test fails in the expected way
(meaning it reports a rename/rename conflict). This makes sure that
all callers actually make the index match head. The next commit will
then enforce the condition that index matches head earlier so this
problem doesn't return in the future.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-17 18:41:28 +00:00
|
|
|
# ignore the return code; it only fails because the input is weird...
|
2016-08-13 12:16:04 +00:00
|
|
|
test_must_fail git -c merge.verbosity=5 merge-recursive $(cat trees) -- $c1 $c3 >out &&
|
|
|
|
|
Ensure index matches head before invoking merge machinery, round N
This is the bug that just won't die; there always seems to be another
form of it somewhere. See the commit message of 55f39cf7551b ("merge:
fix misleading pre-merge check documentation", 2018-06-30) for a more
detailed explanation), but in short:
<quick summary>
builtin/merge.c contains this important requirement for merge
strategies:
...the index must be in sync with the head commit. The strategies are
responsible to ensure this.
This condition is important to enforce because there are two likely
failure cases when the index isn't in sync with the head commit:
* we silently throw away changes the user had staged before the merge
* we accidentally (and silently) include changes in the merge that
were not part of either of the branches/trees being merged
Discarding users' work and mis-merging are both bad outcomes, especially
when done silently, so naturally this rule was stated sternly -- but,
unfortunately totally ignored in practice unless and until actual bugs
were found. But, fear not: the bugs from this were fixed in commit
ee6566e8d70d ("[PATCH] Rewrite read-tree", 2005-09-05)
through a rewrite of read-tree (again, commit 55f39cf7551b has a more
detailed explanation of how this affected merge). And it was fixed
again in commit
160252f81626 ("git-merge-ours: make sure our index matches HEAD", 2005-11-03)
...and it was fixed again in commit
3ec62ad9ffba ("merge-octopus: abort if index does not match HEAD", 2016-04-09)
...and again in commit
65170c07d466 ("merge-recursive: avoid incorporating uncommitted changes in a merge", 2017-12-21)
...and again in commit
eddd1a411d93 ("merge-recursive: enforce rule that index matches head before merging", 2018-06-30)
...with multiple testcases added to the testsuite that could be
enumerated in even more commits.
Then, finally, in a patch in the same series as the last fix above, the
documentation about this requirement was fixed in commit 55f39cf7551b
("merge: fix misleading pre-merge check documentation", 2018-06-30), and
we all lived happily ever after...
</quick summary>
Unfortunately, "ever after" apparently denotes a limited time and it
expired today. The merge-recursive rule to enforce that index matches
head was at the beginning of merge_trees() and would only trigger when
opt->call_depth was 0. Since merge_recursive() doesn't call
merge_trees() until after returning from recursing, this meant that the
check wasn't triggered by merge_recursive() until it had first finished
all the intermediate merges to create virtual merge bases. That is a
potentially HUGE amount of computation (and writing of intermediate
merge results into the .git/objects directory) before it errors out and
says, in effect, "Sorry, I can't do any merging because you have some
local changes that would be overwritten."
Trying to enforce that all of merge_trees(), merge_recursive(), and
merge_recursive_generic() checked the index == head condition earlier
resulted in a bunch of broken tests. It turns out that
merge_recursive() has code to drop and reload the cache while recursing
to create intermediate virtual merge bases, but unfortunately that code
runs even when no recursion is necessary. This unconditional dropping
and reloading of the cache masked a few bugs:
* builtin/merge-recursive.c: didn't even bother loading the index.
* builtin/stash.c: feels like a fake 'builtin' because it repeatedly
invokes git subprocesses all over the place, mixed with other
operations. In particular, invoking "git reset" will reset the
index on disk, but the parent process that invoked it won't
automatically have its in-memory index updated.
* t3030-merge-recursive.h: this test has always been broken in that it
didn't make sure to make index match head before running. But, it
didn't care about the index or even the merge result, just the
verbose output while running. While commit eddd1a411d93
("merge-recursive: enforce rule that index matches head before
merging", 2018-06-30) should have uncovered this broken test, it
used a test_must_fail wrapper around the merge-recursive call
because it was known that the merge resulted in a rename/rename
conflict. Thus, that fix only made this test fail for a different
reason, and since the index == head check didn't happen until after
coming all the way back out of the recursion, the testcase had
enough information to pass the one check that it did perform.
So, load the index in builtin/merge-recursive.c, reload the in-memory
index in builtin/stash.c, and modify the t3030 testcase to correctly
setup the index and make sure that the test fails in the expected way
(meaning it reports a rename/rename conflict). This makes sure that
all callers actually make the index match head. The next commit will
then enforce the condition that index matches head earlier so this
problem doesn't return in the future.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-17 18:41:28 +00:00
|
|
|
# ...but make sure it fails in the expected way
|
|
|
|
test_i18ngrep CONFLICT.*rename/rename out &&
|
|
|
|
|
2016-08-13 12:16:04 +00:00
|
|
|
# merge-recursive prints in reverse order, but we do not care
|
|
|
|
sort <trees >expect &&
|
|
|
|
sed -n "s/^virtual //p" out | sort >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2018-01-09 18:05:51 +00:00
|
|
|
test_expect_success 'merge-recursive internal merge resolves to the sameness' '
|
|
|
|
git reset --hard HEAD &&
|
|
|
|
|
|
|
|
# We are going to create a history leading to two criss-cross
|
|
|
|
# branches A and B. The common ancestor at the bottom, O0,
|
|
|
|
# has two child commits O1 and O2, both of which will be merge
|
|
|
|
# base between A and B, like so:
|
|
|
|
#
|
|
|
|
# O1---A
|
|
|
|
# / \ /
|
|
|
|
# O0 .
|
|
|
|
# \ / \
|
|
|
|
# O2---B
|
|
|
|
#
|
|
|
|
# The recently added "check to see if the index is different from
|
|
|
|
# the tree into which something else is getting merged" check must
|
|
|
|
# NOT kick in when an inner merge between O1 and O2 is made. Both
|
|
|
|
# O1 and O2 happen to have the same tree as O0 in this test to
|
|
|
|
# trigger the bug---whether the inner merge is made by merging O2
|
|
|
|
# into O1 or O1 into O2, their common ancestor O0 and the branch
|
|
|
|
# being merged have the same tree. We should not trigger the "is
|
|
|
|
# the index dirty?" check in this case.
|
|
|
|
|
|
|
|
echo "zero" >file &&
|
|
|
|
git add file &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "O0" &&
|
|
|
|
O0=$(git rev-parse HEAD) &&
|
|
|
|
|
|
|
|
test_tick &&
|
|
|
|
git commit --allow-empty -m "O1" &&
|
|
|
|
O1=$(git rev-parse HEAD) &&
|
|
|
|
|
|
|
|
git reset --hard $O0 &&
|
|
|
|
test_tick &&
|
|
|
|
git commit --allow-empty -m "O2" &&
|
|
|
|
O2=$(git rev-parse HEAD) &&
|
|
|
|
|
|
|
|
test_tick &&
|
|
|
|
git merge -s ours $O1 &&
|
|
|
|
B=$(git rev-parse HEAD) &&
|
|
|
|
|
|
|
|
git reset --hard $O1 &&
|
|
|
|
test_tick &&
|
|
|
|
git merge -s ours $O2 &&
|
|
|
|
A=$(git rev-parse HEAD) &&
|
|
|
|
|
|
|
|
git merge $B
|
|
|
|
'
|
|
|
|
|
2007-04-07 14:17:35 +00:00
|
|
|
test_done
|