submodule merge: update conflict error message

When attempting to merge in a superproject with conflicting submodule
pointers that cannot be fast-forwarded or trivially resolved, the merge
fails and Git prints an error message that accurately describes the
failure, but does not provide steps for the user to resolve the error.

Git is left in a conflicted state, which requires the user to:
 1. merge submodules or update submodules to an already existing
	commit that reflects the merge
 2. add submodules changes to the superproject
 3. finish merging superproject
These steps are non-obvious for newer submodule users to figure out
based on the error message and neither `git submodule status` nor `git
status` provide any useful pointers.

Update error message to provide steps to resolve submodule merge
conflict. Future work could involve adding an advice flag to the
message. Although the message is long, it also has the id of the
submodule commit that needs to be merged, which could be useful
information for the user.

Additionally, 5 merge failures that resulted in an early return have
been updated to reflect the status of the merge.
1. Null merge base (null o): CONFLICT_SUBMODULE_NULL_MERGE_BASE added
   as a new conflict type and will print updated error message.
2. Null merge side a (null a): BUG(). See [1] for discussion
3. Null merge side b (null b): BUG(). See [1] for discussion
4. Submodule not checked out: added NEEDSWORK bit
5. Submodule commits not present: added NEEDSWORK bit
The errors with a NEEDSWORK bit deserve a more detailed explanation of
how to resolve them. See [2] for more context.

[1] https://lore.kernel.org/git/CABPp-BE0qGwUy80dmVszkJQ+tcpfLRW0OZyErymzhZ9+HWY1mw@mail.gmail.com/
[2] https://lore.kernel.org/git/xmqqpmhjjwo9.fsf@gitster.g/

Signed-off-by: Calvin Wan <calvinwan@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Calvin Wan
2022-08-04 19:51:05 +00:00
committed by Junio C Hamano
parent 71a8fab31b
commit 4057523a40
3 changed files with 231 additions and 17 deletions

View File

@@ -103,8 +103,25 @@ test_expect_success 'setup for merge search' '
echo "file-c" > file-c &&
git add file-c &&
git commit -m "sub-c") &&
git commit -a -m "c" &&
git commit -a -m "c")
'
test_expect_success 'merging should conflict for non fast-forward' '
test_when_finished "git -C merge-search reset --hard" &&
(cd merge-search &&
git checkout -b test-nonforward-a b &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_must_fail git merge c >actual &&
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
grep "$sub_expect" actual
else
test_must_fail git merge c 2> actual
fi)
'
test_expect_success 'finish setup for merge-search' '
(cd merge-search &&
git checkout -b d a &&
(cd sub &&
git checkout -b sub-d sub-b &&
@@ -129,14 +146,16 @@ test_expect_success 'merge with one side as a fast-forward of the other' '
test_cmp expect actual)
'
test_expect_success 'merging should conflict for non fast-forward' '
test_expect_success 'merging should conflict for non fast-forward (resolution exists)' '
(cd merge-search &&
git checkout -b test-nonforward b &&
git checkout -b test-nonforward-b b &&
(cd sub &&
git rev-parse --short sub-d > ../expect) &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_must_fail git merge c >actual
test_must_fail git merge c >actual &&
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
grep "$sub_expect" actual
else
test_must_fail git merge c 2> actual
fi &&
@@ -161,7 +180,9 @@ test_expect_success 'merging should fail for ambiguous common parent' '
) &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
test_must_fail git merge c >actual
test_must_fail git merge c >actual &&
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
grep "$sub_expect" actual
else
test_must_fail git merge c 2> actual
fi &&
@@ -205,7 +226,12 @@ test_expect_success 'merging should fail for changes that are backwards' '
git commit -a -m "f" &&
git checkout -b test-backward e &&
test_must_fail git merge f)
test_must_fail git merge f >actual &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)" &&
grep "$sub_expect" actual
fi)
'
@@ -476,4 +502,44 @@ test_expect_failure 'directory/submodule conflict; merge --abort works afterward
)
'
# Setup:
# - Submodule has 2 commits: a and b
# - Superproject branch 'a' adds and commits submodule pointing to 'commit a'
# - Superproject branch 'b' adds and commits submodule pointing to 'commit b'
# If these two branches are now merged, there is no merge base
test_expect_success 'setup for null merge base' '
mkdir no-merge-base &&
(cd no-merge-base &&
git init &&
mkdir sub &&
(cd sub &&
git init &&
echo "file-a" > file-a &&
git add file-a &&
git commit -m "commit a") &&
git commit --allow-empty -m init &&
git branch init &&
git checkout -b a init &&
git add sub &&
git commit -m "a" &&
git switch main &&
(cd sub &&
echo "file-b" > file-b &&
git add file-b &&
git commit -m "commit b"))
'
test_expect_success 'merging should fail with no merge base' '
(cd no-merge-base &&
git checkout -b b init &&
git add sub &&
git commit -m "b" &&
test_must_fail git merge a >actual &&
if test "$GIT_TEST_MERGE_ALGORITHM" = ort
then
sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)" &&
grep "$sub_expect" actual
fi)
'
test_done