git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/3] Add missing rename-related corner cases for merging
@ 2018-07-02 13:30 Elijah Newren
  2018-07-02 13:30 ` [PATCH 1/3] t6042: add testcase covering rename/add/delete conflict type Elijah Newren
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Elijah Newren @ 2018-07-02 13:30 UTC (permalink / raw)
  To: git; +Cc: gitster, Elijah Newren

In merging, every rename acts as a two-piece lego in terms of conflicts.
We have long realized that the other branch can (1) delete the source
side of a rename, giving a rename/delete conflict, or (2) add a file in
the way of the rename destination, giving a rename/add conflict, or (3)
have a rename of its own touching either the same destination or source
path, giving either a rename/rename(2to1) or rename/rename(1to2)
conflict.  But only in one case did we ever consider chaining these
merge-conflict lego pieces (namely with rename/rename(1to2)/add/add
conflicts).  Add some testcases that show other ways these conflicts can
be chained.

In short, any rename's source side can attach to a delete or another
rename, and any rename's destination side can attach to an add or
another rename.

This series was spurred by Robert Dailey's report back in March of a
rename case that git currently handles poorly:
  https://public-inbox.org/git/CAHd499Axo7HFviUJavigTZ6BGZCkj9iOSeNVndu1oPivkPv+5Q@mail.gmail.com/

This series adds a testcase covering the issue he reported, and then
rounds things out additional testcases demonstrating other ways rename
conflicts could be "chained" together.


Elijah Newren (3):
  t6042: add testcase covering rename/add/delete conflict type
  t6042: add testcase covering rename/rename(2to1)/delete/delete
    conflict
  t6042: add testcase covering long chains of rename conflicts

 t/t6042-merge-rename-corner-cases.sh | 245 +++++++++++++++++++++++++++
 1 file changed, 245 insertions(+)

-- 
2.18.0.130.gd703bbb5d


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] t6042: add testcase covering rename/add/delete conflict type
  2018-07-02 13:30 [PATCH 0/3] Add missing rename-related corner cases for merging Elijah Newren
@ 2018-07-02 13:30 ` Elijah Newren
  2018-07-02 13:30 ` [PATCH 2/3] t6042: add testcase covering rename/rename(2to1)/delete/delete conflict Elijah Newren
  2018-07-02 13:30 ` [PATCH 3/3] t6042: add testcase covering long chains of rename conflicts Elijah Newren
  2 siblings, 0 replies; 4+ messages in thread
From: Elijah Newren @ 2018-07-02 13:30 UTC (permalink / raw)
  To: git; +Cc: gitster, Elijah Newren

If a file is renamed on one side of history, and the other side of history
both deletes the original file and adds a new unrelated file in the way of
the rename, then we have what I call a rename/add/delete conflict.  Add a
testcase covering this scenario.

Reported-by: Robert Dailey <rcdailey.lists@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
---
 t/t6042-merge-rename-corner-cases.sh | 66 ++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
index 1cbd946fc..788a31451 100755
--- a/t/t6042-merge-rename-corner-cases.sh
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -693,4 +693,70 @@ test_expect_success 'rename/rename/add-dest merge still knows about conflicting
 	)
 '
 
+# Testcase rad, rename/add/delete
+#   Commit O: foo
+#   Commit A: rm foo, add different bar
+#   Commit B: rename foo->bar
+#   Expected: CONFLICT (rename/add/delete), two-way merged bar
+
+test_expect_success 'rad-setup: rename/add/delete conflict' '
+	test_create_repo rad &&
+	(
+		cd rad &&
+		echo "original file" >foo &&
+		git add foo &&
+		git commit -m "original" &&
+
+		git branch O &&
+		git branch A &&
+		git branch B &&
+
+		git checkout A &&
+		git rm foo &&
+		echo "different file" >bar &&
+		git add bar &&
+		git commit -m "Remove foo, add bar" &&
+
+		git checkout B &&
+		git mv foo bar &&
+		git commit -m "rename foo to bar"
+	)
+'
+
+test_expect_failure 'rad-check: rename/add/delete conflict' '
+	(
+		cd rad &&
+
+		git checkout B^0 &&
+		test_must_fail git merge -s recursive A^0 >out 2>err &&
+
+		# Not sure whether the output should contain just one
+		# "CONFLICT (rename/add/delete)" line, or if it should break
+		# it into a pair of "CONFLICT (rename/delete)" and
+		# "CONFLICT (rename/add)"; allow for either.
+		test_i18ngrep "CONFLICT (rename.*add)" out &&
+		test_i18ngrep "CONFLICT (rename.*delete)" out &&
+		test_must_be_empty err &&
+
+		git ls-files -s >file_count &&
+		test_line_count = 2 file_count &&
+		git ls-files -u >file_count &&
+		test_line_count = 2 file_count &&
+		git ls-files -o >file_count &&
+		test_line_count = 2 file_count &&
+
+		git rev-parse >actual \
+			:2:bar :3:bar &&
+		git rev-parse >expect \
+			B:bar  A:bar  &&
+
+		test_cmp file_is_missing foo &&
+		# bar should have two-way merged contents of the different
+		# versions of bar; check that content from both sides is
+		# present.
+		grep original bar &&
+		grep different bar
+	)
+'
+
 test_done
