just playing with tangled
at ig/vimdiffwarn 1490 lines 52 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 test_case::test_case; 18 19use crate::common::CommandOutput; 20use crate::common::TestEnvironment; 21 22/// Test adding a second workspace 23#[test] 24fn test_workspaces_add_second_workspace() { 25 let test_env = TestEnvironment::default(); 26 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 27 let main_path = test_env.env_root().join("main"); 28 let secondary_path = test_env.env_root().join("secondary"); 29 30 std::fs::write(main_path.join("file"), "contents").unwrap(); 31 test_env 32 .run_jj_in(&main_path, ["commit", "-m", "initial"]) 33 .success(); 34 35 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 36 insta::assert_snapshot!(output, @r" 37 default: rlvkpnrz 8183d0fc (empty) (no description set) 38 [EOF] 39 "); 40 41 let output = test_env.run_jj_in( 42 &main_path, 43 ["workspace", "add", "--name", "second", "../secondary"], 44 ); 45 insta::assert_snapshot!(output.normalize_backslash(), @r#" 46 ------- stderr ------- 47 Created workspace in "../secondary" 48 Working copy (@) now at: rzvqmyuk 5ed2222c (empty) (no description set) 49 Parent commit (@-) : qpvuntsm 751b12b7 initial 50 Added 1 files, modified 0 files, removed 0 files 51 [EOF] 52 "#); 53 54 // Can see the working-copy commit in each workspace in the log output. The "@" 55 // node in the graph indicates the current workspace's working-copy commit. 56 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 57 @ 8183d0fcaa4c default@ 58 │ ○ 5ed2222c28e2 second@ 59 ├─╯ 60 ○ 751b12b7b981 61 ◆ 000000000000 62 [EOF] 63 "); 64 insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), @r" 65 @ 5ed2222c28e2 second@ 66 │ ○ 8183d0fcaa4c default@ 67 ├─╯ 68 ○ 751b12b7b981 69 ◆ 000000000000 70 [EOF] 71 "); 72 73 // Both workspaces show up when we list them 74 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 75 insta::assert_snapshot!(output, @r" 76 default: rlvkpnrz 8183d0fc (empty) (no description set) 77 second: rzvqmyuk 5ed2222c (empty) (no description set) 78 [EOF] 79 "); 80} 81 82/// Test how sparse patterns are inherited 83#[test] 84fn test_workspaces_sparse_patterns() { 85 let test_env = TestEnvironment::default(); 86 test_env.run_jj_in(".", ["git", "init", "ws1"]).success(); 87 let ws1_path = test_env.env_root().join("ws1"); 88 let ws2_path = test_env.env_root().join("ws2"); 89 let ws3_path = test_env.env_root().join("ws3"); 90 let ws4_path = test_env.env_root().join("ws4"); 91 let ws5_path = test_env.env_root().join("ws5"); 92 let ws6_path = test_env.env_root().join("ws6"); 93 94 test_env 95 .run_jj_in(&ws1_path, ["sparse", "set", "--clear", "--add=foo"]) 96 .success(); 97 test_env 98 .run_jj_in(&ws1_path, ["workspace", "add", "../ws2"]) 99 .success(); 100 let output = test_env.run_jj_in(&ws2_path, ["sparse", "list"]); 101 insta::assert_snapshot!(output, @r" 102 foo 103 [EOF] 104 "); 105 test_env 106 .run_jj_in(&ws2_path, ["sparse", "set", "--add=bar"]) 107 .success(); 108 test_env 109 .run_jj_in(&ws2_path, ["workspace", "add", "../ws3"]) 110 .success(); 111 let output = test_env.run_jj_in(&ws3_path, ["sparse", "list"]); 112 insta::assert_snapshot!(output, @r" 113 bar 114 foo 115 [EOF] 116 "); 117 // --sparse-patterns behavior 118 test_env 119 .run_jj_in( 120 &ws3_path, 121 ["workspace", "add", "--sparse-patterns=copy", "../ws4"], 122 ) 123 .success(); 124 let output = test_env.run_jj_in(&ws4_path, ["sparse", "list"]); 125 insta::assert_snapshot!(output, @r" 126 bar 127 foo 128 [EOF] 129 "); 130 test_env 131 .run_jj_in( 132 &ws3_path, 133 ["workspace", "add", "--sparse-patterns=full", "../ws5"], 134 ) 135 .success(); 136 let output = test_env.run_jj_in(&ws5_path, ["sparse", "list"]); 137 insta::assert_snapshot!(output, @r" 138 . 139 [EOF] 140 "); 141 test_env 142 .run_jj_in( 143 &ws3_path, 144 ["workspace", "add", "--sparse-patterns=empty", "../ws6"], 145 ) 146 .success(); 147 let output = test_env.run_jj_in(&ws6_path, ["sparse", "list"]); 148 insta::assert_snapshot!(output, @""); 149} 150 151/// Test adding a second workspace while the current workspace is editing a 152/// merge 153#[test] 154fn test_workspaces_add_second_workspace_on_merge() { 155 let test_env = TestEnvironment::default(); 156 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 157 let main_path = test_env.env_root().join("main"); 158 159 test_env 160 .run_jj_in(&main_path, ["describe", "-m=left"]) 161 .success(); 162 test_env 163 .run_jj_in(&main_path, ["new", "@-", "-m=right"]) 164 .success(); 165 test_env 166 .run_jj_in(&main_path, ["new", "all:@-+", "-m=merge"]) 167 .success(); 168 169 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 170 insta::assert_snapshot!(output, @r" 171 default: zsuskuln 35e47bff (empty) merge 172 [EOF] 173 "); 174 175 test_env 176 .run_jj_in( 177 &main_path, 178 ["workspace", "add", "--name", "second", "../secondary"], 179 ) 180 .success(); 181 182 // The new workspace's working-copy commit shares all parents with the old one. 183 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 184 @ 35e47bff781e default@ 185 ├─╮ 186 │ │ ○ 7013a493bd09 second@ 187 ╭─┬─╯ 188 │ ○ 444b77e99d43 189 ○ │ 1694f2ddf8ec 190 ├─╯ 191 ◆ 000000000000 192 [EOF] 193 "); 194} 195 196/// Test that --ignore-working-copy is respected 197#[test] 198fn test_workspaces_add_ignore_working_copy() { 199 let test_env = TestEnvironment::default(); 200 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 201 let main_path = test_env.env_root().join("main"); 202 203 // TODO: maybe better to error out early? 204 let output = test_env.run_jj_in( 205 &main_path, 206 ["workspace", "add", "--ignore-working-copy", "../secondary"], 207 ); 208 insta::assert_snapshot!(output.normalize_backslash(), @r#" 209 ------- stderr ------- 210 Created workspace in "../secondary" 211 Error: This command must be able to update the working copy. 212 Hint: Don't use --ignore-working-copy. 213 [EOF] 214 [exit status: 1] 215 "#); 216} 217 218/// Test that --at-op is respected 219#[test] 220fn test_workspaces_add_at_operation() { 221 let test_env = TestEnvironment::default(); 222 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 223 let main_path = test_env.env_root().join("main"); 224 225 std::fs::write(main_path.join("file1"), "").unwrap(); 226 let output = test_env.run_jj_in(&main_path, ["commit", "-m1"]); 227 insta::assert_snapshot!(output, @r" 228 ------- stderr ------- 229 Working copy (@) now at: rlvkpnrz 18d8b994 (empty) (no description set) 230 Parent commit (@-) : qpvuntsm 3364a7ed 1 231 [EOF] 232 "); 233 234 std::fs::write(main_path.join("file2"), "").unwrap(); 235 let output = test_env.run_jj_in(&main_path, ["commit", "-m2"]); 236 insta::assert_snapshot!(output, @r" 237 ------- stderr ------- 238 Working copy (@) now at: kkmpptxz 2e7dc5ab (empty) (no description set) 239 Parent commit (@-) : rlvkpnrz 0dbaa19a 2 240 [EOF] 241 "); 242 243 // --at-op should disable snapshot in the main workspace, but the newly 244 // created workspace should still be writable. 245 std::fs::write(main_path.join("file3"), "").unwrap(); 246 let output = test_env.run_jj_in( 247 &main_path, 248 ["workspace", "add", "--at-op=@-", "../secondary"], 249 ); 250 insta::assert_snapshot!(output.normalize_backslash(), @r#" 251 ------- stderr ------- 252 Created workspace in "../secondary" 253 Working copy (@) now at: rzvqmyuk a4d1cbc9 (empty) (no description set) 254 Parent commit (@-) : qpvuntsm 3364a7ed 1 255 Added 1 files, modified 0 files, removed 0 files 256 [EOF] 257 "#); 258 let secondary_path = test_env.env_root().join("secondary"); 259 260 // New snapshot can be taken in the secondary workspace. 261 std::fs::write(secondary_path.join("file4"), "").unwrap(); 262 let output = test_env.run_jj_in(&secondary_path, ["status"]); 263 insta::assert_snapshot!(output, @r" 264 Working copy changes: 265 A file4 266 Working copy (@) : rzvqmyuk 2ba74f85 (no description set) 267 Parent commit (@-): qpvuntsm 3364a7ed 1 268 [EOF] 269 ------- stderr ------- 270 Concurrent modification detected, resolving automatically. 271 [EOF] 272 "); 273 274 let output = test_env.run_jj_in(&secondary_path, ["op", "log", "-Tdescription"]); 275 insta::assert_snapshot!(output, @r" 276 @ snapshot working copy 277 ○ reconcile divergent operations 278 ├─╮ 279 ○ │ commit cd06097124e3e5860867e35c2bb105902c28ea38 280 │ ○ create initial working-copy commit in workspace secondary 281 │ ○ add workspace 'secondary' 282 ├─╯ 283 ○ snapshot working copy 284 ○ commit 1c867a0762e30de4591890ea208849f793742c1b 285 ○ snapshot working copy 286 ○ add workspace 'default' 287 288 [EOF] 289 "); 290} 291 292/// Test adding a workspace, but at a specific revision using '-r' 293#[test] 294fn test_workspaces_add_workspace_at_revision() { 295 let test_env = TestEnvironment::default(); 296 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 297 let main_path = test_env.env_root().join("main"); 298 let secondary_path = test_env.env_root().join("secondary"); 299 300 std::fs::write(main_path.join("file-1"), "contents").unwrap(); 301 test_env 302 .run_jj_in(&main_path, ["commit", "-m", "first"]) 303 .success(); 304 305 std::fs::write(main_path.join("file-2"), "contents").unwrap(); 306 test_env 307 .run_jj_in(&main_path, ["commit", "-m", "second"]) 308 .success(); 309 310 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 311 insta::assert_snapshot!(output, @r" 312 default: kkmpptxz dadeedb4 (empty) (no description set) 313 [EOF] 314 "); 315 316 let output = test_env.run_jj_in( 317 &main_path, 318 [ 319 "workspace", 320 "add", 321 "--name", 322 "second", 323 "../secondary", 324 "-r", 325 "@--", 326 ], 327 ); 328 insta::assert_snapshot!(output.normalize_backslash(), @r#" 329 ------- stderr ------- 330 Created workspace in "../secondary" 331 Working copy (@) now at: zxsnswpr e374e74a (empty) (no description set) 332 Parent commit (@-) : qpvuntsm f6097c2f first 333 Added 1 files, modified 0 files, removed 0 files 334 [EOF] 335 "#); 336 337 // Can see the working-copy commit in each workspace in the log output. The "@" 338 // node in the graph indicates the current workspace's working-copy commit. 339 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 340 @ dadeedb493e8 default@ 341 ○ c420244c6398 342 │ ○ e374e74aa0c8 second@ 343 ├─╯ 344 ○ f6097c2f7cac 345 ◆ 000000000000 346 [EOF] 347 "); 348 insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), @r" 349 @ e374e74aa0c8 second@ 350 │ ○ dadeedb493e8 default@ 351 │ ○ c420244c6398 352 ├─╯ 353 ○ f6097c2f7cac 354 ◆ 000000000000 355 [EOF] 356 "); 357} 358 359/// Test multiple `-r` flags to `workspace add` to create a workspace 360/// working-copy commit with multiple parents. 361#[test] 362fn test_workspaces_add_workspace_multiple_revisions() { 363 let test_env = TestEnvironment::default(); 364 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 365 let main_path = test_env.env_root().join("main"); 366 367 std::fs::write(main_path.join("file-1"), "contents").unwrap(); 368 test_env 369 .run_jj_in(&main_path, ["commit", "-m", "first"]) 370 .success(); 371 test_env 372 .run_jj_in(&main_path, ["new", "-r", "root()"]) 373 .success(); 374 375 std::fs::write(main_path.join("file-2"), "contents").unwrap(); 376 test_env 377 .run_jj_in(&main_path, ["commit", "-m", "second"]) 378 .success(); 379 test_env 380 .run_jj_in(&main_path, ["new", "-r", "root()"]) 381 .success(); 382 383 std::fs::write(main_path.join("file-3"), "contents").unwrap(); 384 test_env 385 .run_jj_in(&main_path, ["commit", "-m", "third"]) 386 .success(); 387 test_env 388 .run_jj_in(&main_path, ["new", "-r", "root()"]) 389 .success(); 390 391 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 392 @ 5b36783cd11c 393 │ ○ 6c843d62ca29 394 ├─╯ 395 │ ○ 544cd61f2d26 396 ├─╯ 397 │ ○ f6097c2f7cac 398 ├─╯ 399 ◆ 000000000000 400 [EOF] 401 "); 402 403 let output = test_env.run_jj_in( 404 &main_path, 405 [ 406 "workspace", 407 "add", 408 "--name=merge", 409 "../merged", 410 "-r=description(third)", 411 "-r=description(second)", 412 "-r=description(first)", 413 ], 414 ); 415 insta::assert_snapshot!(output.normalize_backslash(), @r#" 416 ------- stderr ------- 417 Created workspace in "../merged" 418 Working copy (@) now at: wmwvqwsz f4fa64f4 (empty) (no description set) 419 Parent commit (@-) : mzvwutvl 6c843d62 third 420 Parent commit (@-) : kkmpptxz 544cd61f second 421 Parent commit (@-) : qpvuntsm f6097c2f first 422 Added 3 files, modified 0 files, removed 0 files 423 [EOF] 424 "#); 425 426 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 427 @ 5b36783cd11c default@ 428 │ ○ f4fa64f40944 merge@ 429 │ ├─┬─╮ 430 │ │ │ ○ f6097c2f7cac 431 ├─────╯ 432 │ │ ○ 544cd61f2d26 433 ├───╯ 434 │ ○ 6c843d62ca29 435 ├─╯ 436 ◆ 000000000000 437 [EOF] 438 "); 439} 440 441#[test] 442fn test_workspaces_add_workspace_from_subdir() { 443 let test_env = TestEnvironment::default(); 444 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 445 let main_path = test_env.env_root().join("main"); 446 let subdir_path = main_path.join("subdir"); 447 let secondary_path = test_env.env_root().join("secondary"); 448 449 std::fs::create_dir(&subdir_path).unwrap(); 450 std::fs::write(subdir_path.join("file"), "contents").unwrap(); 451 test_env 452 .run_jj_in(&main_path, ["commit", "-m", "initial"]) 453 .success(); 454 455 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 456 insta::assert_snapshot!(output, @r" 457 default: rlvkpnrz e1038e77 (empty) (no description set) 458 [EOF] 459 "); 460 461 // Create workspace while in sub-directory of current workspace 462 let output = test_env.run_jj_in(&subdir_path, ["workspace", "add", "../../secondary"]); 463 insta::assert_snapshot!(output.normalize_backslash(), @r#" 464 ------- stderr ------- 465 Created workspace in "../../secondary" 466 Working copy (@) now at: rzvqmyuk 7ad84461 (empty) (no description set) 467 Parent commit (@-) : qpvuntsm a3a43d9e initial 468 Added 1 files, modified 0 files, removed 0 files 469 [EOF] 470 "#); 471 472 // Both workspaces show up when we list them 473 let output = test_env.run_jj_in(&secondary_path, ["workspace", "list"]); 474 insta::assert_snapshot!(output, @r" 475 default: rlvkpnrz e1038e77 (empty) (no description set) 476 secondary: rzvqmyuk 7ad84461 (empty) (no description set) 477 [EOF] 478 "); 479} 480 481#[test] 482fn test_workspaces_add_workspace_in_current_workspace() { 483 let test_env = TestEnvironment::default(); 484 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 485 let main_path = test_env.env_root().join("main"); 486 487 std::fs::write(main_path.join("file"), "contents").unwrap(); 488 test_env 489 .run_jj_in(&main_path, ["commit", "-m", "initial"]) 490 .success(); 491 492 // Try to create workspace using name instead of path 493 let output = test_env.run_jj_in(&main_path, ["workspace", "add", "secondary"]); 494 insta::assert_snapshot!(output.normalize_backslash(), @r#" 495 ------- stderr ------- 496 Created workspace in "secondary" 497 Warning: Workspace created inside current directory. If this was unintentional, delete the "secondary" directory and run `jj workspace forget secondary` to remove it. 498 Working copy (@) now at: pmmvwywv 0a77a39d (empty) (no description set) 499 Parent commit (@-) : qpvuntsm 751b12b7 initial 500 Added 1 files, modified 0 files, removed 0 files 501 [EOF] 502 "#); 503 504 // Workspace created despite warning 505 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 506 insta::assert_snapshot!(output, @r" 507 default: rlvkpnrz 46d9ba8b (no description set) 508 secondary: pmmvwywv 0a77a39d (empty) (no description set) 509 [EOF] 510 "); 511 512 // Use explicit path instead (no warning) 513 let output = test_env.run_jj_in(&main_path, ["workspace", "add", "./third"]); 514 insta::assert_snapshot!(output.normalize_backslash(), @r#" 515 ------- stderr ------- 516 Created workspace in "third" 517 Working copy (@) now at: zxsnswpr 64746d4b (empty) (no description set) 518 Parent commit (@-) : qpvuntsm 751b12b7 initial 519 Added 1 files, modified 0 files, removed 0 files 520 [EOF] 521 "#); 522 523 // Both workspaces created 524 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 525 insta::assert_snapshot!(output, @r" 526 default: rlvkpnrz 477c647f (no description set) 527 secondary: pmmvwywv 0a77a39d (empty) (no description set) 528 third: zxsnswpr 64746d4b (empty) (no description set) 529 [EOF] 530 "); 531 532 // Can see files from the other workspaces in main workspace, since they are 533 // child directories and will therefore be snapshotted 534 let output = test_env.run_jj_in(&main_path, ["file", "list"]); 535 insta::assert_snapshot!(output.normalize_backslash(), @r" 536 file 537 secondary/file 538 third/file 539 [EOF] 540 "); 541} 542 543/// Test making changes to the working copy in a workspace as it gets rewritten 544/// from another workspace 545#[test] 546fn test_workspaces_conflicting_edits() { 547 let test_env = TestEnvironment::default(); 548 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 549 let main_path = test_env.env_root().join("main"); 550 let secondary_path = test_env.env_root().join("secondary"); 551 552 std::fs::write(main_path.join("file"), "contents\n").unwrap(); 553 test_env.run_jj_in(&main_path, ["new"]).success(); 554 555 test_env 556 .run_jj_in(&main_path, ["workspace", "add", "../secondary"]) 557 .success(); 558 559 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 560 @ 06b57f44a3ca default@ 561 │ ○ 3224de8ae048 secondary@ 562 ├─╯ 563 ○ 506f4ec3c2c6 564 ◆ 000000000000 565 [EOF] 566 "); 567 568 // Make changes in both working copies 569 std::fs::write(main_path.join("file"), "changed in main\n").unwrap(); 570 std::fs::write(secondary_path.join("file"), "changed in second\n").unwrap(); 571 // Squash the changes from the main workspace into the initial commit (before 572 // running any command in the secondary workspace 573 let output = test_env.run_jj_in(&main_path, ["squash"]); 574 insta::assert_snapshot!(output, @r" 575 ------- stderr ------- 576 Rebased 1 descendant commits 577 Working copy (@) now at: mzvwutvl a58c9a9b (empty) (no description set) 578 Parent commit (@-) : qpvuntsm d4124476 (no description set) 579 [EOF] 580 "); 581 582 // The secondary workspace's working-copy commit was updated 583 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 584 @ a58c9a9b19ce default@ 585 │ ○ e82cd4ee8faa secondary@ 586 ├─╯ 587 ○ d41244767d45 588 ◆ 000000000000 589 [EOF] 590 "); 591 let output = test_env.run_jj_in(&secondary_path, ["st"]); 592 insta::assert_snapshot!(output, @r" 593 ------- stderr ------- 594 Error: The working copy is stale (not updated since operation c81af45155a2). 595 Hint: Run `jj workspace update-stale` to update it. 596 See https://jj-vcs.github.io/jj/latest/working-copy/#stale-working-copy for more information. 597 [EOF] 598 [exit status: 1] 599 "); 600 // Same error on second run, and from another command 601 let output = test_env.run_jj_in(&secondary_path, ["log"]); 602 insta::assert_snapshot!(output, @r" 603 ------- stderr ------- 604 Error: The working copy is stale (not updated since operation c81af45155a2). 605 Hint: Run `jj workspace update-stale` to update it. 606 See https://jj-vcs.github.io/jj/latest/working-copy/#stale-working-copy for more information. 607 [EOF] 608 [exit status: 1] 609 "); 610 // It was detected that the working copy is now stale. 611 // Since there was an uncommitted change in the working copy, it should 612 // have been committed first (causing divergence) 613 let output = test_env.run_jj_in(&secondary_path, ["workspace", "update-stale"]); 614 insta::assert_snapshot!(output, @r" 615 ------- stderr ------- 616 Concurrent modification detected, resolving automatically. 617 Rebased 1 descendant commits onto commits rewritten by other operation 618 Working copy (@) now at: pmmvwywv?? e82cd4ee (empty) (no description set) 619 Parent commit (@-) : qpvuntsm d4124476 (no description set) 620 Added 0 files, modified 1 files, removed 0 files 621 Updated working copy to fresh commit e82cd4ee8faa 622 [EOF] 623 "); 624 insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), 625 @r" 626 @ e82cd4ee8faa secondary@ (divergent) 627 │ × 30816012e0da (divergent) 628 ├─╯ 629 │ ○ a58c9a9b19ce default@ 630 ├─╯ 631 ○ d41244767d45 632 ◆ 000000000000 633 [EOF] 634 "); 635 // The stale working copy should have been resolved by the previous command 636 insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), @r" 637 @ e82cd4ee8faa secondary@ (divergent) 638 │ × 30816012e0da (divergent) 639 ├─╯ 640 │ ○ a58c9a9b19ce default@ 641 ├─╯ 642 ○ d41244767d45 643 ◆ 000000000000 644 [EOF] 645 "); 646} 647 648/// Test a clean working copy that gets rewritten from another workspace 649#[test] 650fn test_workspaces_updated_by_other() { 651 let test_env = TestEnvironment::default(); 652 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 653 let main_path = test_env.env_root().join("main"); 654 let secondary_path = test_env.env_root().join("secondary"); 655 656 std::fs::write(main_path.join("file"), "contents\n").unwrap(); 657 test_env.run_jj_in(&main_path, ["new"]).success(); 658 659 test_env 660 .run_jj_in(&main_path, ["workspace", "add", "../secondary"]) 661 .success(); 662 663 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 664 @ 06b57f44a3ca default@ 665 │ ○ 3224de8ae048 secondary@ 666 ├─╯ 667 ○ 506f4ec3c2c6 668 ◆ 000000000000 669 [EOF] 670 "); 671 672 // Rewrite the check-out commit in one workspace. 673 std::fs::write(main_path.join("file"), "changed in main\n").unwrap(); 674 let output = test_env.run_jj_in(&main_path, ["squash"]); 675 insta::assert_snapshot!(output, @r" 676 ------- stderr ------- 677 Rebased 1 descendant commits 678 Working copy (@) now at: mzvwutvl a58c9a9b (empty) (no description set) 679 Parent commit (@-) : qpvuntsm d4124476 (no description set) 680 [EOF] 681 "); 682 683 // The secondary workspace's working-copy commit was updated. 684 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 685 @ a58c9a9b19ce default@ 686 │ ○ e82cd4ee8faa secondary@ 687 ├─╯ 688 ○ d41244767d45 689 ◆ 000000000000 690 [EOF] 691 "); 692 let output = test_env.run_jj_in(&secondary_path, ["st"]); 693 insta::assert_snapshot!(output, @r" 694 ------- stderr ------- 695 Error: The working copy is stale (not updated since operation c81af45155a2). 696 Hint: Run `jj workspace update-stale` to update it. 697 See https://jj-vcs.github.io/jj/latest/working-copy/#stale-working-copy for more information. 698 [EOF] 699 [exit status: 1] 700 "); 701 // It was detected that the working copy is now stale, but clean. So no 702 // divergent commit should be created. 703 let output = test_env.run_jj_in(&secondary_path, ["workspace", "update-stale"]); 704 insta::assert_snapshot!(output, @r" 705 ------- stderr ------- 706 Working copy (@) now at: pmmvwywv e82cd4ee (empty) (no description set) 707 Parent commit (@-) : qpvuntsm d4124476 (no description set) 708 Added 0 files, modified 1 files, removed 0 files 709 Updated working copy to fresh commit e82cd4ee8faa 710 [EOF] 711 "); 712 insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), 713 @r" 714 @ e82cd4ee8faa secondary@ 715 │ ○ a58c9a9b19ce default@ 716 ├─╯ 717 ○ d41244767d45 718 ◆ 000000000000 719 [EOF] 720 "); 721} 722 723/// Test a clean working copy that gets rewritten from another workspace 724#[test] 725fn test_workspaces_updated_by_other_automatic() { 726 let test_env = TestEnvironment::default(); 727 test_env.add_config("[snapshot]\nauto-update-stale = true\n"); 728 729 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 730 let main_path = test_env.env_root().join("main"); 731 let secondary_path = test_env.env_root().join("secondary"); 732 733 std::fs::write(main_path.join("file"), "contents\n").unwrap(); 734 test_env.run_jj_in(&main_path, ["new"]).success(); 735 736 test_env 737 .run_jj_in(&main_path, ["workspace", "add", "../secondary"]) 738 .success(); 739 740 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 741 @ 06b57f44a3ca default@ 742 │ ○ 3224de8ae048 secondary@ 743 ├─╯ 744 ○ 506f4ec3c2c6 745 ◆ 000000000000 746 [EOF] 747 "); 748 749 // Rewrite the check-out commit in one workspace. 750 std::fs::write(main_path.join("file"), "changed in main\n").unwrap(); 751 let output = test_env.run_jj_in(&main_path, ["squash"]); 752 insta::assert_snapshot!(output, @r" 753 ------- stderr ------- 754 Rebased 1 descendant commits 755 Working copy (@) now at: mzvwutvl a58c9a9b (empty) (no description set) 756 Parent commit (@-) : qpvuntsm d4124476 (no description set) 757 [EOF] 758 "); 759 760 // The secondary workspace's working-copy commit was updated. 761 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 762 @ a58c9a9b19ce default@ 763 │ ○ e82cd4ee8faa secondary@ 764 ├─╯ 765 ○ d41244767d45 766 ◆ 000000000000 767 [EOF] 768 "); 769 770 // The first working copy gets automatically updated. 771 let output = test_env.run_jj_in(&secondary_path, ["st"]); 772 insta::assert_snapshot!(output, @r" 773 The working copy has no changes. 774 Working copy (@) : pmmvwywv e82cd4ee (empty) (no description set) 775 Parent commit (@-): qpvuntsm d4124476 (no description set) 776 [EOF] 777 ------- stderr ------- 778 Working copy (@) now at: pmmvwywv e82cd4ee (empty) (no description set) 779 Parent commit (@-) : qpvuntsm d4124476 (no description set) 780 Added 0 files, modified 1 files, removed 0 files 781 Updated working copy to fresh commit e82cd4ee8faa 782 [EOF] 783 "); 784 785 insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), 786 @r" 787 @ e82cd4ee8faa secondary@ 788 │ ○ a58c9a9b19ce default@ 789 ├─╯ 790 ○ d41244767d45 791 ◆ 000000000000 792 [EOF] 793 "); 794} 795 796#[test_case(false; "manual")] 797#[test_case(true; "automatic")] 798fn test_workspaces_current_op_discarded_by_other(automatic: bool) { 799 let test_env = TestEnvironment::default(); 800 if automatic { 801 test_env.add_config("[snapshot]\nauto-update-stale = true\n"); 802 } 803 804 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 805 let main_path = test_env.env_root().join("main"); 806 let secondary_path = test_env.env_root().join("secondary"); 807 808 std::fs::write(main_path.join("modified"), "base\n").unwrap(); 809 std::fs::write(main_path.join("deleted"), "base\n").unwrap(); 810 std::fs::write(main_path.join("sparse"), "base\n").unwrap(); 811 test_env.run_jj_in(&main_path, ["new"]).success(); 812 std::fs::write(main_path.join("modified"), "main\n").unwrap(); 813 test_env.run_jj_in(&main_path, ["new"]).success(); 814 815 test_env 816 .run_jj_in(&main_path, ["workspace", "add", "../secondary"]) 817 .success(); 818 // Make unsnapshotted writes in the secondary working copy 819 test_env 820 .run_jj_in( 821 &secondary_path, 822 [ 823 "sparse", 824 "set", 825 "--clear", 826 "--add=modified", 827 "--add=deleted", 828 "--add=added", 829 ], 830 ) 831 .success(); 832 std::fs::write(secondary_path.join("modified"), "secondary\n").unwrap(); 833 std::fs::remove_file(secondary_path.join("deleted")).unwrap(); 834 std::fs::write(secondary_path.join("added"), "secondary\n").unwrap(); 835 836 // Create an op by abandoning the parent commit. Importantly, that commit also 837 // changes the target tree in the secondary workspace. 838 test_env.run_jj_in(&main_path, ["abandon", "@-"]).success(); 839 840 let output = test_env.run_jj_in( 841 &main_path, 842 [ 843 "operation", 844 "log", 845 "--template", 846 r#"id.short(10) ++ " " ++ description"#, 847 ], 848 ); 849 insta::allow_duplicates! { 850 insta::assert_snapshot!(output, @r" 851 @ 64d9b429d9 abandon commit dc638a7f20571df2c846c84d1469b9fcd0edafc0 852 ○ 129f2dca87 create initial working-copy commit in workspace secondary 853 ○ 1516a7f851 add workspace 'secondary' 854 ○ 19bf99b2b1 new empty commit 855 ○ 38c9c18632 snapshot working copy 856 ○ 5e4f01399f new empty commit 857 ○ 299bc7a187 snapshot working copy 858 ○ eac759b9ab add workspace 'default' 859 ○ 0000000000 860 [EOF] 861 "); 862 } 863 864 // Abandon ops, including the one the secondary workspace is currently on. 865 test_env 866 .run_jj_in(&main_path, ["operation", "abandon", "..@-"]) 867 .success(); 868 test_env 869 .run_jj_in(&main_path, ["util", "gc", "--expire=now"]) 870 .success(); 871 872 insta::allow_duplicates! { 873 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 874 @ 2d02e07ed190 default@ 875 │ ○ 3df3bf89ddf1 secondary@ 876 ├─╯ 877 ○ e734830954d8 878 ◆ 000000000000 879 [EOF] 880 "); 881 } 882 883 if automatic { 884 // Run a no-op command to set the randomness seed for commit hashes. 885 test_env.run_jj_in(&secondary_path, ["help"]).success(); 886 887 let output = test_env.run_jj_in(&secondary_path, ["st"]); 888 insta::assert_snapshot!(output, @r" 889 Working copy changes: 890 C {modified => added} 891 D deleted 892 M modified 893 Working copy (@) : kmkuslsw 0b518140 RECOVERY COMMIT FROM `jj workspace update-stale` 894 Parent commit (@-): rzvqmyuk 3df3bf89 (empty) (no description set) 895 [EOF] 896 ------- stderr ------- 897 Failed to read working copy's current operation; attempting recovery. Error message from read attempt: Object 129f2dca870b954e2966fba35893bb47a5bc6358db6e8c4065cee91d2d49073efc3e055b9b81269a13c443d964abb18e83d25de73db2376ff434c876c59976ac of type operation not found 898 Created and checked out recovery commit 8ed0355c5d31 899 [EOF] 900 "); 901 } else { 902 let output = test_env.run_jj_in(&secondary_path, ["st"]); 903 insta::assert_snapshot!(output, @r" 904 ------- stderr ------- 905 Error: Could not read working copy's operation. 906 Hint: Run `jj workspace update-stale` to recover. 907 See https://jj-vcs.github.io/jj/latest/working-copy/#stale-working-copy for more information. 908 [EOF] 909 [exit status: 1] 910 "); 911 912 let output = test_env.run_jj_in(&secondary_path, ["workspace", "update-stale"]); 913 insta::assert_snapshot!(output, @r" 914 ------- stderr ------- 915 Failed to read working copy's current operation; attempting recovery. Error message from read attempt: Object 129f2dca870b954e2966fba35893bb47a5bc6358db6e8c4065cee91d2d49073efc3e055b9b81269a13c443d964abb18e83d25de73db2376ff434c876c59976ac of type operation not found 916 Created and checked out recovery commit 8ed0355c5d31 917 [EOF] 918 "); 919 } 920 921 insta::allow_duplicates! { 922 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 923 @ 2d02e07ed190 default@ 924 │ ○ 0b5181407d03 secondary@ 925 │ ○ 3df3bf89ddf1 926 ├─╯ 927 ○ e734830954d8 928 ◆ 000000000000 929 [EOF] 930 "); 931 } 932 933 // The sparse patterns should remain 934 let output = test_env.run_jj_in(&secondary_path, ["sparse", "list"]); 935 insta::allow_duplicates! { 936 insta::assert_snapshot!(output, @r" 937 added 938 deleted 939 modified 940 [EOF] 941 "); 942 } 943 let output = test_env.run_jj_in(&secondary_path, ["st"]); 944 insta::allow_duplicates! { 945 insta::assert_snapshot!(output, @r" 946 Working copy changes: 947 C {modified => added} 948 D deleted 949 M modified 950 Working copy (@) : kmkuslsw 0b518140 RECOVERY COMMIT FROM `jj workspace update-stale` 951 Parent commit (@-): rzvqmyuk 3df3bf89 (empty) (no description set) 952 [EOF] 953 "); 954 } 955 insta::allow_duplicates! { 956 // The modified file should have the same contents it had before (not reset to 957 // the base contents) 958 insta::assert_snapshot!(std::fs::read_to_string(secondary_path.join("modified")).unwrap(), @"secondary"); 959 } 960 961 let output = test_env.run_jj_in(&secondary_path, ["evolog"]); 962 insta::allow_duplicates! { 963 insta::assert_snapshot!(output, @r" 964 @ kmkuslsw test.user@example.com 2001-02-03 08:05:18 secondary@ 0b518140 965 │ RECOVERY COMMIT FROM `jj workspace update-stale` 966 ○ kmkuslsw hidden test.user@example.com 2001-02-03 08:05:18 8ed0355c 967 (empty) RECOVERY COMMIT FROM `jj workspace update-stale` 968 [EOF] 969 "); 970 } 971} 972 973#[test] 974fn test_workspaces_update_stale_noop() { 975 let test_env = TestEnvironment::default(); 976 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 977 let main_path = test_env.env_root().join("main"); 978 979 let output = test_env.run_jj_in(&main_path, ["workspace", "update-stale"]); 980 insta::assert_snapshot!(output, @r" 981 ------- stderr ------- 982 Attempted recovery, but the working copy is not stale 983 [EOF] 984 "); 985 986 let output = test_env.run_jj_in( 987 &main_path, 988 ["workspace", "update-stale", "--ignore-working-copy"], 989 ); 990 insta::assert_snapshot!(output, @r" 991 ------- stderr ------- 992 Error: This command must be able to update the working copy. 993 Hint: Don't use --ignore-working-copy. 994 [EOF] 995 [exit status: 1] 996 "); 997 998 let output = test_env.run_jj_in(&main_path, ["op", "log", "-Tdescription"]); 999 insta::assert_snapshot!(output, @r" 1000 @ add workspace 'default' 10011002 [EOF] 1003 "); 1004} 1005 1006/// Test "update-stale" in a dirty, but not stale working copy. 1007#[test] 1008fn test_workspaces_update_stale_snapshot() { 1009 let test_env = TestEnvironment::default(); 1010 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1011 let main_path = test_env.env_root().join("main"); 1012 let secondary_path = test_env.env_root().join("secondary"); 1013 1014 std::fs::write(main_path.join("file"), "changed in main\n").unwrap(); 1015 test_env.run_jj_in(&main_path, ["new"]).success(); 1016 test_env 1017 .run_jj_in(&main_path, ["workspace", "add", "../secondary"]) 1018 .success(); 1019 1020 // Record new operation in one workspace. 1021 test_env.run_jj_in(&main_path, ["new"]).success(); 1022 1023 // Snapshot the other working copy, which unfortunately results in concurrent 1024 // operations, but should be resolved cleanly. 1025 std::fs::write(secondary_path.join("file"), "changed in second\n").unwrap(); 1026 let output = test_env.run_jj_in(&secondary_path, ["workspace", "update-stale"]); 1027 insta::assert_snapshot!(output, @r" 1028 ------- stderr ------- 1029 Concurrent modification detected, resolving automatically. 1030 Attempted recovery, but the working copy is not stale 1031 [EOF] 1032 "); 1033 1034 insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), @r" 1035 @ e672fd8fefac secondary@ 1036 │ ○ ea37b073f5ab default@ 1037 │ ○ b13c81dedc64 1038 ├─╯ 1039 ○ e6e9989f1179 1040 ◆ 000000000000 1041 [EOF] 1042 "); 1043} 1044 1045/// Test forgetting workspaces 1046#[test] 1047fn test_workspaces_forget() { 1048 let test_env = TestEnvironment::default(); 1049 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1050 let main_path = test_env.env_root().join("main"); 1051 1052 std::fs::write(main_path.join("file"), "contents").unwrap(); 1053 test_env.run_jj_in(&main_path, ["new"]).success(); 1054 1055 test_env 1056 .run_jj_in(&main_path, ["workspace", "add", "../secondary"]) 1057 .success(); 1058 let output = test_env.run_jj_in(&main_path, ["workspace", "forget"]); 1059 insta::assert_snapshot!(output, @""); 1060 1061 // When listing workspaces, only the secondary workspace shows up 1062 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 1063 insta::assert_snapshot!(output, @r" 1064 secondary: pmmvwywv 18463f43 (empty) (no description set) 1065 [EOF] 1066 "); 1067 1068 // `jj status` tells us that there's no working copy here 1069 let output = test_env.run_jj_in(&main_path, ["st"]); 1070 insta::assert_snapshot!(output, @r" 1071 No working copy 1072 [EOF] 1073 "); 1074 1075 // The old working copy doesn't get an "@" in the log output 1076 // TODO: It seems useful to still have the "secondary@" marker here even though 1077 // there's only one workspace. We should show it when the command is not run 1078 // from that workspace. 1079 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 1080 ○ 18463f438cc9 1081 ○ 4e8f9d2be039 1082 ◆ 000000000000 1083 [EOF] 1084 "); 1085 1086 // Revision "@" cannot be used 1087 let output = test_env.run_jj_in(&main_path, ["log", "-r", "@"]); 1088 insta::assert_snapshot!(output, @r" 1089 ------- stderr ------- 1090 Error: Workspace `default` doesn't have a working-copy commit 1091 [EOF] 1092 [exit status: 1] 1093 "); 1094 1095 // Try to add back the workspace 1096 // TODO: We should make this just add it back instead of failing 1097 let output = test_env.run_jj_in(&main_path, ["workspace", "add", "."]); 1098 insta::assert_snapshot!(output, @r" 1099 ------- stderr ------- 1100 Error: Workspace already exists 1101 [EOF] 1102 [exit status: 1] 1103 "); 1104 1105 // Add a third workspace... 1106 test_env 1107 .run_jj_in(&main_path, ["workspace", "add", "../third"]) 1108 .success(); 1109 // ... and then forget it, and the secondary workspace too 1110 let output = test_env.run_jj_in(&main_path, ["workspace", "forget", "secondary", "third"]); 1111 insta::assert_snapshot!(output, @""); 1112 // No workspaces left 1113 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 1114 insta::assert_snapshot!(output, @""); 1115} 1116 1117#[test] 1118fn test_workspaces_forget_multi_transaction() { 1119 let test_env = TestEnvironment::default(); 1120 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1121 let main_path = test_env.env_root().join("main"); 1122 1123 std::fs::write(main_path.join("file"), "contents").unwrap(); 1124 test_env.run_jj_in(&main_path, ["new"]).success(); 1125 1126 test_env 1127 .run_jj_in(&main_path, ["workspace", "add", "../second"]) 1128 .success(); 1129 test_env 1130 .run_jj_in(&main_path, ["workspace", "add", "../third"]) 1131 .success(); 1132 1133 // there should be three workspaces 1134 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 1135 insta::assert_snapshot!(output, @r" 1136 default: rlvkpnrz 909d51b1 (empty) (no description set) 1137 second: pmmvwywv 18463f43 (empty) (no description set) 1138 third: rzvqmyuk cc383fa2 (empty) (no description set) 1139 [EOF] 1140 "); 1141 1142 // delete two at once, in a single tx 1143 test_env 1144 .run_jj_in(&main_path, ["workspace", "forget", "second", "third"]) 1145 .success(); 1146 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 1147 insta::assert_snapshot!(output, @r" 1148 default: rlvkpnrz 909d51b1 (empty) (no description set) 1149 [EOF] 1150 "); 1151 1152 // the op log should have multiple workspaces forgotten in a single tx 1153 let output = test_env.run_jj_in(&main_path, ["op", "log", "--limit", "1"]); 1154 insta::assert_snapshot!(output, @r" 1155 @ 60b2b5a71a84 test-username@host.example.com 2001-02-03 04:05:12.000 +07:00 - 2001-02-03 04:05:12.000 +07:00 1156 │ forget workspaces second, third 1157 │ args: jj workspace forget second third 1158 [EOF] 1159 "); 1160 1161 // now, undo, and that should restore both workspaces 1162 test_env.run_jj_in(&main_path, ["op", "undo"]).success(); 1163 1164 // finally, there should be three workspaces at the end 1165 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 1166 insta::assert_snapshot!(output, @r" 1167 default: rlvkpnrz 909d51b1 (empty) (no description set) 1168 second: pmmvwywv 18463f43 (empty) (no description set) 1169 third: rzvqmyuk cc383fa2 (empty) (no description set) 1170 [EOF] 1171 "); 1172} 1173 1174#[test] 1175fn test_workspaces_forget_abandon_commits() { 1176 let test_env = TestEnvironment::default(); 1177 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1178 let main_path = test_env.env_root().join("main"); 1179 1180 std::fs::write(main_path.join("file"), "contents").unwrap(); 1181 1182 test_env 1183 .run_jj_in(&main_path, ["workspace", "add", "../second"]) 1184 .success(); 1185 test_env 1186 .run_jj_in(&main_path, ["workspace", "add", "../third"]) 1187 .success(); 1188 test_env 1189 .run_jj_in(&main_path, ["workspace", "add", "../fourth"]) 1190 .success(); 1191 let third_path = test_env.env_root().join("third"); 1192 test_env 1193 .run_jj_in(&third_path, ["edit", "second@"]) 1194 .success(); 1195 let fourth_path = test_env.env_root().join("fourth"); 1196 test_env 1197 .run_jj_in(&fourth_path, ["edit", "second@"]) 1198 .success(); 1199 1200 // there should be four workspaces, three of which are at the same empty commit 1201 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 1202 insta::assert_snapshot!(output, @r" 1203 default: qpvuntsm 4e8f9d2b (no description set) 1204 fourth: uuqppmxq 57d63245 (empty) (no description set) 1205 second: uuqppmxq 57d63245 (empty) (no description set) 1206 third: uuqppmxq 57d63245 (empty) (no description set) 1207 [EOF] 1208 "); 1209 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 1210 @ 4e8f9d2be039 default@ 1211 │ ○ 57d63245a308 fourth@ second@ third@ 1212 ├─╯ 1213 ◆ 000000000000 1214 [EOF] 1215 "); 1216 1217 // delete the default workspace (should not abandon commit since not empty) 1218 test_env 1219 .run_jj_in(&main_path, ["workspace", "forget", "default"]) 1220 .success(); 1221 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 1222 ○ 57d63245a308 fourth@ second@ third@ 1223 │ ○ 4e8f9d2be039 1224 ├─╯ 1225 ◆ 000000000000 1226 [EOF] 1227 "); 1228 1229 // delete the second workspace (should not abandon commit since other workspaces 1230 // still have commit checked out) 1231 test_env 1232 .run_jj_in(&main_path, ["workspace", "forget", "second"]) 1233 .success(); 1234 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 1235 ○ 57d63245a308 fourth@ third@ 1236 │ ○ 4e8f9d2be039 1237 ├─╯ 1238 ◆ 000000000000 1239 [EOF] 1240 "); 1241 1242 // delete the last 2 workspaces (commit should be abandoned now even though 1243 // forgotten in same tx) 1244 test_env 1245 .run_jj_in(&main_path, ["workspace", "forget", "third", "fourth"]) 1246 .success(); 1247 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 1248 ○ 4e8f9d2be039 1249 ◆ 000000000000 1250 [EOF] 1251 "); 1252} 1253 1254/// Test context of commit summary template 1255#[test] 1256fn test_list_workspaces_template() { 1257 let test_env = TestEnvironment::default(); 1258 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1259 test_env.add_config( 1260 r#" 1261 templates.commit_summary = """commit_id.short() ++ " " ++ description.first_line() ++ 1262 if(current_working_copy, " (current)")""" 1263 "#, 1264 ); 1265 let main_path = test_env.env_root().join("main"); 1266 let secondary_path = test_env.env_root().join("secondary"); 1267 1268 std::fs::write(main_path.join("file"), "contents").unwrap(); 1269 test_env 1270 .run_jj_in(&main_path, ["commit", "-m", "initial"]) 1271 .success(); 1272 test_env 1273 .run_jj_in( 1274 &main_path, 1275 ["workspace", "add", "--name", "second", "../secondary"], 1276 ) 1277 .success(); 1278 1279 // "current_working_copy" should point to the workspace we operate on 1280 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 1281 insta::assert_snapshot!(output, @r" 1282 default: 8183d0fcaa4c (current) 1283 second: 0a77a39d7d6f 1284 [EOF] 1285 "); 1286 1287 let output = test_env.run_jj_in(&secondary_path, ["workspace", "list"]); 1288 insta::assert_snapshot!(output, @r" 1289 default: 8183d0fcaa4c 1290 second: 0a77a39d7d6f (current) 1291 [EOF] 1292 "); 1293} 1294 1295/// Test getting the workspace root from primary and secondary workspaces 1296#[test] 1297fn test_workspaces_root() { 1298 let test_env = TestEnvironment::default(); 1299 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1300 let main_path = test_env.env_root().join("main"); 1301 let secondary_path = test_env.env_root().join("secondary"); 1302 1303 let output = test_env.run_jj_in(&main_path, ["workspace", "root"]); 1304 insta::assert_snapshot!(output, @r" 1305 $TEST_ENV/main 1306 [EOF] 1307 "); 1308 let main_subdir_path = main_path.join("subdir"); 1309 std::fs::create_dir(&main_subdir_path).unwrap(); 1310 let output = test_env.run_jj_in(&main_subdir_path, ["workspace", "root"]); 1311 insta::assert_snapshot!(output, @r" 1312 $TEST_ENV/main 1313 [EOF] 1314 "); 1315 1316 test_env 1317 .run_jj_in( 1318 &main_path, 1319 ["workspace", "add", "--name", "secondary", "../secondary"], 1320 ) 1321 .success(); 1322 let output = test_env.run_jj_in(&secondary_path, ["workspace", "root"]); 1323 insta::assert_snapshot!(output, @r" 1324 $TEST_ENV/secondary 1325 [EOF] 1326 "); 1327 let secondary_subdir_path = secondary_path.join("subdir"); 1328 std::fs::create_dir(&secondary_subdir_path).unwrap(); 1329 let output = test_env.run_jj_in(&secondary_subdir_path, ["workspace", "root"]); 1330 insta::assert_snapshot!(output, @r" 1331 $TEST_ENV/secondary 1332 [EOF] 1333 "); 1334} 1335 1336#[test] 1337fn test_debug_snapshot() { 1338 let test_env = TestEnvironment::default(); 1339 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1340 let repo_path = test_env.env_root().join("repo"); 1341 1342 std::fs::write(repo_path.join("file"), "contents").unwrap(); 1343 test_env 1344 .run_jj_in(&repo_path, ["debug", "snapshot"]) 1345 .success(); 1346 let output = test_env.run_jj_in(&repo_path, ["op", "log"]); 1347 insta::assert_snapshot!(output, @r" 1348 @ c55ebc67e3db test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 1349 │ snapshot working copy 1350 │ args: jj debug snapshot 1351 ○ eac759b9ab75 test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 1352 │ add workspace 'default' 1353 ○ 000000000000 root() 1354 [EOF] 1355 "); 1356 test_env 1357 .run_jj_in(&repo_path, ["describe", "-m", "initial"]) 1358 .success(); 1359 let output = test_env.run_jj_in(&repo_path, ["op", "log"]); 1360 insta::assert_snapshot!(output, @r" 1361 @ c9a40b951848 test-username@host.example.com 2001-02-03 04:05:10.000 +07:00 - 2001-02-03 04:05:10.000 +07:00 1362 │ describe commit 4e8f9d2be039994f589b4e57ac5e9488703e604d 1363 │ args: jj describe -m initial 1364 ○ c55ebc67e3db test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 1365 │ snapshot working copy 1366 │ args: jj debug snapshot 1367 ○ eac759b9ab75 test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 1368 │ add workspace 'default' 1369 ○ 000000000000 root() 1370 [EOF] 1371 "); 1372} 1373 1374#[test] 1375fn test_workspaces_rename_nothing_changed() { 1376 let test_env = TestEnvironment::default(); 1377 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1378 let main_path = test_env.env_root().join("main"); 1379 let output = test_env.run_jj_in(&main_path, ["workspace", "rename", "default"]); 1380 insta::assert_snapshot!(output, @r" 1381 ------- stderr ------- 1382 Nothing changed. 1383 [EOF] 1384 "); 1385} 1386 1387#[test] 1388fn test_workspaces_rename_new_workspace_name_already_used() { 1389 let test_env = TestEnvironment::default(); 1390 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1391 let main_path = test_env.env_root().join("main"); 1392 test_env 1393 .run_jj_in( 1394 &main_path, 1395 ["workspace", "add", "--name", "second", "../secondary"], 1396 ) 1397 .success(); 1398 let output = test_env.run_jj_in(&main_path, ["workspace", "rename", "second"]); 1399 insta::assert_snapshot!(output, @r" 1400 ------- stderr ------- 1401 Error: Failed to rename a workspace 1402 Caused by: Workspace second already exists 1403 [EOF] 1404 [exit status: 1] 1405 "); 1406} 1407 1408#[test] 1409fn test_workspaces_rename_forgotten_workspace() { 1410 let test_env = TestEnvironment::default(); 1411 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1412 let main_path = test_env.env_root().join("main"); 1413 test_env 1414 .run_jj_in( 1415 &main_path, 1416 ["workspace", "add", "--name", "second", "../secondary"], 1417 ) 1418 .success(); 1419 test_env 1420 .run_jj_in(&main_path, ["workspace", "forget", "second"]) 1421 .success(); 1422 let secondary_path = test_env.env_root().join("secondary"); 1423 let output = test_env.run_jj_in(&secondary_path, ["workspace", "rename", "third"]); 1424 insta::assert_snapshot!(output, @r" 1425 ------- stderr ------- 1426 Error: The current workspace 'second' is not tracked in the repo. 1427 [EOF] 1428 [exit status: 1] 1429 "); 1430} 1431 1432#[test] 1433fn test_workspaces_rename_workspace() { 1434 let test_env = TestEnvironment::default(); 1435 test_env.run_jj_in(".", ["git", "init", "main"]).success(); 1436 let main_path = test_env.env_root().join("main"); 1437 test_env 1438 .run_jj_in( 1439 &main_path, 1440 ["workspace", "add", "--name", "second", "../secondary"], 1441 ) 1442 .success(); 1443 let secondary_path = test_env.env_root().join("secondary"); 1444 1445 // Both workspaces show up when we list them 1446 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 1447 insta::assert_snapshot!(output, @r" 1448 default: qpvuntsm 230dd059 (empty) (no description set) 1449 second: uuqppmxq 57d63245 (empty) (no description set) 1450 [EOF] 1451 "); 1452 1453 let output = test_env.run_jj_in(&secondary_path, ["workspace", "rename", "third"]); 1454 insta::assert_snapshot!(output, @""); 1455 1456 let output = test_env.run_jj_in(&main_path, ["workspace", "list"]); 1457 insta::assert_snapshot!(output, @r" 1458 default: qpvuntsm 230dd059 (empty) (no description set) 1459 third: uuqppmxq 57d63245 (empty) (no description set) 1460 [EOF] 1461 "); 1462 1463 // Can see the working-copy commit in each workspace in the log output. 1464 insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r" 1465 @ 230dd059e1b0 default@ 1466 │ ○ 57d63245a308 third@ 1467 ├─╯ 1468 ◆ 000000000000 1469 [EOF] 1470 "); 1471 insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), @r" 1472 @ 57d63245a308 third@ 1473 │ ○ 230dd059e1b0 default@ 1474 ├─╯ 1475 ◆ 000000000000 1476 [EOF] 1477 "); 1478} 1479 1480#[must_use] 1481fn get_log_output(test_env: &TestEnvironment, cwd: &Path) -> CommandOutput { 1482 let template = r#" 1483 separate(" ", 1484 commit_id.short(), 1485 working_copies, 1486 if(divergent, "(divergent)"), 1487 ) 1488 "#; 1489 test_env.run_jj_in(cwd, ["log", "-T", template, "-r", "all()"]) 1490}