just playing with tangled
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 crate::common::CommandOutput;
16use crate::common::TestEnvironment;
17use crate::common::TestWorkDir;
18
19#[test]
20fn test_new() {
21 let test_env = TestEnvironment::default();
22 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
23 let work_dir = test_env.work_dir("repo");
24
25 work_dir.run_jj(["describe", "-m", "add a file"]).success();
26 work_dir.run_jj(["new", "-m", "a new commit"]).success();
27
28 insta::assert_snapshot!(get_log_output(&work_dir), @r"
29 @ 34f3c770f1db22ac5c58df21d587aed1a030201f a new commit
30 ○ bf8753cb48b860b68386c5c8cc997e8e37122485 add a file
31 ◆ 0000000000000000000000000000000000000000
32 [EOF]
33 ");
34
35 // Start a new change off of a specific commit (the root commit in this case).
36 work_dir
37 .run_jj(["new", "-m", "off of root", "root()"])
38 .success();
39 insta::assert_snapshot!(get_log_output(&work_dir), @r"
40 @ 026537ddb96b801b9cb909985d5443aab44616c1 off of root
41 │ ○ 34f3c770f1db22ac5c58df21d587aed1a030201f a new commit
42 │ ○ bf8753cb48b860b68386c5c8cc997e8e37122485 add a file
43 ├─╯
44 ◆ 0000000000000000000000000000000000000000
45 [EOF]
46 ");
47
48 // --edit is a no-op
49 work_dir
50 .run_jj(["new", "--edit", "-m", "yet another commit"])
51 .success();
52 insta::assert_snapshot!(get_log_output(&work_dir), @r"
53 @ 101cbec5cae8049cb9850a906ef3675631ed48fa yet another commit
54 ○ 026537ddb96b801b9cb909985d5443aab44616c1 off of root
55 │ ○ 34f3c770f1db22ac5c58df21d587aed1a030201f a new commit
56 │ ○ bf8753cb48b860b68386c5c8cc997e8e37122485 add a file
57 ├─╯
58 ◆ 0000000000000000000000000000000000000000
59 [EOF]
60 ");
61
62 // --edit cannot be used with --no-edit
63 let output = work_dir.run_jj(["new", "--edit", "B", "--no-edit", "D"]);
64 insta::assert_snapshot!(output, @r"
65 ------- stderr -------
66 error: the argument '--edit' cannot be used with '--no-edit'
67
68 Usage: jj new <REVSETS>...
69
70 For more information, try '--help'.
71 [EOF]
72 [exit status: 2]
73 ");
74}
75
76#[test]
77fn test_new_merge() {
78 let test_env = TestEnvironment::default();
79 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
80 let work_dir = test_env.work_dir("repo");
81
82 work_dir
83 .run_jj(["bookmark", "create", "-r@", "main"])
84 .success();
85 work_dir.run_jj(["describe", "-m", "add file1"]).success();
86 work_dir.write_file("file1", "a");
87 work_dir
88 .run_jj(["new", "root()", "-m", "add file2"])
89 .success();
90 work_dir.write_file("file2", "b");
91
92 // Create a merge commit
93 work_dir.run_jj(["new", "main", "@"]).success();
94 insta::assert_snapshot!(get_log_output(&work_dir), @r"
95 @ 2f9a61ea1fef257eca52fcee2feec1cbd2e41660
96 ├─╮
97 │ ○ f399209d9dda06e8a25a0c8e9a0cde9f421ff35d add file2
98 ○ │ 8d996e001c23e298d0d353ab455665c81bf2080c add file1
99 ├─╯
100 ◆ 0000000000000000000000000000000000000000
101 [EOF]
102 ");
103 let output = work_dir.run_jj(["file", "show", "file1"]);
104 insta::assert_snapshot!(output, @"a[EOF]");
105 let output = work_dir.run_jj(["file", "show", "file2"]);
106 insta::assert_snapshot!(output, @"b[EOF]");
107
108 // Same test with `--no-edit`
109 work_dir.run_jj(["undo"]).success();
110 let output = work_dir.run_jj(["new", "main", "@", "--no-edit"]);
111 insta::assert_snapshot!(output, @r"
112 ------- stderr -------
113 Created new commit znkkpsqq 496490a6 (empty) (no description set)
114 [EOF]
115 ");
116 insta::assert_snapshot!(get_log_output(&work_dir), @r"
117 ○ 496490a66cebb31730c4103b7b22a1098d49af91
118 ├─╮
119 │ @ f399209d9dda06e8a25a0c8e9a0cde9f421ff35d add file2
120 ○ │ 8d996e001c23e298d0d353ab455665c81bf2080c add file1
121 ├─╯
122 ◆ 0000000000000000000000000000000000000000
123 [EOF]
124 ");
125
126 // Same test with `jj new`
127 work_dir.run_jj(["undo"]).success();
128 work_dir.run_jj(["new", "main", "@"]).success();
129 insta::assert_snapshot!(get_log_output(&work_dir), @r"
130 @ 114023233c454e2eca22b8b209f9e42f755eb28c
131 ├─╮
132 │ ○ f399209d9dda06e8a25a0c8e9a0cde9f421ff35d add file2
133 ○ │ 8d996e001c23e298d0d353ab455665c81bf2080c add file1
134 ├─╯
135 ◆ 0000000000000000000000000000000000000000
136 [EOF]
137 ");
138
139 // merge with non-unique revisions
140 let output = work_dir.run_jj(["new", "@", "3a44e"]);
141 insta::assert_snapshot!(output, @r"
142 ------- stderr -------
143 Error: Revision `3a44e` doesn't exist
144 [EOF]
145 [exit status: 1]
146 ");
147 // if prefixed with all:, duplicates are allowed
148 let output = work_dir.run_jj(["new", "@", "all:visible_heads()"]);
149 insta::assert_snapshot!(output, @r"
150 ------- stderr -------
151 Working copy (@) now at: nkmrtpmo ed2dc1d9 (empty) (no description set)
152 Parent commit (@-) : wqnwkozp 11402323 (empty) (no description set)
153 [EOF]
154 ");
155
156 // merge with root
157 let output = work_dir.run_jj(["new", "@", "root()"]);
158 insta::assert_snapshot!(output, @r"
159 ------- stderr -------
160 Error: The Git backend does not support creating merge commits with the root commit as one of the parents.
161 [EOF]
162 [exit status: 1]
163 ");
164}
165
166#[test]
167fn test_new_insert_after() {
168 let test_env = TestEnvironment::default();
169 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
170 let work_dir = test_env.work_dir("repo");
171 setup_before_insertion(&work_dir);
172 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
173 @ F
174 ├─╮
175 │ ○ E
176 ○ │ D
177 ├─╯
178 │ ○ C
179 │ ○ B
180 │ ○ A
181 ├─╯
182 ◆ root
183 [EOF]
184 ");
185
186 // --insert-after can be repeated; --after is an alias
187 let output = work_dir.run_jj(["new", "-m", "G", "--insert-after", "B", "--after", "D"]);
188 insta::assert_snapshot!(output, @r"
189 ------- stderr -------
190 Rebased 2 descendant commits
191 Working copy (@) now at: kxryzmor 1fc93fd1 (empty) G
192 Parent commit (@-) : kkmpptxz bfd4157e B | (empty) B
193 Parent commit (@-) : vruxwmqv c9257eff D | (empty) D
194 [EOF]
195 ");
196 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
197 ○ C
198 │ ○ F
199 ╭─┤
200 @ │ G
201 ├───╮
202 │ │ ○ D
203 ○ │ │ B
204 ○ │ │ A
205 ├───╯
206 │ ○ E
207 ├─╯
208 ◆ root
209 [EOF]
210 ");
211
212 let output = work_dir.run_jj(["new", "-m", "H", "--insert-after", "D"]);
213 insta::assert_snapshot!(output, @r"
214 ------- stderr -------
215 Rebased 3 descendant commits
216 Working copy (@) now at: uyznsvlq fcf8281b (empty) H
217 Parent commit (@-) : vruxwmqv c9257eff D | (empty) D
218 [EOF]
219 ");
220 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
221 ○ C
222 │ ○ F
223 ╭─┤
224 ○ │ G
225 ├───╮
226 │ │ @ H
227 │ │ ○ D
228 ○ │ │ B
229 ○ │ │ A
230 ├───╯
231 │ ○ E
232 ├─╯
233 ◆ root
234 [EOF]
235 ");
236
237 // --after cannot be used with revisions
238 let output = work_dir.run_jj(["new", "--after", "B", "D"]);
239 insta::assert_snapshot!(output, @r"
240 ------- stderr -------
241 error: the argument '--insert-after <REVSETS>' cannot be used with '[REVSETS]...'
242
243 Usage: jj new --insert-after <REVSETS> [REVSETS]...
244
245 For more information, try '--help'.
246 [EOF]
247 [exit status: 2]
248 ");
249}
250
251#[test]
252fn test_new_insert_after_children() {
253 let test_env = TestEnvironment::default();
254 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
255 let work_dir = test_env.work_dir("repo");
256 setup_before_insertion(&work_dir);
257 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
258 @ F
259 ├─╮
260 │ ○ E
261 ○ │ D
262 ├─╯
263 │ ○ C
264 │ ○ B
265 │ ○ A
266 ├─╯
267 ◆ root
268 [EOF]
269 ");
270
271 // Attempting to insert G after A and C errors out due to the cycle created
272 // as A is an ancestor of C.
273 let output = work_dir.run_jj([
274 "new",
275 "-m",
276 "G",
277 "--insert-after",
278 "A",
279 "--insert-after",
280 "C",
281 ]);
282 insta::assert_snapshot!(output, @r"
283 ------- stderr -------
284 Error: Refusing to create a loop: commit 83376b270925 would be both an ancestor and a descendant of the new commit
285 [EOF]
286 [exit status: 1]
287 ");
288}
289
290#[test]
291fn test_new_insert_before() {
292 let test_env = TestEnvironment::default();
293 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
294 let work_dir = test_env.work_dir("repo");
295 setup_before_insertion(&work_dir);
296 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
297 @ F
298 ├─╮
299 │ ○ E
300 ○ │ D
301 ├─╯
302 │ ○ C
303 │ ○ B
304 │ ○ A
305 ├─╯
306 ◆ root
307 [EOF]
308 ");
309
310 let output = work_dir.run_jj([
311 "new",
312 "-m",
313 "G",
314 "--insert-before",
315 "C",
316 "--insert-before",
317 "F",
318 ]);
319 insta::assert_snapshot!(output, @r"
320 ------- stderr -------
321 Rebased 2 descendant commits
322 Working copy (@) now at: kxryzmor 7ed2d6ff (empty) G
323 Parent commit (@-) : kkmpptxz bfd4157e B | (empty) B
324 Parent commit (@-) : vruxwmqv c9257eff D | (empty) D
325 Parent commit (@-) : znkkpsqq 41a89ffc E | (empty) E
326 [EOF]
327 ");
328 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
329 ○ F
330 │ ○ C
331 ├─╯
332 @ G
333 ├─┬─╮
334 │ │ ○ E
335 │ ○ │ D
336 │ ├─╯
337 ○ │ B
338 ○ │ A
339 ├─╯
340 ◆ root
341 [EOF]
342 ");
343
344 // --before cannot be used with revisions
345 let output = work_dir.run_jj(["new", "--before", "B", "D"]);
346 insta::assert_snapshot!(output, @r"
347 ------- stderr -------
348 error: the argument '--insert-before <REVSETS>' cannot be used with '[REVSETS]...'
349
350 Usage: jj new --insert-before <REVSETS> [REVSETS]...
351
352 For more information, try '--help'.
353 [EOF]
354 [exit status: 2]
355 ");
356}
357
358#[test]
359fn test_new_insert_before_root_successors() {
360 let test_env = TestEnvironment::default();
361 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
362 let work_dir = test_env.work_dir("repo");
363 setup_before_insertion(&work_dir);
364 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
365 @ F
366 ├─╮
367 │ ○ E
368 ○ │ D
369 ├─╯
370 │ ○ C
371 │ ○ B
372 │ ○ A
373 ├─╯
374 ◆ root
375 [EOF]
376 ");
377
378 let output = work_dir.run_jj([
379 "new",
380 "-m",
381 "G",
382 "--insert-before",
383 "A",
384 "--insert-before",
385 "D",
386 ]);
387 insta::assert_snapshot!(output, @r"
388 ------- stderr -------
389 Rebased 5 descendant commits
390 Working copy (@) now at: kxryzmor 36541977 (empty) G
391 Parent commit (@-) : zzzzzzzz 00000000 (empty) (no description set)
392 [EOF]
393 ");
394 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
395 ○ F
396 ├─╮
397 │ ○ E
398 ○ │ D
399 │ │ ○ C
400 │ │ ○ B
401 │ │ ○ A
402 ├───╯
403 @ │ G
404 ├─╯
405 ◆ root
406 [EOF]
407 ");
408}
409
410#[test]
411fn test_new_insert_before_no_loop() {
412 let test_env = TestEnvironment::default();
413 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
414 let work_dir = test_env.work_dir("repo");
415 setup_before_insertion(&work_dir);
416 let template = r#"commit_id.short() ++ " " ++ if(description, description, "root")"#;
417 let output = work_dir.run_jj(["log", "-T", template]);
418 insta::assert_snapshot!(output, @r"
419 @ 7705d353bf5d F
420 ├─╮
421 │ ○ 41a89ffcbba2 E
422 ○ │ c9257eff5bf9 D
423 ├─╯
424 │ ○ 83376b270925 C
425 │ ○ bfd4157e6ea4 B
426 │ ○ 5ef24e4bf2be A
427 ├─╯
428 ◆ 000000000000 root
429 [EOF]
430 ");
431
432 let output = work_dir.run_jj([
433 "new",
434 "-m",
435 "G",
436 "--insert-before",
437 "A",
438 "--insert-before",
439 "C",
440 ]);
441 insta::assert_snapshot!(output, @r"
442 ------- stderr -------
443 Error: Refusing to create a loop: commit bfd4157e6ea4 would be both an ancestor and a descendant of the new commit
444 [EOF]
445 [exit status: 1]
446 ");
447}
448
449#[test]
450fn test_new_insert_before_no_root_merge() {
451 let test_env = TestEnvironment::default();
452 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
453 let work_dir = test_env.work_dir("repo");
454 setup_before_insertion(&work_dir);
455 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
456 @ F
457 ├─╮
458 │ ○ E
459 ○ │ D
460 ├─╯
461 │ ○ C
462 │ ○ B
463 │ ○ A
464 ├─╯
465 ◆ root
466 [EOF]
467 ");
468
469 let output = work_dir.run_jj([
470 "new",
471 "-m",
472 "G",
473 "--insert-before",
474 "B",
475 "--insert-before",
476 "D",
477 ]);
478 insta::assert_snapshot!(output, @r"
479 ------- stderr -------
480 Error: The Git backend does not support creating merge commits with the root commit as one of the parents.
481 [EOF]
482 [exit status: 1]
483 ");
484}
485
486#[test]
487fn test_new_insert_before_root() {
488 let test_env = TestEnvironment::default();
489 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
490 let work_dir = test_env.work_dir("repo");
491 setup_before_insertion(&work_dir);
492 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
493 @ F
494 ├─╮
495 │ ○ E
496 ○ │ D
497 ├─╯
498 │ ○ C
499 │ ○ B
500 │ ○ A
501 ├─╯
502 ◆ root
503 [EOF]
504 ");
505
506 let output = work_dir.run_jj(["new", "-m", "G", "--insert-before", "root()"]);
507 insta::assert_snapshot!(output, @r"
508 ------- stderr -------
509 Error: The root commit 000000000000 is immutable
510 [EOF]
511 [exit status: 1]
512 ");
513}
514
515#[test]
516fn test_new_insert_after_before() {
517 let test_env = TestEnvironment::default();
518 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
519 let work_dir = test_env.work_dir("repo");
520 setup_before_insertion(&work_dir);
521 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
522 @ F
523 ├─╮
524 │ ○ E
525 ○ │ D
526 ├─╯
527 │ ○ C
528 │ ○ B
529 │ ○ A
530 ├─╯
531 ◆ root
532 [EOF]
533 ");
534
535 let output = work_dir.run_jj(["new", "-m", "G", "--after", "C", "--before", "F"]);
536 insta::assert_snapshot!(output, @r"
537 ------- stderr -------
538 Rebased 1 descendant commits
539 Working copy (@) now at: kxryzmor 78a97058 (empty) G
540 Parent commit (@-) : mzvwutvl 83376b27 C | (empty) C
541 [EOF]
542 ");
543 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
544 ○ F
545 ├─┬─╮
546 │ │ @ G
547 │ │ ○ C
548 │ │ ○ B
549 │ │ ○ A
550 │ ○ │ E
551 │ ├─╯
552 ○ │ D
553 ├─╯
554 ◆ root
555 [EOF]
556 ");
557
558 let output = work_dir.run_jj(["new", "-m", "H", "--after", "D", "--before", "B"]);
559 insta::assert_snapshot!(output, @r"
560 ------- stderr -------
561 Rebased 4 descendant commits
562 Working copy (@) now at: uyznsvlq fcf8281b (empty) H
563 Parent commit (@-) : vruxwmqv c9257eff D | (empty) D
564 [EOF]
565 ");
566 insta::assert_snapshot!(get_short_log_output(&work_dir), @r"
567 ○ F
568 ├─┬─╮
569 │ │ ○ G
570 │ │ ○ C
571 │ │ ○ B
572 │ │ ├─╮
573 │ │ │ @ H
574 ├─────╯
575 ○ │ │ D
576 │ │ ○ A
577 ├───╯
578 │ ○ E
579 ├─╯
580 ◆ root
581 [EOF]
582 ");
583}
584
585#[test]
586fn test_new_insert_after_before_no_loop() {
587 let test_env = TestEnvironment::default();
588 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
589 let work_dir = test_env.work_dir("repo");
590 setup_before_insertion(&work_dir);
591 let template = r#"commit_id.short() ++ " " ++ if(description, description, "root")"#;
592 let output = work_dir.run_jj(["log", "-T", template]);
593 insta::assert_snapshot!(output, @r"
594 @ 7705d353bf5d F
595 ├─╮
596 │ ○ 41a89ffcbba2 E
597 ○ │ c9257eff5bf9 D
598 ├─╯
599 │ ○ 83376b270925 C
600 │ ○ bfd4157e6ea4 B
601 │ ○ 5ef24e4bf2be A
602 ├─╯
603 ◆ 000000000000 root
604 [EOF]
605 ");
606
607 let output = work_dir.run_jj([
608 "new",
609 "-m",
610 "G",
611 "--insert-before",
612 "A",
613 "--insert-after",
614 "C",
615 ]);
616 insta::assert_snapshot!(output, @r"
617 ------- stderr -------
618 Error: Refusing to create a loop: commit 83376b270925 would be both an ancestor and a descendant of the new commit
619 [EOF]
620 [exit status: 1]
621 ");
622}
623
624#[test]
625fn test_new_conflicting_bookmarks() {
626 let test_env = TestEnvironment::default();
627 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
628 let work_dir = test_env.work_dir("repo");
629
630 work_dir.run_jj(["describe", "-m", "one"]).success();
631 work_dir.run_jj(["new", "-m", "two", "@-"]).success();
632 work_dir
633 .run_jj(["bookmark", "create", "-r@", "foo"])
634 .success();
635 work_dir
636 .run_jj([
637 "--at-op=@-",
638 "bookmark",
639 "create",
640 "foo",
641 "-r",
642 r#"description("one")"#,
643 ])
644 .success();
645
646 // Trigger resolution of divergent operations
647 work_dir.run_jj(["st"]).success();
648
649 let output = work_dir.run_jj(["new", "foo"]);
650 insta::assert_snapshot!(output, @r"
651 ------- stderr -------
652 Error: Revset `foo` resolved to more than one revision
653 Hint: Bookmark foo resolved to multiple revisions because it's conflicted.
654 It resolved to these revisions:
655 kkmpptxz 66c6502d foo?? | (empty) two
656 qpvuntsm 876f4b7e foo?? | (empty) one
657 Hint: Set which revision the bookmark points to with `jj bookmark set foo -r <REVISION>`.
658 [EOF]
659 [exit status: 1]
660 ");
661}
662
663#[test]
664fn test_new_conflicting_change_ids() {
665 let test_env = TestEnvironment::default();
666 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
667 let work_dir = test_env.work_dir("repo");
668
669 work_dir.run_jj(["describe", "-m", "one"]).success();
670 work_dir
671 .run_jj(["--at-op=@-", "describe", "-m", "two"])
672 .success();
673
674 // Trigger resolution of divergent operations
675 work_dir.run_jj(["st"]).success();
676
677 let output = work_dir.run_jj(["new", "qpvuntsm"]);
678 insta::assert_snapshot!(output, @r"
679 ------- stderr -------
680 Error: Revset `qpvuntsm` resolved to more than one revision
681 Hint: The revset `qpvuntsm` resolved to these revisions:
682 qpvuntsm?? 66c6502d (empty) two
683 qpvuntsm?? 876f4b7e (empty) one
684 Hint: Some of these commits have the same change id. Abandon one of them with `jj abandon -r <REVISION>`.
685 [EOF]
686 [exit status: 1]
687 ");
688}
689
690#[test]
691fn test_new_error_revision_does_not_exist() {
692 let test_env = TestEnvironment::default();
693 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
694 let work_dir = test_env.work_dir("repo");
695
696 work_dir.run_jj(["describe", "-m", "one"]).success();
697 work_dir.run_jj(["new", "-m", "two"]).success();
698
699 let output = work_dir.run_jj(["new", "this"]);
700 insta::assert_snapshot!(output, @r"
701 ------- stderr -------
702 Error: Revision `this` doesn't exist
703 [EOF]
704 [exit status: 1]
705 ");
706}
707
708fn setup_before_insertion(work_dir: &TestWorkDir) {
709 work_dir
710 .run_jj(["bookmark", "create", "-r@", "A"])
711 .success();
712 work_dir.run_jj(["commit", "-m", "A"]).success();
713 work_dir
714 .run_jj(["bookmark", "create", "-r@", "B"])
715 .success();
716 work_dir.run_jj(["commit", "-m", "B"]).success();
717 work_dir
718 .run_jj(["bookmark", "create", "-r@", "C"])
719 .success();
720 work_dir.run_jj(["describe", "-m", "C"]).success();
721 work_dir.run_jj(["new", "-m", "D", "root()"]).success();
722 work_dir
723 .run_jj(["bookmark", "create", "-r@", "D"])
724 .success();
725 work_dir.run_jj(["new", "-m", "E", "root()"]).success();
726 work_dir
727 .run_jj(["bookmark", "create", "-r@", "E"])
728 .success();
729 // Any number of -r's is ignored
730 work_dir
731 .run_jj(["new", "-m", "F", "-r", "D", "-r", "E"])
732 .success();
733 work_dir
734 .run_jj(["bookmark", "create", "-r@", "F"])
735 .success();
736}
737
738#[must_use]
739fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput {
740 let template = r#"commit_id ++ " " ++ description"#;
741 work_dir.run_jj(["log", "-T", template])
742}
743
744#[must_use]
745fn get_short_log_output(work_dir: &TestWorkDir) -> CommandOutput {
746 let template = r#"if(description, description, "root")"#;
747 work_dir.run_jj(["log", "-T", template])
748}