2016-04-10 08:13:37 +02:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description="merges with unrelated index changes"
|
|
|
|
|
|
|
|
. ./test-lib.sh
|
|
|
|
|
|
|
|
# Testcase for some simple merges
|
|
|
|
# A
|
2017-12-21 20:19:05 +01:00
|
|
|
# o-------o B
|
2016-04-10 08:13:37 +02:00
|
|
|
# \
|
2017-12-21 20:19:05 +01:00
|
|
|
# \-----o C
|
2016-04-10 08:13:37 +02:00
|
|
|
# \
|
2017-12-21 20:19:05 +01:00
|
|
|
# \---o D
|
2016-04-10 08:13:37 +02:00
|
|
|
# \
|
2017-12-21 20:19:05 +01:00
|
|
|
# \-o E
|
|
|
|
# \
|
|
|
|
# o F
|
2016-04-10 08:13:37 +02:00
|
|
|
# Commit A: some file a
|
|
|
|
# Commit B: adds file b, modifies end of a
|
|
|
|
# Commit C: adds file c
|
|
|
|
# Commit D: adds file d, modifies beginning of a
|
|
|
|
# Commit E: renames a->subdir/a, adds subdir/e
|
2017-12-21 20:19:05 +01:00
|
|
|
# Commit F: empty commit
|
2016-04-10 08:13:37 +02:00
|
|
|
|
|
|
|
test_expect_success 'setup trivial merges' '
|
2016-05-18 07:51:39 +02:00
|
|
|
test_seq 1 10 >a &&
|
2016-04-10 08:13:37 +02:00
|
|
|
git add a &&
|
|
|
|
test_tick && git commit -m A &&
|
|
|
|
|
|
|
|
git branch A &&
|
|
|
|
git branch B &&
|
|
|
|
git branch C &&
|
|
|
|
git branch D &&
|
|
|
|
git branch E &&
|
2017-12-21 20:19:05 +01:00
|
|
|
git branch F &&
|
2016-04-10 08:13:37 +02:00
|
|
|
|
|
|
|
git checkout B &&
|
|
|
|
echo b >b &&
|
|
|
|
echo 11 >>a &&
|
|
|
|
git add a b &&
|
|
|
|
test_tick && git commit -m B &&
|
|
|
|
|
|
|
|
git checkout C &&
|
|
|
|
echo c >c &&
|
|
|
|
git add c &&
|
|
|
|
test_tick && git commit -m C &&
|
|
|
|
|
|
|
|
git checkout D &&
|
2016-05-18 07:51:39 +02:00
|
|
|
test_seq 2 10 >a &&
|
2016-04-10 08:13:37 +02:00
|
|
|
echo d >d &&
|
|
|
|
git add a d &&
|
|
|
|
test_tick && git commit -m D &&
|
|
|
|
|
|
|
|
git checkout E &&
|
|
|
|
mkdir subdir &&
|
|
|
|
git mv a subdir/a &&
|
|
|
|
echo e >subdir/e &&
|
|
|
|
git add subdir &&
|
2017-12-21 20:19:05 +01:00
|
|
|
test_tick && git commit -m E &&
|
|
|
|
|
|
|
|
git checkout F &&
|
|
|
|
test_tick && git commit --allow-empty -m F
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'ff update' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout A^0 &&
|
|
|
|
|
|
|
|
touch random_file && git add random_file &&
|
|
|
|
|
|
|
|
git merge E^0 &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:random_file &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test "$(git diff --name-only --cached E)" = "random_file" &&
|
|
|
|
test_path_is_file random_file &&
|
|
|
|
git rev-parse --verify :random_file
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'ff update, important file modified' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout A^0 &&
|
|
|
|
|
|
|
|
mkdir subdir &&
|
|
|
|
touch subdir/e &&
|
|
|
|
git add subdir/e &&
|
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge E^0 &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test_path_is_file subdir/e &&
|
|
|
|
git rev-parse --verify :subdir/e &&
|
2018-07-01 03:24:57 +02:00
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'resolve, trivial' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
touch random_file && git add random_file &&
|
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge -s resolve C^0 &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test_path_is_file random_file &&
|
|
|
|
git rev-parse --verify :random_file &&
|
2018-07-01 03:24:57 +02:00
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'resolve, non-trivial' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
touch random_file && git add random_file &&
|
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge -s resolve D^0 &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test_path_is_file random_file &&
|
|
|
|
git rev-parse --verify :random_file &&
|
2018-07-01 03:24:57 +02:00
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
2022-07-23 03:53:13 +02:00
|
|
|
test_expect_success 'resolve, trivial, related file removed' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
git rm a &&
|
|
|
|
test_path_is_missing a &&
|
|
|
|
|
|
|
|
test_must_fail git merge -s resolve C^0 &&
|
|
|
|
|
|
|
|
test_path_is_missing a &&
|
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
|
|
|
'
|
|
|
|
|
merge-resolve: abort if index does not match HEAD
As noted in commit 9822175d2b ("Ensure index matches head before
invoking merge machinery, round N", 2019-08-17), we have had a very
long history of problems with failing to enforce the requirement that
index matches HEAD when starting a merge. One of the commits
referenced in the long tale of issues arising from lax enforcement of
this requirement was commit 55f39cf755 ("merge: fix misleading
pre-merge check documentation", 2018-06-30), which tried to document
the requirement and noted there were some exceptions. As mentioned in
that commit message, the `resolve` strategy was the one strategy that
did not have an explicit index matching HEAD check, and the reason it
didn't was that I wasn't able to discover any cases where the
implementation would fail to catch the problem and abort, and didn't
want to introduce unnecessary performance overhead of adding another
check.
Well, today I discovered a testcase where the implementation does not
catch the problem and so an explicit check is needed. Add a testcase
that previously would have failed, and update git-merge-resolve.sh to
have an explicit check. Note that the code is copied from 3ec62ad9ff
("merge-octopus: abort if index does not match HEAD", 2016-04-09), so
that we reuse the same message and avoid making translators need to
translate some new message.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 03:53:12 +02:00
|
|
|
test_expect_success 'resolve, non-trivial, related file removed' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
git rm a &&
|
|
|
|
test_path_is_missing a &&
|
|
|
|
|
2022-07-23 03:53:13 +02:00
|
|
|
# We also ask for recursive in order to turn off the "allow_trivial"
|
|
|
|
# setting in builtin/merge.c, and ensure that resolve really does
|
|
|
|
# correctly fail the merge (I guess this also tests that recursive
|
|
|
|
# correctly fails the merge, but the main thing we are attempting
|
|
|
|
# to test here is resolve and are just using the side effect of
|
|
|
|
# adding recursive to ensure that resolve is actually tested rather
|
|
|
|
# than the trivial merge codepath)
|
|
|
|
test_must_fail git merge -s resolve -s recursive D^0 &&
|
merge-resolve: abort if index does not match HEAD
As noted in commit 9822175d2b ("Ensure index matches head before
invoking merge machinery, round N", 2019-08-17), we have had a very
long history of problems with failing to enforce the requirement that
index matches HEAD when starting a merge. One of the commits
referenced in the long tale of issues arising from lax enforcement of
this requirement was commit 55f39cf755 ("merge: fix misleading
pre-merge check documentation", 2018-06-30), which tried to document
the requirement and noted there were some exceptions. As mentioned in
that commit message, the `resolve` strategy was the one strategy that
did not have an explicit index matching HEAD check, and the reason it
didn't was that I wasn't able to discover any cases where the
implementation would fail to catch the problem and abort, and didn't
want to introduce unnecessary performance overhead of adding another
check.
Well, today I discovered a testcase where the implementation does not
catch the problem and so an explicit check is needed. Add a testcase
that previously would have failed, and update git-merge-resolve.sh to
have an explicit check. Note that the code is copied from 3ec62ad9ff
("merge-octopus: abort if index does not match HEAD", 2016-04-09), so
that we reuse the same message and avoid making translators need to
translate some new message.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 03:53:12 +02:00
|
|
|
|
|
|
|
test_path_is_missing a &&
|
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
|
|
|
'
|
|
|
|
|
2016-04-10 08:13:37 +02:00
|
|
|
test_expect_success 'recursive' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
touch random_file && git add random_file &&
|
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge -s recursive C^0 &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test_path_is_file random_file &&
|
|
|
|
git rev-parse --verify :random_file &&
|
2018-07-01 03:24:57 +02:00
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
2018-07-01 03:24:59 +02:00
|
|
|
test_expect_success 'recursive, when merge branch matches merge base' '
|
2017-12-21 20:19:05 +01:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
touch random_file && git add random_file &&
|
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge -s recursive F^0 &&
|
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
2017-12-21 20:19:05 +01:00
|
|
|
'
|
|
|
|
|
2018-07-01 03:25:00 +02:00
|
|
|
test_expect_success 'merge-recursive, when index==head but head!=HEAD' '
|
t6044: add a testcase for index matching head, when head doesn't match HEAD
The `git merge-recursive` command allows the user to directly specify
three commits to merge -- base, head, and remote. (More than three can be
specified in the case of multiple merge bases.) Note that since the user
is allowed to specify head, it need not match HEAD.
Virtually every test and script in the current git.git codebase calls `git
merge-recursive` with head=HEAD, and likely external callers do as well,
which is why this has gone unnoticed. There is one notable
counter-example: git-stash.sh. However, git-stash called `git
merge-recursive` with an index that matches the expected merge result,
which happens to be a currently allowed exception to the "index must match
head" rule, so this never triggered an error previously.
Since we would like to tighten up the "index must match head" rule, we
need to make sure we are comparing to the correct head. Add a testcase
that demonstrates the failure when we check the wrong HEAD.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-01 03:24:58 +02:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout C^0 &&
|
|
|
|
|
|
|
|
# Make index match B
|
|
|
|
git diff C B -- | git apply --cached &&
|
2021-09-11 19:08:42 +02:00
|
|
|
test_when_finished "git clean -fd" && # Do not leave untracked around
|
t6044: add a testcase for index matching head, when head doesn't match HEAD
The `git merge-recursive` command allows the user to directly specify
three commits to merge -- base, head, and remote. (More than three can be
specified in the case of multiple merge bases.) Note that since the user
is allowed to specify head, it need not match HEAD.
Virtually every test and script in the current git.git codebase calls `git
merge-recursive` with head=HEAD, and likely external callers do as well,
which is why this has gone unnoticed. There is one notable
counter-example: git-stash.sh. However, git-stash called `git
merge-recursive` with an index that matches the expected merge result,
which happens to be a currently allowed exception to the "index must match
head" rule, so this never triggered an error previously.
Since we would like to tighten up the "index must match head" rule, we
need to make sure we are comparing to the correct head. Add a testcase
that demonstrates the failure when we check the wrong HEAD.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-01 03:24:58 +02:00
|
|
|
# Merge B & F, with B as "head"
|
|
|
|
git merge-recursive A -- B F > out &&
|
|
|
|
test_i18ngrep "Already up to date" out
|
|
|
|
'
|
|
|
|
|
merge-recursive: enforce rule that index matches head before merging
builtin/merge.c says that when we are about to perform a merge:
...the index must be in sync with the head commit. The strategies are
responsible to ensure this.
merge-recursive has always relied on unpack_trees() to enforce this
requirement, except in the case of an "Already up to date!" merge.
unpack-trees.c does not actually enforce this requirement, though. It
allows for a pair of exceptions, in cases which it refers to as #14(ALT)
and #2ALT. Documentation/technical/trivial-merge.txt can be consulted for
the precise meanings of the various case numbers and their meanings for
unpack-trees.c, but we have a high-level description of the intent behind
these two exceptions in a combined and summarized form in
Documentation/git-merge.txt:
...[merge will] abort if there are any changes registered in the index
relative to the `HEAD` commit. (One exception is when the changed index
entries are in the state that would result from the merge already.)
While this high-level description does describe conditions under which it
would be safe to allow the index to diverge from HEAD, it does not match
what is actually implemented. In particular, unpack-trees.c has no
knowledge of renames, and these two exceptions were written assuming that
no renames take place. Once renames get into the mix, it is no longer
safe to allow the index to not match for #2ALT. We could modify
unpack-trees to only allow #14(ALT) as an exception, but that would be
more strict than required for the resolve strategy (since the resolve
strategy doesn't handle renames at all). Therefore, unpack_trees.c seems
like the wrong place to fix this.
Further, if someone fixes the combination of break and rename detection
and modifies merge-recursive to take advantage of the combination, then it
will also no longer be safe to allow the index to not match for #14(ALT)
when the recursive strategy is in use. Therefore, leaving one of the
exceptions in place with the recursive merge strategy feels like we are
just leaving a latent bug in the code for folks in the future to stumble
across.
It may be possible to fix both unpack-trees and merge-recursive in a way
that implements the exception as stated in Documentation/git-merge.txt,
but it would be somewhat complex, possibly also buggy at first, and
ultimately, not all that valuable. Instead, just enforce the requirement
stated in builtin/merge.c; error out if the index does not match the HEAD
commit, just like the 'ours' and 'octopus' strategies do.
Some testcase fixups were in order:
t7611: had many tests designed to show that `git merge --abort` could
not always restore the index and working tree to the state they
were in before the merge started. The tests that were associated
with having changes in the index before the merge started are no
longer applicable, so they have been removed.
t7504: had a few tests that had stray staged changes that were not
actually part of the test under consideration
t6044: We no longer expect stray staged changes to sometimes result
in the merge continuing. Also, fix a case where a merge
didn't abort but should have.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-01 03:25:02 +02:00
|
|
|
test_expect_success 'recursive, when file has staged changes not matching HEAD nor what a merge would give' '
|
2018-07-01 03:25:01 +02:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
mkdir subdir &&
|
|
|
|
test_seq 1 10 >subdir/a &&
|
|
|
|
git add subdir/a &&
|
2022-05-19 20:59:53 +02:00
|
|
|
git rev-parse --verify :subdir/a >expect &&
|
2018-07-01 03:25:01 +02:00
|
|
|
|
merge-recursive: enforce rule that index matches head before merging
builtin/merge.c says that when we are about to perform a merge:
...the index must be in sync with the head commit. The strategies are
responsible to ensure this.
merge-recursive has always relied on unpack_trees() to enforce this
requirement, except in the case of an "Already up to date!" merge.
unpack-trees.c does not actually enforce this requirement, though. It
allows for a pair of exceptions, in cases which it refers to as #14(ALT)
and #2ALT. Documentation/technical/trivial-merge.txt can be consulted for
the precise meanings of the various case numbers and their meanings for
unpack-trees.c, but we have a high-level description of the intent behind
these two exceptions in a combined and summarized form in
Documentation/git-merge.txt:
...[merge will] abort if there are any changes registered in the index
relative to the `HEAD` commit. (One exception is when the changed index
entries are in the state that would result from the merge already.)
While this high-level description does describe conditions under which it
would be safe to allow the index to diverge from HEAD, it does not match
what is actually implemented. In particular, unpack-trees.c has no
knowledge of renames, and these two exceptions were written assuming that
no renames take place. Once renames get into the mix, it is no longer
safe to allow the index to not match for #2ALT. We could modify
unpack-trees to only allow #14(ALT) as an exception, but that would be
more strict than required for the resolve strategy (since the resolve
strategy doesn't handle renames at all). Therefore, unpack_trees.c seems
like the wrong place to fix this.
Further, if someone fixes the combination of break and rename detection
and modifies merge-recursive to take advantage of the combination, then it
will also no longer be safe to allow the index to not match for #14(ALT)
when the recursive strategy is in use. Therefore, leaving one of the
exceptions in place with the recursive merge strategy feels like we are
just leaving a latent bug in the code for folks in the future to stumble
across.
It may be possible to fix both unpack-trees and merge-recursive in a way
that implements the exception as stated in Documentation/git-merge.txt,
but it would be somewhat complex, possibly also buggy at first, and
ultimately, not all that valuable. Instead, just enforce the requirement
stated in builtin/merge.c; error out if the index does not match the HEAD
commit, just like the 'ours' and 'octopus' strategies do.
Some testcase fixups were in order:
t7611: had many tests designed to show that `git merge --abort` could
not always restore the index and working tree to the state they
were in before the merge started. The tests that were associated
with having changes in the index before the merge started are no
longer applicable, so they have been removed.
t7504: had a few tests that had stray staged changes that were not
actually part of the test under consideration
t6044: We no longer expect stray staged changes to sometimes result
in the merge continuing. Also, fix a case where a merge
didn't abort but should have.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-01 03:25:02 +02:00
|
|
|
# We have staged changes; merge should error out
|
|
|
|
test_must_fail git merge -s recursive E^0 2>err &&
|
2022-05-19 20:59:53 +02:00
|
|
|
git rev-parse --verify :subdir/a >actual &&
|
|
|
|
test_cmp expect actual &&
|
merge-recursive: enforce rule that index matches head before merging
builtin/merge.c says that when we are about to perform a merge:
...the index must be in sync with the head commit. The strategies are
responsible to ensure this.
merge-recursive has always relied on unpack_trees() to enforce this
requirement, except in the case of an "Already up to date!" merge.
unpack-trees.c does not actually enforce this requirement, though. It
allows for a pair of exceptions, in cases which it refers to as #14(ALT)
and #2ALT. Documentation/technical/trivial-merge.txt can be consulted for
the precise meanings of the various case numbers and their meanings for
unpack-trees.c, but we have a high-level description of the intent behind
these two exceptions in a combined and summarized form in
Documentation/git-merge.txt:
...[merge will] abort if there are any changes registered in the index
relative to the `HEAD` commit. (One exception is when the changed index
entries are in the state that would result from the merge already.)
While this high-level description does describe conditions under which it
would be safe to allow the index to diverge from HEAD, it does not match
what is actually implemented. In particular, unpack-trees.c has no
knowledge of renames, and these two exceptions were written assuming that
no renames take place. Once renames get into the mix, it is no longer
safe to allow the index to not match for #2ALT. We could modify
unpack-trees to only allow #14(ALT) as an exception, but that would be
more strict than required for the resolve strategy (since the resolve
strategy doesn't handle renames at all). Therefore, unpack_trees.c seems
like the wrong place to fix this.
Further, if someone fixes the combination of break and rename detection
and modifies merge-recursive to take advantage of the combination, then it
will also no longer be safe to allow the index to not match for #14(ALT)
when the recursive strategy is in use. Therefore, leaving one of the
exceptions in place with the recursive merge strategy feels like we are
just leaving a latent bug in the code for folks in the future to stumble
across.
It may be possible to fix both unpack-trees and merge-recursive in a way
that implements the exception as stated in Documentation/git-merge.txt,
but it would be somewhat complex, possibly also buggy at first, and
ultimately, not all that valuable. Instead, just enforce the requirement
stated in builtin/merge.c; error out if the index does not match the HEAD
commit, just like the 'ours' and 'octopus' strategies do.
Some testcase fixups were in order:
t7611: had many tests designed to show that `git merge --abort` could
not always restore the index and working tree to the state they
were in before the merge started. The tests that were associated
with having changes in the index before the merge started are no
longer applicable, so they have been removed.
t7504: had a few tests that had stray staged changes that were not
actually part of the test under consideration
t6044: We no longer expect stray staged changes to sometimes result
in the merge continuing. Also, fix a case where a merge
didn't abort but should have.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-01 03:25:02 +02:00
|
|
|
test_i18ngrep "changes to the following files would be overwritten" err
|
2018-07-01 03:25:01 +02:00
|
|
|
'
|
|
|
|
|
merge-recursive: enforce rule that index matches head before merging
builtin/merge.c says that when we are about to perform a merge:
...the index must be in sync with the head commit. The strategies are
responsible to ensure this.
merge-recursive has always relied on unpack_trees() to enforce this
requirement, except in the case of an "Already up to date!" merge.
unpack-trees.c does not actually enforce this requirement, though. It
allows for a pair of exceptions, in cases which it refers to as #14(ALT)
and #2ALT. Documentation/technical/trivial-merge.txt can be consulted for
the precise meanings of the various case numbers and their meanings for
unpack-trees.c, but we have a high-level description of the intent behind
these two exceptions in a combined and summarized form in
Documentation/git-merge.txt:
...[merge will] abort if there are any changes registered in the index
relative to the `HEAD` commit. (One exception is when the changed index
entries are in the state that would result from the merge already.)
While this high-level description does describe conditions under which it
would be safe to allow the index to diverge from HEAD, it does not match
what is actually implemented. In particular, unpack-trees.c has no
knowledge of renames, and these two exceptions were written assuming that
no renames take place. Once renames get into the mix, it is no longer
safe to allow the index to not match for #2ALT. We could modify
unpack-trees to only allow #14(ALT) as an exception, but that would be
more strict than required for the resolve strategy (since the resolve
strategy doesn't handle renames at all). Therefore, unpack_trees.c seems
like the wrong place to fix this.
Further, if someone fixes the combination of break and rename detection
and modifies merge-recursive to take advantage of the combination, then it
will also no longer be safe to allow the index to not match for #14(ALT)
when the recursive strategy is in use. Therefore, leaving one of the
exceptions in place with the recursive merge strategy feels like we are
just leaving a latent bug in the code for folks in the future to stumble
across.
It may be possible to fix both unpack-trees and merge-recursive in a way
that implements the exception as stated in Documentation/git-merge.txt,
but it would be somewhat complex, possibly also buggy at first, and
ultimately, not all that valuable. Instead, just enforce the requirement
stated in builtin/merge.c; error out if the index does not match the HEAD
commit, just like the 'ours' and 'octopus' strategies do.
Some testcase fixups were in order:
t7611: had many tests designed to show that `git merge --abort` could
not always restore the index and working tree to the state they
were in before the merge started. The tests that were associated
with having changes in the index before the merge started are no
longer applicable, so they have been removed.
t7504: had a few tests that had stray staged changes that were not
actually part of the test under consideration
t6044: We no longer expect stray staged changes to sometimes result
in the merge continuing. Also, fix a case where a merge
didn't abort but should have.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-01 03:25:02 +02:00
|
|
|
test_expect_success 'recursive, when file has staged changes matching what a merge would give' '
|
2018-07-01 03:25:01 +02:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
mkdir subdir &&
|
|
|
|
test_seq 1 11 >subdir/a &&
|
|
|
|
git add subdir/a &&
|
2022-05-19 20:59:53 +02:00
|
|
|
git rev-parse --verify :subdir/a >expect &&
|
2018-07-01 03:25:01 +02:00
|
|
|
|
merge-recursive: enforce rule that index matches head before merging
builtin/merge.c says that when we are about to perform a merge:
...the index must be in sync with the head commit. The strategies are
responsible to ensure this.
merge-recursive has always relied on unpack_trees() to enforce this
requirement, except in the case of an "Already up to date!" merge.
unpack-trees.c does not actually enforce this requirement, though. It
allows for a pair of exceptions, in cases which it refers to as #14(ALT)
and #2ALT. Documentation/technical/trivial-merge.txt can be consulted for
the precise meanings of the various case numbers and their meanings for
unpack-trees.c, but we have a high-level description of the intent behind
these two exceptions in a combined and summarized form in
Documentation/git-merge.txt:
...[merge will] abort if there are any changes registered in the index
relative to the `HEAD` commit. (One exception is when the changed index
entries are in the state that would result from the merge already.)
While this high-level description does describe conditions under which it
would be safe to allow the index to diverge from HEAD, it does not match
what is actually implemented. In particular, unpack-trees.c has no
knowledge of renames, and these two exceptions were written assuming that
no renames take place. Once renames get into the mix, it is no longer
safe to allow the index to not match for #2ALT. We could modify
unpack-trees to only allow #14(ALT) as an exception, but that would be
more strict than required for the resolve strategy (since the resolve
strategy doesn't handle renames at all). Therefore, unpack_trees.c seems
like the wrong place to fix this.
Further, if someone fixes the combination of break and rename detection
and modifies merge-recursive to take advantage of the combination, then it
will also no longer be safe to allow the index to not match for #14(ALT)
when the recursive strategy is in use. Therefore, leaving one of the
exceptions in place with the recursive merge strategy feels like we are
just leaving a latent bug in the code for folks in the future to stumble
across.
It may be possible to fix both unpack-trees and merge-recursive in a way
that implements the exception as stated in Documentation/git-merge.txt,
but it would be somewhat complex, possibly also buggy at first, and
ultimately, not all that valuable. Instead, just enforce the requirement
stated in builtin/merge.c; error out if the index does not match the HEAD
commit, just like the 'ours' and 'octopus' strategies do.
Some testcase fixups were in order:
t7611: had many tests designed to show that `git merge --abort` could
not always restore the index and working tree to the state they
were in before the merge started. The tests that were associated
with having changes in the index before the merge started are no
longer applicable, so they have been removed.
t7504: had a few tests that had stray staged changes that were not
actually part of the test under consideration
t6044: We no longer expect stray staged changes to sometimes result
in the merge continuing. Also, fix a case where a merge
didn't abort but should have.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-01 03:25:02 +02:00
|
|
|
# We have staged changes; merge should error out
|
|
|
|
test_must_fail git merge -s recursive E^0 2>err &&
|
2022-05-19 20:59:53 +02:00
|
|
|
git rev-parse --verify :subdir/a >actual &&
|
|
|
|
test_cmp expect actual &&
|
merge-recursive: enforce rule that index matches head before merging
builtin/merge.c says that when we are about to perform a merge:
...the index must be in sync with the head commit. The strategies are
responsible to ensure this.
merge-recursive has always relied on unpack_trees() to enforce this
requirement, except in the case of an "Already up to date!" merge.
unpack-trees.c does not actually enforce this requirement, though. It
allows for a pair of exceptions, in cases which it refers to as #14(ALT)
and #2ALT. Documentation/technical/trivial-merge.txt can be consulted for
the precise meanings of the various case numbers and their meanings for
unpack-trees.c, but we have a high-level description of the intent behind
these two exceptions in a combined and summarized form in
Documentation/git-merge.txt:
...[merge will] abort if there are any changes registered in the index
relative to the `HEAD` commit. (One exception is when the changed index
entries are in the state that would result from the merge already.)
While this high-level description does describe conditions under which it
would be safe to allow the index to diverge from HEAD, it does not match
what is actually implemented. In particular, unpack-trees.c has no
knowledge of renames, and these two exceptions were written assuming that
no renames take place. Once renames get into the mix, it is no longer
safe to allow the index to not match for #2ALT. We could modify
unpack-trees to only allow #14(ALT) as an exception, but that would be
more strict than required for the resolve strategy (since the resolve
strategy doesn't handle renames at all). Therefore, unpack_trees.c seems
like the wrong place to fix this.
Further, if someone fixes the combination of break and rename detection
and modifies merge-recursive to take advantage of the combination, then it
will also no longer be safe to allow the index to not match for #14(ALT)
when the recursive strategy is in use. Therefore, leaving one of the
exceptions in place with the recursive merge strategy feels like we are
just leaving a latent bug in the code for folks in the future to stumble
across.
It may be possible to fix both unpack-trees and merge-recursive in a way
that implements the exception as stated in Documentation/git-merge.txt,
but it would be somewhat complex, possibly also buggy at first, and
ultimately, not all that valuable. Instead, just enforce the requirement
stated in builtin/merge.c; error out if the index does not match the HEAD
commit, just like the 'ours' and 'octopus' strategies do.
Some testcase fixups were in order:
t7611: had many tests designed to show that `git merge --abort` could
not always restore the index and working tree to the state they
were in before the merge started. The tests that were associated
with having changes in the index before the merge started are no
longer applicable, so they have been removed.
t7504: had a few tests that had stray staged changes that were not
actually part of the test under consideration
t6044: We no longer expect stray staged changes to sometimes result
in the merge continuing. Also, fix a case where a merge
didn't abort but should have.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-01 03:25:02 +02:00
|
|
|
test_i18ngrep "changes to the following files would be overwritten" err
|
2018-07-01 03:25:01 +02:00
|
|
|
'
|
|
|
|
|
2016-04-10 08:13:38 +02:00
|
|
|
test_expect_success 'octopus, unrelated file touched' '
|
2016-04-10 08:13:37 +02:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
touch random_file && git add random_file &&
|
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge C^0 D^0 &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test_path_is_missing .git/MERGE_HEAD &&
|
|
|
|
git rev-parse --verify :random_file &&
|
|
|
|
test_path_exists random_file
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
2016-04-10 08:13:38 +02:00
|
|
|
test_expect_success 'octopus, related file removed' '
|
2016-04-10 08:13:37 +02:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
git rm b &&
|
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge C^0 D^0 &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test_path_is_missing b &&
|
|
|
|
test_must_fail git rev-parse --verify :b &&
|
2018-07-01 03:24:57 +02:00
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
2016-04-10 08:13:38 +02:00
|
|
|
test_expect_success 'octopus, related file modified' '
|
2016-04-10 08:13:37 +02:00
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
echo 12 >>a && git add a &&
|
2022-05-19 20:59:53 +02:00
|
|
|
git rev-parse --verify :a >expect &&
|
2016-04-10 08:13:37 +02:00
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge C^0 D^0 &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test_path_is_file a &&
|
|
|
|
git rev-parse --verify :a >actual &&
|
|
|
|
test_cmp expect actual &&
|
2018-07-01 03:24:57 +02:00
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'ours' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
touch random_file && git add random_file &&
|
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge -s ours C^0 &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test_path_is_file random_file &&
|
|
|
|
git rev-parse --verify :random_file &&
|
2018-07-01 03:24:57 +02:00
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'subtree' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
touch random_file && git add random_file &&
|
|
|
|
|
2018-07-01 03:24:57 +02:00
|
|
|
test_must_fail git merge -s subtree E^0 &&
|
2022-05-19 20:59:53 +02:00
|
|
|
test_path_is_file random_file &&
|
|
|
|
git rev-parse --verify :random_file &&
|
2018-07-01 03:24:57 +02:00
|
|
|
test_path_is_missing .git/MERGE_HEAD
|
2016-04-10 08:13:37 +02:00
|
|
|
'
|
|
|
|
|
2022-07-23 03:53:15 +02:00
|
|
|
test_expect_success 'avoid failure due to stat-dirty files' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
# Make "a" be stat-dirty
|
|
|
|
test-tool chmtime =+1 a &&
|
|
|
|
|
|
|
|
# stat-dirty file should not prevent stash creation in builtin/merge.c
|
|
|
|
git merge -s resolve -s recursive D^0
|
|
|
|
'
|
|
|
|
|
2022-07-23 03:53:14 +02:00
|
|
|
test_expect_success 'with multiple strategies, recursive or ort failure do not early abort' '
|
|
|
|
git reset --hard &&
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
|
|
|
test_seq 0 10 >a &&
|
|
|
|
git add a &&
|
merge: make restore_state() restore staged state too
There are multiple issues at play here:
1) If `git merge` is invoked with staged changes, it should abort
without doing any merging, and the user's working tree and index
should be the same as before merge was invoked.
2) Merge strategies are responsible for enforcing the index == HEAD
requirement. (See 9822175d2b ("Ensure index matches head before
invoking merge machinery, round N", 2019-08-17) for some history
around this.)
3) Merge strategies can bail saying they are not an appropriate
handler for the merge in question (possibly allowing other
strategies to be used instead).
4) Merge strategies can make changes to the index and working tree,
and have no expectation to clean up after themselves, *even* if
they bail out and say they are not an appropriate handler for
the merge in question. (The `octopus` merge strategy does this,
for example.)
5) Because of (3) and (4), builtin/merge.c stashes state before
trying merge strategies and restores it afterward.
Unfortunately, if users had staged changes before calling `git merge`,
builtin/merge.c could do the following:
* stash the changes, in order to clean up after the strategies
* try all the merge strategies in turn, each of which report they
cannot function due to the index not matching HEAD
* restore the changes via "git stash apply"
But that last step would have the net effect of unstaging the user's
changes. Fix this by adding the "--index" option to "git stash apply".
While at it, also squelch the stash apply output; we already report
"Rewinding the tree to pristine..." and don't need a detailed `git
status` report afterwards. Also while at it, switch to using strvec
so folks don't have to count the arguments to ensure we avoided an
off-by-one error, and so it's easier to add additional arguments to
the command.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 03:53:16 +02:00
|
|
|
git rev-parse :a >expect &&
|
2022-07-23 03:53:14 +02:00
|
|
|
|
|
|
|
sane_unset GIT_TEST_MERGE_ALGORITHM &&
|
|
|
|
test_must_fail git merge -s recursive -s ort -s octopus C^0 >output 2>&1 &&
|
|
|
|
|
|
|
|
grep "Trying merge strategy recursive..." output &&
|
|
|
|
grep "Trying merge strategy ort..." output &&
|
|
|
|
grep "Trying merge strategy octopus..." output &&
|
merge: make restore_state() restore staged state too
There are multiple issues at play here:
1) If `git merge` is invoked with staged changes, it should abort
without doing any merging, and the user's working tree and index
should be the same as before merge was invoked.
2) Merge strategies are responsible for enforcing the index == HEAD
requirement. (See 9822175d2b ("Ensure index matches head before
invoking merge machinery, round N", 2019-08-17) for some history
around this.)
3) Merge strategies can bail saying they are not an appropriate
handler for the merge in question (possibly allowing other
strategies to be used instead).
4) Merge strategies can make changes to the index and working tree,
and have no expectation to clean up after themselves, *even* if
they bail out and say they are not an appropriate handler for
the merge in question. (The `octopus` merge strategy does this,
for example.)
5) Because of (3) and (4), builtin/merge.c stashes state before
trying merge strategies and restores it afterward.
Unfortunately, if users had staged changes before calling `git merge`,
builtin/merge.c could do the following:
* stash the changes, in order to clean up after the strategies
* try all the merge strategies in turn, each of which report they
cannot function due to the index not matching HEAD
* restore the changes via "git stash apply"
But that last step would have the net effect of unstaging the user's
changes. Fix this by adding the "--index" option to "git stash apply".
While at it, also squelch the stash apply output; we already report
"Rewinding the tree to pristine..." and don't need a detailed `git
status` report afterwards. Also while at it, switch to using strvec
so folks don't have to count the arguments to ensure we avoided an
off-by-one error, and so it's easier to add additional arguments to
the command.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 03:53:16 +02:00
|
|
|
grep "No merge strategy handled the merge." output &&
|
|
|
|
|
|
|
|
# Changes to "a" should remain staged
|
|
|
|
git rev-parse :a >actual &&
|
|
|
|
test_cmp expect actual
|
2022-07-23 03:53:14 +02:00
|
|
|
'
|
|
|
|
|
2016-04-10 08:13:37 +02:00
|
|
|
test_done
|