conflicts.rs: label conflict number and sides next to conflict markers

For example, 

```
<<<<<<< Conflict 1 of 3
+++++++ Contents of side #1
left 3.1
left 3.2
left 3.3
%%%%%%% Changes from base to side #2
-line 3
+right 3.1
>>>>>>>
```

or

```
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-line 3
+right 3.1
+++++++ Contents of side #2
left 3.1
left 3.2
left 3.3
>>>>>>>
```

Currently, there is no way to disable these, this is TODO for a future
PR. Other TODOs for future PRs: make these labels configurable. After
that, we could support a `diff3/git`-like conflict format as well, in
principle.

Counting conflicts helps with knowing whether you fixed all the
conflicts while you are in the editor.

While labeling "side #1", etc, does not tell you the commit id or
description as requested in #1176, I still think it's an improvement.
Most importantly, I hope this will make `jj`'s conflict format less
scary-looking for new users.

I've used this for a bit, and I like it. Without the labels, I would see
that the two conflicts have a different order of conflict markers, but I
wouldn't be able to remember what that means. For longer diffs, it can
be tricky for me to quickly tell that it's a diff as opposed to one of
the sides. This also creates some hope of being able to navigate a
conflict with more than 2 sides.

Another not-so-secret goal for this is explained in
https://github.com/martinvonz/jj/pull/3109#issuecomment-2014140627. The
idea is a little weird, but I *think* it could be helpful, and I'd like
to experiment with it.
This commit is contained in:
Ilya Grigoriev 2024-03-23 15:16:28 -07:00
parent 2f48f76e85
commit 70b517ca64
11 changed files with 210 additions and 166 deletions

View file

@ -18,6 +18,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `jj tag list` now prints commit summary along with the tag name.
* Conflict markers now include an explanation of what each part of the conflict
represents.
>>>>>>>
### Fixed bugs
## [0.17.0] - 2024-05-01

View file

