diff --git a/CHANGELOG.md b/CHANGELOG.md index e607bbb516..b08be2e688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). * `jj squash` has gained `--insert-before`, `--insert-after`, and `--destination` options. +* Merge tools can use the `$path` argument to learn where the file they + are merging will end up in the repository. + ### Fixed bugs * `jj git clone` now correctly fetches all tags, unless `--fetch-tags` is diff --git a/cli/src/config/merge_tools.toml b/cli/src/config/merge_tools.toml index 5c6f45bdac..e9fa1c5a2b 100644 --- a/cli/src/config/merge_tools.toml +++ b/cli/src/config/merge_tools.toml @@ -43,7 +43,7 @@ edit-args = ["$left", "$output", "$right", "-o", "$output"] # algorithm doesn't always maintain comments and spacing in the merge output # (even parts without conflicts), but you can remove it if you want to use a full structural merge. program = "mergiraf" -merge-args = ["merge", "$base", "$left", "$right", "-o", "$output", "-l", "$marker_length", "--fast"] +merge-args = ["merge", "$base", "$left", "$right", "-o", "$output", "-l", "$marker_length", "-p", "$path", "--fast"] merge-conflict-exit-codes = [1] # Non-interactive merge tool edit-args = [] diff --git a/cli/src/merge_tools/external.rs b/cli/src/merge_tools/external.rs index a587087686..3aae0c244e 100644 --- a/cli/src/merge_tools/external.rs +++ b/cli/src/merge_tools/external.rs @@ -253,6 +253,7 @@ fn run_mergetool_external_single_file( }) .try_collect()?; variables.insert("marker_length", conflict_marker_len.to_string()); + variables.insert("path", repo_path.as_internal_file_string().to_string()); let mut cmd = Command::new(&editor.program); cmd.args(interpolate_variables(&editor.merge_args, &variables)); diff --git a/cli/tests/test_resolve_command.rs b/cli/tests/test_resolve_command.rs index 16ae6bcd7b..d0f74292c5 100644 --- a/cli/tests/test_resolve_command.rs +++ b/cli/tests/test_resolve_command.rs @@ -1364,6 +1364,80 @@ fn test_resolve_change_delete_executable() { "); } +#[test] +fn test_pass_path_argument() { + let mut test_env = TestEnvironment::default(); + let editor_script = test_env.set_up_fake_editor(); + test_env.run_jj_in(".", ["git", "init", "repo"]).success(); + let work_dir = test_env.work_dir("repo"); + + // Makes it easier to read the diffs between conflicts + test_env.add_config("ui.conflict-marker-style = 'snapshot'"); + + // Create a conflict + create_commit_with_files(&work_dir, "base", &[], &[("file", "base\n")]); + create_commit_with_files(&work_dir, "a", &["base"], &[("file", "a\n")]); + create_commit_with_files(&work_dir, "b", &["base"], &[("file", "b\n")]); + create_commit_with_files(&work_dir, "conflict", &["a", "b"], &[]); + insta::assert_snapshot!(work_dir.run_jj(["resolve", "--list"]), @r" + file 2-sided conflict + [EOF] + "); + insta::assert_snapshot!(work_dir.read_file("file"), @r" + <<<<<<< Conflict 1 of 1 + +++++++ Contents of side #1 + a + ------- Contents of base + base + +++++++ Contents of side #2 + b + >>>>>>> Conflict 1 of 1 ends + " + ); + + // If the merge tool accepts the "$path" argument, then it should be passed + std::fs::write( + &editor_script, + indoc! {b" + expect-arg 0 + file\0write + resolution + \0"}, + ) + .unwrap(); + let output = work_dir.run_jj([ + "resolve", + "file", + r#"--config=merge-tools.fake-editor.merge-args=["$output", "$path"]"#, + ]); + insta::assert_snapshot!(output, @r###" + ------- stderr ------- + Resolving conflicts in: file + Working copy (@) now at: vruxwmqv 682816de conflict | conflict + Parent commit (@-) : zsuskuln 45537d53 a | a + Parent commit (@-) : royxmykx 89d1b299 b | b + Added 0 files, modified 1 files, removed 0 files + [EOF] + "###); + insta::assert_snapshot!(work_dir.run_jj(["diff", "--git"]), @r" + diff --git a/file b/file + index 0000000000..88425ec521 100644 + --- a/file + +++ b/file + @@ -1,8 +1,1 @@ + -<<<<<<< Conflict 1 of 1 + -+++++++ Contents of side #1 + -a + -------- Contents of base + -base + -+++++++ Contents of side #2 + -b + ->>>>>>> Conflict 1 of 1 ends + +resolution + [EOF] + "); +} + #[test] fn test_resolve_long_conflict_markers() { let mut test_env = TestEnvironment::default(); diff --git a/docs/config.md b/docs/config.md index ee62d6dce9..0b8b0f074a 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1147,6 +1147,10 @@ merge-tool-edits-conflict-markers = true # See below for an explanation and/or generates conflict markers. Usually, `jj` uses conflict markers of length 7, but they can be longer if necessary to make parsing unambiguous. +- `$path` is replaced with the path in the repository at which the file + will be eventually stored. It is relative to the root directory of the + repository and uses `/` as separators. + Unlike `diff-args` or `edit-args`, there is no default value for `merge-args`. If `merge-args` are not specified, the tool cannot be used for conflict resolution.