just playing with tangled
at diffedit3 1141 lines 43 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 crate::common::TestEnvironment; 18 19#[test] 20fn test_squash() { 21 let test_env = TestEnvironment::default(); 22 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 23 let repo_path = test_env.env_root().join("repo"); 24 25 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "a"]); 26 std::fs::write(repo_path.join("file1"), "a\n").unwrap(); 27 test_env.jj_cmd_ok(&repo_path, &["new"]); 28 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "b"]); 29 std::fs::write(repo_path.join("file1"), "b\n").unwrap(); 30 test_env.jj_cmd_ok(&repo_path, &["new"]); 31 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "c"]); 32 std::fs::write(repo_path.join("file1"), "c\n").unwrap(); 33 // Test the setup 34 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 35 @ 90fe0a96fc90 c 36 ◉ fa5efbdf533c b 37 ◉ 90aeefd03044 a 38 ◉ 000000000000 39 "###); 40 41 // Squashes the working copy into the parent by default 42 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash"]); 43 insta::assert_snapshot!(stdout, @""); 44 insta::assert_snapshot!(stderr, @r###" 45 Working copy now at: vruxwmqv b9280a98 (empty) (no description set) 46 Parent commit : kkmpptxz 6ca29c9d b c | (no description set) 47 "###); 48 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 49 @ b9280a9898cb 50 ◉ 6ca29c9d2e7c b c 51 ◉ 90aeefd03044 a 52 ◉ 000000000000 53 "###); 54 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]); 55 insta::assert_snapshot!(stdout, @r###" 56 c 57 "###); 58 59 // Can squash a given commit into its parent 60 test_env.jj_cmd_ok(&repo_path, &["undo"]); 61 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "-r", "b"]); 62 insta::assert_snapshot!(stdout, @""); 63 insta::assert_snapshot!(stderr, @r###" 64 Rebased 1 descendant commits 65 Working copy now at: mzvwutvl e87cf8eb c | (no description set) 66 Parent commit : qpvuntsm 893c93ae a b | (no description set) 67 "###); 68 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 69 @ e87cf8ebc7e1 c 70 ◉ 893c93ae2a87 a b 71 ◉ 000000000000 72 "###); 73 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "b"]); 74 insta::assert_snapshot!(stdout, @r###" 75 b 76 "###); 77 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]); 78 insta::assert_snapshot!(stdout, @r###" 79 c 80 "###); 81 82 // Cannot squash a merge commit (because it's unclear which parent it should go 83 // into) 84 test_env.jj_cmd_ok(&repo_path, &["undo"]); 85 test_env.jj_cmd_ok(&repo_path, &["edit", "b"]); 86 test_env.jj_cmd_ok(&repo_path, &["new"]); 87 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "d"]); 88 std::fs::write(repo_path.join("file2"), "d\n").unwrap(); 89 test_env.jj_cmd_ok(&repo_path, &["new", "c", "d"]); 90 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "e"]); 91 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 92 @ c7a11b36d333 e 93 ├─╮ 94 │ ◉ 5658521e0f8b d 95 ◉ │ 90fe0a96fc90 c 96 ├─╯ 97 ◉ fa5efbdf533c b 98 ◉ 90aeefd03044 a 99 ◉ 000000000000 100 "###); 101 let stderr = test_env.jj_cmd_failure(&repo_path, &["squash"]); 102 insta::assert_snapshot!(stderr, @r###" 103 Error: Cannot squash merge commits 104 "###); 105 106 // Can squash into a merge commit 107 test_env.jj_cmd_ok(&repo_path, &["new", "e"]); 108 std::fs::write(repo_path.join("file1"), "e\n").unwrap(); 109 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash"]); 110 insta::assert_snapshot!(stdout, @""); 111 insta::assert_snapshot!(stderr, @r###" 112 Working copy now at: xlzxqlsl 959145c1 (empty) (no description set) 113 Parent commit : nmzmmopx 80960125 e | (no description set) 114 "###); 115 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 116 @ 959145c11426 117 ◉ 80960125bb96 e 118 ├─╮ 119 │ ◉ 5658521e0f8b d 120 ◉ │ 90fe0a96fc90 c 121 ├─╯ 122 ◉ fa5efbdf533c b 123 ◉ 90aeefd03044 a 124 ◉ 000000000000 125 "###); 126 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "e"]); 127 insta::assert_snapshot!(stdout, @r###" 128 e 129 "###); 130} 131 132#[test] 133fn test_squash_partial() { 134 let mut test_env = TestEnvironment::default(); 135 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 136 let repo_path = test_env.env_root().join("repo"); 137 138 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "a"]); 139 std::fs::write(repo_path.join("file1"), "a\n").unwrap(); 140 std::fs::write(repo_path.join("file2"), "a\n").unwrap(); 141 test_env.jj_cmd_ok(&repo_path, &["new"]); 142 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "b"]); 143 std::fs::write(repo_path.join("file1"), "b\n").unwrap(); 144 std::fs::write(repo_path.join("file2"), "b\n").unwrap(); 145 test_env.jj_cmd_ok(&repo_path, &["new"]); 146 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "c"]); 147 std::fs::write(repo_path.join("file1"), "c\n").unwrap(); 148 std::fs::write(repo_path.join("file2"), "c\n").unwrap(); 149 // Test the setup 150 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 151 @ d989314f3df0 c 152 ◉ 2a2d19a3283f b 153 ◉ 47a1e795d146 a 154 ◉ 000000000000 155 "###); 156 157 // If we don't make any changes in the diff-editor, the whole change is moved 158 // into the parent 159 let edit_script = test_env.set_up_fake_diff_editor(); 160 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "-r", "b", "-i"]); 161 insta::assert_snapshot!(stdout, @""); 162 insta::assert_snapshot!(stderr, @r###" 163 Rebased 1 descendant commits 164 Working copy now at: mzvwutvl f03d5ce4 c | (no description set) 165 Parent commit : qpvuntsm c9f931cd a b | (no description set) 166 "###); 167 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 168 @ f03d5ce4a973 c 169 ◉ c9f931cd78af a b 170 ◉ 000000000000 171 "###); 172 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "a"]); 173 insta::assert_snapshot!(stdout, @r###" 174 b 175 "###); 176 177 // Can squash only some changes in interactive mode 178 test_env.jj_cmd_ok(&repo_path, &["undo"]); 179 std::fs::write(&edit_script, "reset file1").unwrap(); 180 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "-r", "b", "-i"]); 181 insta::assert_snapshot!(stdout, @""); 182 insta::assert_snapshot!(stderr, @r###" 183 Rebased 2 descendant commits 184 Working copy now at: mzvwutvl e7a40106 c | (no description set) 185 Parent commit : kkmpptxz 05d95164 b | (no description set) 186 "###); 187 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 188 @ e7a40106bee6 c 189 ◉ 05d951646873 b 190 ◉ 0c5ddc685260 a 191 ◉ 000000000000 192 "###); 193 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "a"]); 194 insta::assert_snapshot!(stdout, @r###" 195 a 196 "###); 197 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "a"]); 198 insta::assert_snapshot!(stdout, @r###" 199 b 200 "###); 201 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "b"]); 202 insta::assert_snapshot!(stdout, @r###" 203 b 204 "###); 205 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "b"]); 206 insta::assert_snapshot!(stdout, @r###" 207 b 208 "###); 209 210 // Can squash only some changes in non-interactive mode 211 test_env.jj_cmd_ok(&repo_path, &["undo"]); 212 // Clear the script so we know it won't be used even without -i 213 std::fs::write(&edit_script, "").unwrap(); 214 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "-r", "b", "file2"]); 215 insta::assert_snapshot!(stdout, @""); 216 insta::assert_snapshot!(stderr, @r###" 217 Rebased 2 descendant commits 218 Working copy now at: mzvwutvl a911fa1d c | (no description set) 219 Parent commit : kkmpptxz fb73ad17 b | (no description set) 220 "###); 221 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 222 @ a911fa1d0627 c 223 ◉ fb73ad17899f b 224 ◉ 70621f4c7a42 a 225 ◉ 000000000000 226 "###); 227 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "a"]); 228 insta::assert_snapshot!(stdout, @r###" 229 a 230 "###); 231 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "a"]); 232 insta::assert_snapshot!(stdout, @r###" 233 b 234 "###); 235 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "b"]); 236 insta::assert_snapshot!(stdout, @r###" 237 b 238 "###); 239 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "b"]); 240 insta::assert_snapshot!(stdout, @r###" 241 b 242 "###); 243 244 // If we specify only a non-existent file, then nothing changes. 245 test_env.jj_cmd_ok(&repo_path, &["undo"]); 246 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "-r", "b", "nonexistent"]); 247 insta::assert_snapshot!(stdout, @""); 248 insta::assert_snapshot!(stderr, @r###" 249 Nothing changed. 250 "###); 251 252 // We get a warning if we pass a positional argument that looks like a revset 253 test_env.jj_cmd_ok(&repo_path, &["undo"]); 254 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "b"]); 255 insta::assert_snapshot!(stderr, @r###" 256 Warning: The argument "b" is being interpreted as a path. To specify a revset, pass -r "b" instead. 257 Nothing changed. 258 "###); 259 insta::assert_snapshot!(stdout, @""); 260} 261 262#[test] 263fn test_squash_from_to() { 264 let test_env = TestEnvironment::default(); 265 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 266 let repo_path = test_env.env_root().join("repo"); 267 268 // Create history like this: 269 // F 270 // | 271 // E C 272 // | | 273 // D B 274 // |/ 275 // A 276 // 277 // When moving changes between e.g. C and F, we should not get unrelated changes 278 // from B and D. 279 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "a"]); 280 std::fs::write(repo_path.join("file1"), "a\n").unwrap(); 281 std::fs::write(repo_path.join("file2"), "a\n").unwrap(); 282 std::fs::write(repo_path.join("file3"), "a\n").unwrap(); 283 test_env.jj_cmd_ok(&repo_path, &["new"]); 284 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "b"]); 285 std::fs::write(repo_path.join("file3"), "b\n").unwrap(); 286 test_env.jj_cmd_ok(&repo_path, &["new"]); 287 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "c"]); 288 std::fs::write(repo_path.join("file1"), "c\n").unwrap(); 289 test_env.jj_cmd_ok(&repo_path, &["edit", "a"]); 290 test_env.jj_cmd_ok(&repo_path, &["new"]); 291 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "d"]); 292 std::fs::write(repo_path.join("file3"), "d\n").unwrap(); 293 test_env.jj_cmd_ok(&repo_path, &["new"]); 294 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "e"]); 295 std::fs::write(repo_path.join("file2"), "e\n").unwrap(); 296 test_env.jj_cmd_ok(&repo_path, &["new"]); 297 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "f"]); 298 std::fs::write(repo_path.join("file2"), "f\n").unwrap(); 299 // Test the setup 300 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 301 @ 0d7353584003 f 302 ◉ e9515f21068c e 303 ◉ bdd835cae844 d 304 │ ◉ caa4d0b23201 c 305 │ ◉ 55171e33db26 b 306 ├─╯ 307 ◉ 3db0a2f5b535 a 308 ◉ 000000000000 309 "###); 310 311 // Errors out if source and destination are the same 312 let stderr = test_env.jj_cmd_failure(&repo_path, &["squash", "--into", "@"]); 313 insta::assert_snapshot!(stderr, @r###" 314 Error: Source and destination cannot be the same 315 "###); 316 317 // Can squash from sibling, which results in the source being abandoned 318 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "c"]); 319 insta::assert_snapshot!(stdout, @""); 320 insta::assert_snapshot!(stderr, @r###" 321 Working copy now at: kmkuslsw 5337fca9 f | (no description set) 322 Parent commit : znkkpsqq e9515f21 e | (no description set) 323 Added 0 files, modified 1 files, removed 0 files 324 "###); 325 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 326 @ 5337fca918e8 f 327 ◉ e9515f21068c e 328 ◉ bdd835cae844 d 329 │ ◉ 55171e33db26 b c 330 ├─╯ 331 ◉ 3db0a2f5b535 a 332 ◉ 000000000000 333 "###); 334 // The change from the source has been applied 335 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]); 336 insta::assert_snapshot!(stdout, @r###" 337 c 338 "###); 339 // File `file2`, which was not changed in source, is unchanged 340 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]); 341 insta::assert_snapshot!(stdout, @r###" 342 f 343 "###); 344 345 // Can squash from ancestor 346 test_env.jj_cmd_ok(&repo_path, &["undo"]); 347 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "@--"]); 348 insta::assert_snapshot!(stdout, @""); 349 insta::assert_snapshot!(stderr, @r###" 350 Working copy now at: kmkuslsw 66ff309f f | (no description set) 351 Parent commit : znkkpsqq 16f4e7c4 e | (no description set) 352 "###); 353 // The change has been removed from the source (the change pointed to by 'd' 354 // became empty and was abandoned) 355 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 356 @ 66ff309f65e8 f 357 ◉ 16f4e7c4886f e 358 │ ◉ caa4d0b23201 c 359 │ ◉ 55171e33db26 b 360 ├─╯ 361 ◉ 3db0a2f5b535 a d 362 ◉ 000000000000 363 "###); 364 // The change from the source has been applied (the file contents were already 365 // "f", as is typically the case when moving changes from an ancestor) 366 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]); 367 insta::assert_snapshot!(stdout, @r###" 368 f 369 "###); 370 371 // Can squash from descendant 372 test_env.jj_cmd_ok(&repo_path, &["undo"]); 373 let (stdout, stderr) = 374 test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "e", "--into", "d"]); 375 insta::assert_snapshot!(stdout, @""); 376 insta::assert_snapshot!(stderr, @r###" 377 Rebased 1 descendant commits 378 Working copy now at: kmkuslsw b4f8051d f | (no description set) 379 Parent commit : vruxwmqv f74c102f d e | (no description set) 380 "###); 381 // The change has been removed from the source (the change pointed to by 'e' 382 // became empty and was abandoned) 383 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 384 @ b4f8051d8466 f 385 ◉ f74c102ff29a d e 386 │ ◉ caa4d0b23201 c 387 │ ◉ 55171e33db26 b 388 ├─╯ 389 ◉ 3db0a2f5b535 a 390 ◉ 000000000000 391 "###); 392 // The change from the source has been applied 393 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "d"]); 394 insta::assert_snapshot!(stdout, @r###" 395 e 396 "###); 397} 398 399#[test] 400fn test_squash_from_to_partial() { 401 let mut test_env = TestEnvironment::default(); 402 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 403 let repo_path = test_env.env_root().join("repo"); 404 405 // Create history like this: 406 // C 407 // | 408 // D B 409 // |/ 410 // A 411 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "a"]); 412 std::fs::write(repo_path.join("file1"), "a\n").unwrap(); 413 std::fs::write(repo_path.join("file2"), "a\n").unwrap(); 414 std::fs::write(repo_path.join("file3"), "a\n").unwrap(); 415 test_env.jj_cmd_ok(&repo_path, &["new"]); 416 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "b"]); 417 std::fs::write(repo_path.join("file3"), "b\n").unwrap(); 418 test_env.jj_cmd_ok(&repo_path, &["new"]); 419 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "c"]); 420 std::fs::write(repo_path.join("file1"), "c\n").unwrap(); 421 std::fs::write(repo_path.join("file2"), "c\n").unwrap(); 422 test_env.jj_cmd_ok(&repo_path, &["edit", "a"]); 423 test_env.jj_cmd_ok(&repo_path, &["new"]); 424 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "d"]); 425 std::fs::write(repo_path.join("file3"), "d\n").unwrap(); 426 // Test the setup 427 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 428 @ bdd835cae844 d 429 │ ◉ 5028db694b6b c 430 │ ◉ 55171e33db26 b 431 ├─╯ 432 ◉ 3db0a2f5b535 a 433 ◉ 000000000000 434 "###); 435 436 let edit_script = test_env.set_up_fake_diff_editor(); 437 438 // If we don't make any changes in the diff-editor, the whole change is moved 439 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "-i", "--from", "c"]); 440 insta::assert_snapshot!(stdout, @""); 441 insta::assert_snapshot!(stderr, @r###" 442 Working copy now at: vruxwmqv 71b69e43 d | (no description set) 443 Parent commit : qpvuntsm 3db0a2f5 a | (no description set) 444 Added 0 files, modified 2 files, removed 0 files 445 "###); 446 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 447 @ 71b69e433fbc d 448 │ ◉ 55171e33db26 b c 449 ├─╯ 450 ◉ 3db0a2f5b535 a 451 ◉ 000000000000 452 "###); 453 // The changes from the source has been applied 454 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]); 455 insta::assert_snapshot!(stdout, @r###" 456 c 457 "###); 458 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]); 459 insta::assert_snapshot!(stdout, @r###" 460 c 461 "###); 462 // File `file3`, which was not changed in source, is unchanged 463 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file3"]); 464 insta::assert_snapshot!(stdout, @r###" 465 d 466 "###); 467 468 // Can squash only part of the change in interactive mode 469 test_env.jj_cmd_ok(&repo_path, &["undo"]); 470 std::fs::write(&edit_script, "reset file2").unwrap(); 471 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "-i", "--from", "c"]); 472 insta::assert_snapshot!(stdout, @""); 473 insta::assert_snapshot!(stderr, @r###" 474 Working copy now at: vruxwmqv 63f1a6e9 d | (no description set) 475 Parent commit : qpvuntsm 3db0a2f5 a | (no description set) 476 Added 0 files, modified 1 files, removed 0 files 477 "###); 478 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 479 @ 63f1a6e96edb d 480 │ ◉ d027c6e3e6bc c 481 │ ◉ 55171e33db26 b 482 ├─╯ 483 ◉ 3db0a2f5b535 a 484 ◉ 000000000000 485 "###); 486 // The selected change from the source has been applied 487 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]); 488 insta::assert_snapshot!(stdout, @r###" 489 c 490 "###); 491 // The unselected change from the source has not been applied 492 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]); 493 insta::assert_snapshot!(stdout, @r###" 494 a 495 "###); 496 // File `file3`, which was changed in source's parent, is unchanged 497 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file3"]); 498 insta::assert_snapshot!(stdout, @r###" 499 d 500 "###); 501 502 // Can squash only part of the change from a sibling in non-interactive mode 503 test_env.jj_cmd_ok(&repo_path, &["undo"]); 504 // Clear the script so we know it won't be used 505 std::fs::write(&edit_script, "").unwrap(); 506 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "c", "file1"]); 507 insta::assert_snapshot!(stdout, @""); 508 insta::assert_snapshot!(stderr, @r###" 509 Working copy now at: vruxwmqv 17c2e663 d | (no description set) 510 Parent commit : qpvuntsm 3db0a2f5 a | (no description set) 511 Added 0 files, modified 1 files, removed 0 files 512 "###); 513 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 514 @ 17c2e6632cc5 d 515 │ ◉ 6a3ae047a03e c 516 │ ◉ 55171e33db26 b 517 ├─╯ 518 ◉ 3db0a2f5b535 a 519 ◉ 000000000000 520 "###); 521 // The selected change from the source has been applied 522 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]); 523 insta::assert_snapshot!(stdout, @r###" 524 c 525 "###); 526 // The unselected change from the source has not been applied 527 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]); 528 insta::assert_snapshot!(stdout, @r###" 529 a 530 "###); 531 // File `file3`, which was changed in source's parent, is unchanged 532 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file3"]); 533 insta::assert_snapshot!(stdout, @r###" 534 d 535 "###); 536 537 // Can squash only part of the change from a descendant in non-interactive mode 538 test_env.jj_cmd_ok(&repo_path, &["undo"]); 539 // Clear the script so we know it won't be used 540 std::fs::write(&edit_script, "").unwrap(); 541 let (stdout, stderr) = test_env.jj_cmd_ok( 542 &repo_path, 543 &["squash", "--from", "c", "--into", "b", "file1"], 544 ); 545 insta::assert_snapshot!(stdout, @""); 546 insta::assert_snapshot!(stderr, @r###" 547 Rebased 1 descendant commits 548 "###); 549 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 550 ◉ 21253406d416 c 551 ◉ e1cf08aae711 b 552 │ @ bdd835cae844 d 553 ├─╯ 554 ◉ 3db0a2f5b535 a 555 ◉ 000000000000 556 "###); 557 // The selected change from the source has been applied 558 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "b"]); 559 insta::assert_snapshot!(stdout, @r###" 560 c 561 "###); 562 // The unselected change from the source has not been applied 563 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "b"]); 564 insta::assert_snapshot!(stdout, @r###" 565 a 566 "###); 567 568 // If we specify only a non-existent file, then nothing changes. 569 test_env.jj_cmd_ok(&repo_path, &["undo"]); 570 let (stdout, stderr) = 571 test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "c", "nonexistent"]); 572 insta::assert_snapshot!(stdout, @""); 573 insta::assert_snapshot!(stderr, @r###" 574 Nothing changed. 575 "###); 576} 577 578#[test] 579fn test_squash_from_multiple() { 580 let test_env = TestEnvironment::default(); 581 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 582 let repo_path = test_env.env_root().join("repo"); 583 584 // Create history like this: 585 // F 586 // | 587 // E 588 // /|\ 589 // B C D 590 // \|/ 591 // A 592 let file = repo_path.join("file"); 593 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "a"]); 594 std::fs::write(&file, "a\n").unwrap(); 595 test_env.jj_cmd_ok(&repo_path, &["new"]); 596 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "b"]); 597 std::fs::write(&file, "b\n").unwrap(); 598 test_env.jj_cmd_ok(&repo_path, &["new", "@-"]); 599 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "c"]); 600 std::fs::write(&file, "c\n").unwrap(); 601 test_env.jj_cmd_ok(&repo_path, &["new", "@-"]); 602 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "d"]); 603 std::fs::write(&file, "d\n").unwrap(); 604 test_env.jj_cmd_ok(&repo_path, &["new", "all:visible_heads()"]); 605 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "e"]); 606 std::fs::write(&file, "e\n").unwrap(); 607 test_env.jj_cmd_ok(&repo_path, &["new"]); 608 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "f"]); 609 std::fs::write(&file, "f\n").unwrap(); 610 // Test the setup 611 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 612 @ 7c982f87d244 f 613 ◉ 90fb23310e1d e 614 ├─┬─╮ 615 │ │ ◉ 512dff087306 b 616 │ ◉ │ 5ee503da2262 c 617 │ ├─╯ 618 ◉ │ cb214cffd91a d 619 ├─╯ 620 ◉ 37941ee54ace a 621 ◉ 000000000000 622 "###); 623 624 // Squash a few commits sideways 625 let (stdout, stderr) = 626 test_env.jj_cmd_ok(&repo_path, &["squash", "--from=b", "--from=c", "--into=d"]); 627 insta::assert_snapshot!(stdout, @""); 628 insta::assert_snapshot!(stderr, @r###" 629 Rebased 2 descendant commits 630 New conflicts appeared in these commits: 631 yqosqzyt 50bd7d24 d | (conflict) (no description set) 632 To resolve the conflicts, start by updating to it: 633 jj new yqosqzytrlsw 634 Then use `jj resolve`, or edit the conflict markers in the file directly. 635 Once the conflicts are resolved, you may want inspect the result with `jj diff`. 636 Then run `jj squash` to move the resolution into the conflicted commit. 637 Working copy now at: kpqxywon dd653e49 f | (no description set) 638 Parent commit : yostqsxw e40f2544 e | (no description set) 639 "###); 640 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 641 @ dd653e494199 f 642 ◉ e40f2544ad31 e 643 ├─╮ 644 ◉ │ 50bd7d246d8e d 645 ├─╯ 646 ◉ 37941ee54ace a b c 647 ◉ 000000000000 648 "###); 649 // The changes from the sources have been applied 650 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=d", "file"]); 651 insta::assert_snapshot!(stdout, @r###" 652 <<<<<<< Conflict 1 of 1 653 %%%%%%% Changes from base #1 to side #1 654 -a 655 +d 656 %%%%%%% Changes from base #2 to side #2 657 -a 658 +b 659 +++++++ Contents of side #3 660 c 661 >>>>>>> 662 "###); 663 664 // Squash a few commits up an down 665 test_env.jj_cmd_ok(&repo_path, &["undo"]); 666 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "--from=b|c|f", "--into=e"]); 667 insta::assert_snapshot!(stdout, @""); 668 insta::assert_snapshot!(stderr, @r###" 669 Rebased 1 descendant commits 670 Working copy now at: xznxytkn 59801ce3 (empty) (no description set) 671 Parent commit : yostqsxw b7bc1dda e f | (no description set) 672 "###); 673 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 674 @ 59801ce3ff81 675 ◉ b7bc1dda247e e f 676 ├─╮ 677 ◉ │ cb214cffd91a d 678 ├─╯ 679 ◉ 37941ee54ace a b c 680 ◉ 000000000000 681 "###); 682 // The changes from the sources have been applied to the destination 683 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=e", "file"]); 684 insta::assert_snapshot!(stdout, @r###" 685 f 686 "###); 687 688 // Empty squash shouldn't crash 689 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "--from=none()"]); 690 insta::assert_snapshot!(stdout, @""); 691 insta::assert_snapshot!(stderr, @r###" 692 Nothing changed. 693 "###); 694} 695 696#[test] 697fn test_squash_from_multiple_partial() { 698 let test_env = TestEnvironment::default(); 699 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 700 let repo_path = test_env.env_root().join("repo"); 701 702 // Create history like this: 703 // F 704 // | 705 // E 706 // /|\ 707 // B C D 708 // \|/ 709 // A 710 let file1 = repo_path.join("file1"); 711 let file2 = repo_path.join("file2"); 712 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "a"]); 713 std::fs::write(&file1, "a\n").unwrap(); 714 std::fs::write(&file2, "a\n").unwrap(); 715 test_env.jj_cmd_ok(&repo_path, &["new"]); 716 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "b"]); 717 std::fs::write(&file1, "b\n").unwrap(); 718 std::fs::write(&file2, "b\n").unwrap(); 719 test_env.jj_cmd_ok(&repo_path, &["new", "@-"]); 720 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "c"]); 721 std::fs::write(&file1, "c\n").unwrap(); 722 std::fs::write(&file2, "c\n").unwrap(); 723 test_env.jj_cmd_ok(&repo_path, &["new", "@-"]); 724 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "d"]); 725 std::fs::write(&file1, "d\n").unwrap(); 726 std::fs::write(&file2, "d\n").unwrap(); 727 test_env.jj_cmd_ok(&repo_path, &["new", "all:visible_heads()"]); 728 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "e"]); 729 std::fs::write(&file1, "e\n").unwrap(); 730 std::fs::write(&file2, "e\n").unwrap(); 731 test_env.jj_cmd_ok(&repo_path, &["new"]); 732 test_env.jj_cmd_ok(&repo_path, &["branch", "create", "f"]); 733 std::fs::write(&file1, "f\n").unwrap(); 734 std::fs::write(&file2, "f\n").unwrap(); 735 // Test the setup 736 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 737 @ 5adc4b1fb0f9 f 738 ◉ 8ba764396a28 e 739 ├─┬─╮ 740 │ │ ◉ 2a2d19a3283f b 741 │ ◉ │ 864a16169cef c 742 │ ├─╯ 743 ◉ │ 5def0e76dfaf d 744 ├─╯ 745 ◉ 47a1e795d146 a 746 ◉ 000000000000 747 "###); 748 749 // Partially squash a few commits sideways 750 let (stdout, stderr) = 751 test_env.jj_cmd_ok(&repo_path, &["squash", "--from=b|c", "--into=d", "file1"]); 752 insta::assert_snapshot!(stdout, @""); 753 insta::assert_snapshot!(stderr, @r###" 754 Rebased 2 descendant commits 755 New conflicts appeared in these commits: 756 yqosqzyt 85d3ae29 d | (conflict) (no description set) 757 To resolve the conflicts, start by updating to it: 758 jj new yqosqzytrlsw 759 Then use `jj resolve`, or edit the conflict markers in the file directly. 760 Once the conflicts are resolved, you may want inspect the result with `jj diff`. 761 Then run `jj squash` to move the resolution into the conflicted commit. 762 Working copy now at: kpqxywon 97861bbf f | (no description set) 763 Parent commit : yostqsxw 2dbaf4e8 e | (no description set) 764 "###); 765 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 766 @ 97861bbf7ae5 f 767 ◉ 2dbaf4e8c7f7 e 768 ├─┬─╮ 769 │ │ ◉ ba60ddff2d41 b 770 │ ◉ │ 8ef5a315bf7d c 771 │ ├─╯ 772 ◉ │ 85d3ae290b9b d 773 ├─╯ 774 ◉ 47a1e795d146 a 775 ◉ 000000000000 776 "###); 777 // The selected changes have been removed from the sources 778 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=b", "file1"]); 779 insta::assert_snapshot!(stdout, @r###" 780 a 781 "###); 782 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=c", "file1"]); 783 insta::assert_snapshot!(stdout, @r###" 784 a 785 "###); 786 // The selected changes from the sources have been applied 787 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=d", "file1"]); 788 insta::assert_snapshot!(stdout, @r###" 789 <<<<<<< Conflict 1 of 1 790 %%%%%%% Changes from base #1 to side #1 791 -a 792 +d 793 %%%%%%% Changes from base #2 to side #2 794 -a 795 +b 796 +++++++ Contents of side #3 797 c 798 >>>>>>> 799 "###); 800 // The unselected change from the sources have not been applied to the 801 // destination 802 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=d", "file2"]); 803 insta::assert_snapshot!(stdout, @r###" 804 d 805 "###); 806 807 // Partially squash a few commits up an down 808 test_env.jj_cmd_ok(&repo_path, &["undo"]); 809 let (stdout, stderr) = 810 test_env.jj_cmd_ok(&repo_path, &["squash", "--from=b|c|f", "--into=e", "file1"]); 811 insta::assert_snapshot!(stdout, @""); 812 insta::assert_snapshot!(stderr, @r###" 813 Rebased 1 descendant commits 814 Working copy now at: kpqxywon 610a144d f | (no description set) 815 Parent commit : yostqsxw ac27a136 e | (no description set) 816 "###); 817 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 818 @ 610a144de39b f 819 ◉ ac27a1361b09 e 820 ├─┬─╮ 821 │ │ ◉ 0c8eab864a32 b 822 │ ◉ │ ad1776ad0b1b c 823 │ ├─╯ 824 ◉ │ 5def0e76dfaf d 825 ├─╯ 826 ◉ 47a1e795d146 a 827 ◉ 000000000000 828 "###); 829 // The selected changes have been removed from the sources 830 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=b", "file1"]); 831 insta::assert_snapshot!(stdout, @r###" 832 a 833 "###); 834 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=c", "file1"]); 835 insta::assert_snapshot!(stdout, @r###" 836 a 837 "###); 838 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=f", "file1"]); 839 insta::assert_snapshot!(stdout, @r###" 840 f 841 "###); 842 // The selected changes from the sources have been applied to the destination 843 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=e", "file1"]); 844 insta::assert_snapshot!(stdout, @r###" 845 f 846 "###); 847 // The unselected changes from the sources have not been applied 848 let stdout = test_env.jj_cmd_success(&repo_path, &["print", "-r=d", "file2"]); 849 insta::assert_snapshot!(stdout, @r###" 850 d 851 "###); 852} 853 854#[test] 855fn test_squash_from_multiple_partial_no_op() { 856 let test_env = TestEnvironment::default(); 857 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 858 let repo_path = test_env.env_root().join("repo"); 859 860 // Create history like this: 861 // B C D 862 // \|/ 863 // A 864 let file_a = repo_path.join("a"); 865 let file_b = repo_path.join("b"); 866 let file_c = repo_path.join("c"); 867 let file_d = repo_path.join("d"); 868 test_env.jj_cmd_ok(&repo_path, &["describe", "-m=a"]); 869 std::fs::write(file_a, "a\n").unwrap(); 870 test_env.jj_cmd_ok(&repo_path, &["new", "-m=b"]); 871 std::fs::write(file_b, "b\n").unwrap(); 872 test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m=c"]); 873 std::fs::write(file_c, "c\n").unwrap(); 874 test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m=d"]); 875 std::fs::write(file_d, "d\n").unwrap(); 876 // Test the setup 877 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 878 @ 09441f0a6266 d 879 │ ◉ 5ad3ca4090a7 c 880 ├─╯ 881 │ ◉ 285201979c90 b 882 ├─╯ 883 ◉ 3df52ee1f8a9 a 884 ◉ 000000000000 885 "###); 886 887 // Source commits that didn't match the paths are not rewritten 888 let (stdout, stderr) = test_env.jj_cmd_ok( 889 &repo_path, 890 &["squash", "--from=@-+ ~ @", "--into=@", "-m=d", "b"], 891 ); 892 insta::assert_snapshot!(stdout, @""); 893 insta::assert_snapshot!(stderr, @r###" 894 Working copy now at: mzvwutvl 9227d0d7 d 895 Parent commit : qpvuntsm 3df52ee1 a 896 Added 1 files, modified 0 files, removed 0 files 897 "###); 898 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 899 @ 9227d0d780fa d 900 │ ◉ 5ad3ca4090a7 c 901 ├─╯ 902 ◉ 3df52ee1f8a9 a 903 ◉ 000000000000 904 "###); 905 let stdout = test_env.jj_cmd_success( 906 &repo_path, 907 &[ 908 "obslog", 909 "-T", 910 r#"separate(" ", commit_id.short(), description)"#, 911 ], 912 ); 913 insta::assert_snapshot!(stdout, @r###" 914 @ 9227d0d780fa d 915 ├─╮ 916 ◉ │ 09441f0a6266 d 917 ◉ │ cba0f0aa472b d 918 ◉ 285201979c90 b 919 ◉ 81187418277d b 920 "###); 921 922 // If no source commits match the paths, then the whole operation is a no-op 923 test_env.jj_cmd_ok(&repo_path, &["undo"]); 924 let (stdout, stderr) = test_env.jj_cmd_ok( 925 &repo_path, 926 &["squash", "--from=@-+ ~ @", "--into=@", "-m=d", "a"], 927 ); 928 insta::assert_snapshot!(stdout, @""); 929 insta::assert_snapshot!(stderr, @r###" 930 Nothing changed. 931 "###); 932 insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" 933 @ 09441f0a6266 d 934 │ ◉ 5ad3ca4090a7 c 935 ├─╯ 936 │ ◉ 285201979c90 b 937 ├─╯ 938 ◉ 3df52ee1f8a9 a 939 ◉ 000000000000 940 "###); 941} 942 943fn get_log_output(test_env: &TestEnvironment, repo_path: &Path) -> String { 944 let template = r#"separate(" ", commit_id.short(), branches, description)"#; 945 test_env.jj_cmd_success(repo_path, &["log", "-T", template]) 946} 947 948#[test] 949fn test_squash_description() { 950 let mut test_env = TestEnvironment::default(); 951 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 952 let repo_path = test_env.env_root().join("repo"); 953 954 let edit_script = test_env.set_up_fake_editor(); 955 std::fs::write(&edit_script, r#"fail"#).unwrap(); 956 957 // If both descriptions are empty, the resulting description is empty 958 std::fs::write(repo_path.join("file1"), "a\n").unwrap(); 959 std::fs::write(repo_path.join("file2"), "a\n").unwrap(); 960 test_env.jj_cmd_ok(&repo_path, &["new"]); 961 std::fs::write(repo_path.join("file1"), "b\n").unwrap(); 962 std::fs::write(repo_path.join("file2"), "b\n").unwrap(); 963 test_env.jj_cmd_ok(&repo_path, &["squash"]); 964 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@-"), @""); 965 966 // If the destination's description is empty and the source's description is 967 // non-empty, the resulting description is from the source 968 test_env.jj_cmd_ok(&repo_path, &["undo"]); 969 test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "source"]); 970 test_env.jj_cmd_ok(&repo_path, &["squash"]); 971 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@-"), @r###" 972 source 973 "###); 974 975 // If the destination description is non-empty and the source's description is 976 // empty, the resulting description is from the destination 977 test_env.jj_cmd_ok(&repo_path, &["op", "restore", "@--"]); 978 test_env.jj_cmd_ok(&repo_path, &["describe", "@-", "-m", "destination"]); 979 test_env.jj_cmd_ok(&repo_path, &["squash"]); 980 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@-"), @r###" 981 destination 982 "###); 983 984 // An explicit description on the command-line overrides this 985 test_env.jj_cmd_ok(&repo_path, &["undo"]); 986 test_env.jj_cmd_ok(&repo_path, &["squash", "-m", "custom"]); 987 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@-"), @r###" 988 custom 989 "###); 990 991 // If both descriptions were non-empty, we get asked for a combined description 992 test_env.jj_cmd_ok(&repo_path, &["undo"]); 993 test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "source"]); 994 std::fs::write(&edit_script, "dump editor0").unwrap(); 995 test_env.jj_cmd_ok(&repo_path, &["squash"]); 996 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@-"), @r###" 997 destination 998 999 source 1000 "###); 1001 insta::assert_snapshot!( 1002 std::fs::read_to_string(test_env.env_root().join("editor0")).unwrap(), @r###" 1003 JJ: Enter a description for the combined commit. 1004 JJ: Description from the destination commit: 1005 destination 1006 1007 JJ: Description from source commit: 1008 source 1009 1010 JJ: Lines starting with "JJ: " (like this one) will be removed. 1011 "###); 1012 1013 // An explicit description on the command-line overrides prevents launching an 1014 // editor 1015 test_env.jj_cmd_ok(&repo_path, &["undo"]); 1016 test_env.jj_cmd_ok(&repo_path, &["squash", "-m", "custom"]); 1017 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@-"), @r###" 1018 custom 1019 "###); 1020 1021 // If the source's *content* doesn't become empty, then the source remains and 1022 // both descriptions are unchanged 1023 test_env.jj_cmd_ok(&repo_path, &["undo"]); 1024 test_env.jj_cmd_ok(&repo_path, &["squash", "file1"]); 1025 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@-"), @r###" 1026 destination 1027 "###); 1028 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@"), @r###" 1029 source 1030 "###); 1031} 1032 1033#[test] 1034fn test_squash_empty() { 1035 let mut test_env = TestEnvironment::default(); 1036 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 1037 let repo_path = test_env.env_root().join("repo"); 1038 1039 test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "parent"]); 1040 1041 let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash"]); 1042 insta::assert_snapshot!(stdout, @""); 1043 insta::assert_snapshot!(stderr, @r###" 1044 Working copy now at: kkmpptxz e45abe2c (empty) (no description set) 1045 Parent commit : qpvuntsm 1265289b (empty) parent 1046 "###); 1047 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@-"), @r###" 1048 parent 1049 "###); 1050 1051 test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "child"]); 1052 test_env.set_up_fake_editor(); 1053 test_env.jj_cmd_ok(&repo_path, &["squash"]); 1054 insta::assert_snapshot!(get_description(&test_env, &repo_path, "@-"), @r###" 1055 parent 1056 1057 child 1058 "###); 1059} 1060 1061#[test] 1062fn test_squash_use_destination_message() { 1063 let test_env = TestEnvironment::default(); 1064 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 1065 let repo_path = test_env.env_root().join("repo"); 1066 1067 test_env.jj_cmd_ok(&repo_path, &["commit", "-m=a"]); 1068 test_env.jj_cmd_ok(&repo_path, &["commit", "-m=b"]); 1069 test_env.jj_cmd_ok(&repo_path, &["describe", "-m=c"]); 1070 // Test the setup 1071 insta::assert_snapshot!(get_log_output_with_description(&test_env, &repo_path), @r###" 1072 @ 71f7c810d8ed c 1073 ◉ 10dd87c3b4e2 b 1074 ◉ 4c5b3042d9e0 a 1075 ◉ 000000000000 1076 "###); 1077 1078 // Squash the current revision using the short name for the option. 1079 test_env.jj_cmd_ok(&repo_path, &["squash", "-u"]); 1080 insta::assert_snapshot!(get_log_output_with_description(&test_env, &repo_path), @r###" 1081 @ 10e30ce4a910 1082 ◉ 1c21278b775f b 1083 ◉ 4c5b3042d9e0 a 1084 ◉ 000000000000 1085 "###); 1086 1087 // Undo and squash again, but this time squash both "b" and "c" into "a". 1088 test_env.jj_cmd_ok(&repo_path, &["undo"]); 1089 test_env.jj_cmd_ok( 1090 &repo_path, 1091 &[ 1092 "squash", 1093 "--use-destination-message", 1094 "--from", 1095 "description(b)::", 1096 "--into", 1097 "description(a)", 1098 ], 1099 ); 1100 insta::assert_snapshot!(get_log_output_with_description(&test_env, &repo_path), @r###" 1101 @ da1507508bdf 1102 ◉ f1387f804776 a 1103 ◉ 000000000000 1104 "###); 1105} 1106 1107// The --use-destination-message and --message options are incompatible. 1108#[test] 1109fn test_squash_use_destination_message_and_message_mutual_exclusion() { 1110 let test_env = TestEnvironment::default(); 1111 test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]); 1112 let repo_path = test_env.env_root().join("repo"); 1113 test_env.jj_cmd_ok(&repo_path, &["commit", "-m=a"]); 1114 test_env.jj_cmd_ok(&repo_path, &["describe", "-m=b"]); 1115 insta::assert_snapshot!(test_env.jj_cmd_cli_error( 1116 &repo_path, 1117 &[ 1118 "squash", 1119 "--message=123", 1120 "--use-destination-message", 1121 ], 1122 ), @r###" 1123 error: the argument '--message <MESSAGE>' cannot be used with '--use-destination-message' 1124 1125 Usage: jj squash --message <MESSAGE> [PATHS]... 1126 1127 For more information, try '--help'. 1128 "###); 1129} 1130 1131fn get_description(test_env: &TestEnvironment, repo_path: &Path, rev: &str) -> String { 1132 test_env.jj_cmd_success( 1133 repo_path, 1134 &["log", "--no-graph", "-T", "description", "-r", rev], 1135 ) 1136} 1137 1138fn get_log_output_with_description(test_env: &TestEnvironment, repo_path: &Path) -> String { 1139 let template = r#"separate(" ", commit_id.short(), description)"#; 1140 test_env.jj_cmd_success(repo_path, &["log", "-T", template]) 1141}