mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-24 12:48:55 +00:00
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:
parent
2f48f76e85
commit
70b517ca64
11 changed files with 210 additions and 166 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
>>>>>>>
|
||||
"###);
|
||||
|
|
|
@ -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
|
||||
>>>>>>>
|
||||
"###);
|
||||
|
|
|
@ -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
|
||||
>>>>>>>
|
||||
"###);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
->>>>>>>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
>>>>>>>
|
||||
"###);
|
||||
|
|
|
@ -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
|
||||
>>>>>>>
|
||||
"###);
|
||||
|
|
|
@ -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")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
>>>>>>>
|
||||
"###
|
||||
|
|
Loading…
Reference in a new issue