-- 
2.18.0.130.gd703bbb5d


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] t6042: add testcase covering rename/rename(2to1)/delete/delete conflict
  2018-07-02 13:30 [PATCH 0/3] Add missing rename-related corner cases for merging Elijah Newren
  2018-07-02 13:30 ` [PATCH 1/3] t6042: add testcase covering rename/add/delete conflict type Elijah Newren
@ 2018-07-02 13:30 ` Elijah Newren
  2018-07-02 13:30 ` [PATCH 3/3] t6042: add testcase covering long chains of rename conflicts Elijah Newren
  2 siblings, 0 replies; 4+ messages in thread
From: Elijah Newren @ 2018-07-02 13:30 UTC (permalink / raw)
  To: git; +Cc: gitster, Elijah Newren

If either side of a rename/rename(2to1) conflict is itself also involved
in a rename/delete conflict, then the conflict is a little more complex;
we can even have what I'd call a rename/rename(2to1)/delete/delete
conflict.  (In some ways, this is similar to a rename/rename(1to2)/add/add
conflict, as added in commit 3672c9714830 ("merge-recursive: Fix working
copy handling for rename/rename/add/add", 2011-08-11)).  Add a testcase
for such a conflict.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 t/t6042-merge-rename-corner-cases.sh | 68 ++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
index 788a31451..46e1aa7df 100755
--- a/t/t6042-merge-rename-corner-cases.sh
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -759,4 +759,72 @@ test_expect_failure 'rad-check: rename/add/delete conflict' '
 	)
 '
 
+# Testcase rrdd, rename/rename(2to1)/delete/delete
+#   Commit O: foo, bar
+#   Commit A: rename foo->baz, rm bar
+#   Commit B: rename bar->baz, rm foo
+#   Expected: CONFLICT (rename/rename/delete/delete), two-way merged baz
+
+test_expect_success 'rrdd-setup: rename/rename(2to1)/delete/delete conflict' '
+	test_create_repo rrdd &&
+	(
+		cd rrdd &&
+		echo foo >foo &&
+		echo bar >bar &&
+		git add foo bar &&
+		git commit -m O &&
+
+		git branch O &&
+		git branch A &&
+		git branch B &&
+
+		git checkout A &&
+		git mv foo baz &&
+		git rm bar &&
+		git commit -m "Rename foo, remove bar" &&
+
+		git checkout B &&
+		git mv bar baz &&
+		git rm foo &&
+		git commit -m "Rename bar, remove foo"
+	)
+'
+
+test_expect_failure 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '
+	(
+		cd rrdd &&
+
+		git checkout A^0 &&
+		test_must_fail git merge -s recursive B^0 >out 2>err &&
+
+		# Not sure whether the output should contain just one
+		# "CONFLICT (rename/rename/delete/delete)" line, or if it
+		# should break it into three: "CONFLICT (rename/rename)" and
+		# two "CONFLICT (rename/delete)" lines; allow for either.
+		test_i18ngrep "CONFLICT (rename/rename)" out &&
+		test_i18ngrep "CONFLICT (rename.*delete)" out &&
+		test_must_be_empty err &&
+
+		git ls-files -s >file_count &&
+		test_line_count = 2 file_count &&
+		git ls-files -u >file_count &&
+		test_line_count = 2 file_count &&
+		git ls-files -o >file_count &&
+		test_line_count = 2 file_count &&
+
+		git rev-parse >actual \
+			:2:baz :3:baz &&
+		git rev-parse >expect \
+			O:foo  O:bar  &&
+
+		test_cmp file_is_missing foo &&
+		test_cmp file_is_missing bar &&
+		# baz should have two-way merged contents of the original
+		# contents of foo and bar; check that content from both sides
+		# is present.
+		grep foo baz &&
+		grep bar baz
+	)
+'
+
 test_done
-- 
2.18.0.130.gd703bbb5d


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] t6042: add testcase covering long chains of rename conflicts
  2018-07-02 13:30 [PATCH 0/3] Add missing rename-related corner cases for merging Elijah Newren
  2018-07-02 13:30 ` [PATCH 1/3] t6042: add testcase covering rename/add/delete conflict type Elijah Newren
  2018-07-02 13:30 ` [PATCH 2/3] t6042: add testcase covering rename/rename(2to1)/delete/delete conflict Elijah Newren
@ 2018-07-02 13:30 ` Elijah Newren
  2 siblings, 0 replies; 4+ messages in thread
From: Elijah Newren @ 2018-07-02 13:30 UTC (permalink / raw)
  To: git; +Cc: gitster, Elijah Newren

