[v2,11/11] t6425: be more flexible with rename/delete conflict messages
diff mbox series

Message ID 38f65735118955e56af2a7b0a786e167b5f7263d.1596906081.git.gitgitgadget@gmail.com
State New
Headers show
  • Start preparing merge-related tests to work with multiple merge backends
Related show

Commit Message

Johannes Schindelin via GitGitGadget Aug. 8, 2020, 5:01 p.m. UTC
From: Elijah Newren <newren@gmail.com>

t6425 was very picky about the exact output message produced by a
rename/delete conflict, in a way that just scratches the surface of the
mess that was built into merge-recursive.  The idea was that it would
try to find the possible combinations of different conflict types, and
when more than one was present for one path, it would try to provide a
combined message that covered all the cases.

There's a lot to unravel here...

First, there's a basic conflict type known as modify/delete, which is a
content conflict.  It occurs when one side deletes a file, but the other
modifies it.

There is also a path conflict known as a rename/delete.  This occurs
when one side deletes a path, and the other renames it.  This is not a
content conflict, it is a path conflict.  It will often occur in
combination with a content conflict, though, namely a modify/delete.  As
such, these two were often combined.

Another type of conflict that can exist is a directory/file conflict.
For example, one side adds a new file at some path, and the other side
of history adds a directory at the same path.  The path that was "added"
could have been put there by a rename, though.  Thus, we have the
possibility of a single path being affected by a modify/delete, a
rename/delete, and a directory/file conflict.

In part, this was a natural by-product of merge-recursive's design.
Since it was doing a four way merge with the contents of the working
tree being the fourth factor it had to consider, it had working tree
handling spread all over the code.  It also had directory/file conflict
handling spread everywhere through all the other types of conflicts.
And our testsuite has a huge number of directory/file conflict tests
because trying to get them right required modifying so many different
codepaths.  A natural outgrowth of this kind of structure is conflict
messages that combine all the different types that the current codepath
is considering.

However, if we want to make the different conflict types orthogonal and
avoid repeating ourselves and getting very brittle code, then we need to
split the messages from these different conflict types apart.  Besides,
trying to determine all possible permutations is a _royal_ mess.  The
code to handle the rename/delete/directory/file conflict output is
already somewhat hard to parse, and is somewhat brittle.  But if we
really wanted to go that route, then we'd have to have special handling
for the following types of combinations:
  * rename/add/delete:
      on side of history that didn't rename the given file, remove the file
      instead and place an unrelated file in the way of the rename
  * rename/rename(2to1)/mode conflict/delete/delete:
      two different files, one executable and the other not, are renamed
      to the same location, each side deletes the source file that the
      other side renames
  * rename/rename(1to2)/add/add:
      file renamed differently on each side of history, with each side
      placing an unrelated file in the way of the other
  * rename/rename(1to2)/content conflict/file location/(D/F)/(D/F)/:
      both sides modify a file in conflicting way, both rename that file
      but to different paths, one side renames the directory which the
      other side had renamed that file into causing it to possibly need a
      transitive rename, and each side puts a directory in the way of the
      other's path.

Let's back away from this path of insanity, and allow the different
types of conflicts to be handled by separate pieces of non-repeated code
by allowing the conflict messages to be split into their separate types.
(If multiple conflict types affect a single path, the conflict messages
can be printed sequentially.)  Start this path with a simple change:
modify this test to be more flexible and accept the output either merge
backend (recursive or the new ort) will produce.

Signed-off-by: Elijah Newren <newren@gmail.com>
 t/t6425-merge-rename-delete.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff mbox series

diff --git a/t/t6425-merge-rename-delete.sh b/t/t6425-merge-rename-delete.sh
index 5d33577d2f..f79d021590 100755
--- a/t/t6425-merge-rename-delete.sh
+++ b/t/t6425-merge-rename-delete.sh
@@ -17,7 +17,8 @@  test_expect_success 'rename/delete' '
 	git commit -m "delete" &&
 	test_must_fail git merge --strategy=recursive rename >output &&
-	test_i18ngrep "CONFLICT (rename/delete): A deleted in HEAD and renamed to B in rename. Version rename of B left in tree." output
+	test_i18ngrep "CONFLICT (rename/delete): A.* renamed .*to B.* in rename" output &&
+	test_i18ngrep "CONFLICT (rename/delete): A.*deleted in HEAD." output