@ -89,11 +89,11 @@ fn test_cat() {
test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "@", "-d", "@--"]);
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file1"]);
insta::assert_snapshot!(stdout, @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-b
+a
+++++++
+++++++ Contents of side #2
c
>>>>>>>
"###);

View file

@ -71,11 +71,11 @@ fn test_chmod_regular_conflict() {
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]);
insta::assert_snapshot!(stdout,
@r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+x
+++++++
+++++++ Contents of side #2
n
>>>>>>>
"###);
@ -90,11 +90,11 @@ fn test_chmod_regular_conflict() {
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]);
insta::assert_snapshot!(stdout,
@r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+x
+++++++
+++++++ Contents of side #2
n
>>>>>>>
"###);
@ -107,11 +107,11 @@ fn test_chmod_regular_conflict() {
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "file"]);
insta::assert_snapshot!(stdout,
@r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+x
+++++++
+++++++ Contents of side #2
n
>>>>>>>
"###);
@ -201,10 +201,10 @@ fn test_chmod_file_dir_deletion_conflicts() {
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "-r=file_deletion", "file"]);
insta::assert_snapshot!(stdout,
@r###"
<<<<<<<
+++++++
<<<<<<< Conflict 1 of 1
+++++++ Contents of side #1
a
%%%%%%%
%%%%%%% Changes from base to side #2
-base
>>>>>>>
"###);
@ -234,10 +234,10 @@ fn test_chmod_file_dir_deletion_conflicts() {
let stdout = test_env.jj_cmd_success(&repo_path, &["cat", "-r=file_deletion", "file"]);
insta::assert_snapshot!(stdout,
@r###"
<<<<<<<
+++++++
<<<<<<< Conflict 1 of 1
+++++++ Contents of side #1
a
%%%%%%%
%%%%%%% Changes from base to side #2
-base
>>>>>>>
"###);

View file

@ -395,11 +395,11 @@ fn test_diffedit_merge() {
assert!(!repo_path.join("file1").exists());
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]);
insta::assert_snapshot!(stdout, @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-a
+c
+++++++
+++++++ Contents of side #2
b
>>>>>>>
"###);

View file

@ -153,11 +153,11 @@ fn test_interdiff_conflicting() {
--- a/file
+++ b/file
@@ -1,7 +1,1 @@
-<<<<<<<
-%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--foo
-+abc
-+++++++
-+++++++ Contents of side #2
-bar
->>>>>>>
+def

View file

@ -59,10 +59,10 @@ fn test_obslog_with_or_without_diff() {
@ rlvkpnrz test.user@example.com 2001-02-03 08:05:10 66b42ad3
my description
Resolved conflict in file1:
1 1: <<<<<<<resolved
2 : %%%%%%%
1 1: <<<<<<< Conflict 1 of 1resolved
2 : %%%%%%% Changes from base to side #1
3 : -foo
4 : +++++++
4 : +++++++ Contents of side #2
5 : foo
6 : bar
7 : >>>>>>>
@ -111,10 +111,10 @@ fn test_obslog_with_or_without_diff() {
--- a/file1
+++ b/file1
@@ -1,7 +1,1 @@
-<<<<<<<
-%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--foo
-+++++++
-+++++++ Contents of side #2
-foo
-bar
->>>>>>>

View file

@ -69,14 +69,14 @@ fn test_resolution() {
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("file")).unwrap()
, @r###"
<<<<<<<
%%%%%%%
-base
+a
+++++++
b
>>>>>>>
"###);
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+a
+++++++ Contents of side #2
b
>>>>>>>
"###);
let editor_script = test_env.set_up_fake_editor();
// Check that output file starts out empty and resolve the conflict
@ -104,11 +104,11 @@ fn test_resolution() {
--- a/file
+++ b/file
@@ -1,7 +1,1 @@
-<<<<<<<
-%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--base
-+a
-+++++++
-+++++++ Contents of side #2
-b
->>>>>>>
+resolution
@ -144,11 +144,11 @@ fn test_resolution() {
--- a/file
+++ b/file
@@ -1,7 +1,1 @@
-<<<<<<<
-%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--base
-+a
-+++++++
-+++++++ Contents of side #2
-b
->>>>>>>
+resolution
@ -178,11 +178,11 @@ fn test_resolution() {
);
insta::assert_snapshot!(
std::fs::read_to_string(test_env.env_root().join("editor1")).unwrap(), @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+a
+++++++
+++++++ Contents of side #2
b
>>>>>>>
"###);
@ -193,11 +193,11 @@ fn test_resolution() {
--- a/file
+++ b/file
@@ -1,7 +1,1 @@
-<<<<<<<
-%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--base
-+a
-+++++++
-+++++++ Contents of side #2
-b
->>>>>>>
+resolution
@ -253,11 +253,11 @@ fn test_resolution() {
"###);
insta::assert_snapshot!(
std::fs::read_to_string(test_env.env_root().join("editor2")).unwrap(), @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+a
+++++++
+++++++ Contents of side #2
b
>>>>>>>
"###);
@ -268,13 +268,13 @@ fn test_resolution() {
--- a/file
+++ b/file
@@ -1,7 +1,7 @@
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
--base
-+a
+-some
++fake
+++++++
+++++++ Contents of side #2
-b
+conflict
>>>>>>>
@ -328,14 +328,17 @@ fn test_resolution() {
--- a/file
+++ b/file
@@ -1,7 +1,7 @@
<<<<<<<
%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--base
-+a
-+++++++ Contents of side #2
-b
+<<<<<<<
+%%%%%%%
+-some
++fake
+++++++
-b
++++++++
+conflict
>>>>>>>
"###);
@ -398,14 +401,14 @@ fn test_normal_conflict_input_files() {
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("file")).unwrap()
, @r###"
<<<<<<<
%%%%%%%
-base
+a
+++++++
b
>>>>>>>
"###);
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+a
+++++++ Contents of side #2
b
>>>>>>>
"###);
check_resolve_produces_input_file(&mut test_env, &repo_path, "base", "base\n");
check_resolve_produces_input_file(&mut test_env, &repo_path, "left", "a\n");
@ -439,10 +442,10 @@ fn test_baseless_conflict_input_files() {
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("file")).unwrap()
, @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
+a
+++++++
+++++++ Contents of side #2
b
>>>>>>>
"###);
@ -510,10 +513,10 @@ fn test_edit_delete_conflict_input_files() {
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("file")).unwrap()
, @r###"
<<<<<<<
+++++++
<<<<<<< Conflict 1 of 1
+++++++ Contents of side #1
a
%%%%%%%
%%%%%%% Changes from base to side #2
-base
>>>>>>>
"###);
@ -682,22 +685,22 @@ fn test_multiple_conflicts() {
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("this_file_has_a_very_long_name_to_test_padding")).unwrap()
, @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-first base
+first a
+++++++
+++++++ Contents of side #2
first b
>>>>>>>
"###);
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("another_file")).unwrap()
, @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-second base
+second a
+++++++
+++++++ Contents of side #2
second b
>>>>>>>
"###);
@ -742,11 +745,11 @@ fn test_multiple_conflicts() {
--- a/another_file
+++ b/another_file
@@ -1,7 +1,1 @@
-<<<<<<<
-%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--second base
-+second a
-+++++++
-+++++++ Contents of side #2
-second b
->>>>>>>
+resolution another_file
@ -781,11 +784,11 @@ fn test_multiple_conflicts() {
--- a/another_file
+++ b/another_file
@@ -1,7 +1,1 @@
-<<<<<<<
-%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--second base
-+second a
-+++++++
-+++++++ Contents of side #2
-second b
->>>>>>>
+first resolution for auto-chosen file
@ -808,11 +811,11 @@ fn test_multiple_conflicts() {
--- a/another_file
+++ b/another_file
@@ -1,7 +1,1 @@
-<<<<<<<
-%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--second base
-+second a
-+++++++
-+++++++ Contents of side #2
-second b
->>>>>>>
+first resolution for auto-chosen file
@ -821,11 +824,11 @@ fn test_multiple_conflicts() {
--- a/this_file_has_a_very_long_name_to_test_padding
+++ b/this_file_has_a_very_long_name_to_test_padding
@@ -1,7 +1,1 @@
-<<<<<<<
-%%%%%%%
-<<<<<<< Conflict 1 of 1
-%%%%%%% Changes from base to side #1
--first base
-+first a
-+++++++
-+++++++ Contents of side #2
-first b
->>>>>>>
+second resolution for auto-chosen file

View file

@ -171,25 +171,25 @@ fn test_restore_conflicted_merge() {
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("file")).unwrap()
, @r###"
<<<<<<<
%%%%%%%
-base
+a
+++++++
b
>>>>>>>
"###);
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+a
+++++++ Contents of side #2
b
>>>>>>>
"###);
// Overwrite the file...
std::fs::write(repo_path.join("file"), "resolution").unwrap();
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff"]),
@r###"
Resolved conflict in file:
1 : <<<<<<<
2 : %%%%%%%
1 : <<<<<<< Conflict 1 of 1
2 : %%%%%%% Changes from base to side #1
3 : -base
4 : +a
5 : +++++++
5 : +++++++ Contents of side #2
6 : b
7 : >>>>>>>
1: resolution
@ -210,11 +210,11 @@ fn test_restore_conflicted_merge() {
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("file")).unwrap()
, @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+a
+++++++
+++++++ Contents of side #2
b
>>>>>>>
"###);
@ -226,11 +226,11 @@ fn test_restore_conflicted_merge() {
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff"]),
@r###"
Resolved conflict in file:
1 : <<<<<<<
2 : %%%%%%%
1 : <<<<<<< Conflict 1 of 1
2 : %%%%%%% Changes from base to side #1
3 : -base
4 : +a
5 : +++++++
5 : +++++++ Contents of side #2
6 : b
7 : >>>>>>>
1: resolution
@ -251,11 +251,11 @@ fn test_restore_conflicted_merge() {
insta::assert_snapshot!(
std::fs::read_to_string(repo_path.join("file")).unwrap()
, @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-base
+a
+++++++
+++++++ Contents of side #2
b
>>>>>>>
"###);

View file

@ -649,14 +649,14 @@ fn test_squash_from_multiple() {
// The changes from the sources have been applied
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=d", "file"]);
insta::assert_snapshot!(stdout, @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base #1 to side #1
-a
+d
%%%%%%%
%%%%%%% Changes from base #2 to side #2
-a
+b
+++++++
+++++++ Contents of side #3
c
>>>>>>>
"###);
@ -786,14 +786,14 @@ fn test_squash_from_multiple_partial() {
// The selected changes from the sources have been applied
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=d", "file1"]);
insta::assert_snapshot!(stdout, @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base #1 to side #1
-a
+d
%%%%%%%
%%%%%%% Changes from base #2 to side #2
-a
+b
+++++++
+++++++ Contents of side #3
c
>>>>>>>
"###);

View file

@ -29,11 +29,11 @@ use crate::merge::{Merge, MergeBuilder, MergedTreeValue};
use crate::repo_path::RepoPath;
use crate::store::Store;
const CONFLICT_START_LINE: &[u8] = b"<<<<<<<\n";
const CONFLICT_END_LINE: &[u8] = b">>>>>>>\n";
const CONFLICT_DIFF_LINE: &[u8] = b"%%%%%%%\n";
const CONFLICT_MINUS_LINE: &[u8] = b"-------\n";
const CONFLICT_PLUS_LINE: &[u8] = b"+++++++\n";
const CONFLICT_START_LINE: &[u8] = b"<<<<<<<";
const CONFLICT_END_LINE: &[u8] = b">>>>>>>";
const CONFLICT_DIFF_LINE: &[u8] = b"%%%%%%%";
const CONFLICT_MINUS_LINE: &[u8] = b"-------";
const CONFLICT_PLUS_LINE: &[u8] = b"+++++++";
const CONFLICT_START_LINE_CHAR: u8 = CONFLICT_START_LINE[0];
const CONFLICT_END_LINE_CHAR: u8 = CONFLICT_END_LINE[0];
const CONFLICT_DIFF_LINE_CHAR: u8 = CONFLICT_DIFF_LINE[0];
@ -204,19 +204,37 @@ pub fn materialize_merge_result(
output.write_all(&content.0)?;
}
MergeResult::Conflict(hunks) => {
let num_conflicts = hunks
.iter()
.filter(|hunk| hunk.as_resolved().is_none())
.count();
let mut conflict_index = 0;
for hunk in hunks {
if let Some(content) = hunk.as_resolved() {
output.write_all(&content.0)?;
} else {
conflict_index += 1;
output.write_all(CONFLICT_START_LINE)?;
output.write_all(
format!(" Conflict {conflict_index} of {num_conflicts}\n").as_bytes(),
)?;
let mut add_index = 0;
for left in hunk.removes() {
for (base_index, left) in hunk.removes().enumerate() {
// The vast majority of conflicts one actually tries to
// resolve manually have 1 base.
let base_str = if hunk.removes().len() == 1 {
"base".to_string()
} else {
format!("base #{}", base_index + 1)
};
let right1 = if let Some(right1) = hunk.get_add(add_index) {
right1
} else {
// If we have no more positive terms, emit the remaining negative
// terms as snapshots.
output.write_all(CONFLICT_MINUS_LINE)?;
output.write_all(format!(" Contents of {base_str}\n").as_bytes())?;
output.write_all(&left.0)?;
continue;
};
@ -236,8 +254,18 @@ pub fn materialize_merge_result(
// the current positive term as a snapshot and the next
// positive term as a diff.
output.write_all(CONFLICT_PLUS_LINE)?;
output.write_all(
format!(" Contents of side #{}\n", add_index + 1).as_bytes(),
)?;
output.write_all(&right1.0)?;
output.write_all(CONFLICT_DIFF_LINE)?;
output.write_all(
format!(
" Changes from {base_str} to side #{}\n",
add_index + 2
)
.as_bytes(),
)?;
write_diff_hunks(&diff2, output)?;
add_index += 2;
continue;
@ -245,16 +273,24 @@ pub fn materialize_merge_result(
}
output.write_all(CONFLICT_DIFF_LINE)?;
output.write_all(
format!(" Changes from {base_str} to side #{}\n", add_index + 1)
.as_bytes(),
)?;
write_diff_hunks(&diff1, output)?;
add_index += 1;
}
// Emit the remaining positive terms as snapshots.
for slice in hunk.adds().skip(add_index) {
for (add_index, slice) in hunk.adds().enumerate().skip(add_index) {
output.write_all(CONFLICT_PLUS_LINE)?;
output.write_all(
format!(" Contents of side #{}\n", add_index + 1).as_bytes(),
)?;
output.write_all(&slice.0)?;
}
output.write_all(CONFLICT_END_LINE)?;
output.write_all(b"\n")?;
}
}
}

View file

@ -77,12 +77,12 @@ fn test_materialize_conflict_basic() {
@r###"
line 1
line 2
<<<<<<<
+++++++
<<<<<<< Conflict 1 of 1
+++++++ Contents of side #1
left 3.1
left 3.2
left 3.3
%%%%%%%
%%%%%%% Changes from base to side #2
-line 3
+right 3.1
>>>>>>>
@ -101,11 +101,11 @@ fn test_materialize_conflict_basic() {
@r###"
line 1
line 2
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-line 3
+right 3.1
+++++++
+++++++ Contents of side #2
left 3.1
left 3.2
left 3.3
@ -173,16 +173,16 @@ fn test_materialize_conflict_multi_rebase_conflicts() {
&materialize_conflict_string(store, path, &conflict),
@r###"
line 1
<<<<<<<
+++++++
<<<<<<< Conflict 1 of 1
+++++++ Contents of side #1
line 2 a.1
line 2 a.2
line 2 a.3
%%%%%%%
%%%%%%% Changes from base #1 to side #2
-line 2 base
+line 2 b.1
+line 2 b.2
%%%%%%%
%%%%%%% Changes from base #2 to side #3
-line 2 base
+line 2 c.1
>>>>>>>
@ -197,15 +197,15 @@ fn test_materialize_conflict_multi_rebase_conflicts() {
&materialize_conflict_string(store, path, &conflict),
@r###"
line 1
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base #1 to side #1
-line 2 base
+line 2 c.1
%%%%%%%
%%%%%%% Changes from base #2 to side #2
-line 2 base
+line 2 b.1
+line 2 b.2
+++++++
+++++++ Contents of side #3
line 2 a.1
line 2 a.2
line 2 a.3
@ -221,15 +221,15 @@ fn test_materialize_conflict_multi_rebase_conflicts() {
&materialize_conflict_string(store, path, &conflict),
@r###"
line 1
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base #1 to side #1
-line 2 base
+line 2 c.1
+++++++
+++++++ Contents of side #2
line 2 a.1
line 2 a.2
line 2 a.3
%%%%%%%
%%%%%%% Changes from base #2 to side #3
-line 2 base
+line 2 b.1
+line 2 b.2
@ -288,22 +288,22 @@ fn test_materialize_parse_roundtrip() {
insta::assert_snapshot!(
materialized,
@r###"
<<<<<<<
+++++++
<<<<<<< Conflict 1 of 2
+++++++ Contents of side #1
line 1 left
line 2 left
%%%%%%%
%%%%%%% Changes from base to side #2
-line 1
+line 1 right
line 2
>>>>>>>
line 3
<<<<<<<
%%%%%%%
<<<<<<< Conflict 2 of 2
%%%%%%% Changes from base to side #1
line 4
-line 5
+line 5 left
+++++++
+++++++ Contents of side #2
line 4 right
line 5 right
>>>>>>>
@ -385,10 +385,10 @@ fn test_materialize_conflict_modify_delete() {
insta::assert_snapshot!(&materialize_conflict_string(store, path, &conflict), @r###"
line 1
line 2
<<<<<<<
+++++++
<<<<<<< Conflict 1 of 1
+++++++ Contents of side #1
modified
%%%%%%%
%%%%%%% Changes from base to side #2
-line 3
>>>>>>>
line 4
@ -404,10 +404,10 @@ fn test_materialize_conflict_modify_delete() {
insta::assert_snapshot!(&materialize_conflict_string(store, path, &conflict), @r###"
line 1
line 2
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-line 3
+++++++
+++++++ Contents of side #2
modified
>>>>>>>
line 4
@ -421,15 +421,15 @@ fn test_materialize_conflict_modify_delete() {
vec![Some(modified_id.clone()), None],
);
insta::assert_snapshot!(&materialize_conflict_string(store, path, &conflict), @r###"
<<<<<<<
%%%%%%%
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
line 1
line 2
-line 3
+modified
line 4
line 5
+++++++
+++++++ Contents of side #2
>>>>>>>
"###
);
@ -474,16 +474,16 @@ fn test_materialize_conflict_two_forward_diffs() {
insta::assert_snapshot!(
&materialize_conflict_string(store, path, &conflict),
@r###"
<<<<<<<
+++++++
<<<<<<< Conflict 1 of 1
+++++++ Contents of side #1
A
%%%%%%%
%%%%%%% Changes from base #1 to side #2
B
+++++++
+++++++ Contents of side #3
D
%%%%%%%
%%%%%%% Changes from base #2 to side #4
C
-------
------- Contents of base #3
E
>>>>>>>
"###