Each rename is a lego: the source side could be connected to a delete or
another rename, and the destination side could be connected to a rename or a
conflicting add.  Previous tests combined these to get e.g.
rename/rename(1to2)/add/add, rename/rename(2to1)/delete/delete, and
rename/add/delete.  But we can also build bigger chains of conflicts.  Add a
testcase demonstrating this.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 t/t6042-merge-rename-corner-cases.sh | 111 +++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
index 46e1aa7df..d9c4068e9 100755
--- a/t/t6042-merge-rename-corner-cases.sh
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -827,4 +827,115 @@ test_expect_failure 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '
 	)
 '
 
+# Testcase mod6, chains of rename/rename(1to2) and rename/rename(2to1)
+#   Commit O: one,      three,       five
+#   Commit A: one->two, three->four, five->six
+#   Commit B: one->six, three->two,  five->four
+#   Expected: six CONFLICT(rename/rename) messages, each path in two of the
+#             multi-way merged contents found in two, four, six
+
+test_expect_success 'mod6-setup: chains of rename/rename(1to2) and rename/rename(2to1)' '
+	test_create_repo mod6 &&
+	(
+		cd mod6 &&
+		test_seq 11 19 >one &&
+		test_seq 31 39 >three &&
+		test_seq 51 59 >five &&
+		git add . &&
+		test_tick &&
+		git commit -m "O" &&
+
+		git branch O &&
+		git branch A &&
+		git branch B &&
+
+		git checkout A &&
+		test_seq 10 19 >one &&
+		echo 40        >>three &&
+		git add one three &&
+		git mv  one   two  &&
+		git mv  three four &&
+		git mv  five  six  &&
+		test_tick &&
+		git commit -m "A" &&
+
+		git checkout B &&
+		echo 20    >>one       &&
+		echo forty >>three     &&
+		echo 60    >>five      &&
+		git add one three five &&
+		git mv  one   six  &&
+		git mv  three two  &&
+		git mv  five  four &&
+		test_tick &&
+		git commit -m "B"
+	)
+'
+
+test_expect_failure 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '
+	(
+		cd mod6 &&
+
+		git checkout A^0 &&
+
+		test_must_fail git merge -s recursive B^0 >out 2>err &&
+
+		test_i18ngrep "CONFLICT (rename/rename)" out &&
+		test_must_be_empty err &&
+
+		git ls-files -s >file_count &&
+		test_line_count = 6 file_count &&
+		git ls-files -u >file_count &&
+		test_line_count = 6 file_count &&
+		git ls-files -o >file_count &&
+		test_line_count = 3 file_count &&
+
+		test_seq 10 20 >merged-one &&
+		test_seq 51 60 >merged-five &&
+		# Determine what the merge of three would give us.
+		test_seq 30 40 >three-side-A &&
+		test_seq 31 39 >three-side-B &&
+		echo forty >three-side-B &&
+		>empty &&
+		test_must_fail git merge-file \
+			-L "HEAD" \
+			-L "" \
+			-L "B^0" \
+			three-side-A empty three-side-B &&
+		sed -e "s/^\([<=>]\)/\1\1\1/" three-side-A >merged-three &&
+
+		# Verify the index is as expected
+		git rev-parse >actual         \
+			:2:two       :3:two   \
+			:2:four      :3:four  \
+			:2:six       :3:six   &&
+		git hash-object >expect           \
+			merged-one   merged-three \
+			merged-three merged-five  \
+			merged-five  merged-one   &&
+		test_cmp expect actual &&
+
+		git cat-file -p :2:two >expect &&
+		git cat-file -p :3:two >other &&
+		test_must_fail git merge-file    \
+			-L "HEAD"  -L ""  -L "B^0" \
+			expect     empty  other &&
+		test_cmp expect two &&
+
+		git cat-file -p :2:four >expect &&
+		git cat-file -p :3:four >other &&
+		test_must_fail git merge-file    \
+			-L "HEAD"  -L ""  -L "B^0" \
+			expect     empty  other &&
+		test_cmp expect four &&
+
+		git cat-file -p :2:six >expect &&
+		git cat-file -p :3:six >other &&
+		test_must_fail git merge-file    \
+			-L "HEAD"  -L ""  -L "B^0" \
+			expect     empty  other &&
+		test_cmp expect six
+	)
+'
+
 test_done
-- 
2.18.0.130.gd703bbb5d


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-07-02 13:31 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-02 13:30 [PATCH 0/3] Add missing rename-related corner cases for merging Elijah Newren
2018-07-02 13:30 ` [PATCH 1/3] t6042: add testcase covering rename/add/delete conflict type Elijah Newren
2018-07-02 13:30 ` [PATCH 2/3] t6042: add testcase covering rename/rename(2to1)/delete/delete conflict Elijah Newren
2018-07-02 13:30 ` [PATCH 3/3] t6042: add testcase covering long chains of rename conflicts Elijah Newren

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).