just playing with tangled
at ig/vimdiffwarn 2285 lines 78 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 testutils::git; 16 17use crate::common::CommandOutput; 18use crate::common::TestEnvironment; 19use crate::common::TestWorkDir; 20 21fn create_commit_with_refs( 22 repo: &gix::Repository, 23 message: &str, 24 content: &[u8], 25 ref_names: &[&str], 26) { 27 let git::CommitResult { 28 tree_id: _, 29 commit_id, 30 } = git::add_commit(repo, "refs/heads/dummy", "file", content, message, &[]); 31 repo.find_reference("dummy").unwrap().delete().unwrap(); 32 33 for name in ref_names { 34 repo.reference( 35 *name, 36 commit_id, 37 gix::refs::transaction::PreviousValue::Any, 38 "log message", 39 ) 40 .unwrap(); 41 } 42} 43 44#[test] 45fn test_bookmark_multiple_names() { 46 let test_env = TestEnvironment::default(); 47 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 48 let work_dir = test_env.work_dir("repo"); 49 50 let output = work_dir.run_jj(["bookmark", "create", "-r@", "foo", "bar"]); 51 insta::assert_snapshot!(output, @r" 52 ------- stderr ------- 53 Created 2 bookmarks pointing to qpvuntsm 230dd059 bar foo | (empty) (no description set) 54 [EOF] 55 "); 56 insta::assert_snapshot!(get_log_output(&work_dir), @r" 57 @ bar foo 230dd059e1b0 58 ◆ 000000000000 59 [EOF] 60 "); 61 62 work_dir.run_jj(["new"]).success(); 63 let output = work_dir.run_jj(["bookmark", "set", "foo", "bar", "--to=@"]); 64 insta::assert_snapshot!(output, @r" 65 ------- stderr ------- 66 Moved 2 bookmarks to zsuskuln 8bb159bc bar foo | (empty) (no description set) 67 [EOF] 68 "); 69 insta::assert_snapshot!(get_log_output(&work_dir), @r" 70 @ bar foo 8bb159bc30a9 71 ○ 230dd059e1b0 72 ◆ 000000000000 73 [EOF] 74 "); 75 76 let output = work_dir.run_jj(["bookmark", "delete", "foo", "bar", "foo"]); 77 insta::assert_snapshot!(output, @r" 78 ------- stderr ------- 79 Deleted 2 bookmarks. 80 [EOF] 81 "); 82 insta::assert_snapshot!(get_log_output(&work_dir), @r" 83 @ 8bb159bc30a9 84 ○ 230dd059e1b0 85 ◆ 000000000000 86 [EOF] 87 "); 88 89 // Hint should be omitted if -r is specified 90 let output = work_dir.run_jj(["bookmark", "create", "-r@-", "foo", "bar"]); 91 insta::assert_snapshot!(output, @r" 92 ------- stderr ------- 93 Created 2 bookmarks pointing to qpvuntsm 230dd059 bar foo | (empty) (no description set) 94 [EOF] 95 "); 96 97 // Create and move with explicit -r 98 let output = work_dir.run_jj(["bookmark", "set", "-r@", "bar", "baz"]); 99 insta::assert_snapshot!(output, @r" 100 ------- stderr ------- 101 Created 1 bookmarks pointing to zsuskuln 8bb159bc bar baz | (empty) (no description set) 102 Moved 1 bookmarks to zsuskuln 8bb159bc bar baz | (empty) (no description set) 103 [EOF] 104 "); 105 106 // Noop changes should not be included in the stats 107 let output = work_dir.run_jj(["bookmark", "set", "-r@", "foo", "bar", "baz"]); 108 insta::assert_snapshot!(output, @r" 109 ------- stderr ------- 110 Moved 1 bookmarks to zsuskuln 8bb159bc bar baz foo | (empty) (no description set) 111 [EOF] 112 "); 113} 114 115#[test] 116fn test_bookmark_at_root() { 117 let test_env = TestEnvironment::default(); 118 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 119 let work_dir = test_env.work_dir("repo"); 120 121 let output = work_dir.run_jj(["bookmark", "create", "fred", "-r=root()"]); 122 insta::assert_snapshot!(output, @r" 123 ------- stderr ------- 124 Created 1 bookmarks pointing to zzzzzzzz 00000000 fred | (empty) (no description set) 125 [EOF] 126 "); 127 let output = work_dir.run_jj(["git", "export"]); 128 insta::assert_snapshot!(output, @r" 129 ------- stderr ------- 130 Nothing changed. 131 Warning: Failed to export some bookmarks: 132 fred@git: Ref cannot point to the root commit in Git 133 [EOF] 134 "); 135} 136 137#[test] 138fn test_bookmark_bad_name() { 139 let test_env = TestEnvironment::default(); 140 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 141 let work_dir = test_env.work_dir("repo"); 142 143 let output = work_dir.run_jj(["bookmark", "create", "-r@", ""]); 144 insta::assert_snapshot!(output, @r" 145 ------- stderr ------- 146 error: invalid value '' for '<NAMES>...': Failed to parse bookmark name: Syntax error 147 148 For more information, try '--help'. 149 Caused by: --> 1:1 150 | 151 1 | 152 | ^--- 153 | 154 = expected <identifier>, <string_literal>, or <raw_string_literal> 155 Hint: See https://jj-vcs.github.io/jj/latest/revsets/ or use `jj help -k revsets` for how to quote symbols. 156 [EOF] 157 [exit status: 2] 158 "); 159 160 let output = work_dir.run_jj(["bookmark", "set", "''"]); 161 insta::assert_snapshot!(output, @r" 162 ------- stderr ------- 163 error: invalid value '''' for '<NAMES>...': Failed to parse bookmark name: Expected non-empty string 164 165 For more information, try '--help'. 166 Caused by: --> 1:1 167 | 168 1 | '' 169 | ^^ 170 | 171 = Expected non-empty string 172 Hint: See https://jj-vcs.github.io/jj/latest/revsets/ or use `jj help -k revsets` for how to quote symbols. 173 [EOF] 174 [exit status: 2] 175 "); 176 177 let output = work_dir.run_jj(["bookmark", "rename", "x", ""]); 178 insta::assert_snapshot!(output, @r" 179 ------- stderr ------- 180 error: invalid value '' for '<NEW>': Failed to parse bookmark name: Syntax error 181 182 For more information, try '--help'. 183 Caused by: --> 1:1 184 | 185 1 | 186 | ^--- 187 | 188 = expected <identifier>, <string_literal>, or <raw_string_literal> 189 Hint: See https://jj-vcs.github.io/jj/latest/revsets/ or use `jj help -k revsets` for how to quote symbols. 190 [EOF] 191 [exit status: 2] 192 "); 193 194 // common errors 195 let output = work_dir.run_jj(["bookmark", "set", "@-", "foo"]); 196 insta::assert_snapshot!(output, @r" 197 ------- stderr ------- 198 error: invalid value '@-' for '<NAMES>...': Failed to parse bookmark name: Syntax error 199 200 For more information, try '--help'. 201 Caused by: --> 1:1 202 | 203 1 | @- 204 | ^--- 205 | 206 = expected <identifier>, <string_literal>, or <raw_string_literal> 207 Hint: See https://jj-vcs.github.io/jj/latest/revsets/ or use `jj help -k revsets` for how to quote symbols. 208 [EOF] 209 [exit status: 2] 210 "); 211 212 let stderr = work_dir.run_jj(["bookmark", "set", "-r@-", "foo@bar"]); 213 insta::assert_snapshot!(stderr, @r" 214 ------- stderr ------- 215 error: invalid value 'foo@bar' for '<NAMES>...': Failed to parse bookmark name: Syntax error 216 217 For more information, try '--help'. 218 Caused by: --> 1:4 219 | 220 1 | foo@bar 221 | ^--- 222 | 223 = expected <EOI> 224 Hint: Looks like remote bookmark. Run `jj bookmark track foo@bar` to track it. 225 [EOF] 226 [exit status: 2] 227 "); 228 229 // quoted name works 230 let output = work_dir.run_jj(["bookmark", "create", "-r@", "'foo@bar'"]); 231 insta::assert_snapshot!(output, @r" 232 ------- stderr ------- 233 Created 1 bookmarks pointing to qpvuntsm 230dd059 foo@bar | (empty) (no description set) 234 [EOF] 235 "); 236} 237 238#[test] 239fn test_bookmark_move() { 240 let test_env = TestEnvironment::default(); 241 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 242 let work_dir = test_env.work_dir("repo"); 243 244 // Set up remote 245 let git_repo_path = test_env.env_root().join("git-repo"); 246 git::init_bare(git_repo_path); 247 work_dir 248 .run_jj(["git", "remote", "add", "origin", "../git-repo"]) 249 .success(); 250 251 let output = work_dir.run_jj(["bookmark", "move", "foo", "--to=@"]); 252 insta::assert_snapshot!(output, @r" 253 ------- stderr ------- 254 Error: No such bookmark: foo 255 [EOF] 256 [exit status: 1] 257 "); 258 259 let output = work_dir.run_jj(["bookmark", "set", "foo", "--to=@"]); 260 insta::assert_snapshot!(output, @r" 261 ------- stderr ------- 262 Created 1 bookmarks pointing to qpvuntsm 230dd059 foo | (empty) (no description set) 263 [EOF] 264 "); 265 266 work_dir.run_jj(["new"]).success(); 267 let output = work_dir.run_jj(["bookmark", "create", "-r@", "foo"]); 268 insta::assert_snapshot!(output, @r" 269 ------- stderr ------- 270 Error: Bookmark already exists: foo 271 Hint: Use `jj bookmark set` to update it. 272 [EOF] 273 [exit status: 1] 274 "); 275 276 let output = work_dir.run_jj(["bookmark", "set", "foo", "--revision", "@"]); 277 insta::assert_snapshot!(output, @r" 278 ------- stderr ------- 279 Moved 1 bookmarks to mzvwutvl 167f90e7 foo | (empty) (no description set) 280 [EOF] 281 "); 282 283 let output = work_dir.run_jj(["bookmark", "set", "-r@-", "foo"]); 284 insta::assert_snapshot!(output, @r" 285 ------- stderr ------- 286 Error: Refusing to move bookmark backwards or sideways: foo 287 Hint: Use --allow-backwards to allow it. 288 [EOF] 289 [exit status: 1] 290 "); 291 292 let output = work_dir.run_jj(["bookmark", "set", "-r@-", "--allow-backwards", "foo"]); 293 insta::assert_snapshot!(output, @r" 294 ------- stderr ------- 295 Moved 1 bookmarks to qpvuntsm 230dd059 foo | (empty) (no description set) 296 [EOF] 297 "); 298 299 let output = work_dir.run_jj(["bookmark", "move", "foo", "--to=@"]); 300 insta::assert_snapshot!(output, @r" 301 ------- stderr ------- 302 Moved 1 bookmarks to mzvwutvl 167f90e7 foo | (empty) (no description set) 303 [EOF] 304 "); 305 306 let output = work_dir.run_jj(["bookmark", "move", "--to=@-", "foo"]); 307 insta::assert_snapshot!(output, @r" 308 ------- stderr ------- 309 Error: Refusing to move bookmark backwards or sideways: foo 310 Hint: Use --allow-backwards to allow it. 311 [EOF] 312 [exit status: 1] 313 "); 314 315 let output = work_dir.run_jj(["bookmark", "move", "--to=@-", "--allow-backwards", "foo"]); 316 insta::assert_snapshot!(output, @r" 317 ------- stderr ------- 318 Moved 1 bookmarks to qpvuntsm 230dd059 foo | (empty) (no description set) 319 [EOF] 320 "); 321 322 // Delete bookmark locally, but is still tracking remote 323 work_dir.run_jj(["describe", "@-", "-mcommit"]).success(); 324 work_dir 325 .run_jj(["git", "push", "--allow-new", "-r@-"]) 326 .success(); 327 work_dir.run_jj(["bookmark", "delete", "foo"]).success(); 328 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 329 foo (deleted) 330 @origin: qpvuntsm 1eb845f3 (empty) commit 331 [EOF] 332 "); 333 334 // Deleted tracking bookmark name should still be allocated 335 let output = work_dir.run_jj(["bookmark", "create", "-r@", "foo"]); 336 insta::assert_snapshot!(output, @r" 337 ------- stderr ------- 338 Error: Tracked remote bookmarks exist for deleted bookmark: foo 339 Hint: Use `jj bookmark set` to recreate the local bookmark. Run `jj bookmark untrack 'glob:foo@*'` to disassociate them. 340 [EOF] 341 [exit status: 1] 342 "); 343 344 // Restoring local target shouldn't invalidate tracking state 345 let output = work_dir.run_jj(["bookmark", "set", "foo", "--to=@"]); 346 insta::assert_snapshot!(output, @r" 347 ------- stderr ------- 348 Moved 1 bookmarks to mzvwutvl 66d48752 foo* | (empty) (no description set) 349 [EOF] 350 "); 351 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 352 foo: mzvwutvl 66d48752 (empty) (no description set) 353 @origin (behind by 1 commits): qpvuntsm 1eb845f3 (empty) commit 354 [EOF] 355 "); 356 357 // Untracked remote bookmark shouldn't block creation of local bookmark 358 work_dir 359 .run_jj(["bookmark", "untrack", "foo@origin"]) 360 .success(); 361 work_dir.run_jj(["bookmark", "delete", "foo"]).success(); 362 let output = work_dir.run_jj(["bookmark", "create", "-r@", "foo"]); 363 insta::assert_snapshot!(output, @r" 364 ------- stderr ------- 365 Created 1 bookmarks pointing to mzvwutvl 66d48752 foo | (empty) (no description set) 366 [EOF] 367 "); 368 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 369 foo: mzvwutvl 66d48752 (empty) (no description set) 370 foo@origin: qpvuntsm 1eb845f3 (empty) commit 371 [EOF] 372 "); 373} 374 375#[test] 376fn test_bookmark_move_matching() { 377 let test_env = TestEnvironment::default(); 378 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 379 let work_dir = test_env.work_dir("repo"); 380 381 work_dir 382 .run_jj(["bookmark", "create", "-r@", "a1", "a2"]) 383 .success(); 384 work_dir.run_jj(["new", "-mhead1"]).success(); 385 work_dir.run_jj(["new", "root()"]).success(); 386 work_dir 387 .run_jj(["bookmark", "create", "-r@", "b1"]) 388 .success(); 389 work_dir.run_jj(["new"]).success(); 390 work_dir 391 .run_jj(["bookmark", "create", "-r@", "c1"]) 392 .success(); 393 work_dir.run_jj(["new", "-mhead2"]).success(); 394 insta::assert_snapshot!(get_log_output(&work_dir), @r" 395 @ a2781dd9ee37 396 ○ c1 f4f38657a3dd 397 ○ b1 f652c32197cf 398 │ ○ 6b5e840ea72b 399 │ ○ a1 a2 230dd059e1b0 400 ├─╯ 401 ◆ 000000000000 402 [EOF] 403 "); 404 405 // The default could be considered "--from=all() glob:*", but is disabled 406 let output = work_dir.run_jj(["bookmark", "move", "--to=@"]); 407 insta::assert_snapshot!(output, @r" 408 ------- stderr ------- 409 error: the following required arguments were not provided: 410 <--from <REVSETS>|NAMES> 411 412 Usage: jj bookmark move --to <REVSET> <--from <REVSETS>|NAMES> 413 414 For more information, try '--help'. 415 [EOF] 416 [exit status: 2] 417 "); 418 419 // No bookmarks pointing to the source revisions 420 let output = work_dir.run_jj(["bookmark", "move", "--from=none()", "--to=@"]); 421 insta::assert_snapshot!(output, @r" 422 ------- stderr ------- 423 No bookmarks to update. 424 [EOF] 425 "); 426 427 // No matching bookmarks within the source revisions 428 let output = work_dir.run_jj(["bookmark", "move", "--from=::@", "glob:a?", "--to=@"]); 429 insta::assert_snapshot!(output, @r" 430 ------- stderr ------- 431 Error: No matching bookmarks for patterns: a? 432 [EOF] 433 [exit status: 1] 434 "); 435 436 // Noop move 437 let output = work_dir.run_jj(["bookmark", "move", "--to=a1", "a2"]); 438 insta::assert_snapshot!(output, @r" 439 ------- stderr ------- 440 No bookmarks to update. 441 [EOF] 442 "); 443 444 // Move from multiple revisions 445 let output = work_dir.run_jj(["bookmark", "move", "--from=::@", "--to=@"]); 446 insta::assert_snapshot!(output, @r" 447 ------- stderr ------- 448 Moved 2 bookmarks to vruxwmqv a2781dd9 b1 c1 | (empty) head2 449 Hint: Specify bookmark by name to update just one of the bookmarks. 450 [EOF] 451 "); 452 insta::assert_snapshot!(get_log_output(&work_dir), @r" 453 @ b1 c1 a2781dd9ee37 454 ○ f4f38657a3dd 455 ○ f652c32197cf 456 │ ○ 6b5e840ea72b 457 │ ○ a1 a2 230dd059e1b0 458 ├─╯ 459 ◆ 000000000000 460 [EOF] 461 "); 462 work_dir.run_jj(["undo"]).success(); 463 464 // Try to move multiple bookmarks, but one of them isn't fast-forward 465 let output = work_dir.run_jj(["bookmark", "move", "glob:?1", "--to=@"]); 466 insta::assert_snapshot!(output, @r" 467 ------- stderr ------- 468 Error: Refusing to move bookmark backwards or sideways: a1 469 Hint: Use --allow-backwards to allow it. 470 [EOF] 471 [exit status: 1] 472 "); 473 insta::assert_snapshot!(get_log_output(&work_dir), @r" 474 @ a2781dd9ee37 475 ○ c1 f4f38657a3dd 476 ○ b1 f652c32197cf 477 │ ○ 6b5e840ea72b 478 │ ○ a1 a2 230dd059e1b0 479 ├─╯ 480 ◆ 000000000000 481 [EOF] 482 "); 483 484 // Select by revision and name 485 let output = work_dir.run_jj(["bookmark", "move", "--from=::a1+", "--to=a1+", "glob:?1"]); 486 insta::assert_snapshot!(output, @r" 487 ------- stderr ------- 488 Moved 1 bookmarks to kkmpptxz 6b5e840e a1 | (empty) head1 489 [EOF] 490 "); 491 insta::assert_snapshot!(get_log_output(&work_dir), @r" 492 @ a2781dd9ee37 493 ○ c1 f4f38657a3dd 494 ○ b1 f652c32197cf 495 │ ○ a1 6b5e840ea72b 496 │ ○ a2 230dd059e1b0 497 ├─╯ 498 ◆ 000000000000 499 [EOF] 500 "); 501} 502 503#[test] 504fn test_bookmark_move_conflicting() { 505 let test_env = TestEnvironment::default(); 506 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 507 let work_dir = test_env.work_dir("repo"); 508 let get_log = || { 509 let template = r#"separate(" ", description.first_line(), bookmarks)"#; 510 work_dir.run_jj(["log", "-T", template]) 511 }; 512 513 work_dir.run_jj(["new", "root()", "-mA0"]).success(); 514 work_dir.run_jj(["new", "root()", "-mB0"]).success(); 515 work_dir.run_jj(["new", "root()", "-mC0"]).success(); 516 work_dir 517 .run_jj(["new", "description(A0)", "-mA1"]) 518 .success(); 519 520 // Set up conflicting bookmark. 521 work_dir 522 .run_jj(["bookmark", "create", "-rdescription(A0)", "foo"]) 523 .success(); 524 work_dir 525 .run_jj([ 526 "bookmark", 527 "create", 528 "--at-op=@-", 529 "-rdescription(B0)", 530 "foo", 531 ]) 532 .success(); 533 insta::assert_snapshot!(get_log(), @r" 534 @ A1 535 ○ A0 foo?? 536 │ ○ C0 537 ├─╯ 538 │ ○ B0 foo?? 539 ├─╯ 540 541 [EOF] 542 ------- stderr ------- 543 Concurrent modification detected, resolving automatically. 544 [EOF] 545 "); 546 547 // Can't move the bookmark to C0 since it's sibling. 548 let output = work_dir.run_jj(["bookmark", "set", "-rdescription(C0)", "foo"]); 549 insta::assert_snapshot!(output, @r" 550 ------- stderr ------- 551 Error: Refusing to move bookmark backwards or sideways: foo 552 Hint: Use --allow-backwards to allow it. 553 [EOF] 554 [exit status: 1] 555 "); 556 557 // Can move the bookmark to A1 since it's descendant of A0. It's not 558 // descendant of B0, though. 559 let output = work_dir.run_jj(["bookmark", "set", "-rdescription(A1)", "foo"]); 560 insta::assert_snapshot!(output, @r" 561 ------- stderr ------- 562 Moved 1 bookmarks to mzvwutvl 9328d344 foo | (empty) A1 563 [EOF] 564 "); 565 insta::assert_snapshot!(get_log(), @r" 566 @ A1 foo 567 ○ A0 568 │ ○ C0 569 ├─╯ 570 │ ○ B0 571 ├─╯ 572 573 [EOF] 574 "); 575} 576 577#[test] 578fn test_bookmark_rename() { 579 let test_env = TestEnvironment::default(); 580 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 581 let work_dir = test_env.work_dir("repo"); 582 583 // Set up remote 584 let git_repo_path = test_env.env_root().join("git-repo"); 585 git::init_bare(git_repo_path); 586 work_dir 587 .run_jj(["git", "remote", "add", "origin", "../git-repo"]) 588 .success(); 589 590 let output = work_dir.run_jj(["bookmark", "rename", "bnoexist", "blocal"]); 591 insta::assert_snapshot!(output, @r" 592 ------- stderr ------- 593 Error: No such bookmark: bnoexist 594 [EOF] 595 [exit status: 1] 596 "); 597 598 work_dir.run_jj(["describe", "-m=commit-0"]).success(); 599 work_dir 600 .run_jj(["bookmark", "create", "-r@", "blocal"]) 601 .success(); 602 let output = work_dir.run_jj(["bookmark", "rename", "blocal", "blocal1"]); 603 insta::assert_snapshot!(output, @""); 604 605 work_dir.run_jj(["new"]).success(); 606 work_dir.run_jj(["describe", "-m=commit-1"]).success(); 607 work_dir 608 .run_jj(["bookmark", "create", "-r@", "bexist"]) 609 .success(); 610 let output = work_dir.run_jj(["bookmark", "rename", "blocal1", "bexist"]); 611 insta::assert_snapshot!(output, @r" 612 ------- stderr ------- 613 Error: Bookmark already exists: bexist 614 [EOF] 615 [exit status: 1] 616 "); 617 618 work_dir.run_jj(["new"]).success(); 619 work_dir.run_jj(["describe", "-m=commit-2"]).success(); 620 work_dir 621 .run_jj(["bookmark", "create", "-r@", "bremote"]) 622 .success(); 623 work_dir 624 .run_jj(["git", "push", "--allow-new", "-b=bremote"]) 625 .success(); 626 let output = work_dir.run_jj(["bookmark", "rename", "bremote", "bremote2"]); 627 insta::assert_snapshot!(output, @r" 628 ------- stderr ------- 629 Warning: Tracked remote bookmarks for bookmark bremote were not renamed. 630 Hint: To rename the bookmark on the remote, you can `jj git push --bookmark bremote` first (to delete it on the remote), and then `jj git push --bookmark bremote2`. `jj git push --all` would also be sufficient. 631 [EOF] 632 "); 633 let output = work_dir.run_jj(["bookmark", "rename", "bremote2", "bremote"]); 634 insta::assert_snapshot!(output, @r" 635 ------- stderr ------- 636 Warning: Tracked remote bookmarks for bookmark bremote exist. 637 Hint: Run `jj bookmark untrack 'glob:bremote@*'` to disassociate them. 638 [EOF] 639 "); 640} 641 642#[test] 643fn test_bookmark_rename_colocated() { 644 let test_env = TestEnvironment::default(); 645 test_env 646 .run_jj_in(".", ["git", "init", "repo", "--colocate"]) 647 .success(); 648 let work_dir = test_env.work_dir("repo"); 649 650 work_dir.run_jj(["describe", "-m=commit-0"]).success(); 651 work_dir 652 .run_jj(["bookmark", "create", "-r@", "blocal"]) 653 .success(); 654 655 // Make sure that git tracking bookmarks don't cause a warning 656 let output = work_dir.run_jj(["bookmark", "rename", "blocal", "blocal1"]); 657 insta::assert_snapshot!(output, @""); 658} 659 660#[test] 661fn test_bookmark_forget_glob() { 662 let test_env = TestEnvironment::default(); 663 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 664 let work_dir = test_env.work_dir("repo"); 665 666 work_dir 667 .run_jj(["bookmark", "create", "-r@", "foo-1"]) 668 .success(); 669 work_dir 670 .run_jj(["bookmark", "create", "-r@", "bar-2"]) 671 .success(); 672 work_dir 673 .run_jj(["bookmark", "create", "-r@", "foo-3"]) 674 .success(); 675 work_dir 676 .run_jj(["bookmark", "create", "-r@", "foo-4"]) 677 .success(); 678 679 insta::assert_snapshot!(get_log_output(&work_dir), @r" 680 @ bar-2 foo-1 foo-3 foo-4 230dd059e1b0 681 ◆ 000000000000 682 [EOF] 683 "); 684 let output = work_dir.run_jj(["bookmark", "forget", "glob:foo-[1-3]"]); 685 insta::assert_snapshot!(output, @r" 686 ------- stderr ------- 687 Forgot 2 local bookmarks. 688 [EOF] 689 "); 690 work_dir.run_jj(["undo"]).success(); 691 let output = work_dir.run_jj(["bookmark", "forget", "glob:foo-[1-3]"]); 692 insta::assert_snapshot!(output, @r" 693 ------- stderr ------- 694 Forgot 2 local bookmarks. 695 [EOF] 696 "); 697 insta::assert_snapshot!(get_log_output(&work_dir), @r" 698 @ bar-2 foo-4 230dd059e1b0 699 ◆ 000000000000 700 [EOF] 701 "); 702 703 // Forgetting a bookmark via both explicit name and glob pattern, or with 704 // multiple glob patterns, shouldn't produce an error. 705 let output = work_dir.run_jj(["bookmark", "forget", "foo-4", "glob:foo-*", "glob:foo-*"]); 706 insta::assert_snapshot!(output, @r" 707 ------- stderr ------- 708 Forgot 1 local bookmarks. 709 [EOF] 710 "); 711 insta::assert_snapshot!(get_log_output(&work_dir), @r" 712 @ bar-2 230dd059e1b0 713 ◆ 000000000000 714 [EOF] 715 "); 716 717 // Malformed glob 718 let output = work_dir.run_jj(["bookmark", "forget", "glob:foo-[1-3"]); 719 insta::assert_snapshot!(output, @r" 720 ------- stderr ------- 721 error: invalid value 'glob:foo-[1-3' for '<NAMES>...': Pattern syntax error near position 4: invalid range pattern 722 723 For more information, try '--help'. 724 [EOF] 725 [exit status: 2] 726 "); 727 728 // We get an error if none of the globs match anything 729 let output = work_dir.run_jj(["bookmark", "forget", "glob:bar*", "glob:baz*", "glob:boom*"]); 730 insta::assert_snapshot!(output, @r" 731 ------- stderr ------- 732 Error: No matching bookmarks for patterns: baz*, boom* 733 [EOF] 734 [exit status: 1] 735 "); 736} 737 738#[test] 739fn test_bookmark_delete_glob() { 740 // Set up a git repo with a bookmark and a jj repo that has it as a remote. 741 let test_env = TestEnvironment::default(); 742 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 743 let work_dir = test_env.work_dir("repo"); 744 let git_repo_path = test_env.env_root().join("git-repo"); 745 let git_repo = git::init_bare(git_repo_path); 746 let blob_oid = git_repo.write_blob(b"content").unwrap(); 747 let mut tree_editor = git_repo 748 .edit_tree(gix::ObjectId::empty_tree(gix::hash::Kind::default())) 749 .unwrap(); 750 tree_editor 751 .upsert("file", gix::object::tree::EntryKind::Blob, blob_oid) 752 .unwrap(); 753 let _tree_id = tree_editor.write().unwrap(); 754 work_dir 755 .run_jj(["git", "remote", "add", "origin", "../git-repo"]) 756 .success(); 757 758 work_dir.run_jj(["describe", "-m=commit"]).success(); 759 work_dir 760 .run_jj(["bookmark", "create", "-r@", "foo-1"]) 761 .success(); 762 work_dir 763 .run_jj(["bookmark", "create", "-r@", "bar-2"]) 764 .success(); 765 work_dir 766 .run_jj(["bookmark", "create", "-r@", "foo-3"]) 767 .success(); 768 work_dir 769 .run_jj(["bookmark", "create", "-r@", "foo-4"]) 770 .success(); 771 // Push to create remote-tracking bookmarks 772 work_dir.run_jj(["git", "push", "--all"]).success(); 773 774 insta::assert_snapshot!(get_log_output(&work_dir), @r" 775 @ bar-2 foo-1 foo-3 foo-4 312a98d6f27b 776 ◆ 000000000000 777 [EOF] 778 "); 779 let output = work_dir.run_jj(["bookmark", "delete", "glob:foo-[1-3]"]); 780 insta::assert_snapshot!(output, @r" 781 ------- stderr ------- 782 Deleted 2 bookmarks. 783 [EOF] 784 "); 785 work_dir.run_jj(["undo"]).success(); 786 let output = work_dir.run_jj(["bookmark", "delete", "glob:foo-[1-3]"]); 787 insta::assert_snapshot!(output, @r" 788 ------- stderr ------- 789 Deleted 2 bookmarks. 790 [EOF] 791 "); 792 insta::assert_snapshot!(get_log_output(&work_dir), @r" 793 @ bar-2 foo-1@origin foo-3@origin foo-4 312a98d6f27b 794 ◆ 000000000000 795 [EOF] 796 "); 797 798 // We get an error if none of the globs match live bookmarks. Unlike `jj 799 // bookmark forget`, it's not allowed to delete already deleted bookmarks. 800 let output = work_dir.run_jj(["bookmark", "delete", "glob:foo-[1-3]"]); 801 insta::assert_snapshot!(output, @r" 802 ------- stderr ------- 803 Error: No matching bookmarks for patterns: foo-[1-3] 804 [EOF] 805 [exit status: 1] 806 "); 807 808 // Deleting a bookmark via both explicit name and glob pattern, or with 809 // multiple glob patterns, shouldn't produce an error. 810 let output = work_dir.run_jj(["bookmark", "delete", "foo-4", "glob:foo-*", "glob:foo-*"]); 811 insta::assert_snapshot!(output, @r" 812 ------- stderr ------- 813 Deleted 1 bookmarks. 814 [EOF] 815 "); 816 insta::assert_snapshot!(get_log_output(&work_dir), @r" 817 @ bar-2 foo-1@origin foo-3@origin foo-4@origin 312a98d6f27b 818 ◆ 000000000000 819 [EOF] 820 "); 821 822 // The deleted bookmarks are still there 823 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 824 bar-2: qpvuntsm 312a98d6 (empty) commit 825 @origin: qpvuntsm 312a98d6 (empty) commit 826 foo-1 (deleted) 827 @origin: qpvuntsm 312a98d6 (empty) commit 828 foo-3 (deleted) 829 @origin: qpvuntsm 312a98d6 (empty) commit 830 foo-4 (deleted) 831 @origin: qpvuntsm 312a98d6 (empty) commit 832 [EOF] 833 "); 834 835 // Malformed glob 836 let output = work_dir.run_jj(["bookmark", "delete", "glob:foo-[1-3"]); 837 insta::assert_snapshot!(output, @r" 838 ------- stderr ------- 839 error: invalid value 'glob:foo-[1-3' for '<NAMES>...': Pattern syntax error near position 4: invalid range pattern 840 841 For more information, try '--help'. 842 [EOF] 843 [exit status: 2] 844 "); 845 846 // Unknown pattern kind 847 let output = work_dir.run_jj(["bookmark", "forget", "whatever:bookmark"]); 848 insta::assert_snapshot!(output, @r" 849 ------- stderr ------- 850 error: invalid value 'whatever:bookmark' for '<NAMES>...': Invalid string pattern kind `whatever:` 851 852 For more information, try '--help'. 853 Hint: Try prefixing with one of `exact:`, `glob:`, `regex:`, `substring:`, or one of these with `-i` suffix added (e.g. `glob-i:`) for case-insensitive matching 854 [EOF] 855 [exit status: 2] 856 "); 857} 858 859#[test] 860fn test_bookmark_delete_export() { 861 let test_env = TestEnvironment::default(); 862 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 863 let work_dir = test_env.work_dir("repo"); 864 865 work_dir.run_jj(["new"]).success(); 866 work_dir 867 .run_jj(["bookmark", "create", "-r@", "foo"]) 868 .success(); 869 work_dir.run_jj(["git", "export"]).success(); 870 871 work_dir.run_jj(["bookmark", "delete", "foo"]).success(); 872 let output = work_dir.run_jj(["bookmark", "list", "--all-remotes"]); 873 insta::assert_snapshot!(output, @r" 874 foo (deleted) 875 @git: rlvkpnrz 65b6b74e (empty) (no description set) 876 [EOF] 877 ------- stderr ------- 878 Hint: Bookmarks marked as deleted will be deleted from the underlying Git repo on the next `jj git export`. 879 [EOF] 880 "); 881 882 work_dir.run_jj(["git", "export"]).success(); 883 insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); 884} 885 886#[test] 887fn test_bookmark_forget_export() { 888 let test_env = TestEnvironment::default(); 889 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 890 let work_dir = test_env.work_dir("repo"); 891 892 work_dir.run_jj(["new"]).success(); 893 work_dir 894 .run_jj(["bookmark", "create", "-r@", "foo"]) 895 .success(); 896 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 897 foo: rlvkpnrz 65b6b74e (empty) (no description set) 898 [EOF] 899 "); 900 901 // Exporting the bookmark to git creates a local-git tracking bookmark 902 let output = work_dir.run_jj(["git", "export"]); 903 insta::assert_snapshot!(output, @""); 904 let output = work_dir.run_jj(["bookmark", "forget", "--include-remotes", "foo"]); 905 insta::assert_snapshot!(output, @r" 906 ------- stderr ------- 907 Forgot 1 local bookmarks. 908 Forgot 1 remote bookmarks. 909 [EOF] 910 "); 911 // Forgetting a bookmark with --include-remotes deletes local and 912 // remote-tracking bookmarks including the corresponding git-tracking bookmark. 913 insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); 914 let output = work_dir.run_jj(["log", "-r=foo", "--no-graph"]); 915 insta::assert_snapshot!(output, @r" 916 ------- stderr ------- 917 Error: Revision `foo` doesn't exist 918 [EOF] 919 [exit status: 1] 920 "); 921 922 // `jj git export` will delete the bookmark from git. In a colocated repo, 923 // this will happen automatically immediately after a `jj bookmark forget`. 924 // This is demonstrated in `test_git_colocated_bookmark_forget` in 925 // test_git_colocated.rs 926 let output = work_dir.run_jj(["git", "export"]); 927 insta::assert_snapshot!(output, @""); 928 insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); 929} 930 931#[test] 932fn test_bookmark_forget_fetched_bookmark() { 933 // Much of this test is borrowed from `test_git_fetch_remote_only_bookmark` in 934 // test_git_fetch.rs 935 936 // Set up a git repo with a bookmark and a jj repo that has it as a remote. 937 let test_env = TestEnvironment::default(); 938 test_env.add_config("git.auto-local-bookmark = true"); 939 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 940 let work_dir = test_env.work_dir("repo"); 941 let git_repo_path = test_env.env_root().join("git-repo"); 942 let git_repo = git::init_bare(git_repo_path); 943 work_dir 944 .run_jj(["git", "remote", "add", "origin", "../git-repo"]) 945 .success(); 946 // Create a commit and a bookmark in the git repo 947 let git::CommitResult { 948 tree_id, 949 commit_id: first_git_repo_commit, 950 } = git::add_commit( 951 &git_repo, 952 "refs/heads/feature1", 953 "file", 954 b"content", 955 "message", 956 &[], 957 ); 958 959 // Fetch normally 960 work_dir 961 .run_jj(["git", "fetch", "--remote=origin"]) 962 .success(); 963 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 964 feature1: qomsplrm ebeb70d8 message 965 @origin: qomsplrm ebeb70d8 message 966 [EOF] 967 "); 968 969 // TEST 1: with export-import 970 // Forget the bookmark with --include-remotes 971 work_dir 972 .run_jj(["bookmark", "forget", "--include-remotes", "feature1"]) 973 .success(); 974 insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); 975 976 // At this point `jj git export && jj git import` does *not* recreate the 977 // bookmark. This behavior is important in colocated repos, as otherwise a 978 // forgotten bookmark would be immediately resurrected. 979 // 980 // Technically, this is because `jj bookmark forget` preserved 981 // the ref in jj view's `git_refs` tracking the local git repo's remote-tracking 982 // bookmark. 983 // TODO: Show that jj git push is also a no-op 984 let output = work_dir.run_jj(["git", "export"]); 985 insta::assert_snapshot!(output, @""); 986 let output = work_dir.run_jj(["git", "import"]); 987 insta::assert_snapshot!(output, @r" 988 ------- stderr ------- 989 Nothing changed. 990 [EOF] 991 "); 992 insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); 993 994 // We can fetch feature1 again. 995 let output = work_dir.run_jj(["git", "fetch", "--remote=origin"]); 996 insta::assert_snapshot!(output, @r" 997 ------- stderr ------- 998 bookmark: feature1@origin [new] tracked 999 [EOF] 1000 "); 1001 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1002 feature1: qomsplrm ebeb70d8 message 1003 @origin: qomsplrm ebeb70d8 message 1004 [EOF] 1005 "); 1006 1007 // TEST 2: No export/import (otherwise the same as test 1) 1008 work_dir 1009 .run_jj(["bookmark", "forget", "--include-remotes", "feature1"]) 1010 .success(); 1011 insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); 1012 // Fetch works even without the export-import 1013 let output = work_dir.run_jj(["git", "fetch", "--remote=origin"]); 1014 insta::assert_snapshot!(output, @r" 1015 ------- stderr ------- 1016 bookmark: feature1@origin [new] tracked 1017 [EOF] 1018 "); 1019 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1020 feature1: qomsplrm ebeb70d8 message 1021 @origin: qomsplrm ebeb70d8 message 1022 [EOF] 1023 "); 1024 1025 // TEST 3: fetch bookmark that was moved & forgotten with --include-remotes 1026 1027 // Move the bookmark in the git repo. 1028 git::write_commit( 1029 &git_repo, 1030 "refs/heads/feature1", 1031 tree_id, 1032 "another message", 1033 &[first_git_repo_commit], 1034 ); 1035 let output = work_dir.run_jj(["bookmark", "forget", "--include-remotes", "feature1"]); 1036 insta::assert_snapshot!(output, @r" 1037 ------- stderr ------- 1038 Forgot 1 local bookmarks. 1039 Forgot 1 remote bookmarks. 1040 [EOF] 1041 "); 1042 1043 // Fetching a moved bookmark does not create a conflict 1044 let output = work_dir.run_jj(["git", "fetch", "--remote=origin"]); 1045 insta::assert_snapshot!(output, @r" 1046 ------- stderr ------- 1047 bookmark: feature1@origin [new] tracked 1048 [EOF] 1049 "); 1050 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1051 feature1: tyvxnvqr 9175cb32 (empty) another message 1052 @origin: tyvxnvqr 9175cb32 (empty) another message 1053 [EOF] 1054 "); 1055 1056 // TEST 4: If `--include-remotes` isn't used, remote bookmarks are untracked 1057 work_dir 1058 .run_jj(["bookmark", "forget", "feature1"]) 1059 .success(); 1060 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1061 feature1@origin: tyvxnvqr 9175cb32 (empty) another message 1062 [EOF] 1063 "); 1064 // There should be no output here since the remote bookmark wasn't forgotten 1065 let output = work_dir.run_jj(["git", "fetch", "--remote=origin"]); 1066 insta::assert_snapshot!(output, @r" 1067 ------- stderr ------- 1068 Nothing changed. 1069 [EOF] 1070 "); 1071 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1072 feature1@origin: tyvxnvqr 9175cb32 (empty) another message 1073 [EOF] 1074 "); 1075} 1076 1077#[test] 1078fn test_bookmark_forget_deleted_or_nonexistent_bookmark() { 1079 // Much of this test is borrowed from `test_git_fetch_remote_only_bookmark` in 1080 // test_git_fetch.rs 1081 1082 // ======== Beginning of test setup ======== 1083 // Set up a git repo with a bookmark and a jj repo that has it as a remote. 1084 let test_env = TestEnvironment::default(); 1085 test_env.add_config("git.auto-local-bookmark = true"); 1086 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1087 let work_dir = test_env.work_dir("repo"); 1088 let git_repo_path = test_env.env_root().join("git-repo"); 1089 let git_repo = git::init_bare(git_repo_path); 1090 // Create a commit and a bookmark in the git repo 1091 git::add_commit( 1092 &git_repo, 1093 "refs/heads/feature1", 1094 "file", 1095 b"content", 1096 "message", 1097 &[], 1098 ); 1099 work_dir 1100 .run_jj(["git", "remote", "add", "origin", "../git-repo"]) 1101 .success(); 1102 1103 // Fetch and then delete the bookmark 1104 work_dir 1105 .run_jj(["git", "fetch", "--remote=origin"]) 1106 .success(); 1107 work_dir 1108 .run_jj(["bookmark", "delete", "feature1"]) 1109 .success(); 1110 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1111 feature1 (deleted) 1112 @origin: qomsplrm ebeb70d8 message 1113 [EOF] 1114 "); 1115 1116 // ============ End of test setup ============ 1117 1118 // We can forget a deleted bookmark 1119 work_dir 1120 .run_jj(["bookmark", "forget", "--include-remotes", "feature1"]) 1121 .success(); 1122 insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); 1123 1124 // Can't forget a non-existent bookmark 1125 let output = work_dir.run_jj(["bookmark", "forget", "i_do_not_exist"]); 1126 insta::assert_snapshot!(output, @r" 1127 ------- stderr ------- 1128 Error: No such bookmark: i_do_not_exist 1129 [EOF] 1130 [exit status: 1] 1131 "); 1132} 1133 1134#[test] 1135fn test_bookmark_track_untrack() { 1136 let test_env = TestEnvironment::default(); 1137 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1138 let work_dir = test_env.work_dir("repo"); 1139 1140 // Set up remote 1141 let git_repo_path = test_env.env_root().join("git-repo"); 1142 let git_repo = git::init(git_repo_path); 1143 work_dir 1144 .run_jj(["git", "remote", "add", "origin", "../git-repo"]) 1145 .success(); 1146 1147 // Fetch new commit without auto tracking. No local bookmarks should be 1148 // created. 1149 create_commit_with_refs( 1150 &git_repo, 1151 "commit 1", 1152 b"content 1", 1153 &[ 1154 "refs/heads/main", 1155 "refs/heads/feature1", 1156 "refs/heads/feature2", 1157 ], 1158 ); 1159 test_env.add_config("git.auto-local-bookmark = false"); 1160 let output = work_dir.run_jj(["git", "fetch"]); 1161 insta::assert_snapshot!(output, @r" 1162 ------- stderr ------- 1163 bookmark: feature1@origin [new] untracked 1164 bookmark: feature2@origin [new] untracked 1165 bookmark: main@origin [new] untracked 1166 [EOF] 1167 "); 1168 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1169 feature1@origin: qxxqrkql bd843888 commit 1 1170 feature2@origin: qxxqrkql bd843888 commit 1 1171 main@origin: qxxqrkql bd843888 commit 1 1172 [EOF] 1173 "); 1174 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1175 @ 230dd059e1b0 1176 │ ◆ feature1@origin feature2@origin main@origin bd843888ee66 1177 ├─╯ 1178 ◆ 000000000000 1179 [EOF] 1180 "); 1181 1182 // Track new bookmark. Local bookmark should be created. 1183 work_dir 1184 .run_jj(["bookmark", "track", "feature1@origin", "main@origin"]) 1185 .success(); 1186 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1187 feature1: qxxqrkql bd843888 commit 1 1188 @origin: qxxqrkql bd843888 commit 1 1189 feature2@origin: qxxqrkql bd843888 commit 1 1190 main: qxxqrkql bd843888 commit 1 1191 @origin: qxxqrkql bd843888 commit 1 1192 [EOF] 1193 "); 1194 1195 // Track existing bookmark. Local bookmark should result in conflict. 1196 work_dir 1197 .run_jj(["bookmark", "create", "-r@", "feature2"]) 1198 .success(); 1199 work_dir 1200 .run_jj(["bookmark", "track", "feature2@origin"]) 1201 .success(); 1202 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1203 feature1: qxxqrkql bd843888 commit 1 1204 @origin: qxxqrkql bd843888 commit 1 1205 feature2 (conflicted): 1206 + qpvuntsm 230dd059 (empty) (no description set) 1207 + qxxqrkql bd843888 commit 1 1208 @origin (behind by 1 commits): qxxqrkql bd843888 commit 1 1209 main: qxxqrkql bd843888 commit 1 1210 @origin: qxxqrkql bd843888 commit 1 1211 [EOF] 1212 "); 1213 1214 // Untrack existing and locally-deleted bookmarks. Bookmark targets should be 1215 // unchanged 1216 work_dir 1217 .run_jj(["bookmark", "delete", "feature2"]) 1218 .success(); 1219 work_dir 1220 .run_jj(["bookmark", "untrack", "feature1@origin", "feature2@origin"]) 1221 .success(); 1222 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1223 feature1: qxxqrkql bd843888 commit 1 1224 feature1@origin: qxxqrkql bd843888 commit 1 1225 feature2@origin: qxxqrkql bd843888 commit 1 1226 main: qxxqrkql bd843888 commit 1 1227 @origin: qxxqrkql bd843888 commit 1 1228 [EOF] 1229 "); 1230 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1231 @ 230dd059e1b0 1232 │ ◆ feature1 feature1@origin feature2@origin main bd843888ee66 1233 ├─╯ 1234 ◆ 000000000000 1235 [EOF] 1236 "); 1237 1238 // Fetch new commit. Only tracking bookmark "main" should be merged. 1239 create_commit_with_refs( 1240 &git_repo, 1241 "commit 2", 1242 b"content 2", 1243 &[ 1244 "refs/heads/main", 1245 "refs/heads/feature1", 1246 "refs/heads/feature2", 1247 ], 1248 ); 1249 let output = work_dir.run_jj(["git", "fetch"]); 1250 insta::assert_snapshot!(output, @r" 1251 ------- stderr ------- 1252 bookmark: feature1@origin [updated] untracked 1253 bookmark: feature2@origin [updated] untracked 1254 bookmark: main@origin [updated] tracked 1255 [EOF] 1256 "); 1257 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1258 feature1: qxxqrkql bd843888 commit 1 1259 feature1@origin: psynomvr 48ec79a4 commit 2 1260 feature2@origin: psynomvr 48ec79a4 commit 2 1261 main: psynomvr 48ec79a4 commit 2 1262 @origin: psynomvr 48ec79a4 commit 2 1263 [EOF] 1264 "); 1265 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1266 @ 230dd059e1b0 1267 │ ◆ feature1@origin feature2@origin main 48ec79a430e9 1268 ├─╯ 1269 │ ○ feature1 bd843888ee66 1270 ├─╯ 1271 ◆ 000000000000 1272 [EOF] 1273 "); 1274 1275 // Fetch new commit with auto tracking. Tracking bookmark "main" and new 1276 // bookmark "feature3" should be merged. 1277 create_commit_with_refs( 1278 &git_repo, 1279 "commit 3", 1280 b"content 3", 1281 &[ 1282 "refs/heads/main", 1283 "refs/heads/feature1", 1284 "refs/heads/feature2", 1285 "refs/heads/feature3", 1286 ], 1287 ); 1288 test_env.add_config("git.auto-local-bookmark = true"); 1289 let output = work_dir.run_jj(["git", "fetch"]); 1290 insta::assert_snapshot!(output, @r" 1291 ------- stderr ------- 1292 bookmark: feature1@origin [updated] untracked 1293 bookmark: feature2@origin [updated] untracked 1294 bookmark: feature3@origin [new] tracked 1295 bookmark: main@origin [updated] tracked 1296 Abandoned 1 commits that are no longer reachable. 1297 [EOF] 1298 "); 1299 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1300 feature1: qxxqrkql bd843888 commit 1 1301 feature1@origin: yumopmsr d8cd3e02 commit 3 1302 feature2@origin: yumopmsr d8cd3e02 commit 3 1303 feature3: yumopmsr d8cd3e02 commit 3 1304 @origin: yumopmsr d8cd3e02 commit 3 1305 main: yumopmsr d8cd3e02 commit 3 1306 @origin: yumopmsr d8cd3e02 commit 3 1307 [EOF] 1308 "); 1309 insta::assert_snapshot!(get_log_output(&work_dir), @r" 1310 @ 230dd059e1b0 1311 │ ◆ feature1@origin feature2@origin feature3 main d8cd3e020382 1312 ├─╯ 1313 │ ○ feature1 bd843888ee66 1314 ├─╯ 1315 ◆ 000000000000 1316 [EOF] 1317 "); 1318} 1319 1320#[test] 1321fn test_bookmark_track_conflict() { 1322 let test_env = TestEnvironment::default(); 1323 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1324 let work_dir = test_env.work_dir("repo"); 1325 1326 let git_repo_path = test_env.env_root().join("git-repo"); 1327 git::init_bare(git_repo_path); 1328 work_dir 1329 .run_jj(["git", "remote", "add", "origin", "../git-repo"]) 1330 .success(); 1331 work_dir 1332 .run_jj(["bookmark", "create", "-r@", "main"]) 1333 .success(); 1334 work_dir.run_jj(["describe", "-m", "a"]).success(); 1335 work_dir 1336 .run_jj(["git", "push", "--allow-new", "-b", "main"]) 1337 .success(); 1338 work_dir 1339 .run_jj(["bookmark", "untrack", "main@origin"]) 1340 .success(); 1341 work_dir 1342 .run_jj(["describe", "-m", "b", "-r", "main", "--ignore-immutable"]) 1343 .success(); 1344 let output = work_dir.run_jj(["bookmark", "track", "main@origin"]); 1345 insta::assert_snapshot!(output, @r" 1346 ------- stderr ------- 1347 Started tracking 1 remote bookmarks. 1348 main (conflicted): 1349 + qpvuntsm?? e802c4f8 (empty) b 1350 + qpvuntsm?? 427890ea (empty) a 1351 @origin (behind by 1 commits): qpvuntsm?? 427890ea (empty) a 1352 [EOF] 1353 "); 1354} 1355 1356#[test] 1357fn test_bookmark_track_untrack_patterns() { 1358 let test_env = TestEnvironment::default(); 1359 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 1360 let work_dir = test_env.work_dir("repo"); 1361 1362 // Set up remote 1363 let git_repo_path = test_env.env_root().join("git-repo"); 1364 let git_repo = git::init(git_repo_path); 1365 work_dir 1366 .run_jj(["git", "remote", "add", "origin", "../git-repo"]) 1367 .success(); 1368 1369 // Create remote commit 1370 create_commit_with_refs( 1371 &git_repo, 1372 "commit", 1373 b"content", 1374 &["refs/heads/feature1", "refs/heads/feature2"], 1375 ); 1376 1377 // Fetch new commit without auto tracking 1378 test_env.add_config("git.auto-local-bookmark = false"); 1379 let output = work_dir.run_jj(["git", "fetch"]); 1380 insta::assert_snapshot!(output, @r" 1381 ------- stderr ------- 1382 bookmark: feature1@origin [new] untracked 1383 bookmark: feature2@origin [new] untracked 1384 [EOF] 1385 "); 1386 1387 // Track local bookmark 1388 work_dir 1389 .run_jj(["bookmark", "create", "-r@", "main"]) 1390 .success(); 1391 insta::assert_snapshot!(work_dir.run_jj(["bookmark", "track", "main"]), @r" 1392 ------- stderr ------- 1393 error: invalid value 'main' for '<BOOKMARK@REMOTE>...': remote bookmark must be specified in bookmark@remote form 1394 1395 For more information, try '--help'. 1396 [EOF] 1397 [exit status: 2] 1398 "); 1399 1400 // Track/untrack unknown bookmark 1401 insta::assert_snapshot!(work_dir.run_jj(["bookmark", "track", "main@origin"]), @r" 1402 ------- stderr ------- 1403 Error: No such remote bookmark: main@origin 1404 [EOF] 1405 [exit status: 1] 1406 "); 1407 insta::assert_snapshot!(work_dir.run_jj(["bookmark", "untrack", "main@origin"]), @r" 1408 ------- stderr ------- 1409 Error: No such remote bookmark: main@origin 1410 [EOF] 1411 [exit status: 1] 1412 "); 1413 insta::assert_snapshot!(work_dir.run_jj(["bookmark", "track", "glob:maine@*"]), @r" 1414 ------- stderr ------- 1415 Error: No matching remote bookmarks for patterns: maine@* 1416 [EOF] 1417 [exit status: 1] 1418 "); 1419 insta::assert_snapshot!( 1420 work_dir.run_jj(["bookmark", "untrack", "main@origin", "glob:main@o*"]), @r" 1421 ------- stderr ------- 1422 Error: No matching remote bookmarks for patterns: main@origin, main@o* 1423 [EOF] 1424 [exit status: 1] 1425 "); 1426 1427 // Track already tracked bookmark 1428 work_dir 1429 .run_jj(["bookmark", "track", "feature1@origin"]) 1430 .success(); 1431 let output = work_dir.run_jj(["bookmark", "track", "feature1@origin"]); 1432 insta::assert_snapshot!(output, @r" 1433 ------- stderr ------- 1434 Warning: Remote bookmark already tracked: feature1@origin 1435 Nothing changed. 1436 [EOF] 1437 "); 1438 1439 // Untrack non-tracking bookmark 1440 let output = work_dir.run_jj(["bookmark", "untrack", "feature2@origin"]); 1441 insta::assert_snapshot!(output, @r" 1442 ------- stderr ------- 1443 Warning: Remote bookmark not tracked yet: feature2@origin 1444 Nothing changed. 1445 [EOF] 1446 "); 1447 1448 // Untrack Git-tracking bookmark 1449 work_dir.run_jj(["git", "export"]).success(); 1450 let output = work_dir.run_jj(["bookmark", "untrack", "main@git"]); 1451 insta::assert_snapshot!(output, @r" 1452 ------- stderr ------- 1453 Warning: Git-tracking bookmark cannot be untracked: main@git 1454 Nothing changed. 1455 [EOF] 1456 "); 1457 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1458 feature1: yrnqsqlx 41e7a49d commit 1459 @git: yrnqsqlx 41e7a49d commit 1460 @origin: yrnqsqlx 41e7a49d commit 1461 feature2@origin: yrnqsqlx 41e7a49d commit 1462 main: qpvuntsm 230dd059 (empty) (no description set) 1463 @git: qpvuntsm 230dd059 (empty) (no description set) 1464 [EOF] 1465 "); 1466 1467 // Untrack by pattern 1468 let output = work_dir.run_jj(["bookmark", "untrack", "glob:*@*"]); 1469 insta::assert_snapshot!(output, @r" 1470 ------- stderr ------- 1471 Warning: Git-tracking bookmark cannot be untracked: feature1@git 1472 Warning: Remote bookmark not tracked yet: feature2@origin 1473 Warning: Git-tracking bookmark cannot be untracked: main@git 1474 Stopped tracking 1 remote bookmarks. 1475 [EOF] 1476 "); 1477 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1478 feature1: yrnqsqlx 41e7a49d commit 1479 @git: yrnqsqlx 41e7a49d commit 1480 feature1@origin: yrnqsqlx 41e7a49d commit 1481 feature2@origin: yrnqsqlx 41e7a49d commit 1482 main: qpvuntsm 230dd059 (empty) (no description set) 1483 @git: qpvuntsm 230dd059 (empty) (no description set) 1484 [EOF] 1485 "); 1486 1487 // Track by pattern 1488 let output = work_dir.run_jj(["bookmark", "track", "glob:feature?@origin"]); 1489 insta::assert_snapshot!(output, @r" 1490 ------- stderr ------- 1491 Started tracking 2 remote bookmarks. 1492 [EOF] 1493 "); 1494 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 1495 feature1: yrnqsqlx 41e7a49d commit 1496 @git: yrnqsqlx 41e7a49d commit 1497 @origin: yrnqsqlx 41e7a49d commit 1498 feature2: yrnqsqlx 41e7a49d commit 1499 @origin: yrnqsqlx 41e7a49d commit 1500 main: qpvuntsm 230dd059 (empty) (no description set) 1501 @git: qpvuntsm 230dd059 (empty) (no description set) 1502 [EOF] 1503 "); 1504} 1505 1506#[test] 1507fn test_bookmark_list() { 1508 let test_env = TestEnvironment::default(); 1509 test_env.add_config("git.auto-local-bookmark = true"); 1510 1511 // Initialize remote refs 1512 test_env.run_jj_in(".", ["git", "init", "remote"]).success(); 1513 let remote_dir = test_env.work_dir("remote"); 1514 for bookmark in [ 1515 "remote-sync", 1516 "remote-unsync", 1517 "remote-untrack", 1518 "remote-delete", 1519 ] { 1520 remote_dir 1521 .run_jj(["new", "root()", "-m", bookmark]) 1522 .success(); 1523 remote_dir 1524 .run_jj(["bookmark", "create", "-r@", bookmark]) 1525 .success(); 1526 } 1527 remote_dir.run_jj(["new"]).success(); 1528 remote_dir.run_jj(["git", "export"]).success(); 1529 1530 // Initialize local refs 1531 let mut remote_git_path = remote_dir.root().to_owned(); 1532 remote_git_path.extend([".jj", "repo", "store", "git"]); 1533 test_env 1534 .run_jj_in( 1535 ".", 1536 ["git", "clone", remote_git_path.to_str().unwrap(), "local"], 1537 ) 1538 .success(); 1539 let local_dir = test_env.work_dir("local"); 1540 local_dir 1541 .run_jj(["new", "root()", "-m", "local-only"]) 1542 .success(); 1543 local_dir 1544 .run_jj(["bookmark", "create", "-r@", "local-only"]) 1545 .success(); 1546 1547 // Mutate refs in local repository 1548 local_dir 1549 .run_jj(["bookmark", "delete", "remote-delete"]) 1550 .success(); 1551 local_dir 1552 .run_jj(["bookmark", "delete", "remote-untrack"]) 1553 .success(); 1554 local_dir 1555 .run_jj(["bookmark", "untrack", "remote-untrack@origin"]) 1556 .success(); 1557 local_dir 1558 .run_jj([ 1559 "bookmark", 1560 "set", 1561 "--allow-backwards", 1562 "--to=@", 1563 "remote-unsync", 1564 ]) 1565 .success(); 1566 1567 // Synchronized tracking remotes and non-tracking remotes aren't listed by 1568 // default 1569 let output = local_dir.run_jj(["bookmark", "list"]); 1570 insta::assert_snapshot!(output, @r" 1571 local-only: wqnwkozp 4e887f78 (empty) local-only 1572 remote-delete (deleted) 1573 @origin: mnmymoky 203e60eb (empty) remote-delete 1574 remote-sync: zwtyzrop c761c7ea (empty) remote-sync 1575 remote-unsync: wqnwkozp 4e887f78 (empty) local-only 1576 @origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 1577 [EOF] 1578 ------- stderr ------- 1579 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 1580 [EOF] 1581 "); 1582 1583 let output = local_dir.run_jj(["bookmark", "list", "--all-remotes"]); 1584 insta::assert_snapshot!(output, @r" 1585 local-only: wqnwkozp 4e887f78 (empty) local-only 1586 remote-delete (deleted) 1587 @origin: mnmymoky 203e60eb (empty) remote-delete 1588 remote-sync: zwtyzrop c761c7ea (empty) remote-sync 1589 @origin: zwtyzrop c761c7ea (empty) remote-sync 1590 remote-unsync: wqnwkozp 4e887f78 (empty) local-only 1591 @origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 1592 remote-untrack@origin: vmortlor 71a16b05 (empty) remote-untrack 1593 [EOF] 1594 ------- stderr ------- 1595 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 1596 [EOF] 1597 "); 1598 1599 let template = r#" 1600 concat( 1601 "[" ++ name ++ if(remote, "@" ++ remote) ++ "]\n", 1602 separate(" ", "present:", present) ++ "\n", 1603 separate(" ", "conflict:", conflict) ++ "\n", 1604 separate(" ", "normal_target:", normal_target.description().first_line()) ++ "\n", 1605 separate(" ", "removed_targets:", removed_targets.map(|c| c.description().first_line())) ++ "\n", 1606 separate(" ", "added_targets:", added_targets.map(|c| c.description().first_line())) ++ "\n", 1607 separate(" ", "tracked:", tracked) ++ "\n", 1608 separate(" ", "tracking_present:", tracking_present) ++ "\n", 1609 separate(" ", "tracking_ahead_count:", tracking_ahead_count.lower()) ++ "\n", 1610 separate(" ", "tracking_behind_count:", tracking_behind_count.lower()) ++ "\n", 1611 ) 1612 "#; 1613 let output = local_dir.run_jj(["bookmark", "list", "--all-remotes", "-T", template]); 1614 insta::assert_snapshot!(output, @r" 1615 [local-only] 1616 present: true 1617 conflict: false 1618 normal_target: local-only 1619 removed_targets: 1620 added_targets: local-only 1621 tracked: false 1622 tracking_present: false 1623 tracking_ahead_count: <Error: Not a tracked remote ref> 1624 tracking_behind_count: <Error: Not a tracked remote ref> 1625 [remote-delete] 1626 present: false 1627 conflict: false 1628 normal_target: <Error: No Commit available> 1629 removed_targets: 1630 added_targets: 1631 tracked: false 1632 tracking_present: false 1633 tracking_ahead_count: <Error: Not a tracked remote ref> 1634 tracking_behind_count: <Error: Not a tracked remote ref> 1635 [remote-delete@origin] 1636 present: true 1637 conflict: false 1638 normal_target: remote-delete 1639 removed_targets: 1640 added_targets: remote-delete 1641 tracked: true 1642 tracking_present: false 1643 tracking_ahead_count: 2 1644 tracking_behind_count: 0 1645 [remote-sync] 1646 present: true 1647 conflict: false 1648 normal_target: remote-sync 1649 removed_targets: 1650 added_targets: remote-sync 1651 tracked: false 1652 tracking_present: false 1653 tracking_ahead_count: <Error: Not a tracked remote ref> 1654 tracking_behind_count: <Error: Not a tracked remote ref> 1655 [remote-sync@origin] 1656 present: true 1657 conflict: false 1658 normal_target: remote-sync 1659 removed_targets: 1660 added_targets: remote-sync 1661 tracked: true 1662 tracking_present: true 1663 tracking_ahead_count: 0 1664 tracking_behind_count: 0 1665 [remote-unsync] 1666 present: true 1667 conflict: false 1668 normal_target: local-only 1669 removed_targets: 1670 added_targets: local-only 1671 tracked: false 1672 tracking_present: false 1673 tracking_ahead_count: <Error: Not a tracked remote ref> 1674 tracking_behind_count: <Error: Not a tracked remote ref> 1675 [remote-unsync@origin] 1676 present: true 1677 conflict: false 1678 normal_target: remote-unsync 1679 removed_targets: 1680 added_targets: remote-unsync 1681 tracked: true 1682 tracking_present: true 1683 tracking_ahead_count: 1 1684 tracking_behind_count: 1 1685 [remote-untrack@origin] 1686 present: true 1687 conflict: false 1688 normal_target: remote-untrack 1689 removed_targets: 1690 added_targets: remote-untrack 1691 tracked: false 1692 tracking_present: false 1693 tracking_ahead_count: <Error: Not a tracked remote ref> 1694 tracking_behind_count: <Error: Not a tracked remote ref> 1695 [EOF] 1696 ------- stderr ------- 1697 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 1698 [EOF] 1699 "); 1700} 1701 1702#[test] 1703fn test_bookmark_list_filtered() { 1704 let test_env = TestEnvironment::default(); 1705 test_env.add_config("git.auto-local-bookmark = true"); 1706 test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); 1707 1708 // Initialize remote refs 1709 test_env.run_jj_in(".", ["git", "init", "remote"]).success(); 1710 let remote_dir = test_env.work_dir("remote"); 1711 for bookmark in ["remote-keep", "remote-delete", "remote-rewrite"] { 1712 remote_dir 1713 .run_jj(["new", "root()", "-m", bookmark]) 1714 .success(); 1715 remote_dir 1716 .run_jj(["bookmark", "create", "-r@", bookmark]) 1717 .success(); 1718 } 1719 remote_dir.run_jj(["new"]).success(); 1720 remote_dir.run_jj(["git", "export"]).success(); 1721 1722 // Initialize local refs 1723 let mut remote_git_path = remote_dir.root().to_owned(); 1724 remote_git_path.extend([".jj", "repo", "store", "git"]); 1725 test_env 1726 .run_jj_in( 1727 ".", 1728 ["git", "clone", remote_git_path.to_str().unwrap(), "local"], 1729 ) 1730 .success(); 1731 let local_dir = test_env.work_dir("local"); 1732 local_dir 1733 .run_jj(["new", "root()", "-m", "local-keep"]) 1734 .success(); 1735 local_dir 1736 .run_jj(["bookmark", "create", "-r@", "local-keep"]) 1737 .success(); 1738 1739 // Mutate refs in local repository 1740 local_dir 1741 .run_jj(["bookmark", "delete", "remote-delete"]) 1742 .success(); 1743 local_dir 1744 .run_jj(["describe", "-mrewritten", "remote-rewrite"]) 1745 .success(); 1746 1747 let template = r#"separate(" ", commit_id.short(), bookmarks, if(hidden, "(hidden)"))"#; 1748 insta::assert_snapshot!( 1749 local_dir.run_jj(["log", "-r::(bookmarks() | remote_bookmarks())", "-T", template]), @r" 1750 @ c7b4c09cd77c local-keep 1751 │ ○ e31634b64294 remote-rewrite* 1752 ├─╯ 1753 │ ○ 3e9a5af6ef15 remote-rewrite@origin (hidden) 1754 ├─╯ 1755 │ ○ dad5f298ca57 remote-delete@origin 1756 ├─╯ 1757 │ ○ 911e912015fb remote-keep 1758 ├─╯ 1759 ◆ 000000000000 1760 [EOF] 1761 "); 1762 1763 // All bookmarks are listed by default. 1764 let output = local_dir.run_jj(["bookmark", "list"]); 1765 insta::assert_snapshot!(output, @r" 1766 local-keep: kpqxywon c7b4c09c (empty) local-keep 1767 remote-delete (deleted) 1768 @origin: yxusvupt dad5f298 (empty) remote-delete 1769 remote-keep: nlwprzpn 911e9120 (empty) remote-keep 1770 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1771 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1772 [EOF] 1773 ------- stderr ------- 1774 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 1775 [EOF] 1776 "); 1777 1778 let query = 1779 |args: &[&str]| local_dir.run_jj_with(|cmd| cmd.args(["bookmark", "list"]).args(args)); 1780 1781 // "all()" doesn't include deleted bookmarks since they have no local targets. 1782 // So "all()" is identical to "bookmarks()". 1783 insta::assert_snapshot!(query(&["-rall()"]), @r" 1784 local-keep: kpqxywon c7b4c09c (empty) local-keep 1785 remote-keep: nlwprzpn 911e9120 (empty) remote-keep 1786 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1787 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1788 [EOF] 1789 "); 1790 1791 // Exclude remote-only bookmarks. "remote-rewrite@origin" is included since 1792 // local "remote-rewrite" target matches. 1793 insta::assert_snapshot!(query(&["-rbookmarks()"]), @r" 1794 local-keep: kpqxywon c7b4c09c (empty) local-keep 1795 remote-keep: nlwprzpn 911e9120 (empty) remote-keep 1796 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1797 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1798 [EOF] 1799 "); 1800 1801 // Select bookmarks by name. 1802 insta::assert_snapshot!(query(&["remote-rewrite"]), @r" 1803 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1804 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1805 [EOF] 1806 "); 1807 insta::assert_snapshot!(query(&["-rbookmarks(remote-rewrite)"]), @r" 1808 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1809 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1810 [EOF] 1811 "); 1812 1813 // Select bookmarks by name, combined with --all-remotes 1814 local_dir.run_jj(["git", "export"]).success(); 1815 insta::assert_snapshot!(query(&["--all-remotes", "remote-rewrite"]), @r" 1816 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1817 @git: xyxluytn e31634b6 (empty) rewritten 1818 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1819 [EOF] 1820 "); 1821 insta::assert_snapshot!(query(&["--all-remotes", "-rbookmarks(remote-rewrite)"]), @r" 1822 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1823 @git: xyxluytn e31634b6 (empty) rewritten 1824 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1825 [EOF] 1826 "); 1827 1828 // Select bookmarks with --remote 1829 insta::assert_snapshot!(query(&["--remote", "origin"]), @r" 1830 remote-delete (deleted) 1831 @origin: yxusvupt dad5f298 (empty) remote-delete 1832 remote-keep: nlwprzpn 911e9120 (empty) remote-keep 1833 @origin: nlwprzpn 911e9120 (empty) remote-keep 1834 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1835 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1836 [EOF] 1837 ------- stderr ------- 1838 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 1839 [EOF] 1840 "); 1841 insta::assert_snapshot!(query(&["--remote", "glob:gi?"]), @r" 1842 local-keep: kpqxywon c7b4c09c (empty) local-keep 1843 @git: kpqxywon c7b4c09c (empty) local-keep 1844 remote-keep: nlwprzpn 911e9120 (empty) remote-keep 1845 @git: nlwprzpn 911e9120 (empty) remote-keep 1846 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1847 @git: xyxluytn e31634b6 (empty) rewritten 1848 [EOF] 1849 "); 1850 insta::assert_snapshot!(query(&["--remote", "origin", "--remote", "git"]), @r" 1851 local-keep: kpqxywon c7b4c09c (empty) local-keep 1852 @git: kpqxywon c7b4c09c (empty) local-keep 1853 remote-delete (deleted) 1854 @origin: yxusvupt dad5f298 (empty) remote-delete 1855 remote-keep: nlwprzpn 911e9120 (empty) remote-keep 1856 @git: nlwprzpn 911e9120 (empty) remote-keep 1857 @origin: nlwprzpn 911e9120 (empty) remote-keep 1858 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1859 @git: xyxluytn e31634b6 (empty) rewritten 1860 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1861 [EOF] 1862 ------- stderr ------- 1863 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 1864 [EOF] 1865 "); 1866 1867 // Can select deleted bookmark by name pattern, but not by revset. 1868 insta::assert_snapshot!(query(&["remote-delete"]), @r" 1869 remote-delete (deleted) 1870 @origin: yxusvupt dad5f298 (empty) remote-delete 1871 [EOF] 1872 ------- stderr ------- 1873 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 1874 [EOF] 1875 "); 1876 insta::assert_snapshot!(query(&["-rbookmarks(remote-delete)"]), @""); 1877 insta::assert_snapshot!(query(&["-rremote-delete"]), @r" 1878 ------- stderr ------- 1879 Error: Revision `remote-delete` doesn't exist 1880 Hint: Did you mean `remote-delete@origin`, `remote-keep`, `remote-rewrite`, `remote-rewrite@origin`? 1881 [EOF] 1882 [exit status: 1] 1883 "); 1884 1885 // Name patterns are OR-ed. 1886 insta::assert_snapshot!(query(&["glob:*-keep", "remote-delete"]), @r" 1887 local-keep: kpqxywon c7b4c09c (empty) local-keep 1888 remote-delete (deleted) 1889 @origin: yxusvupt dad5f298 (empty) remote-delete 1890 remote-keep: nlwprzpn 911e9120 (empty) remote-keep 1891 [EOF] 1892 ------- stderr ------- 1893 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 1894 [EOF] 1895 "); 1896 1897 // Unmatched name pattern shouldn't be an error. A warning can be added later. 1898 insta::assert_snapshot!(query(&["local-keep", "glob:push-*"]), @r" 1899 local-keep: kpqxywon c7b4c09c (empty) local-keep 1900 [EOF] 1901 "); 1902 1903 // Name pattern and revset are OR-ed. 1904 insta::assert_snapshot!(query(&["local-keep", "-rbookmarks(remote-rewrite)"]), @r" 1905 local-keep: kpqxywon c7b4c09c (empty) local-keep 1906 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1907 @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite 1908 [EOF] 1909 "); 1910 1911 // … but still filtered by --remote 1912 insta::assert_snapshot!(query(&[ 1913 "local-keep", 1914 "-rbookmarks(remote-rewrite)", 1915 "--remote", 1916 "git", 1917 ]), @r" 1918 local-keep: kpqxywon c7b4c09c (empty) local-keep 1919 @git: kpqxywon c7b4c09c (empty) local-keep 1920 remote-rewrite: xyxluytn e31634b6 (empty) rewritten 1921 @git: xyxluytn e31634b6 (empty) rewritten 1922 [EOF] 1923 "); 1924} 1925 1926#[test] 1927fn test_bookmark_list_much_remote_divergence() { 1928 let test_env = TestEnvironment::default(); 1929 test_env.add_config("git.auto-local-bookmark = true"); 1930 1931 // Initialize remote refs 1932 test_env.run_jj_in(".", ["git", "init", "remote"]).success(); 1933 let remote_dir = test_env.work_dir("remote"); 1934 remote_dir 1935 .run_jj(["new", "root()", "-m", "remote-unsync"]) 1936 .success(); 1937 for _ in 0..15 { 1938 remote_dir.run_jj(["new", "-m", "remote-unsync"]).success(); 1939 } 1940 remote_dir 1941 .run_jj(["bookmark", "create", "-r@", "remote-unsync"]) 1942 .success(); 1943 remote_dir.run_jj(["new"]).success(); 1944 remote_dir.run_jj(["git", "export"]).success(); 1945 1946 // Initialize local refs 1947 let mut remote_git_path = remote_dir.root().to_owned(); 1948 remote_git_path.extend([".jj", "repo", "store", "git"]); 1949 test_env 1950 .run_jj_in( 1951 ".", 1952 ["git", "clone", remote_git_path.to_str().unwrap(), "local"], 1953 ) 1954 .success(); 1955 let local_dir = test_env.work_dir("local"); 1956 local_dir 1957 .run_jj(["new", "root()", "-m", "local-only"]) 1958 .success(); 1959 for _ in 0..15 { 1960 local_dir.run_jj(["new", "-m", "local-only"]).success(); 1961 } 1962 local_dir 1963 .run_jj(["bookmark", "create", "-r@", "local-only"]) 1964 .success(); 1965 1966 // Mutate refs in local repository 1967 local_dir 1968 .run_jj([ 1969 "bookmark", 1970 "set", 1971 "--allow-backwards", 1972 "--to=@", 1973 "remote-unsync", 1974 ]) 1975 .success(); 1976 1977 let output = local_dir.run_jj(["bookmark", "list"]); 1978 insta::assert_snapshot!(output, @r" 1979 local-only: zkyosouw 4ab3f751 (empty) local-only 1980 remote-unsync: zkyosouw 4ab3f751 (empty) local-only 1981 @origin (ahead by at least 10 commits, behind by at least 10 commits): lxyktnks 19582022 (empty) remote-unsync 1982 [EOF] 1983 "); 1984} 1985 1986#[test] 1987fn test_bookmark_list_tracked() { 1988 let test_env = TestEnvironment::default(); 1989 test_env.add_config("git.auto-local-bookmark = true"); 1990 1991 // Initialize remote refs 1992 test_env.run_jj_in(".", ["git", "init", "remote"]).success(); 1993 let remote_dir = test_env.work_dir("remote"); 1994 for bookmark in [ 1995 "remote-sync", 1996 "remote-unsync", 1997 "remote-untrack", 1998 "remote-delete", 1999 ] { 2000 remote_dir 2001 .run_jj(["new", "root()", "-m", bookmark]) 2002 .success(); 2003 remote_dir 2004 .run_jj(["bookmark", "create", "-r@", bookmark]) 2005 .success(); 2006 } 2007 remote_dir.run_jj(["new"]).success(); 2008 remote_dir.run_jj(["git", "export"]).success(); 2009 2010 // Initialize local refs 2011 let mut remote_git_path = remote_dir.root().to_owned(); 2012 remote_git_path.extend([".jj", "repo", "store", "git"]); 2013 test_env 2014 .run_jj_in( 2015 ".", 2016 [ 2017 "git", 2018 "clone", 2019 "--colocate", 2020 remote_git_path.to_str().unwrap(), 2021 "local", 2022 ], 2023 ) 2024 .success(); 2025 2026 test_env 2027 .run_jj_in(".", ["git", "init", "upstream"]) 2028 .success(); 2029 2030 // Initialize a second remote 2031 let upstream_dir = test_env.work_dir("upstream"); 2032 upstream_dir 2033 .run_jj(["new", "root()", "-m", "upstream-sync"]) 2034 .success(); 2035 upstream_dir 2036 .run_jj(["bookmark", "create", "-r@", "upstream-sync"]) 2037 .success(); 2038 upstream_dir.run_jj(["new"]).success(); 2039 upstream_dir.run_jj(["git", "export"]).success(); 2040 2041 let mut upstream_git_path = upstream_dir.root().to_owned(); 2042 upstream_git_path.extend([".jj", "repo", "store", "git"]); 2043 2044 let local_dir = test_env.work_dir("local"); 2045 2046 local_dir 2047 .run_jj([ 2048 "git", 2049 "remote", 2050 "add", 2051 "upstream", 2052 upstream_git_path.to_str().unwrap(), 2053 ]) 2054 .success(); 2055 local_dir 2056 .run_jj(["git", "fetch", "--all-remotes"]) 2057 .success(); 2058 2059 local_dir 2060 .run_jj(["new", "root()", "-m", "local-only"]) 2061 .success(); 2062 local_dir 2063 .run_jj(["bookmark", "create", "-r@", "local-only"]) 2064 .success(); 2065 2066 // Mutate refs in local repository 2067 local_dir 2068 .run_jj(["bookmark", "delete", "remote-delete"]) 2069 .success(); 2070 local_dir 2071 .run_jj(["bookmark", "delete", "remote-untrack"]) 2072 .success(); 2073 local_dir 2074 .run_jj(["bookmark", "untrack", "remote-untrack@origin"]) 2075 .success(); 2076 local_dir 2077 .run_jj([ 2078 "git", 2079 "push", 2080 "--allow-new", 2081 "--remote", 2082 "upstream", 2083 "--bookmark", 2084 "remote-unsync", 2085 ]) 2086 .success(); 2087 local_dir 2088 .run_jj([ 2089 "bookmark", 2090 "set", 2091 "--to=@", 2092 "--allow-backwards", 2093 "remote-unsync", 2094 ]) 2095 .success(); 2096 2097 let output = local_dir.run_jj(["bookmark", "list", "--all-remotes"]); 2098 insta::assert_snapshot!(output, @r" 2099 local-only: nmzmmopx e1da745b (empty) local-only 2100 @git: nmzmmopx e1da745b (empty) local-only 2101 remote-delete (deleted) 2102 @origin: mnmymoky 203e60eb (empty) remote-delete 2103 remote-sync: zwtyzrop c761c7ea (empty) remote-sync 2104 @git: zwtyzrop c761c7ea (empty) remote-sync 2105 @origin: zwtyzrop c761c7ea (empty) remote-sync 2106 remote-unsync: nmzmmopx e1da745b (empty) local-only 2107 @git: nmzmmopx e1da745b (empty) local-only 2108 @origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 2109 @upstream (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 2110 remote-untrack@origin: vmortlor 71a16b05 (empty) remote-untrack 2111 upstream-sync: lolpmnqw 32fa6da0 (empty) upstream-sync 2112 @git: lolpmnqw 32fa6da0 (empty) upstream-sync 2113 @upstream: lolpmnqw 32fa6da0 (empty) upstream-sync 2114 [EOF] 2115 ------- stderr ------- 2116 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 2117 [EOF] 2118 "); 2119 2120 let output = local_dir.run_jj(["bookmark", "list", "--tracked"]); 2121 insta::assert_snapshot!(output, @r" 2122 remote-delete (deleted) 2123 @origin: mnmymoky 203e60eb (empty) remote-delete 2124 remote-sync: zwtyzrop c761c7ea (empty) remote-sync 2125 @origin: zwtyzrop c761c7ea (empty) remote-sync 2126 remote-unsync: nmzmmopx e1da745b (empty) local-only 2127 @origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 2128 @upstream (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 2129 upstream-sync: lolpmnqw 32fa6da0 (empty) upstream-sync 2130 @upstream: lolpmnqw 32fa6da0 (empty) upstream-sync 2131 [EOF] 2132 ------- stderr ------- 2133 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 2134 [EOF] 2135 "); 2136 2137 let output = local_dir.run_jj(["bookmark", "list", "--tracked", "--remote", "origin"]); 2138 insta::assert_snapshot!(output, @r" 2139 remote-delete (deleted) 2140 @origin: mnmymoky 203e60eb (empty) remote-delete 2141 remote-sync: zwtyzrop c761c7ea (empty) remote-sync 2142 @origin: zwtyzrop c761c7ea (empty) remote-sync 2143 remote-unsync: nmzmmopx e1da745b (empty) local-only 2144 @origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 2145 [EOF] 2146 ------- stderr ------- 2147 Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. 2148 [EOF] 2149 "); 2150 2151 let output = local_dir.run_jj(["bookmark", "list", "--tracked", "remote-unsync"]); 2152 insta::assert_snapshot!(output, @r" 2153 remote-unsync: nmzmmopx e1da745b (empty) local-only 2154 @origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 2155 @upstream (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 2156 [EOF] 2157 "); 2158 2159 let output = local_dir.run_jj(["bookmark", "list", "--tracked", "remote-untrack"]); 2160 insta::assert_snapshot!(output, @""); 2161 2162 local_dir 2163 .run_jj(["bookmark", "untrack", "remote-unsync@upstream"]) 2164 .success(); 2165 2166 let output = local_dir.run_jj(["bookmark", "list", "--tracked", "remote-unsync"]); 2167 insta::assert_snapshot!(output, @r" 2168 remote-unsync: nmzmmopx e1da745b (empty) local-only 2169 @origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync 2170 [EOF] 2171 "); 2172} 2173 2174#[test] 2175fn test_bookmark_list_conflicted() { 2176 let test_env = TestEnvironment::default(); 2177 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2178 let work_dir = test_env.work_dir("repo"); 2179 2180 // Track existing bookmark. Local bookmark should result in conflict. 2181 work_dir.run_jj(["new", "root()", "-m", "a"]).success(); 2182 work_dir.run_jj(["new", "root()", "-m", "b"]).success(); 2183 work_dir 2184 .run_jj(["bookmark", "create", "-r@", "bar"]) 2185 .success(); 2186 work_dir 2187 .run_jj(["bookmark", "create", "foo", "-r", "description(a)"]) 2188 .success(); 2189 work_dir 2190 .run_jj([ 2191 "bookmark", 2192 "create", 2193 "foo", 2194 "-r", 2195 "description(b)", 2196 "--at-op=@-", 2197 ]) 2198 .success(); 2199 work_dir.run_jj(["status"]).success(); 2200 insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" 2201 bar: kkmpptxz 06a973bc (empty) b 2202 foo (conflicted): 2203 + rlvkpnrz d8d5f980 (empty) a 2204 + kkmpptxz 06a973bc (empty) b 2205 [EOF] 2206 "); 2207 insta::assert_snapshot!(work_dir.run_jj(["bookmark", "list", "--conflicted"]), @r" 2208 foo (conflicted): 2209 + rlvkpnrz d8d5f980 (empty) a 2210 + kkmpptxz 06a973bc (empty) b 2211 [EOF] 2212 "); 2213} 2214 2215#[test] 2216fn test_bookmark_create_with_default_target_revision() { 2217 let test_env = TestEnvironment::default(); 2218 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2219 let work_dir = test_env.work_dir("repo"); 2220 2221 let output = work_dir.run_jj(["bookmark", "create", "foo"]); 2222 insta::assert_snapshot!(output, @r" 2223 ------- stderr ------- 2224 Warning: Target revision was not specified, defaulting to the working copy (-r@). In the near future it will be required to explicitly specify target revision. 2225 Created 1 bookmarks pointing to qpvuntsm 230dd059 foo | (empty) (no description set) 2226 [EOF] 2227 "); 2228} 2229 2230#[test] 2231fn test_bookmark_set_with_default_target_revision() { 2232 let test_env = TestEnvironment::default(); 2233 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2234 let work_dir = test_env.work_dir("repo"); 2235 2236 let output = work_dir.run_jj(["bookmark", "set", "foo"]); 2237 insta::assert_snapshot!(output, @r" 2238 ------- stderr ------- 2239 Warning: Target revision was not specified, defaulting to the working copy (--revision=@). In the near future it will be required to explicitly specify target revision. 2240 Created 1 bookmarks pointing to qpvuntsm 230dd059 foo | (empty) (no description set) 2241 [EOF] 2242 "); 2243} 2244 2245#[test] 2246fn test_bookmark_move_with_default_target_revision() { 2247 let test_env = TestEnvironment::default(); 2248 test_env.run_jj_in(".", ["git", "init", "repo"]).success(); 2249 let work_dir = test_env.work_dir("repo"); 2250 2251 // Set up remote 2252 let git_repo_path = test_env.env_root().join("git-repo"); 2253 git::init_bare(git_repo_path); 2254 work_dir 2255 .run_jj(["git", "remote", "add", "origin", "../git-repo"]) 2256 .success(); 2257 2258 let output = work_dir.run_jj(["bookmark", "create", "foo", "-r@"]); 2259 insta::assert_snapshot!(output, @r" 2260 ------- stderr ------- 2261 Created 1 bookmarks pointing to qpvuntsm 230dd059 foo | (empty) (no description set) 2262 [EOF] 2263 "); 2264 2265 work_dir.run_jj(["new"]).success(); 2266 let output = work_dir.run_jj(["bookmark", "move", "foo"]); 2267 insta::assert_snapshot!(output, @r" 2268 ------- stderr ------- 2269 Warning: Target revision was not specified, defaulting to the working copy (--to=@). In the near future it will be required to explicitly specify it. 2270 Moved 1 bookmarks to zsuskuln 8bb159bc foo | (empty) (no description set) 2271 [EOF] 2272 "); 2273} 2274 2275#[must_use] 2276fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput { 2277 let template = r#"bookmarks ++ " " ++ commit_id.short()"#; 2278 work_dir.run_jj(["log", "-T", template]) 2279} 2280 2281#[must_use] 2282fn get_bookmark_output(work_dir: &TestWorkDir) -> CommandOutput { 2283 // --quiet to suppress deleted bookmarks hint 2284 work_dir.run_jj(["bookmark", "list", "--all-remotes", "--quiet"]) 2285}