just playing with tangled
at diffedit3 845 lines 29 kB view raw
1// Copyright 2022 The Jujutsu Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15use std::path::Path; 16 17use indoc::indoc; 18 19use crate::common::TestEnvironment; 20 21fn create_commit( 22 test_env: &TestEnvironment, 23 repo_path: &Path, 24 name: &str, 25 parents: &[&str], 26 files: &[(&str, &str)], 27) { 28 if parents.is_empty() { 29 test_env.jj_cmd_ok(repo_path, &["new", "root()", "-m", name]); 30 } else { 31 let mut args = vec!["new", "-m", name]; 32 args.extend(parents); 33 test_env.jj_cmd_ok(repo_path, &args); 34 } 35 for (name, content) in files { 36 std::fs::write(repo_path.join(name), content).unwrap(); 37 } 38 test_env.jj_cmd_ok(repo_path, &["branch", "create", name]); 39} 40 41fn get_log_output(test_env: &TestEnvironment, repo_path: &Path) -> String { 42 test_env.jj_cmd_success(repo_path, &["log", "-T", "branches"]) 43} 44 45#[test] 46fn test_resolution() { 47 let mut test_env = TestEnvironment::default(); 48 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 49 let repo_path = test_env.env_root().join("repo"); 50 51 create_commit(&test_env, &repo_path, "base", &[], &[("file", "base\n")]); 52 create_commit(&test_env, &repo_path, "a", &["base"], &[("file", "a\n")]); 53 create_commit(&test_env, &repo_path, "b", &["base"], &[("file", "b\n")]); 54 create_commit(&test_env, &repo_path, "conflict", &["a", "b"], &[]); 55 // Test the setup 56 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 57 @ conflict 58 ├─╮ 59 │ ◉ b 60 ◉ │ a 61 ├─╯ 62 ◉ base 63 64 "###); 65 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 66 @r###" 67 file 2-sided conflict 68 "###); 69 insta::assert_snapshot!( 70 std::fs::read_to_string(repo_path.join("file")).unwrap() 71 , @r###" 72 <<<<<<< Conflict 1 of 1 73 %%%%%%% Changes from base to side #1 74 -base 75 +a 76 +++++++ Contents of side #2 77 b 78 >>>>>>> 79 "###); 80 81 let editor_script = test_env.set_up_fake_editor(); 82 // Check that output file starts out empty and resolve the conflict 83 std::fs::write( 84 &editor_script, 85 ["dump editor0", "write\nresolution\n"].join("\0"), 86 ) 87 .unwrap(); 88 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["resolve"]); 89 insta::assert_snapshot!(stdout, @""); 90 insta::assert_snapshot!(stderr, @r###" 91 Resolving conflicts in: file 92 Working copy now at: vruxwmqv e069f073 conflict | conflict 93 Parent commit : zsuskuln aa493daf a | a 94 Parent commit : royxmykx db6a4daf b | b 95 Added 0 files, modified 1 files, removed 0 files 96 "###); 97 insta::assert_snapshot!( 98 std::fs::read_to_string(test_env.env_root().join("editor0")).unwrap(), @r###" 99 "###); 100 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 101 @r###" 102 diff --git a/file b/file 103 index 0000000000...88425ec521 100644 104 --- a/file 105 +++ b/file 106 @@ -1,7 +1,1 @@ 107 -<<<<<<< Conflict 1 of 1 108 -%%%%%%% Changes from base to side #1 109 --base 110 -+a 111 -+++++++ Contents of side #2 112 -b 113 ->>>>>>> 114 +resolution 115 "###); 116 insta::assert_snapshot!(test_env.jj_cmd_cli_error(&repo_path, &["resolve", "--list"]), 117 @r###" 118 Error: No conflicts found at this revision 119 "###); 120 121 // Try again with --tool=<name> 122 test_env.jj_cmd_ok(&repo_path, &["undo"]); 123 std::fs::write(&editor_script, "write\nresolution\n").unwrap(); 124 let (stdout, stderr) = test_env.jj_cmd_ok( 125 &repo_path, 126 &[ 127 "resolve", 128 "--config-toml=ui.merge-editor='false'", 129 "--tool=fake-editor", 130 ], 131 ); 132 insta::assert_snapshot!(stdout, @""); 133 insta::assert_snapshot!(stderr, @r###" 134 Resolving conflicts in: file 135 Working copy now at: vruxwmqv 1a70c7c6 conflict | conflict 136 Parent commit : zsuskuln aa493daf a | a 137 Parent commit : royxmykx db6a4daf b | b 138 Added 0 files, modified 1 files, removed 0 files 139 "###); 140 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 141 @r###" 142 diff --git a/file b/file 143 index 0000000000...88425ec521 100644 144 --- a/file 145 +++ b/file 146 @@ -1,7 +1,1 @@ 147 -<<<<<<< Conflict 1 of 1 148 -%%%%%%% Changes from base to side #1 149 --base 150 -+a 151 -+++++++ Contents of side #2 152 -b 153 ->>>>>>> 154 +resolution 155 "###); 156 insta::assert_snapshot!(test_env.jj_cmd_cli_error(&repo_path, &["resolve", "--list"]), 157 @r###" 158 Error: No conflicts found at this revision 159 "###); 160 161 // Check that the output file starts with conflict markers if 162 // `merge-tool-edits-conflict-markers=true` 163 test_env.jj_cmd_ok(&repo_path, &["undo"]); 164 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 165 @""); 166 std::fs::write( 167 &editor_script, 168 ["dump editor1", "write\nresolution\n"].join("\0"), 169 ) 170 .unwrap(); 171 test_env.jj_cmd_ok( 172 &repo_path, 173 &[ 174 "resolve", 175 "--config-toml", 176 "merge-tools.fake-editor.merge-tool-edits-conflict-markers=true", 177 ], 178 ); 179 insta::assert_snapshot!( 180 std::fs::read_to_string(test_env.env_root().join("editor1")).unwrap(), @r###" 181 <<<<<<< Conflict 1 of 1 182 %%%%%%% Changes from base to side #1 183 -base 184 +a 185 +++++++ Contents of side #2 186 b 187 >>>>>>> 188 "###); 189 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 190 @r###" 191 diff --git a/file b/file 192 index 0000000000...88425ec521 100644 193 --- a/file 194 +++ b/file 195 @@ -1,7 +1,1 @@ 196 -<<<<<<< Conflict 1 of 1 197 -%%%%%%% Changes from base to side #1 198 --base 199 -+a 200 -+++++++ Contents of side #2 201 -b 202 ->>>>>>> 203 +resolution 204 "###); 205 206 // Check that if merge tool leaves conflict markers in output file and 207 // `merge-tool-edits-conflict-markers=true`, these markers are properly parsed. 208 test_env.jj_cmd_ok(&repo_path, &["undo"]); 209 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 210 @""); 211 std::fs::write( 212 &editor_script, 213 [ 214 "dump editor2", 215 indoc! {" 216 write 217 <<<<<<< 218 %%%%%%% 219 -some 220 +fake 221 +++++++ 222 conflict 223 >>>>>>> 224 "}, 225 ] 226 .join("\0"), 227 ) 228 .unwrap(); 229 let (stdout, stderr) = test_env.jj_cmd_ok( 230 &repo_path, 231 &[ 232 "resolve", 233 "--config-toml", 234 "merge-tools.fake-editor.merge-tool-edits-conflict-markers=true", 235 ], 236 ); 237 insta::assert_snapshot!(stdout, @""); 238 insta::assert_snapshot!(stderr, @r###" 239 Resolving conflicts in: file 240 New conflicts appeared in these commits: 241 vruxwmqv 7699b9c3 conflict | (conflict) conflict 242 To resolve the conflicts, start by updating to it: 243 jj new vruxwmqvtpmx 244 Then use `jj resolve`, or edit the conflict markers in the file directly. 245 Once the conflicts are resolved, you may want inspect the result with `jj diff`. 246 Then run `jj squash` to move the resolution into the conflicted commit. 247 Working copy now at: vruxwmqv 7699b9c3 conflict | (conflict) conflict 248 Parent commit : zsuskuln aa493daf a | a 249 Parent commit : royxmykx db6a4daf b | b 250 Added 0 files, modified 1 files, removed 0 files 251 There are unresolved conflicts at these paths: 252 file 2-sided conflict 253 "###); 254 insta::assert_snapshot!( 255 std::fs::read_to_string(test_env.env_root().join("editor2")).unwrap(), @r###" 256 <<<<<<< Conflict 1 of 1 257 %%%%%%% Changes from base to side #1 258 -base 259 +a 260 +++++++ Contents of side #2 261 b 262 >>>>>>> 263 "###); 264 // Note the "Modified" below 265 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 266 @r###" 267 diff --git a/file b/file 268 --- a/file 269 +++ b/file 270 @@ -1,7 +1,7 @@ 271 <<<<<<< Conflict 1 of 1 272 %%%%%%% Changes from base to side #1 273 --base 274 -+a 275 +-some 276 ++fake 277 +++++++ Contents of side #2 278 -b 279 +conflict 280 >>>>>>> 281 "###); 282 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 283 @r###" 284 file 2-sided conflict 285 "###); 286 287 // Check that if merge tool leaves conflict markers in output file but 288 // `merge-tool-edits-conflict-markers=false` or is not specified, 289 // `jj` considers the conflict resolved. 290 test_env.jj_cmd_ok(&repo_path, &["undo"]); 291 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 292 @""); 293 std::fs::write( 294 &editor_script, 295 [ 296 "dump editor3", 297 indoc! {" 298 write 299 <<<<<<< 300 %%%%%%% 301 -some 302 +fake 303 +++++++ 304 conflict 305 >>>>>>> 306 "}, 307 ] 308 .join("\0"), 309 ) 310 .unwrap(); 311 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["resolve"]); 312 insta::assert_snapshot!(stdout, @""); 313 insta::assert_snapshot!(stderr, @r###" 314 Resolving conflicts in: file 315 Working copy now at: vruxwmqv 3166dfd2 conflict | conflict 316 Parent commit : zsuskuln aa493daf a | a 317 Parent commit : royxmykx db6a4daf b | b 318 Added 0 files, modified 1 files, removed 0 files 319 "###); 320 insta::assert_snapshot!( 321 std::fs::read_to_string(test_env.env_root().join("editor3")).unwrap(), @r###" 322 "###); 323 // Note the "Resolved" below 324 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 325 @r###" 326 diff --git a/file b/file 327 index 0000000000...0610716cc1 100644 328 --- a/file 329 +++ b/file 330 @@ -1,7 +1,7 @@ 331 -<<<<<<< Conflict 1 of 1 332 -%%%%%%% Changes from base to side #1 333 --base 334 -+a 335 -+++++++ Contents of side #2 336 -b 337 +<<<<<<< 338 +%%%%%%% 339 +-some 340 ++fake 341 ++++++++ 342 +conflict 343 >>>>>>> 344 "###); 345 insta::assert_snapshot!(test_env.jj_cmd_cli_error(&repo_path, &["resolve", "--list"]), 346 @r###" 347 Error: No conflicts found at this revision 348 "###); 349 350 // TODO: Check that running `jj new` and then `jj resolve -r conflict` works 351 // correctly. 352} 353 354fn check_resolve_produces_input_file( 355 test_env: &mut TestEnvironment, 356 repo_path: &Path, 357 role: &str, 358 expected_content: &str, 359) { 360 let editor_script = test_env.set_up_fake_editor(); 361 std::fs::write(editor_script, format!("expect\n{expected_content}")).unwrap(); 362 363 let merge_arg_config = format!(r#"merge-tools.fake-editor.merge-args = ["${role}"]"#); 364 // This error means that fake-editor exited successfully but did not modify the 365 // output file. 366 // We cannot use `insta::assert_snapshot!` here after insta 1.22 due to 367 // https://github.com/mitsuhiko/insta/commit/745b45b. Hopefully, this will again become possible 368 // in the future. See also https://github.com/mitsuhiko/insta/issues/313. 369 assert_eq!( 370 &test_env.jj_cmd_failure(repo_path, &["resolve", "--config-toml", &merge_arg_config]), 371 "Resolving conflicts in: file\nError: Failed to resolve conflicts\nCaused by: The output \ 372 file is either unchanged or empty after the editor quit (run with --debug to see the \ 373 exact invocation).\n" 374 ); 375} 376 377#[test] 378fn test_normal_conflict_input_files() { 379 let mut test_env = TestEnvironment::default(); 380 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 381 let repo_path = test_env.env_root().join("repo"); 382 383 create_commit(&test_env, &repo_path, "base", &[], &[("file", "base\n")]); 384 create_commit(&test_env, &repo_path, "a", &["base"], &[("file", "a\n")]); 385 create_commit(&test_env, &repo_path, "b", &["base"], &[("file", "b\n")]); 386 create_commit(&test_env, &repo_path, "conflict", &["a", "b"], &[]); 387 // Test the setup 388 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 389 @ conflict 390 ├─╮ 391 │ ◉ b 392 ◉ │ a 393 ├─╯ 394 ◉ base 395396 "###); 397 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 398 @r###" 399 file 2-sided conflict 400 "###); 401 insta::assert_snapshot!( 402 std::fs::read_to_string(repo_path.join("file")).unwrap() 403 , @r###" 404 <<<<<<< Conflict 1 of 1 405 %%%%%%% Changes from base to side #1 406 -base 407 +a 408 +++++++ Contents of side #2 409 b 410 >>>>>>> 411 "###); 412 413 check_resolve_produces_input_file(&mut test_env, &repo_path, "base", "base\n"); 414 check_resolve_produces_input_file(&mut test_env, &repo_path, "left", "a\n"); 415 check_resolve_produces_input_file(&mut test_env, &repo_path, "right", "b\n"); 416} 417 418#[test] 419fn test_baseless_conflict_input_files() { 420 let mut test_env = TestEnvironment::default(); 421 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 422 let repo_path = test_env.env_root().join("repo"); 423 424 create_commit(&test_env, &repo_path, "base", &[], &[]); 425 create_commit(&test_env, &repo_path, "a", &["base"], &[("file", "a\n")]); 426 create_commit(&test_env, &repo_path, "b", &["base"], &[("file", "b\n")]); 427 create_commit(&test_env, &repo_path, "conflict", &["a", "b"], &[]); 428 // Test the setup 429 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 430 @ conflict 431 ├─╮ 432 │ ◉ b 433 ◉ │ a 434 ├─╯ 435 ◉ base 436437 "###); 438 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 439 @r###" 440 file 2-sided conflict 441 "###); 442 insta::assert_snapshot!( 443 std::fs::read_to_string(repo_path.join("file")).unwrap() 444 , @r###" 445 <<<<<<< Conflict 1 of 1 446 %%%%%%% Changes from base to side #1 447 +a 448 +++++++ Contents of side #2 449 b 450 >>>>>>> 451 "###); 452 453 check_resolve_produces_input_file(&mut test_env, &repo_path, "base", ""); 454 check_resolve_produces_input_file(&mut test_env, &repo_path, "left", "a\n"); 455 check_resolve_produces_input_file(&mut test_env, &repo_path, "right", "b\n"); 456} 457 458#[test] 459fn test_too_many_parents() { 460 let test_env = TestEnvironment::default(); 461 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 462 let repo_path = test_env.env_root().join("repo"); 463 464 create_commit(&test_env, &repo_path, "base", &[], &[("file", "base\n")]); 465 create_commit(&test_env, &repo_path, "a", &["base"], &[("file", "a\n")]); 466 create_commit(&test_env, &repo_path, "b", &["base"], &[("file", "b\n")]); 467 create_commit(&test_env, &repo_path, "c", &["base"], &[("file", "c\n")]); 468 create_commit(&test_env, &repo_path, "conflict", &["a", "b", "c"], &[]); 469 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 470 @r###" 471 file 3-sided conflict 472 "###); 473 // Test warning color 474 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list", "--color=always"]), 475 @r###" 476 file 3-sided conflict 477 "###); 478 479 let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]); 480 insta::assert_snapshot!(error, @r###" 481 Hint: Using default editor ':builtin-tui'; run `jj config set --user ui.merge-editor :builtin` to disable this message. 482 Resolving conflicts in: file 483 Error: Failed to resolve conflicts 484 Caused by: The conflict at "file" has 3 sides. At most 2 sides are supported. 485 "###); 486} 487 488#[test] 489fn test_edit_delete_conflict_input_files() { 490 let mut test_env = TestEnvironment::default(); 491 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 492 let repo_path = test_env.env_root().join("repo"); 493 494 create_commit(&test_env, &repo_path, "base", &[], &[("file", "base\n")]); 495 create_commit(&test_env, &repo_path, "a", &["base"], &[("file", "a\n")]); 496 create_commit(&test_env, &repo_path, "b", &["base"], &[]); 497 std::fs::remove_file(repo_path.join("file")).unwrap(); 498 create_commit(&test_env, &repo_path, "conflict", &["a", "b"], &[]); 499 // Test the setup 500 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 501 @ conflict 502 ├─╮ 503 │ ◉ b 504 ◉ │ a 505 ├─╯ 506 ◉ base 507508 "###); 509 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 510 @r###" 511 file 2-sided conflict including 1 deletion 512 "###); 513 insta::assert_snapshot!( 514 std::fs::read_to_string(repo_path.join("file")).unwrap() 515 , @r###" 516 <<<<<<< Conflict 1 of 1 517 +++++++ Contents of side #1 518 a 519 %%%%%%% Changes from base to side #2 520 -base 521 >>>>>>> 522 "###); 523 524 check_resolve_produces_input_file(&mut test_env, &repo_path, "base", "base\n"); 525 check_resolve_produces_input_file(&mut test_env, &repo_path, "left", "a\n"); 526 check_resolve_produces_input_file(&mut test_env, &repo_path, "right", ""); 527} 528 529#[test] 530fn test_file_vs_dir() { 531 let test_env = TestEnvironment::default(); 532 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 533 let repo_path = test_env.env_root().join("repo"); 534 535 create_commit(&test_env, &repo_path, "base", &[], &[("file", "base\n")]); 536 create_commit(&test_env, &repo_path, "a", &["base"], &[("file", "a\n")]); 537 create_commit(&test_env, &repo_path, "b", &["base"], &[]); 538 std::fs::remove_file(repo_path.join("file")).unwrap(); 539 std::fs::create_dir(repo_path.join("file")).unwrap(); 540 // Without a placeholder file, `jj` ignores an empty directory 541 std::fs::write(repo_path.join("file").join("placeholder"), "").unwrap(); 542 create_commit(&test_env, &repo_path, "conflict", &["a", "b"], &[]); 543 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 544 @ conflict 545 ├─╮ 546 │ ◉ b 547 ◉ │ a 548 ├─╯ 549 ◉ base 550551 "###); 552 553 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 554 @r###" 555 file 2-sided conflict including a directory 556 "###); 557 let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]); 558 insta::assert_snapshot!(error, @r###" 559 Hint: Using default editor ':builtin-tui'; run `jj config set --user ui.merge-editor :builtin` to disable this message. 560 Resolving conflicts in: file 561 Error: Failed to resolve conflicts 562 Caused by: Only conflicts that involve normal files (not symlinks, not executable, etc.) are supported. Conflict summary for "file": 563 Conflict: 564 Removing file with id df967b96a579e45a18b8251732d16804b2e56a55 565 Adding file with id 78981922613b2afb6025042ff6bd878ac1994e85 566 Adding tree with id 133bb38fc4e4bf6b551f1f04db7e48f04cac2877 567 568 "###); 569} 570 571#[test] 572fn test_description_with_dir_and_deletion() { 573 let test_env = TestEnvironment::default(); 574 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 575 let repo_path = test_env.env_root().join("repo"); 576 577 create_commit(&test_env, &repo_path, "base", &[], &[("file", "base\n")]); 578 create_commit(&test_env, &repo_path, "edit", &["base"], &[("file", "b\n")]); 579 create_commit(&test_env, &repo_path, "dir", &["base"], &[]); 580 std::fs::remove_file(repo_path.join("file")).unwrap(); 581 std::fs::create_dir(repo_path.join("file")).unwrap(); 582 // Without a placeholder file, `jj` ignores an empty directory 583 std::fs::write(repo_path.join("file").join("placeholder"), "").unwrap(); 584 create_commit(&test_env, &repo_path, "del", &["base"], &[]); 585 std::fs::remove_file(repo_path.join("file")).unwrap(); 586 create_commit( 587 &test_env, 588 &repo_path, 589 "conflict", 590 &["edit", "dir", "del"], 591 &[], 592 ); 593 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 594 @ conflict 595 ├─┬─╮ 596 │ │ ◉ del 597 │ ◉ │ dir 598 │ ├─╯ 599 ◉ │ edit 600 ├─╯ 601 ◉ base 602603 "###); 604 605 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 606 @r###" 607 file 3-sided conflict including 1 deletion and a directory 608 "###); 609 // Test warning color. The deletion is fine, so it's not highlighted 610 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list", "--color=always"]), 611 @r###" 612 file 3-sided conflict including 1 deletion and a directory 613 "###); 614 let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]); 615 insta::assert_snapshot!(error, @r###" 616 Hint: Using default editor ':builtin-tui'; run `jj config set --user ui.merge-editor :builtin` to disable this message. 617 Resolving conflicts in: file 618 Error: Failed to resolve conflicts 619 Caused by: Only conflicts that involve normal files (not symlinks, not executable, etc.) are supported. Conflict summary for "file": 620 Conflict: 621 Removing file with id df967b96a579e45a18b8251732d16804b2e56a55 622 Removing file with id df967b96a579e45a18b8251732d16804b2e56a55 623 Adding file with id 61780798228d17af2d34fce4cfbdf35556832472 624 Adding tree with id 133bb38fc4e4bf6b551f1f04db7e48f04cac2877 625 626 "###); 627} 628 629#[test] 630fn test_multiple_conflicts() { 631 let mut test_env = TestEnvironment::default(); 632 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 633 let repo_path = test_env.env_root().join("repo"); 634 635 create_commit( 636 &test_env, 637 &repo_path, 638 "base", 639 &[], 640 &[ 641 ( 642 "this_file_has_a_very_long_name_to_test_padding", 643 "first base\n", 644 ), 645 ("another_file", "second base\n"), 646 ], 647 ); 648 create_commit( 649 &test_env, 650 &repo_path, 651 "a", 652 &["base"], 653 &[ 654 ( 655 "this_file_has_a_very_long_name_to_test_padding", 656 "first a\n", 657 ), 658 ("another_file", "second a\n"), 659 ], 660 ); 661 create_commit( 662 &test_env, 663 &repo_path, 664 "b", 665 &["base"], 666 &[ 667 ( 668 "this_file_has_a_very_long_name_to_test_padding", 669 "first b\n", 670 ), 671 ("another_file", "second b\n"), 672 ], 673 ); 674 create_commit(&test_env, &repo_path, "conflict", &["a", "b"], &[]); 675 // Test the setup 676 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 677 @ conflict 678 ├─╮ 679 │ ◉ b 680 ◉ │ a 681 ├─╯ 682 ◉ base 683684 "###); 685 insta::assert_snapshot!( 686 std::fs::read_to_string(repo_path.join("this_file_has_a_very_long_name_to_test_padding")).unwrap() 687 , @r###" 688 <<<<<<< Conflict 1 of 1 689 %%%%%%% Changes from base to side #1 690 -first base 691 +first a 692 +++++++ Contents of side #2 693 first b 694 >>>>>>> 695 "###); 696 insta::assert_snapshot!( 697 std::fs::read_to_string(repo_path.join("another_file")).unwrap() 698 , @r###" 699 <<<<<<< Conflict 1 of 1 700 %%%%%%% Changes from base to side #1 701 -second base 702 +second a 703 +++++++ Contents of side #2 704 second b 705 >>>>>>> 706 "###); 707 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 708 @r###" 709 another_file 2-sided conflict 710 this_file_has_a_very_long_name_to_test_padding 2-sided conflict 711 "###); 712 // Test colors 713 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list", "--color=always"]), 714 @r###" 715 another_file 2-sided conflict 716 this_file_has_a_very_long_name_to_test_padding 2-sided conflict 717 "###); 718 719 let editor_script = test_env.set_up_fake_editor(); 720 721 // Check that we can manually pick which of the conflicts to resolve first 722 std::fs::write(&editor_script, "expect\n\0write\nresolution another_file\n").unwrap(); 723 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["resolve", "another_file"]); 724 insta::assert_snapshot!(stdout, @""); 725 insta::assert_snapshot!(stderr, @r###" 726 Resolving conflicts in: another_file 727 New conflicts appeared in these commits: 728 vruxwmqv 6a90e546 conflict | (conflict) conflict 729 To resolve the conflicts, start by updating to it: 730 jj new vruxwmqvtpmx 731 Then use `jj resolve`, or edit the conflict markers in the file directly. 732 Once the conflicts are resolved, you may want inspect the result with `jj diff`. 733 Then run `jj squash` to move the resolution into the conflicted commit. 734 Working copy now at: vruxwmqv 6a90e546 conflict | (conflict) conflict 735 Parent commit : zsuskuln de7553ef a | a 736 Parent commit : royxmykx f68bc2f0 b | b 737 Added 0 files, modified 1 files, removed 0 files 738 There are unresolved conflicts at these paths: 739 this_file_has_a_very_long_name_to_test_padding 2-sided conflict 740 "###); 741 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 742 @r###" 743 diff --git a/another_file b/another_file 744 index 0000000000...a9fcc7d486 100644 745 --- a/another_file 746 +++ b/another_file 747 @@ -1,7 +1,1 @@ 748 -<<<<<<< Conflict 1 of 1 749 -%%%%%%% Changes from base to side #1 750 --second base 751 -+second a 752 -+++++++ Contents of side #2 753 -second b 754 ->>>>>>> 755 +resolution another_file 756 "###); 757 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 758 @r###" 759 this_file_has_a_very_long_name_to_test_padding 2-sided conflict 760 "###); 761 762 // Repeat the above with the `--quiet` option. 763 test_env.jj_cmd_ok(&repo_path, &["undo"]); 764 std::fs::write(&editor_script, "expect\n\0write\nresolution another_file\n").unwrap(); 765 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["resolve", "--quiet", "another_file"]); 766 insta::assert_snapshot!(stdout, @""); 767 insta::assert_snapshot!(stderr, @""); 768 769 // For the rest of the test, we call `jj resolve` several times in a row to 770 // resolve each conflict in the order it chooses. 771 test_env.jj_cmd_ok(&repo_path, &["undo"]); 772 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 773 @""); 774 std::fs::write( 775 &editor_script, 776 "expect\n\0write\nfirst resolution for auto-chosen file\n", 777 ) 778 .unwrap(); 779 test_env.jj_cmd_ok(&repo_path, &["resolve"]); 780 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 781 @r###" 782 diff --git a/another_file b/another_file 783 index 0000000000...7903e1c1c7 100644 784 --- a/another_file 785 +++ b/another_file 786 @@ -1,7 +1,1 @@ 787 -<<<<<<< Conflict 1 of 1 788 -%%%%%%% Changes from base to side #1 789 --second base 790 -+second a 791 -+++++++ Contents of side #2 792 -second b 793 ->>>>>>> 794 +first resolution for auto-chosen file 795 "###); 796 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]), 797 @r###" 798 this_file_has_a_very_long_name_to_test_padding 2-sided conflict 799 "###); 800 std::fs::write( 801 &editor_script, 802 "expect\n\0write\nsecond resolution for auto-chosen file\n", 803 ) 804 .unwrap(); 805 806 test_env.jj_cmd_ok(&repo_path, &["resolve"]); 807 insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--git"]), 808 @r###" 809 diff --git a/another_file b/another_file 810 index 0000000000...7903e1c1c7 100644 811 --- a/another_file 812 +++ b/another_file 813 @@ -1,7 +1,1 @@ 814 -<<<<<<< Conflict 1 of 1 815 -%%%%%%% Changes from base to side #1 816 --second base 817 -+second a 818 -+++++++ Contents of side #2 819 -second b 820 ->>>>>>> 821 +first resolution for auto-chosen file 822 diff --git a/this_file_has_a_very_long_name_to_test_padding b/this_file_has_a_very_long_name_to_test_padding 823 index 0000000000...f8c72adf17 100644 824 --- a/this_file_has_a_very_long_name_to_test_padding 825 +++ b/this_file_has_a_very_long_name_to_test_padding 826 @@ -1,7 +1,1 @@ 827 -<<<<<<< Conflict 1 of 1 828 -%%%%%%% Changes from base to side #1 829 --first base 830 -+first a 831 -+++++++ Contents of side #2 832 -first b 833 ->>>>>>> 834 +second resolution for auto-chosen file 835 "###); 836 837 insta::assert_snapshot!(test_env.jj_cmd_cli_error(&repo_path, &["resolve", "--list"]), 838 @r###" 839 Error: No conflicts found at this revision 840 "###); 841 insta::assert_snapshot!(test_env.jj_cmd_cli_error(&repo_path, &["resolve"]), 842 @r###" 843 Error: No conflicts found at this revision 844 "###); 845}