just playing with tangled
1// Copyright 2023 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::create_commit;
16use crate::common::CommandOutput;
17use crate::common::TestEnvironment;
18use crate::common::TestWorkDir;
19
20#[test]
21fn test_duplicate() {
22 let test_env = TestEnvironment::default();
23 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
24 let work_dir = test_env.work_dir("repo");
25
26 create_commit(&work_dir, "a", &[]);
27 create_commit(&work_dir, "b", &[]);
28 create_commit(&work_dir, "c", &["a", "b"]);
29 // Test the setup
30 insta::assert_snapshot!(get_log_output(&work_dir), @r"
31 @ 387b928721d9 c
32 ├─╮
33 │ ○ d18ca3e87135 b
34 ○ │ 7d980be7a1d4 a
35 ├─╯
36 ◆ 000000000000
37 [EOF]
38 ");
39
40 let output = work_dir.run_jj(["duplicate", "all()"]);
41 insta::assert_snapshot!(output, @r"
42 ------- stderr -------
43 Error: Cannot duplicate the root commit
44 [EOF]
45 [exit status: 1]
46 ");
47
48 let output = work_dir.run_jj(["duplicate", "none()"]);
49 insta::assert_snapshot!(output, @r"
50 ------- stderr -------
51 No revisions to duplicate.
52 [EOF]
53 ");
54
55 let output = work_dir.run_jj(["duplicate", "a"]);
56 insta::assert_snapshot!(output, @r"
57 ------- stderr -------
58 Duplicated 7d980be7a1d4 as kpqxywon 13eb8bd0 a
59 [EOF]
60 ");
61 insta::assert_snapshot!(get_log_output(&work_dir), @r"
62 @ 387b928721d9 c
63 ├─╮
64 │ ○ d18ca3e87135 b
65 ○ │ 7d980be7a1d4 a
66 ├─╯
67 │ ○ 13eb8bd0a547 a
68 ├─╯
69 ◆ 000000000000
70 [EOF]
71 ");
72
73 let output = work_dir.run_jj(["undo"]);
74 insta::assert_snapshot!(output, @r"
75 ------- stderr -------
76 Undid operation: 76386e059136 (2001-02-03 08:05:17) duplicate 1 commit(s)
77 [EOF]
78 ");
79 let output = work_dir.run_jj(["duplicate" /* duplicates `c` */]);
80 insta::assert_snapshot!(output, @r"
81 ------- stderr -------
82 Duplicated 387b928721d9 as lylxulpl 71c64df5 c
83 [EOF]
84 ");
85 insta::assert_snapshot!(get_log_output(&work_dir), @r"
86 @ 387b928721d9 c
87 ├─╮
88 │ │ ○ 71c64df584dc c
89 ╭─┬─╯
90 │ ○ d18ca3e87135 b
91 ○ │ 7d980be7a1d4 a
92 ├─╯
93 ◆ 000000000000
94 [EOF]
95 ");
96}
97
98#[test]
99fn test_duplicate_many() {
100 let test_env = TestEnvironment::default();
101 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
102 let work_dir = test_env.work_dir("repo");
103
104 create_commit(&work_dir, "a", &[]);
105 create_commit(&work_dir, "b", &["a"]);
106 create_commit(&work_dir, "c", &["a"]);
107 create_commit(&work_dir, "d", &["c"]);
108 create_commit(&work_dir, "e", &["b", "d"]);
109 // Test the setup
110 insta::assert_snapshot!(get_log_output(&work_dir), @r"
111 @ 0559be9bd4d0 e
112 ├─╮
113 │ ○ a2dbb1aad514 d
114 │ ○ 991a7501d660 c
115 ○ │ 123b4d91f6e5 b
116 ├─╯
117 ○ 7d980be7a1d4 a
118 ◆ 000000000000
119 [EOF]
120 ");
121
122 let output = work_dir.run_jj(["duplicate", "b::"]);
123 insta::assert_snapshot!(output, @r"
124 ------- stderr -------
125 Duplicated 123b4d91f6e5 as wqnwkozp 10059c86 b
126 Duplicated 0559be9bd4d0 as mouksmqu 0afe2f34 e
127 [EOF]
128 ");
129 insta::assert_snapshot!(get_log_output(&work_dir), @r"
130 @ 0559be9bd4d0 e
131 ├─╮
132 ○ │ 123b4d91f6e5 b
133 │ │ ○ 0afe2f348a93 e
134 │ ╭─┤
135 │ ○ │ a2dbb1aad514 d
136 │ ○ │ 991a7501d660 c
137 ├─╯ │
138 │ ○ 10059c8651d7 b
139 ├───╯
140 ○ 7d980be7a1d4 a
141 ◆ 000000000000
142 [EOF]
143 ");
144
145 // Try specifying the same commit twice directly
146 work_dir.run_jj(["undo"]).success();
147 let output = work_dir.run_jj(["duplicate", "b", "b"]);
148 insta::assert_snapshot!(output, @r"
149 ------- stderr -------
150 Duplicated 123b4d91f6e5 as nkmrtpmo 1ccf2589 b
151 [EOF]
152 ");
153 insta::assert_snapshot!(get_log_output(&work_dir), @r"
154 @ 0559be9bd4d0 e
155 ├─╮
156 │ ○ a2dbb1aad514 d
157 │ ○ 991a7501d660 c
158 ○ │ 123b4d91f6e5 b
159 ├─╯
160 │ ○ 1ccf2589bfd1 b
161 ├─╯
162 ○ 7d980be7a1d4 a
163 ◆ 000000000000
164 [EOF]
165 ");
166
167 // Try specifying the same commit twice indirectly
168 work_dir.run_jj(["undo"]).success();
169 let output = work_dir.run_jj(["duplicate", "b::", "d::"]);
170 insta::assert_snapshot!(output, @r"
171 ------- stderr -------
172 Duplicated 123b4d91f6e5 as xtnwkqum 1a94ffc6 b
173 Duplicated a2dbb1aad514 as pqrnrkux 6a17a96d d
174 Duplicated 0559be9bd4d0 as ztxkyksq b113bd5c e
175 [EOF]
176 ");
177 insta::assert_snapshot!(get_log_output(&work_dir), @r"
178 @ 0559be9bd4d0 e
179 ├─╮
180 │ ○ a2dbb1aad514 d
181 ○ │ 123b4d91f6e5 b
182 │ │ ○ b113bd5c550a e
183 │ │ ├─╮
184 │ │ │ ○ 6a17a96d77d2 d
185 │ ├───╯
186 │ ○ │ 991a7501d660 c
187 ├─╯ │
188 │ ○ 1a94ffc6e6aa b
189 ├───╯
190 ○ 7d980be7a1d4 a
191 ◆ 000000000000
192 [EOF]
193 ");
194
195 work_dir.run_jj(["undo"]).success();
196 // Reminder of the setup
197 insta::assert_snapshot!(get_log_output(&work_dir), @r"
198 @ 0559be9bd4d0 e
199 ├─╮
200 │ ○ a2dbb1aad514 d
201 │ ○ 991a7501d660 c
202 ○ │ 123b4d91f6e5 b
203 ├─╯
204 ○ 7d980be7a1d4 a
205 ◆ 000000000000
206 [EOF]
207 ");
208 let output = work_dir.run_jj(["duplicate", "d::", "a"]);
209 insta::assert_snapshot!(output, @r"
210 ------- stderr -------
211 Duplicated 7d980be7a1d4 as nlrtlrxv 117dd806 a
212 Duplicated a2dbb1aad514 as plymsszl f2ec1b7f d
213 Duplicated 0559be9bd4d0 as urrlptpw 9e54f34c e
214 [EOF]
215 ");
216 insta::assert_snapshot!(get_log_output(&work_dir), @r"
217 @ 0559be9bd4d0 e
218 ├─╮
219 │ ○ a2dbb1aad514 d
220 │ │ ○ 9e54f34ca238 e
221 ╭───┤
222 │ │ ○ f2ec1b7f4e82 d
223 │ ├─╯
224 │ ○ 991a7501d660 c
225 ○ │ 123b4d91f6e5 b
226 ├─╯
227 ○ 7d980be7a1d4 a
228 │ ○ 117dd80623e6 a
229 ├─╯
230 ◆ 000000000000
231 [EOF]
232 ");
233
234 // Check for BUG -- makes too many 'a'-s, etc.
235 work_dir.run_jj(["undo"]).success();
236 let output = work_dir.run_jj(["duplicate", "a::"]);
237 insta::assert_snapshot!(output, @r"
238 ------- stderr -------
239 Duplicated 7d980be7a1d4 as uuuvxpvw cb730319 a
240 Duplicated 123b4d91f6e5 as nmpuuozl b00a23f6 b
241 Duplicated 991a7501d660 as kzpokyyw 7c1b86d5 c
242 Duplicated a2dbb1aad514 as yxrlprzz 2f5494bb d
243 Duplicated 0559be9bd4d0 as mvkzkxrl 8a4c81fe e
244 [EOF]
245 ");
246 insta::assert_snapshot!(get_log_output(&work_dir), @r"
247 @ 0559be9bd4d0 e
248 ├─╮
249 │ ○ a2dbb1aad514 d
250 │ ○ 991a7501d660 c
251 ○ │ 123b4d91f6e5 b
252 ├─╯
253 ○ 7d980be7a1d4 a
254 │ ○ 8a4c81fee5f1 e
255 │ ├─╮
256 │ │ ○ 2f5494bb9bce d
257 │ │ ○ 7c1b86d551da c
258 │ ○ │ b00a23f660bf b
259 │ ├─╯
260 │ ○ cb7303191ed7 a
261 ├─╯
262 ◆ 000000000000
263 [EOF]
264 ");
265}
266
267#[test]
268fn test_duplicate_destination() {
269 let test_env = TestEnvironment::default();
270 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
271 let work_dir = test_env.work_dir("repo");
272
273 create_commit(&work_dir, "a1", &[]);
274 create_commit(&work_dir, "a2", &["a1"]);
275 create_commit(&work_dir, "a3", &["a2"]);
276 create_commit(&work_dir, "b", &[]);
277 create_commit(&work_dir, "c", &[]);
278 create_commit(&work_dir, "d", &[]);
279 let setup_opid = work_dir.current_operation_id();
280
281 // Test the setup
282 insta::assert_snapshot!(get_log_output(&work_dir), @r"
283 @ 5248650c3314 d
284 │ ○ 22370aa928dc c
285 ├─╯
286 │ ○ c406dbab05ac b
287 ├─╯
288 │ ○ 5fb83d2b58d6 a3
289 │ ○ 7bfd9fbe959c a2
290 │ ○ 5d93a4b8f4bd a1
291 ├─╯
292 ◆ 000000000000
293 [EOF]
294 ");
295
296 // Duplicate a single commit onto a single destination.
297 let output = work_dir.run_jj(["duplicate", "a1", "-d", "c"]);
298 insta::assert_snapshot!(output, @r"
299 ------- stderr -------
300 Duplicated 5d93a4b8f4bd as nkmrtpmo f7a7a3f6 a1
301 [EOF]
302 ");
303 insta::assert_snapshot!(get_log_output(&work_dir), @r"
304 @ 5248650c3314 d
305 │ ○ f7a7a3f627a2 a1
306 │ ○ 22370aa928dc c
307 ├─╯
308 │ ○ c406dbab05ac b
309 ├─╯
310 │ ○ 5fb83d2b58d6 a3
311 │ ○ 7bfd9fbe959c a2
312 │ ○ 5d93a4b8f4bd a1
313 ├─╯
314 ◆ 000000000000
315 [EOF]
316 ");
317 work_dir.run_jj(["op", "restore", &setup_opid]).success();
318
319 // Duplicate a single commit onto multiple destinations.
320 let output = work_dir.run_jj(["duplicate", "a1", "-d", "c", "-d", "d"]);
321 insta::assert_snapshot!(output, @r"
322 ------- stderr -------
323 Duplicated 5d93a4b8f4bd as xtnwkqum a515a8a7 a1
324 [EOF]
325 ");
326 insta::assert_snapshot!(get_log_output(&work_dir), @r"
327 ○ a515a8a7055d a1
328 ├─╮
329 │ @ 5248650c3314 d
330 ○ │ 22370aa928dc c
331 ├─╯
332 │ ○ c406dbab05ac b
333 ├─╯
334 │ ○ 5fb83d2b58d6 a3
335 │ ○ 7bfd9fbe959c a2
336 │ ○ 5d93a4b8f4bd a1
337 ├─╯
338 ◆ 000000000000
339 [EOF]
340 ");
341 work_dir.run_jj(["op", "restore", &setup_opid]).success();
342
343 // Duplicate a single commit onto its descendant.
344 let output = work_dir.run_jj(["duplicate", "a1", "-d", "a3"]);
345 insta::assert_snapshot!(output, @r"
346 ------- stderr -------
347 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
348 Duplicated 5d93a4b8f4bd as wvuyspvk d80473de (empty) a1
349 [EOF]
350 ");
351 insta::assert_snapshot!(get_log_output(&work_dir), @r"
352 @ 5248650c3314 d
353 │ ○ 22370aa928dc c
354 ├─╯
355 │ ○ c406dbab05ac b
356 ├─╯
357 │ ○ d80473de843a a1
358 │ ○ 5fb83d2b58d6 a3
359 │ ○ 7bfd9fbe959c a2
360 │ ○ 5d93a4b8f4bd a1
361 ├─╯
362 ◆ 000000000000
363 [EOF]
364 ");
365
366 work_dir.run_jj(["op", "restore", &setup_opid]).success();
367 // Duplicate multiple commits without a direct ancestry relationship onto a
368 // single destination.
369 let output = work_dir.run_jj(["duplicate", "-r=a1", "-r=b", "-d", "c"]);
370 insta::assert_snapshot!(output, @r"
371 ------- stderr -------
372 Duplicated 5d93a4b8f4bd as xlzxqlsl bfc29032 a1
373 Duplicated c406dbab05ac as vnkwvqxw c57bb4be b
374 [EOF]
375 ");
376 insta::assert_snapshot!(get_log_output(&work_dir), @r"
377 @ 5248650c3314 d
378 │ ○ c57bb4beac33 b
379 │ │ ○ bfc29032c3ff a1
380 │ ├─╯
381 │ ○ 22370aa928dc c
382 ├─╯
383 │ ○ c406dbab05ac b
384 ├─╯
385 │ ○ 5fb83d2b58d6 a3
386 │ ○ 7bfd9fbe959c a2
387 │ ○ 5d93a4b8f4bd a1
388 ├─╯
389 ◆ 000000000000
390 [EOF]
391 ");
392 work_dir.run_jj(["op", "restore", &setup_opid]).success();
393
394 // Duplicate multiple commits without a direct ancestry relationship onto
395 // multiple destinations.
396 let output = work_dir.run_jj(["duplicate", "-r=a1", "b", "-d", "c", "-d", "d"]);
397 insta::assert_snapshot!(output, @r"
398 ------- stderr -------
399 Duplicated 5d93a4b8f4bd as oupztwtk 83113cdf a1
400 Duplicated c406dbab05ac as yxsqzptr 469ed79e b
401 [EOF]
402 ");
403 insta::assert_snapshot!(get_log_output(&work_dir), @r"
404 ○ 469ed79e4b00 b
405 ├─╮
406 │ │ ○ 83113cdff475 a1
407 ╭─┬─╯
408 │ @ 5248650c3314 d
409 ○ │ 22370aa928dc c
410 ├─╯
411 │ ○ c406dbab05ac b
412 ├─╯
413 │ ○ 5fb83d2b58d6 a3
414 │ ○ 7bfd9fbe959c a2
415 │ ○ 5d93a4b8f4bd a1
416 ├─╯
417 ◆ 000000000000
418 [EOF]
419 ");
420 work_dir.run_jj(["op", "restore", &setup_opid]).success();
421
422 // Duplicate multiple commits with an ancestry relationship onto a
423 // single destination.
424 let output = work_dir.run_jj(["duplicate", "a1", "a3", "-d", "c"]);
425 insta::assert_snapshot!(output, @r"
426 ------- stderr -------
427 Duplicated 5d93a4b8f4bd as wtszoswq 31bc8e32 a1
428 Duplicated 5fb83d2b58d6 as qmykwtmu 2a318b78 a3
429 [EOF]
430 ");
431 insta::assert_snapshot!(get_log_output(&work_dir), @r"
432 @ 5248650c3314 d
433 │ ○ 2a318b7805df a3
434 │ ○ 31bc8e32bcd5 a1
435 │ ○ 22370aa928dc c
436 ├─╯
437 │ ○ c406dbab05ac b
438 ├─╯
439 │ ○ 5fb83d2b58d6 a3
440 │ ○ 7bfd9fbe959c a2
441 │ ○ 5d93a4b8f4bd a1
442 ├─╯
443 ◆ 000000000000
444 [EOF]
445 ");
446 work_dir.run_jj(["op", "restore", &setup_opid]).success();
447
448 // Duplicate multiple commits with an ancestry relationship onto
449 // multiple destinations.
450 let output = work_dir.run_jj(["duplicate", "a1", "a3", "-d", "c", "-d", "d"]);
451 insta::assert_snapshot!(output, @r"
452 ------- stderr -------
453 Duplicated 5d93a4b8f4bd as rkoyqlrv d7d45f05 a1
454 Duplicated 5fb83d2b58d6 as zxvrqtmq 44d5cb38 a3
455 [EOF]
456 ");
457 insta::assert_snapshot!(get_log_output(&work_dir), @r"
458 ○ 44d5cb3876a2 a3
459 ○ d7d45f051a3c a1
460 ├─╮
461 │ @ 5248650c3314 d
462 ○ │ 22370aa928dc c
463 ├─╯
464 │ ○ c406dbab05ac b
465 ├─╯
466 │ ○ 5fb83d2b58d6 a3
467 │ ○ 7bfd9fbe959c a2
468 │ ○ 5d93a4b8f4bd a1
469 ├─╯
470 ◆ 000000000000
471 [EOF]
472 ");
473}
474
475#[test]
476fn test_duplicate_insert_after() {
477 let test_env = TestEnvironment::default();
478 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
479 let work_dir = test_env.work_dir("repo");
480
481 create_commit(&work_dir, "a1", &[]);
482 create_commit(&work_dir, "a2", &["a1"]);
483 create_commit(&work_dir, "a3", &["a2"]);
484 create_commit(&work_dir, "a4", &["a3"]);
485 create_commit(&work_dir, "b1", &[]);
486 create_commit(&work_dir, "b2", &["b1"]);
487 create_commit(&work_dir, "c1", &[]);
488 create_commit(&work_dir, "c2", &["c1"]);
489 create_commit(&work_dir, "d1", &[]);
490 create_commit(&work_dir, "d2", &["d1"]);
491 let setup_opid = work_dir.current_operation_id();
492
493 // Test the setup
494 insta::assert_snapshot!(get_log_output(&work_dir), @r"
495 @ 3e122d6a4b70 d2
496 ○ ae61a031221a d1
497 │ ○ 47a79ab4bbc6 c2
498 │ ○ 9b24b49f717e c1
499 ├─╯
500 │ ○ 65b6f1fe6b41 b2
501 │ ○ 6a9343b8797a b1
502 ├─╯
503 │ ○ e9b68b6313be a4
504 │ ○ 5fb83d2b58d6 a3
505 │ ○ 7bfd9fbe959c a2
506 │ ○ 5d93a4b8f4bd a1
507 ├─╯
508 ◆ 000000000000
509 [EOF]
510 ");
511
512 // Duplicate a single commit after a single commit with no direct relationship.
513 let output = work_dir.run_jj(["duplicate", "a1", "--after", "b1"]);
514 insta::assert_snapshot!(output, @r"
515 ------- stderr -------
516 Duplicated 5d93a4b8f4bd as pzsxstzt a5a114e3 a1
517 Rebased 1 commits onto duplicated commits
518 [EOF]
519 ");
520 insta::assert_snapshot!(get_log_output(&work_dir), @r"
521 @ 3e122d6a4b70 d2
522 ○ ae61a031221a d1
523 │ ○ 47a79ab4bbc6 c2
524 │ ○ 9b24b49f717e c1
525 ├─╯
526 │ ○ 3efc0755f6a0 b2
527 │ ○ a5a114e3c1ff a1
528 │ ○ 6a9343b8797a b1
529 ├─╯
530 │ ○ e9b68b6313be a4
531 │ ○ 5fb83d2b58d6 a3
532 │ ○ 7bfd9fbe959c a2
533 │ ○ 5d93a4b8f4bd a1
534 ├─╯
535 ◆ 000000000000
536 [EOF]
537 ");
538 work_dir.run_jj(["op", "restore", &setup_opid]).success();
539
540 // Duplicate a single commit after a single ancestor commit.
541 let output = work_dir.run_jj(["duplicate", "a3", "--after", "a1"]);
542 insta::assert_snapshot!(output, @r"
543 ------- stderr -------
544 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
545 Duplicated 5fb83d2b58d6 as qmkrwlvp 4048f2fb a3
546 Rebased 3 commits onto duplicated commits
547 [EOF]
548 ");
549 insta::assert_snapshot!(get_log_output(&work_dir), @r"
550 @ 3e122d6a4b70 d2
551 ○ ae61a031221a d1
552 │ ○ 47a79ab4bbc6 c2
553 │ ○ 9b24b49f717e c1
554 ├─╯
555 │ ○ 65b6f1fe6b41 b2
556 │ ○ 6a9343b8797a b1
557 ├─╯
558 │ ○ d6d86a8bdfda a4
559 │ ○ 25c595527054 a3
560 │ ○ 4b55efbf3237 a2
561 │ ○ 4048f2fbcf5c a3
562 │ ○ 5d93a4b8f4bd a1
563 ├─╯
564 ◆ 000000000000
565 [EOF]
566 ");
567 work_dir.run_jj(["op", "restore", &setup_opid]).success();
568
569 // Duplicate a single commit after a single descendant commit.
570 let output = work_dir.run_jj(["duplicate", "a1", "--after", "a3"]);
571 insta::assert_snapshot!(output, @r"
572 ------- stderr -------
573 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
574 Duplicated 5d93a4b8f4bd as qwyusntz bf508d28 (empty) a1
575 Rebased 1 commits onto duplicated commits
576 [EOF]
577 ");
578 insta::assert_snapshot!(get_log_output(&work_dir), @r"
579 @ 3e122d6a4b70 d2
580 ○ ae61a031221a d1
581 │ ○ 47a79ab4bbc6 c2
582 │ ○ 9b24b49f717e c1
583 ├─╯
584 │ ○ 65b6f1fe6b41 b2
585 │ ○ 6a9343b8797a b1
586 ├─╯
587 │ ○ 4231eba1accc a4
588 │ ○ bf508d280e4e a1
589 │ ○ 5fb83d2b58d6 a3
590 │ ○ 7bfd9fbe959c a2
591 │ ○ 5d93a4b8f4bd a1
592 ├─╯
593 ◆ 000000000000
594 [EOF]
595 ");
596 work_dir.run_jj(["op", "restore", &setup_opid]).success();
597
598 // Duplicate a single commit after multiple commits with no direct
599 // relationship.
600 let output = work_dir.run_jj(["duplicate", "a1", "--after", "b1", "--after", "c1"]);
601 insta::assert_snapshot!(output, @r"
602 ------- stderr -------
603 Duplicated 5d93a4b8f4bd as soqnvnyz 7e84ab7f a1
604 Rebased 2 commits onto duplicated commits
605 [EOF]
606 ");
607 insta::assert_snapshot!(get_log_output(&work_dir), @r"
608 @ 3e122d6a4b70 d2
609 ○ ae61a031221a d1
610 │ ○ 848cd66b5194 c2
611 │ │ ○ d68f684471e0 b2
612 │ ├─╯
613 │ ○ 7e84ab7f347e a1
614 │ ├─╮
615 │ │ ○ 9b24b49f717e c1
616 ├───╯
617 │ ○ 6a9343b8797a b1
618 ├─╯
619 │ ○ e9b68b6313be a4
620 │ ○ 5fb83d2b58d6 a3
621 │ ○ 7bfd9fbe959c a2
622 │ ○ 5d93a4b8f4bd a1
623 ├─╯
624 ◆ 000000000000
625 [EOF]
626 ");
627 work_dir.run_jj(["op", "restore", &setup_opid]).success();
628
629 // Duplicate a single commit after multiple commits including an ancestor.
630 let output = work_dir.run_jj(["duplicate", "a3", "--after", "a2", "--after", "b2"]);
631 insta::assert_snapshot!(output, @r"
632 ------- stderr -------
633 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
634 Duplicated 5fb83d2b58d6 as nsrwusvy d4608971 a3
635 Rebased 2 commits onto duplicated commits
636 [EOF]
637 ");
638 insta::assert_snapshot!(get_log_output(&work_dir), @r"
639 @ 3e122d6a4b70 d2
640 ○ ae61a031221a d1
641 │ ○ 47a79ab4bbc6 c2
642 │ ○ 9b24b49f717e c1
643 ├─╯
644 │ ○ 7f51acdb957f a4
645 │ ○ d9b98cc0291c a3
646 │ ○ d46089711a62 a3
647 │ ├─╮
648 │ │ ○ 65b6f1fe6b41 b2
649 │ │ ○ 6a9343b8797a b1
650 ├───╯
651 │ ○ 7bfd9fbe959c a2
652 │ ○ 5d93a4b8f4bd a1
653 ├─╯
654 ◆ 000000000000
655 [EOF]
656 ");
657 work_dir.run_jj(["op", "restore", &setup_opid]).success();
658
659 // Duplicate a single commit after multiple commits including a descendant.
660 let output = work_dir.run_jj(["duplicate", "a1", "--after", "a3", "--after", "b2"]);
661 insta::assert_snapshot!(output, @r"
662 ------- stderr -------
663 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
664 Duplicated 5d93a4b8f4bd as xpnwykqz 5a767b8b (empty) a1
665 Rebased 1 commits onto duplicated commits
666 [EOF]
667 ");
668 insta::assert_snapshot!(get_log_output(&work_dir), @r"
669 @ 3e122d6a4b70 d2
670 ○ ae61a031221a d1
671 │ ○ 47a79ab4bbc6 c2
672 │ ○ 9b24b49f717e c1
673 ├─╯
674 │ ○ 1cc19988fa94 a4
675 │ ○ 5a767b8b010f a1
676 │ ├─╮
677 │ │ ○ 65b6f1fe6b41 b2
678 │ │ ○ 6a9343b8797a b1
679 ├───╯
680 │ ○ 5fb83d2b58d6 a3
681 │ ○ 7bfd9fbe959c a2
682 │ ○ 5d93a4b8f4bd a1
683 ├─╯
684 ◆ 000000000000
685 [EOF]
686 ");
687 work_dir.run_jj(["op", "restore", &setup_opid]).success();
688
689 // Duplicate multiple commits without a direct ancestry relationship after a
690 // single commit without a direct relationship.
691 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--after", "c1"]);
692 insta::assert_snapshot!(output, @r"
693 ------- stderr -------
694 Duplicated 5d93a4b8f4bd as sryyqqkq c5744841 a1
695 Duplicated 6a9343b8797a as pxnqtknr 7ed6ac45 b1
696 Rebased 1 commits onto duplicated commits
697 [EOF]
698 ");
699 insta::assert_snapshot!(get_log_output(&work_dir), @r"
700 @ 3e122d6a4b70 d2
701 ○ ae61a031221a d1
702 │ ○ 0c968c7bf23e c2
703 │ ├─╮
704 │ │ ○ 7ed6ac45ebcf b1
705 │ ○ │ c57448416766 a1
706 │ ├─╯
707 │ ○ 9b24b49f717e c1
708 ├─╯
709 │ ○ 65b6f1fe6b41 b2
710 │ ○ 6a9343b8797a b1
711 ├─╯
712 │ ○ e9b68b6313be a4
713 │ ○ 5fb83d2b58d6 a3
714 │ ○ 7bfd9fbe959c a2
715 │ ○ 5d93a4b8f4bd a1
716 ├─╯
717 ◆ 000000000000
718 [EOF]
719 ");
720 work_dir.run_jj(["op", "restore", &setup_opid]).success();
721
722 // Duplicate multiple commits without a direct ancestry relationship after a
723 // single commit which is an ancestor of one of the duplicated commits.
724 let output = work_dir.run_jj(["duplicate", "a3", "b1", "--after", "a2"]);
725 insta::assert_snapshot!(output, @r"
726 ------- stderr -------
727 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
728 Duplicated 5fb83d2b58d6 as pyoswmwk 5f4bd02b a3
729 Duplicated 6a9343b8797a as yqnpwwmq d0cc3580 b1
730 Rebased 2 commits onto duplicated commits
731 [EOF]
732 ");
733 insta::assert_snapshot!(get_log_output(&work_dir), @r"
734 @ 3e122d6a4b70 d2
735 ○ ae61a031221a d1
736 │ ○ 47a79ab4bbc6 c2
737 │ ○ 9b24b49f717e c1
738 ├─╯
739 │ ○ 65b6f1fe6b41 b2
740 │ ○ 6a9343b8797a b1
741 ├─╯
742 │ ○ d2ac58d2e44a a4
743 │ ○ 88d3b0f2dde5 a3
744 │ ├─╮
745 │ │ ○ d0cc35804628 b1
746 │ ○ │ 5f4bd02b76d2 a3
747 │ ├─╯
748 │ ○ 7bfd9fbe959c a2
749 │ ○ 5d93a4b8f4bd a1
750 ├─╯
751 ◆ 000000000000
752 [EOF]
753 ");
754 work_dir.run_jj(["op", "restore", &setup_opid]).success();
755
756 // Duplicate multiple commits without a direct ancestry relationship after a
757 // single commit which is a descendant of one of the duplicated commits.
758 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--after", "a3"]);
759 insta::assert_snapshot!(output, @r"
760 ------- stderr -------
761 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
762 Duplicated 5d93a4b8f4bd as tpmlxquz 5ca04404 (empty) a1
763 Duplicated 6a9343b8797a as uukzylyy d72c12f0 b1
764 Rebased 1 commits onto duplicated commits
765 [EOF]
766 ");
767 insta::assert_snapshot!(get_log_output(&work_dir), @r"
768 @ 3e122d6a4b70 d2
769 ○ ae61a031221a d1
770 │ ○ 47a79ab4bbc6 c2
771 │ ○ 9b24b49f717e c1
772 ├─╯
773 │ ○ 65b6f1fe6b41 b2
774 │ ○ 6a9343b8797a b1
775 ├─╯
776 │ ○ cee03c20a724 a4
777 │ ├─╮
778 │ │ ○ d72c12f062ea b1
779 │ ○ │ 5ca044045de1 a1
780 │ ├─╯
781 │ ○ 5fb83d2b58d6 a3
782 │ ○ 7bfd9fbe959c a2
783 │ ○ 5d93a4b8f4bd a1
784 ├─╯
785 ◆ 000000000000
786 [EOF]
787 ");
788 work_dir.run_jj(["op", "restore", &setup_opid]).success();
789
790 // Duplicate multiple commits without a direct ancestry relationship after
791 // multiple commits without a direct relationship to the duplicated commits.
792 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--after", "c1", "--after", "d1"]);
793 insta::assert_snapshot!(output, @r"
794 ------- stderr -------
795 Duplicated 5d93a4b8f4bd as knltnxnu b1a94bc3 a1
796 Duplicated 6a9343b8797a as krtqozmx c43e8c46 b1
797 Rebased 2 commits onto duplicated commits
798 Working copy (@) now at: nmzmmopx 03190907 d2 | d2
799 Parent commit (@-) : knltnxnu b1a94bc3 a1
800 Parent commit (@-) : krtqozmx c43e8c46 b1
801 Added 3 files, modified 0 files, removed 0 files
802 [EOF]
803 ");
804 insta::assert_snapshot!(get_log_output(&work_dir), @r"
805 @ 03190907af36 d2
806 ├─╮
807 │ │ ○ 44e3521f0e5a c2
808 ╭─┬─╯
809 │ ○ c43e8c469e80 b1
810 │ ├─╮
811 ○ │ │ b1a94bc3e53c a1
812 ╰─┬─╮
813 │ ○ ae61a031221a d1
814 ○ │ 9b24b49f717e c1
815 ├─╯
816 ○ │ 65b6f1fe6b41 b2
817 ○ │ 6a9343b8797a b1
818 ├─╯
819 │ ○ e9b68b6313be a4
820 │ ○ 5fb83d2b58d6 a3
821 │ ○ 7bfd9fbe959c a2
822 │ ○ 5d93a4b8f4bd a1
823 ├─╯
824 ◆ 000000000000
825 [EOF]
826 ");
827 work_dir.run_jj(["op", "restore", &setup_opid]).success();
828
829 // Duplicate multiple commits without a direct ancestry relationship after
830 // multiple commits including an ancestor of one of the duplicated commits.
831 let output = work_dir.run_jj(["duplicate", "a3", "b1", "--after", "a1", "--after", "c1"]);
832 insta::assert_snapshot!(output, @r"
833 ------- stderr -------
834 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
835 Duplicated 5fb83d2b58d6 as wxzmtyol c560d597 a3
836 Duplicated 6a9343b8797a as musouqkq 6fb77fdd b1
837 Rebased 4 commits onto duplicated commits
838 [EOF]
839 ");
840 insta::assert_snapshot!(get_log_output(&work_dir), @r"
841 @ 3e122d6a4b70 d2
842 ○ ae61a031221a d1
843 │ ○ 4afd614e7e5d c2
844 │ ├─╮
845 │ │ │ ○ 651826a78259 a4
846 │ │ │ ○ 1f1810d0c067 a3
847 │ │ │ ○ 06062ed2c764 a2
848 │ ╭─┬─╯
849 │ │ ○ 6fb77fdd9246 b1
850 │ │ ├─╮
851 │ ○ │ │ c560d597e5ad a3
852 │ ╰─┬─╮
853 │ │ ○ 9b24b49f717e c1
854 ├─────╯
855 │ ○ 5d93a4b8f4bd a1
856 ├───╯
857 │ ○ 65b6f1fe6b41 b2
858 │ ○ 6a9343b8797a b1
859 ├─╯
860 ◆ 000000000000
861 [EOF]
862 ");
863 work_dir.run_jj(["op", "restore", &setup_opid]).success();
864
865 // Duplicate multiple commits without a direct ancestry relationship after
866 // multiple commits including a descendant of one of the duplicated commits.
867 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--after", "a3", "--after", "c2"]);
868 insta::assert_snapshot!(output, @r"
869 ------- stderr -------
870 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
871 Duplicated 5d93a4b8f4bd as quyylypw 62721448 (empty) a1
872 Duplicated 6a9343b8797a as prukwozq adc4a60a b1
873 Rebased 1 commits onto duplicated commits
874 [EOF]
875 ");
876 insta::assert_snapshot!(get_log_output(&work_dir), @r"
877 @ 3e122d6a4b70 d2
878 ○ ae61a031221a d1
879 │ ○ 1771e0dc1980 a4
880 │ ├─╮
881 │ │ ○ adc4a60abc7f b1
882 │ │ ├─╮
883 │ ○ │ │ 62721448a2d3 a1
884 │ ╰─┬─╮
885 │ │ ○ 47a79ab4bbc6 c2
886 │ │ ○ 9b24b49f717e c1
887 ├─────╯
888 │ ○ 5fb83d2b58d6 a3
889 │ ○ 7bfd9fbe959c a2
890 │ ○ 5d93a4b8f4bd a1
891 ├───╯
892 │ ○ 65b6f1fe6b41 b2
893 │ ○ 6a9343b8797a b1
894 ├─╯
895 ◆ 000000000000
896 [EOF]
897 ");
898 work_dir.run_jj(["op", "restore", &setup_opid]).success();
899
900 // Duplicate multiple commits with an ancestry relationship after a single
901 // commit without a direct relationship.
902 let output = work_dir.run_jj(["duplicate", "a1", "a3", "--after", "c2"]);
903 insta::assert_snapshot!(output, @r"
904 ------- stderr -------
905 Duplicated 5d93a4b8f4bd as vvvtksvt 3b8c0610 a1
906 Duplicated 5fb83d2b58d6 as yvrnrpnw 065f8c48 a3
907 [EOF]
908 ");
909 insta::assert_snapshot!(get_log_output(&work_dir), @r"
910 @ 3e122d6a4b70 d2
911 ○ ae61a031221a d1
912 │ ○ 065f8c485faf a3
913 │ ○ 3b8c061087d5 a1
914 │ ○ 47a79ab4bbc6 c2
915 │ ○ 9b24b49f717e c1
916 ├─╯
917 │ ○ 65b6f1fe6b41 b2
918 │ ○ 6a9343b8797a b1
919 ├─╯
920 │ ○ e9b68b6313be a4
921 │ ○ 5fb83d2b58d6 a3
922 │ ○ 7bfd9fbe959c a2
923 │ ○ 5d93a4b8f4bd a1
924 ├─╯
925 ◆ 000000000000
926 [EOF]
927 ");
928 work_dir.run_jj(["op", "restore", &setup_opid]).success();
929
930 // Duplicate multiple commits with an ancestry relationship after a single
931 // ancestor commit.
932 let output = work_dir.run_jj(["duplicate", "a2", "a3", "--after", "a1"]);
933 insta::assert_snapshot!(output, @r"
934 ------- stderr -------
935 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
936 Warning: Duplicating commit 7bfd9fbe959c as an ancestor of itself
937 Duplicated 7bfd9fbe959c as sukptuzs 8ea56d6a a2
938 Duplicated 5fb83d2b58d6 as rxnrppxl 7dfd4afc a3
939 Rebased 3 commits onto duplicated commits
940 [EOF]
941 ");
942 insta::assert_snapshot!(get_log_output(&work_dir), @r"
943 @ 3e122d6a4b70 d2
944 ○ ae61a031221a d1
945 │ ○ 47a79ab4bbc6 c2
946 │ ○ 9b24b49f717e c1
947 ├─╯
948 │ ○ 65b6f1fe6b41 b2
949 │ ○ 6a9343b8797a b1
950 ├─╯
951 │ ○ 75ffab7951db a4
952 │ ○ 6b0d57a3b912 a3
953 │ ○ d0bf50e30335 a2
954 │ ○ 7dfd4afcc2b9 a3
955 │ ○ 8ea56d6ad70b a2
956 │ ○ 5d93a4b8f4bd a1
957 ├─╯
958 ◆ 000000000000
959 [EOF]
960 ");
961 work_dir.run_jj(["op", "restore", &setup_opid]).success();
962
963 // Duplicate multiple commits with an ancestry relationship after a single
964 // descendant commit.
965 let output = work_dir.run_jj(["duplicate", "a1", "a2", "--after", "a3"]);
966 insta::assert_snapshot!(output, @r"
967 ------- stderr -------
968 Warning: Duplicating commit 7bfd9fbe959c as a descendant of itself
969 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
970 Duplicated 5d93a4b8f4bd as rwkyzntp 2e22df69 (empty) a1
971 Duplicated 7bfd9fbe959c as nqtyztop 4a1cab80 (empty) a2
972 Rebased 1 commits onto duplicated commits
973 [EOF]
974 ");
975 insta::assert_snapshot!(get_log_output(&work_dir), @r"
976 @ 3e122d6a4b70 d2
977 ○ ae61a031221a d1
978 │ ○ 47a79ab4bbc6 c2
979 │ ○ 9b24b49f717e c1
980 ├─╯
981 │ ○ 65b6f1fe6b41 b2
982 │ ○ 6a9343b8797a b1
983 ├─╯
984 │ ○ edfcd526983a a4
985 │ ○ 4a1cab80c404 a2
986 │ ○ 2e22df6994f9 a1
987 │ ○ 5fb83d2b58d6 a3
988 │ ○ 7bfd9fbe959c a2
989 │ ○ 5d93a4b8f4bd a1
990 ├─╯
991 ◆ 000000000000
992 [EOF]
993 ");
994 work_dir.run_jj(["op", "restore", &setup_opid]).success();
995
996 // Duplicate multiple commits with an ancestry relationship after multiple
997 // commits without a direct relationship to the duplicated commits.
998 let output = work_dir.run_jj(["duplicate", "a1", "a3", "--after", "c2", "--after", "d2"]);
999 insta::assert_snapshot!(output, @r"
1000 ------- stderr -------
1001 Duplicated 5d93a4b8f4bd as nwmqwkzz d4471259 a1
1002 Duplicated 5fb83d2b58d6 as uwrrnrtx 2d619dac a3
1003 [EOF]
1004 ");
1005 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1006 ○ 2d619dacc18a a3
1007 ○ d447125943ed a1
1008 ├─╮
1009 │ @ 3e122d6a4b70 d2
1010 │ ○ ae61a031221a d1
1011 ○ │ 47a79ab4bbc6 c2
1012 ○ │ 9b24b49f717e c1
1013 ├─╯
1014 │ ○ 65b6f1fe6b41 b2
1015 │ ○ 6a9343b8797a b1
1016 ├─╯
1017 │ ○ e9b68b6313be a4
1018 │ ○ 5fb83d2b58d6 a3
1019 │ ○ 7bfd9fbe959c a2
1020 │ ○ 5d93a4b8f4bd a1
1021 ├─╯
1022 ◆ 000000000000
1023 [EOF]
1024 ");
1025 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1026
1027 // Duplicate multiple commits with an ancestry relationship after multiple
1028 // commits including an ancestor of one of the duplicated commits.
1029 let output = work_dir.run_jj(["duplicate", "a3", "a4", "--after", "a2", "--after", "c2"]);
1030 insta::assert_snapshot!(output, @r"
1031 ------- stderr -------
1032 Warning: Duplicating commit e9b68b6313be as an ancestor of itself
1033 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
1034 Duplicated 5fb83d2b58d6 as wunttkrp 2c3a430f a3
1035 Duplicated e9b68b6313be as puxpuzrm f1705363 a4
1036 Rebased 2 commits onto duplicated commits
1037 [EOF]
1038 ");
1039 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1040 @ 3e122d6a4b70 d2
1041 ○ ae61a031221a d1
1042 │ ○ 81dc0bb0c3b8 a4
1043 │ ○ c56d8a18caca a3
1044 │ ○ f17053639e87 a4
1045 │ ○ 2c3a430f6116 a3
1046 │ ├─╮
1047 │ │ ○ 47a79ab4bbc6 c2
1048 │ │ ○ 9b24b49f717e c1
1049 ├───╯
1050 │ ○ 7bfd9fbe959c a2
1051 │ ○ 5d93a4b8f4bd a1
1052 ├─╯
1053 │ ○ 65b6f1fe6b41 b2
1054 │ ○ 6a9343b8797a b1
1055 ├─╯
1056 ◆ 000000000000
1057 [EOF]
1058 ");
1059 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1060
1061 // Duplicate multiple commits with an ancestry relationship after multiple
1062 // commits including a descendant of one of the duplicated commits.
1063 let output = work_dir.run_jj(["duplicate", "a1", "a2", "--after", "a3", "--after", "c2"]);
1064 insta::assert_snapshot!(output, @r"
1065 ------- stderr -------
1066 Warning: Duplicating commit 7bfd9fbe959c as a descendant of itself
1067 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
1068 Duplicated 5d93a4b8f4bd as zwvplpop 0679c0a3 (empty) a1
1069 Duplicated 7bfd9fbe959c as znsksvls 4d69ff37 (empty) a2
1070 Rebased 1 commits onto duplicated commits
1071 [EOF]
1072 ");
1073 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1074 @ 3e122d6a4b70 d2
1075 ○ ae61a031221a d1
1076 │ ○ 352c4687b8a8 a4
1077 │ ○ 4d69ff370b1c a2
1078 │ ○ 0679c0a3fcd1 a1
1079 │ ├─╮
1080 │ │ ○ 47a79ab4bbc6 c2
1081 │ │ ○ 9b24b49f717e c1
1082 ├───╯
1083 │ ○ 5fb83d2b58d6 a3
1084 │ ○ 7bfd9fbe959c a2
1085 │ ○ 5d93a4b8f4bd a1
1086 ├─╯
1087 │ ○ 65b6f1fe6b41 b2
1088 │ ○ 6a9343b8797a b1
1089 ├─╯
1090 ◆ 000000000000
1091 [EOF]
1092 ");
1093 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1094
1095 // Should error if a loop will be created.
1096 let output = work_dir.run_jj(["duplicate", "a1", "--after", "b1", "--after", "b2"]);
1097 insta::assert_snapshot!(output, @r"
1098 ------- stderr -------
1099 Error: Refusing to create a loop: commit 65b6f1fe6b41 would be both an ancestor and a descendant of the duplicated commits
1100 [EOF]
1101 [exit status: 1]
1102 ");
1103}
1104
1105#[test]
1106fn test_duplicate_insert_before() {
1107 let test_env = TestEnvironment::default();
1108 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
1109 let work_dir = test_env.work_dir("repo");
1110
1111 create_commit(&work_dir, "a1", &[]);
1112 create_commit(&work_dir, "a2", &["a1"]);
1113 create_commit(&work_dir, "a3", &["a2"]);
1114 create_commit(&work_dir, "a4", &["a3"]);
1115 create_commit(&work_dir, "b1", &[]);
1116 create_commit(&work_dir, "b2", &["b1"]);
1117 create_commit(&work_dir, "c1", &[]);
1118 create_commit(&work_dir, "c2", &["c1"]);
1119 create_commit(&work_dir, "d1", &[]);
1120 create_commit(&work_dir, "d2", &["d1"]);
1121 let setup_opid = work_dir.current_operation_id();
1122
1123 // Test the setup
1124 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1125 @ 3e122d6a4b70 d2
1126 ○ ae61a031221a d1
1127 │ ○ 47a79ab4bbc6 c2
1128 │ ○ 9b24b49f717e c1
1129 ├─╯
1130 │ ○ 65b6f1fe6b41 b2
1131 │ ○ 6a9343b8797a b1
1132 ├─╯
1133 │ ○ e9b68b6313be a4
1134 │ ○ 5fb83d2b58d6 a3
1135 │ ○ 7bfd9fbe959c a2
1136 │ ○ 5d93a4b8f4bd a1
1137 ├─╯
1138 ◆ 000000000000
1139 [EOF]
1140 ");
1141
1142 // Duplicate a single commit before a single commit with no direct relationship.
1143 let output = work_dir.run_jj(["duplicate", "a1", "--before", "b2"]);
1144 insta::assert_snapshot!(output, @r"
1145 ------- stderr -------
1146 Duplicated 5d93a4b8f4bd as pzsxstzt a5a114e3 a1
1147 Rebased 1 commits onto duplicated commits
1148 [EOF]
1149 ");
1150 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1151 @ 3e122d6a4b70 d2
1152 ○ ae61a031221a d1
1153 │ ○ 47a79ab4bbc6 c2
1154 │ ○ 9b24b49f717e c1
1155 ├─╯
1156 │ ○ 3efc0755f6a0 b2
1157 │ ○ a5a114e3c1ff a1
1158 │ ○ 6a9343b8797a b1
1159 ├─╯
1160 │ ○ e9b68b6313be a4
1161 │ ○ 5fb83d2b58d6 a3
1162 │ ○ 7bfd9fbe959c a2
1163 │ ○ 5d93a4b8f4bd a1
1164 ├─╯
1165 ◆ 000000000000
1166 [EOF]
1167 ");
1168 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1169
1170 // Duplicate a single commit before a single ancestor commit.
1171 let output = work_dir.run_jj(["duplicate", "a3", "--before", "a1"]);
1172 insta::assert_snapshot!(output, @r"
1173 ------- stderr -------
1174 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
1175 Duplicated 5fb83d2b58d6 as qmkrwlvp 12bdfd40 a3
1176 Rebased 4 commits onto duplicated commits
1177 [EOF]
1178 ");
1179 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1180 @ 3e122d6a4b70 d2
1181 ○ ae61a031221a d1
1182 │ ○ 34b04bbb49e6 a4
1183 │ ○ 5c5cd23039e8 a3
1184 │ ○ 66ae7f9cd402 a2
1185 │ ○ c42e00e5d967 a1
1186 │ ○ 12bdfd4031ac a3
1187 ├─╯
1188 │ ○ 47a79ab4bbc6 c2
1189 │ ○ 9b24b49f717e c1
1190 ├─╯
1191 │ ○ 65b6f1fe6b41 b2
1192 │ ○ 6a9343b8797a b1
1193 ├─╯
1194 ◆ 000000000000
1195 [EOF]
1196 ");
1197 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1198
1199 // Duplicate a single commit before a single descendant commit.
1200 let output = work_dir.run_jj(["duplicate", "a1", "--before", "a3"]);
1201 insta::assert_snapshot!(output, @r"
1202 ------- stderr -------
1203 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
1204 Duplicated 5d93a4b8f4bd as qwyusntz f9b156e7 (empty) a1
1205 Rebased 2 commits onto duplicated commits
1206 [EOF]
1207 ");
1208 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1209 @ 3e122d6a4b70 d2
1210 ○ ae61a031221a d1
1211 │ ○ 47a79ab4bbc6 c2
1212 │ ○ 9b24b49f717e c1
1213 ├─╯
1214 │ ○ 65b6f1fe6b41 b2
1215 │ ○ 6a9343b8797a b1
1216 ├─╯
1217 │ ○ 4586d15aa692 a4
1218 │ ○ 11f942e98d1b a3
1219 │ ○ f9b156e79e8b a1
1220 │ ○ 7bfd9fbe959c a2
1221 │ ○ 5d93a4b8f4bd a1
1222 ├─╯
1223 ◆ 000000000000
1224 [EOF]
1225 ");
1226 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1227
1228 // Duplicate a single commit before multiple commits with no direct
1229 // relationship.
1230 let output = work_dir.run_jj(["duplicate", "a1", "--before", "b2", "--before", "c2"]);
1231 insta::assert_snapshot!(output, @r"
1232 ------- stderr -------
1233 Duplicated 5d93a4b8f4bd as soqnvnyz 7e84ab7f a1
1234 Rebased 2 commits onto duplicated commits
1235 [EOF]
1236 ");
1237 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1238 @ 3e122d6a4b70 d2
1239 ○ ae61a031221a d1
1240 │ ○ 848cd66b5194 c2
1241 │ │ ○ d68f684471e0 b2
1242 │ ├─╯
1243 │ ○ 7e84ab7f347e a1
1244 │ ├─╮
1245 │ │ ○ 9b24b49f717e c1
1246 ├───╯
1247 │ ○ 6a9343b8797a b1
1248 ├─╯
1249 │ ○ e9b68b6313be a4
1250 │ ○ 5fb83d2b58d6 a3
1251 │ ○ 7bfd9fbe959c a2
1252 │ ○ 5d93a4b8f4bd a1
1253 ├─╯
1254 ◆ 000000000000
1255 [EOF]
1256 ");
1257 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1258
1259 // Duplicate a single commit before multiple commits including an ancestor.
1260 let output = work_dir.run_jj(["duplicate", "a3", "--before", "a2", "--before", "b2"]);
1261 insta::assert_snapshot!(output, @r"
1262 ------- stderr -------
1263 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
1264 Duplicated 5fb83d2b58d6 as nsrwusvy 1fbb9ed2 a3
1265 Rebased 4 commits onto duplicated commits
1266 [EOF]
1267 ");
1268 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1269 @ 3e122d6a4b70 d2
1270 ○ ae61a031221a d1
1271 │ ○ 47a79ab4bbc6 c2
1272 │ ○ 9b24b49f717e c1
1273 ├─╯
1274 │ ○ 19cfc3d27f27 b2
1275 │ │ ○ daf5b2e6bea1 a4
1276 │ │ ○ 436e574b93c8 a3
1277 │ │ ○ aa581314212c a2
1278 │ ├─╯
1279 │ ○ 1fbb9ed2e53b a3
1280 │ ├─╮
1281 │ │ ○ 6a9343b8797a b1
1282 ├───╯
1283 │ ○ 5d93a4b8f4bd a1
1284 ├─╯
1285 ◆ 000000000000
1286 [EOF]
1287 ");
1288 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1289
1290 // Duplicate a single commit before multiple commits including a descendant.
1291 let output = work_dir.run_jj(["duplicate", "a1", "--before", "a3", "--before", "b2"]);
1292 insta::assert_snapshot!(output, @r"
1293 ------- stderr -------
1294 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
1295 Duplicated 5d93a4b8f4bd as xpnwykqz f829aabe (empty) a1
1296 Rebased 3 commits onto duplicated commits
1297 [EOF]
1298 ");
1299 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1300 @ 3e122d6a4b70 d2
1301 ○ ae61a031221a d1
1302 │ ○ 47a79ab4bbc6 c2
1303 │ ○ 9b24b49f717e c1
1304 ├─╯
1305 │ ○ 43e7fd47784c b2
1306 │ │ ○ 62300ba27133 a4
1307 │ │ ○ 601308b69f16 a3
1308 │ ├─╯
1309 │ ○ f829aabe2f51 a1
1310 │ ├─╮
1311 │ │ ○ 6a9343b8797a b1
1312 ├───╯
1313 │ ○ 7bfd9fbe959c a2
1314 │ ○ 5d93a4b8f4bd a1
1315 ├─╯
1316 ◆ 000000000000
1317 [EOF]
1318 ");
1319 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1320
1321 // Duplicate multiple commits without a direct ancestry relationship before a
1322 // single commit without a direct relationship.
1323 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--before", "c1"]);
1324 insta::assert_snapshot!(output, @r"
1325 ------- stderr -------
1326 Duplicated 5d93a4b8f4bd as sryyqqkq d3570b8d a1
1327 Duplicated 6a9343b8797a as pxnqtknr a298a26e b1
1328 Rebased 2 commits onto duplicated commits
1329 [EOF]
1330 ");
1331 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1332 @ 3e122d6a4b70 d2
1333 ○ ae61a031221a d1
1334 │ ○ 1c97956e2968 c2
1335 │ ○ 56e6d6b25ef7 c1
1336 │ ├─╮
1337 │ │ ○ a298a26ec5c9 b1
1338 ├───╯
1339 │ ○ d3570b8d6109 a1
1340 ├─╯
1341 │ ○ 65b6f1fe6b41 b2
1342 │ ○ 6a9343b8797a b1
1343 ├─╯
1344 │ ○ e9b68b6313be a4
1345 │ ○ 5fb83d2b58d6 a3
1346 │ ○ 7bfd9fbe959c a2
1347 │ ○ 5d93a4b8f4bd a1
1348 ├─╯
1349 ◆ 000000000000
1350 [EOF]
1351 ");
1352 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1353
1354 // Duplicate multiple commits without a direct ancestry relationship before a
1355 // single commit which is an ancestor of one of the duplicated commits.
1356 let output = work_dir.run_jj(["duplicate", "a3", "b1", "--before", "a2"]);
1357 insta::assert_snapshot!(output, @r"
1358 ------- stderr -------
1359 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
1360 Duplicated 5fb83d2b58d6 as pyoswmwk 6d382f0a a3
1361 Duplicated 6a9343b8797a as yqnpwwmq 7a8b8049 b1
1362 Rebased 3 commits onto duplicated commits
1363 [EOF]
1364 ");
1365 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1366 @ 3e122d6a4b70 d2
1367 ○ ae61a031221a d1
1368 │ ○ 47a79ab4bbc6 c2
1369 │ ○ 9b24b49f717e c1
1370 ├─╯
1371 │ ○ 65b6f1fe6b41 b2
1372 │ ○ 6a9343b8797a b1
1373 ├─╯
1374 │ ○ d73c86fdc91f a4
1375 │ ○ 06dafd59a24a a3
1376 │ ○ 536a010d2ac2 a2
1377 │ ├─╮
1378 │ │ ○ 7a8b80497eb5 b1
1379 │ ○ │ 6d382f0aecca a3
1380 │ ├─╯
1381 │ ○ 5d93a4b8f4bd a1
1382 ├─╯
1383 ◆ 000000000000
1384 [EOF]
1385 ");
1386 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1387
1388 // Duplicate multiple commits without a direct ancestry relationship before a
1389 // single commit which is a descendant of one of the duplicated commits.
1390 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--before", "a3"]);
1391 insta::assert_snapshot!(output, @r"
1392 ------- stderr -------
1393 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
1394 Duplicated 5d93a4b8f4bd as tpmlxquz 609ecdcd (empty) a1
1395 Duplicated 6a9343b8797a as uukzylyy b225b93f b1
1396 Rebased 2 commits onto duplicated commits
1397 [EOF]
1398 ");
1399 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1400 @ 3e122d6a4b70 d2
1401 ○ ae61a031221a d1
1402 │ ○ 47a79ab4bbc6 c2
1403 │ ○ 9b24b49f717e c1
1404 ├─╯
1405 │ ○ 65b6f1fe6b41 b2
1406 │ ○ 6a9343b8797a b1
1407 ├─╯
1408 │ ○ efd540e1c353 a4
1409 │ ○ 4433cae3e37f a3
1410 │ ├─╮
1411 │ │ ○ b225b93fdf2a b1
1412 │ ○ │ 609ecdcd4537 a1
1413 │ ├─╯
1414 │ ○ 7bfd9fbe959c a2
1415 │ ○ 5d93a4b8f4bd a1
1416 ├─╯
1417 ◆ 000000000000
1418 [EOF]
1419 ");
1420 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1421
1422 // Duplicate multiple commits without a direct ancestry relationship before
1423 // multiple commits without a direct relationship to the duplicated commits.
1424 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--before", "c1", "--before", "d1"]);
1425 insta::assert_snapshot!(output, @r"
1426 ------- stderr -------
1427 Duplicated 5d93a4b8f4bd as knltnxnu 5ff608b7 a1
1428 Duplicated 6a9343b8797a as krtqozmx d90775d6 b1
1429 Rebased 4 commits onto duplicated commits
1430 Working copy (@) now at: nmzmmopx 90d9e046 d2 | d2
1431 Parent commit (@-) : xznxytkn c97d9dd1 d1 | d1
1432 Added 2 files, modified 0 files, removed 0 files
1433 [EOF]
1434 ");
1435 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1436 @ 90d9e046049a d2
1437 ○ c97d9dd11c08 d1
1438 ├─╮
1439 │ │ ○ b26d4b0049cc c2
1440 │ │ ○ f4ac74618f17 c1
1441 ╭─┬─╯
1442 │ ○ d90775d6f189 b1
1443 ○ │ 5ff608b7ed1c a1
1444 ├─╯
1445 │ ○ 65b6f1fe6b41 b2
1446 │ ○ 6a9343b8797a b1
1447 ├─╯
1448 │ ○ e9b68b6313be a4
1449 │ ○ 5fb83d2b58d6 a3
1450 │ ○ 7bfd9fbe959c a2
1451 │ ○ 5d93a4b8f4bd a1
1452 ├─╯
1453 ◆ 000000000000
1454 [EOF]
1455 ");
1456 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1457
1458 // Duplicate multiple commits without a direct ancestry relationship before
1459 // multiple commits including an ancestor of one of the duplicated commits.
1460 let output = work_dir.run_jj(["duplicate", "a3", "b1", "--before", "a1", "--before", "c1"]);
1461 insta::assert_snapshot!(output, @r"
1462 ------- stderr -------
1463 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
1464 Duplicated 5fb83d2b58d6 as wxzmtyol 589d5def a3
1465 Duplicated 6a9343b8797a as musouqkq bfc0bdd5 b1
1466 Rebased 6 commits onto duplicated commits
1467 [EOF]
1468 ");
1469 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1470 @ 3e122d6a4b70 d2
1471 ○ ae61a031221a d1
1472 │ ○ 46eaff09efae c2
1473 │ ○ d76157ebc72f c1
1474 │ ├─╮
1475 │ │ │ ○ 96a7e7505923 a4
1476 │ │ │ ○ 0e0b1ee222fd a3
1477 │ │ │ ○ 296a318721f2 a2
1478 │ │ │ ○ a3bd387e7dbf a1
1479 │ ╭─┬─╯
1480 │ │ ○ bfc0bdd59039 b1
1481 ├───╯
1482 │ ○ 589d5defb274 a3
1483 ├─╯
1484 │ ○ 65b6f1fe6b41 b2
1485 │ ○ 6a9343b8797a b1
1486 ├─╯
1487 ◆ 000000000000
1488 [EOF]
1489 ");
1490 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1491
1492 // Duplicate multiple commits without a direct ancestry relationship before
1493 // multiple commits including a descendant of one of the duplicated commits.
1494 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--before", "a3", "--before", "c2"]);
1495 insta::assert_snapshot!(output, @r"
1496 ------- stderr -------
1497 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
1498 Duplicated 5d93a4b8f4bd as quyylypw 67396c17 (empty) a1
1499 Duplicated 6a9343b8797a as prukwozq b43f94ae b1
1500 Rebased 3 commits onto duplicated commits
1501 [EOF]
1502 ");
1503 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1504 @ 3e122d6a4b70 d2
1505 ○ ae61a031221a d1
1506 │ ○ 3805f705f18c c2
1507 │ ├─╮
1508 │ │ │ ○ 73ae5483e043 a4
1509 │ │ │ ○ 06954bb8314f a3
1510 │ ╭─┬─╯
1511 │ │ ○ b43f94ae704a b1
1512 │ │ ├─╮
1513 │ ○ │ │ 67396c171ca4 a1
1514 │ ╰─┬─╮
1515 │ │ ○ 9b24b49f717e c1
1516 ├─────╯
1517 │ ○ 7bfd9fbe959c a2
1518 │ ○ 5d93a4b8f4bd a1
1519 ├───╯
1520 │ ○ 65b6f1fe6b41 b2
1521 │ ○ 6a9343b8797a b1
1522 ├─╯
1523 ◆ 000000000000
1524 [EOF]
1525 ");
1526 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1527
1528 // Duplicate multiple commits with an ancestry relationship before a single
1529 // commit without a direct relationship.
1530 let output = work_dir.run_jj(["duplicate", "a1", "a3", "--before", "c2"]);
1531 insta::assert_snapshot!(output, @r"
1532 ------- stderr -------
1533 Duplicated 5d93a4b8f4bd as vvvtksvt da397430 a1
1534 Duplicated 5fb83d2b58d6 as yvrnrpnw 39e64981 a3
1535 Rebased 1 commits onto duplicated commits
1536 [EOF]
1537 ");
1538 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1539 @ 3e122d6a4b70 d2
1540 ○ ae61a031221a d1
1541 │ ○ cf5a6e4b5bde c2
1542 │ ○ 39e64981a9f3 a3
1543 │ ○ da397430d587 a1
1544 │ ○ 9b24b49f717e c1
1545 ├─╯
1546 │ ○ 65b6f1fe6b41 b2
1547 │ ○ 6a9343b8797a b1
1548 ├─╯
1549 │ ○ e9b68b6313be a4
1550 │ ○ 5fb83d2b58d6 a3
1551 │ ○ 7bfd9fbe959c a2
1552 │ ○ 5d93a4b8f4bd a1
1553 ├─╯
1554 ◆ 000000000000
1555 [EOF]
1556 ");
1557 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1558
1559 // Duplicate multiple commits with an ancestry relationship before a single
1560 // ancestor commit.
1561 let output = work_dir.run_jj(["duplicate", "a1", "a3", "--before", "a1"]);
1562 insta::assert_snapshot!(output, @r"
1563 ------- stderr -------
1564 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
1565 Warning: Duplicating commit 5d93a4b8f4bd as an ancestor of itself
1566 Duplicated 5d93a4b8f4bd as sukptuzs c1e67cc4 a1
1567 Duplicated 5fb83d2b58d6 as rxnrppxl d224a34d a3
1568 Rebased 4 commits onto duplicated commits
1569 [EOF]
1570 ");
1571 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1572 @ 3e122d6a4b70 d2
1573 ○ ae61a031221a d1
1574 │ ○ 21bcc8fa5b2d a4
1575 │ ○ 3d16228126ce a3
1576 │ ○ cbba38177a37 a2
1577 │ ○ ef99cb80d765 a1
1578 │ ○ d224a34d206e a3
1579 │ ○ c1e67cc44e94 a1
1580 ├─╯
1581 │ ○ 47a79ab4bbc6 c2
1582 │ ○ 9b24b49f717e c1
1583 ├─╯
1584 │ ○ 65b6f1fe6b41 b2
1585 │ ○ 6a9343b8797a b1
1586 ├─╯
1587 ◆ 000000000000
1588 [EOF]
1589 ");
1590 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1591
1592 // Duplicate multiple commits with an ancestry relationship before a single
1593 // descendant commit.
1594 let output = work_dir.run_jj(["duplicate", "a1", "a2", "--before", "a3"]);
1595 insta::assert_snapshot!(output, @r"
1596 ------- stderr -------
1597 Warning: Duplicating commit 7bfd9fbe959c as a descendant of itself
1598 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
1599 Duplicated 5d93a4b8f4bd as rwkyzntp 8939e563 (empty) a1
1600 Duplicated 7bfd9fbe959c as nqtyztop 8f0c1f03 (empty) a2
1601 Rebased 2 commits onto duplicated commits
1602 [EOF]
1603 ");
1604 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1605 @ 3e122d6a4b70 d2
1606 ○ ae61a031221a d1
1607 │ ○ 47a79ab4bbc6 c2
1608 │ ○ 9b24b49f717e c1
1609 ├─╯
1610 │ ○ 65b6f1fe6b41 b2
1611 │ ○ 6a9343b8797a b1
1612 ├─╯
1613 │ ○ 29333bd03e54 a4
1614 │ ○ a3fb0a82f5eb a3
1615 │ ○ 8f0c1f038c57 a2
1616 │ ○ 8939e563743c a1
1617 │ ○ 7bfd9fbe959c a2
1618 │ ○ 5d93a4b8f4bd a1
1619 ├─╯
1620 ◆ 000000000000
1621 [EOF]
1622 ");
1623 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1624
1625 // Duplicate multiple commits with an ancestry relationship before multiple
1626 // commits without a direct relationship to the duplicated commits.
1627 let output = work_dir.run_jj(["duplicate", "a1", "a3", "--before", "c2", "--before", "d2"]);
1628 insta::assert_snapshot!(output, @r"
1629 ------- stderr -------
1630 Duplicated 5d93a4b8f4bd as nwmqwkzz 0c42d8f6 a1
1631 Duplicated 5fb83d2b58d6 as uwrrnrtx 5dc4c51b a3
1632 Rebased 2 commits onto duplicated commits
1633 Working copy (@) now at: nmzmmopx dee40354 d2 | d2
1634 Parent commit (@-) : uwrrnrtx 5dc4c51b a3
1635 Added 3 files, modified 0 files, removed 0 files
1636 [EOF]
1637 ");
1638 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1639 @ dee40354cc51 d2
1640 │ ○ 84fe86982803 c2
1641 ├─╯
1642 ○ 5dc4c51b1af5 a3
1643 ○ 0c42d8f65b5f a1
1644 ├─╮
1645 │ ○ ae61a031221a d1
1646 ○ │ 9b24b49f717e c1
1647 ├─╯
1648 │ ○ 65b6f1fe6b41 b2
1649 │ ○ 6a9343b8797a b1
1650 ├─╯
1651 │ ○ e9b68b6313be a4
1652 │ ○ 5fb83d2b58d6 a3
1653 │ ○ 7bfd9fbe959c a2
1654 │ ○ 5d93a4b8f4bd a1
1655 ├─╯
1656 ◆ 000000000000
1657 [EOF]
1658 ");
1659 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1660
1661 // Duplicate multiple commits with an ancestry relationship before multiple
1662 // commits including an ancestor of one of the duplicated commits.
1663 let output = work_dir.run_jj(["duplicate", "a3", "a4", "--before", "a2", "--before", "c2"]);
1664 insta::assert_snapshot!(output, @r"
1665 ------- stderr -------
1666 Warning: Duplicating commit e9b68b6313be as an ancestor of itself
1667 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
1668 Duplicated 5fb83d2b58d6 as wunttkrp 34d7d114 a3
1669 Duplicated e9b68b6313be as puxpuzrm f2f4e48c a4
1670 Rebased 4 commits onto duplicated commits
1671 [EOF]
1672 ");
1673 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1674 @ 3e122d6a4b70 d2
1675 ○ ae61a031221a d1
1676 │ ○ 90e363bf45c9 c2
1677 │ │ ○ 27b30a1f951d a4
1678 │ │ ○ c82aa4009567 a3
1679 │ │ ○ cb2359418fba a2
1680 │ ├─╯
1681 │ ○ f2f4e48c7b5f a4
1682 │ ○ 34d7d114f747 a3
1683 │ ├─╮
1684 │ │ ○ 9b24b49f717e c1
1685 ├───╯
1686 │ ○ 5d93a4b8f4bd a1
1687 ├─╯
1688 │ ○ 65b6f1fe6b41 b2
1689 │ ○ 6a9343b8797a b1
1690 ├─╯
1691 ◆ 000000000000
1692 [EOF]
1693 ");
1694 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1695
1696 // Duplicate multiple commits with an ancestry relationship before multiple
1697 // commits including a descendant of one of the duplicated commits.
1698 let output = work_dir.run_jj(["duplicate", "a1", "a2", "--before", "a3", "--before", "c2"]);
1699 insta::assert_snapshot!(output, @r"
1700 ------- stderr -------
1701 Warning: Duplicating commit 7bfd9fbe959c as a descendant of itself
1702 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
1703 Duplicated 5d93a4b8f4bd as zwvplpop 8028cd9b (empty) a1
1704 Duplicated 7bfd9fbe959c as znsksvls 2c7805ae (empty) a2
1705 Rebased 3 commits onto duplicated commits
1706 [EOF]
1707 ");
1708 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1709 @ 3e122d6a4b70 d2
1710 ○ ae61a031221a d1
1711 │ ○ 47a3ddc184c2 c2
1712 │ │ ○ 9514cf056d7f a4
1713 │ │ ○ c3caf7b0f6aa a3
1714 │ ├─╯
1715 │ ○ 2c7805ae55e6 a2
1716 │ ○ 8028cd9b91ae a1
1717 │ ├─╮
1718 │ │ ○ 9b24b49f717e c1
1719 ├───╯
1720 │ ○ 7bfd9fbe959c a2
1721 │ ○ 5d93a4b8f4bd a1
1722 ├─╯
1723 │ ○ 65b6f1fe6b41 b2
1724 │ ○ 6a9343b8797a b1
1725 ├─╯
1726 ◆ 000000000000
1727 [EOF]
1728 ");
1729 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1730
1731 // Should error if a loop will be created.
1732 let output = work_dir.run_jj(["duplicate", "a1", "--before", "b1", "--before", "b2"]);
1733 insta::assert_snapshot!(output, @r"
1734 ------- stderr -------
1735 Error: Refusing to create a loop: commit 6a9343b8797a would be both an ancestor and a descendant of the duplicated commits
1736 [EOF]
1737 [exit status: 1]
1738 ");
1739}
1740
1741#[test]
1742fn test_duplicate_insert_after_before() {
1743 let test_env = TestEnvironment::default();
1744 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
1745 let work_dir = test_env.work_dir("repo");
1746
1747 create_commit(&work_dir, "a1", &[]);
1748 create_commit(&work_dir, "a2", &["a1"]);
1749 create_commit(&work_dir, "a3", &["a2"]);
1750 create_commit(&work_dir, "a4", &["a3"]);
1751 create_commit(&work_dir, "b1", &[]);
1752 create_commit(&work_dir, "b2", &["b1"]);
1753 create_commit(&work_dir, "c1", &[]);
1754 create_commit(&work_dir, "c2", &["c1"]);
1755 create_commit(&work_dir, "d1", &[]);
1756 create_commit(&work_dir, "d2", &["d1"]);
1757 let setup_opid = work_dir.current_operation_id();
1758
1759 // Test the setup
1760 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1761 @ 3e122d6a4b70 d2
1762 ○ ae61a031221a d1
1763 │ ○ 47a79ab4bbc6 c2
1764 │ ○ 9b24b49f717e c1
1765 ├─╯
1766 │ ○ 65b6f1fe6b41 b2
1767 │ ○ 6a9343b8797a b1
1768 ├─╯
1769 │ ○ e9b68b6313be a4
1770 │ ○ 5fb83d2b58d6 a3
1771 │ ○ 7bfd9fbe959c a2
1772 │ ○ 5d93a4b8f4bd a1
1773 ├─╯
1774 ◆ 000000000000
1775 [EOF]
1776 ");
1777
1778 // Duplicate a single commit in between commits with no direct relationship.
1779 let output = work_dir.run_jj(["duplicate", "a1", "--before", "b2", "--after", "c2"]);
1780 insta::assert_snapshot!(output, @r"
1781 ------- stderr -------
1782 Duplicated 5d93a4b8f4bd as pzsxstzt d144734f a1
1783 Rebased 1 commits onto duplicated commits
1784 [EOF]
1785 ");
1786 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1787 @ 3e122d6a4b70 d2
1788 ○ ae61a031221a d1
1789 │ ○ e0b0802624fc b2
1790 │ ├─╮
1791 │ │ ○ d144734f7749 a1
1792 │ │ ○ 47a79ab4bbc6 c2
1793 │ │ ○ 9b24b49f717e c1
1794 ├───╯
1795 │ ○ 6a9343b8797a b1
1796 ├─╯
1797 │ ○ e9b68b6313be a4
1798 │ ○ 5fb83d2b58d6 a3
1799 │ ○ 7bfd9fbe959c a2
1800 │ ○ 5d93a4b8f4bd a1
1801 ├─╯
1802 ◆ 000000000000
1803 [EOF]
1804 ");
1805 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1806
1807 // Duplicate a single commit in between ancestor commits.
1808 let output = work_dir.run_jj(["duplicate", "a3", "--before", "a2", "--after", "a1"]);
1809 insta::assert_snapshot!(output, @r"
1810 ------- stderr -------
1811 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
1812 Duplicated 5fb83d2b58d6 as qmkrwlvp 4048f2fb a3
1813 Rebased 3 commits onto duplicated commits
1814 [EOF]
1815 ");
1816 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1817 @ 3e122d6a4b70 d2
1818 ○ ae61a031221a d1
1819 │ ○ 47a79ab4bbc6 c2
1820 │ ○ 9b24b49f717e c1
1821 ├─╯
1822 │ ○ 65b6f1fe6b41 b2
1823 │ ○ 6a9343b8797a b1
1824 ├─╯
1825 │ ○ d6d86a8bdfda a4
1826 │ ○ 25c595527054 a3
1827 │ ○ 4b55efbf3237 a2
1828 │ ○ 4048f2fbcf5c a3
1829 │ ○ 5d93a4b8f4bd a1
1830 ├─╯
1831 ◆ 000000000000
1832 [EOF]
1833 ");
1834 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1835
1836 // Duplicate a single commit in between an ancestor commit and a commit with no
1837 // direct relationship.
1838 let output = work_dir.run_jj(["duplicate", "a3", "--before", "a2", "--after", "b2"]);
1839 insta::assert_snapshot!(output, @r"
1840 ------- stderr -------
1841 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
1842 Duplicated 5fb83d2b58d6 as qwyusntz 5bcb3c14 a3
1843 Rebased 3 commits onto duplicated commits
1844 [EOF]
1845 ");
1846 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1847 @ 3e122d6a4b70 d2
1848 ○ ae61a031221a d1
1849 │ ○ 47a79ab4bbc6 c2
1850 │ ○ 9b24b49f717e c1
1851 ├─╯
1852 │ ○ 332ac36618b3 a4
1853 │ ○ 5d1795632655 a3
1854 │ ○ 9852ab50af53 a2
1855 │ ├─╮
1856 │ │ ○ 5bcb3c14e204 a3
1857 │ │ ○ 65b6f1fe6b41 b2
1858 │ │ ○ 6a9343b8797a b1
1859 ├───╯
1860 │ ○ 5d93a4b8f4bd a1
1861 ├─╯
1862 ◆ 000000000000
1863 [EOF]
1864 ");
1865 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1866
1867 // Duplicate a single commit in between descendant commits.
1868 let output = work_dir.run_jj(["duplicate", "a1", "--after", "a3", "--before", "a4"]);
1869 insta::assert_snapshot!(output, @r"
1870 ------- stderr -------
1871 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
1872 Duplicated 5d93a4b8f4bd as soqnvnyz 339f4932 (empty) a1
1873 Rebased 1 commits onto duplicated commits
1874 [EOF]
1875 ");
1876 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1877 @ 3e122d6a4b70 d2
1878 ○ ae61a031221a d1
1879 │ ○ 47a79ab4bbc6 c2
1880 │ ○ 9b24b49f717e c1
1881 ├─╯
1882 │ ○ 65b6f1fe6b41 b2
1883 │ ○ 6a9343b8797a b1
1884 ├─╯
1885 │ ○ e0b17484318d a4
1886 │ ○ 339f4932b49e a1
1887 │ ○ 5fb83d2b58d6 a3
1888 │ ○ 7bfd9fbe959c a2
1889 │ ○ 5d93a4b8f4bd a1
1890 ├─╯
1891 ◆ 000000000000
1892 [EOF]
1893 ");
1894 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1895
1896 // Duplicate a single commit in between a descendant commit and a commit with no
1897 // direct relationship.
1898 let output = work_dir.run_jj(["duplicate", "a1", "--after", "a3", "--before", "b2"]);
1899 insta::assert_snapshot!(output, @r"
1900 ------- stderr -------
1901 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
1902 Duplicated 5d93a4b8f4bd as nsrwusvy 26bc52e1 (empty) a1
1903 Rebased 1 commits onto duplicated commits
1904 [EOF]
1905 ");
1906 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1907 @ 3e122d6a4b70 d2
1908 ○ ae61a031221a d1
1909 │ ○ 47a79ab4bbc6 c2
1910 │ ○ 9b24b49f717e c1
1911 ├─╯
1912 │ ○ f5c84c8e017a b2
1913 │ ├─╮
1914 │ │ ○ 26bc52e1184c a1
1915 │ ○ │ 6a9343b8797a b1
1916 ├─╯ │
1917 │ ○ │ e9b68b6313be a4
1918 │ ├─╯
1919 │ ○ 5fb83d2b58d6 a3
1920 │ ○ 7bfd9fbe959c a2
1921 │ ○ 5d93a4b8f4bd a1
1922 ├─╯
1923 ◆ 000000000000
1924 [EOF]
1925 ");
1926 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1927
1928 // Duplicate a single commit in between an ancestor commit and a descendant
1929 // commit.
1930 let output = work_dir.run_jj(["duplicate", "a2", "--after", "a1", "--before", "a4"]);
1931 insta::assert_snapshot!(output, @r"
1932 ------- stderr -------
1933 Duplicated 7bfd9fbe959c as xpnwykqz 26961c35 a2
1934 Rebased 1 commits onto duplicated commits
1935 [EOF]
1936 ");
1937 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1938 @ 3e122d6a4b70 d2
1939 ○ ae61a031221a d1
1940 │ ○ 47a79ab4bbc6 c2
1941 │ ○ 9b24b49f717e c1
1942 ├─╯
1943 │ ○ 65b6f1fe6b41 b2
1944 │ ○ 6a9343b8797a b1
1945 ├─╯
1946 │ ○ 3bd6eedeb5d3 a4
1947 │ ├─╮
1948 │ │ ○ 26961c351338 a2
1949 │ ○ │ 5fb83d2b58d6 a3
1950 │ ○ │ 7bfd9fbe959c a2
1951 │ ├─╯
1952 │ ○ 5d93a4b8f4bd a1
1953 ├─╯
1954 ◆ 000000000000
1955 [EOF]
1956 ");
1957 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1958
1959 // Duplicate multiple commits without a direct ancestry relationship between
1960 // commits without a direct relationship.
1961 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--after", "c1", "--before", "d2"]);
1962 insta::assert_snapshot!(output, @r"
1963 ------- stderr -------
1964 Duplicated 5d93a4b8f4bd as sryyqqkq c5744841 a1
1965 Duplicated 6a9343b8797a as pxnqtknr 7ed6ac45 b1
1966 Rebased 1 commits onto duplicated commits
1967 Working copy (@) now at: nmzmmopx c786fa10 d2 | d2
1968 Parent commit (@-) : xznxytkn ae61a031 d1 | d1
1969 Parent commit (@-) : sryyqqkq c5744841 a1
1970 Parent commit (@-) : pxnqtknr 7ed6ac45 b1
1971 Added 3 files, modified 0 files, removed 0 files
1972 [EOF]
1973 ");
1974 insta::assert_snapshot!(get_log_output(&work_dir), @r"
1975 @ c786fa10d5b9 d2
1976 ├─┬─╮
1977 │ │ ○ 7ed6ac45ebcf b1
1978 │ ○ │ c57448416766 a1
1979 │ ├─╯
1980 ○ │ ae61a031221a d1
1981 │ │ ○ 47a79ab4bbc6 c2
1982 │ ├─╯
1983 │ ○ 9b24b49f717e c1
1984 ├─╯
1985 │ ○ 65b6f1fe6b41 b2
1986 │ ○ 6a9343b8797a b1
1987 ├─╯
1988 │ ○ e9b68b6313be a4
1989 │ ○ 5fb83d2b58d6 a3
1990 │ ○ 7bfd9fbe959c a2
1991 │ ○ 5d93a4b8f4bd a1
1992 ├─╯
1993 ◆ 000000000000
1994 [EOF]
1995 ");
1996 work_dir.run_jj(["op", "restore", &setup_opid]).success();
1997
1998 // Duplicate multiple commits without a direct ancestry relationship between a
1999 // commit which is an ancestor of one of the duplicated commits and a commit
2000 // with no direct relationship.
2001 let output = work_dir.run_jj(["duplicate", "a3", "b1", "--after", "a2", "--before", "c2"]);
2002 insta::assert_snapshot!(output, @r"
2003 ------- stderr -------
2004 Duplicated 5fb83d2b58d6 as pyoswmwk 5f4bd02b a3
2005 Duplicated 6a9343b8797a as yqnpwwmq d0cc3580 b1
2006 Rebased 1 commits onto duplicated commits
2007 [EOF]
2008 ");
2009 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2010 @ 3e122d6a4b70 d2
2011 ○ ae61a031221a d1
2012 │ ○ 2adae1b5ccbf c2
2013 │ ├─┬─╮
2014 │ │ │ ○ d0cc35804628 b1
2015 │ │ ○ │ 5f4bd02b76d2 a3
2016 │ │ ├─╯
2017 │ ○ │ 9b24b49f717e c1
2018 ├─╯ │
2019 │ ○ │ 65b6f1fe6b41 b2
2020 │ ○ │ 6a9343b8797a b1
2021 ├─╯ │
2022 │ ○ │ e9b68b6313be a4
2023 │ ○ │ 5fb83d2b58d6 a3
2024 │ ├─╯
2025 │ ○ 7bfd9fbe959c a2
2026 │ ○ 5d93a4b8f4bd a1
2027 ├─╯
2028 ◆ 000000000000
2029 [EOF]
2030 ");
2031 work_dir.run_jj(["op", "restore", &setup_opid]).success();
2032
2033 // Duplicate multiple commits without a direct ancestry relationship between a
2034 // commit which is a descendant of one of the duplicated commits and a
2035 // commit with no direct relationship.
2036 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--after", "a3", "--before", "c2"]);
2037 insta::assert_snapshot!(output, @r"
2038 ------- stderr -------
2039 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
2040 Duplicated 5d93a4b8f4bd as tpmlxquz 5ca04404 (empty) a1
2041 Duplicated 6a9343b8797a as uukzylyy d72c12f0 b1
2042 Rebased 1 commits onto duplicated commits
2043 [EOF]
2044 ");
2045 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2046 @ 3e122d6a4b70 d2
2047 ○ ae61a031221a d1
2048 │ ○ 05d64557cccd c2
2049 │ ├─┬─╮
2050 │ │ │ ○ d72c12f062ea b1
2051 │ │ ○ │ 5ca044045de1 a1
2052 │ │ ├─╯
2053 │ ○ │ 9b24b49f717e c1
2054 ├─╯ │
2055 │ ○ │ 65b6f1fe6b41 b2
2056 │ ○ │ 6a9343b8797a b1
2057 ├─╯ │
2058 │ ○ │ e9b68b6313be a4
2059 │ ├─╯
2060 │ ○ 5fb83d2b58d6 a3
2061 │ ○ 7bfd9fbe959c a2
2062 │ ○ 5d93a4b8f4bd a1
2063 ├─╯
2064 ◆ 000000000000
2065 [EOF]
2066 ");
2067 work_dir.run_jj(["op", "restore", &setup_opid]).success();
2068
2069 // Duplicate multiple commits without a direct ancestry relationship between
2070 // commits without a direct relationship to the duplicated commits.
2071 let output = work_dir.run_jj(["duplicate", "a1", "b1", "--after", "c1", "--before", "d2"]);
2072 insta::assert_snapshot!(output, @r"
2073 ------- stderr -------
2074 Duplicated 5d93a4b8f4bd as knltnxnu e6b0ec9f a1
2075 Duplicated 6a9343b8797a as krtqozmx 7acc5250 b1
2076 Rebased 1 commits onto duplicated commits
2077 Working copy (@) now at: nmzmmopx 1fdeca3e d2 | d2
2078 Parent commit (@-) : xznxytkn ae61a031 d1 | d1
2079 Parent commit (@-) : knltnxnu e6b0ec9f a1
2080 Parent commit (@-) : krtqozmx 7acc5250 b1
2081 Added 3 files, modified 0 files, removed 0 files
2082 [EOF]
2083 ");
2084 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2085 @ 1fdeca3ece59 d2
2086 ├─┬─╮
2087 │ │ ○ 7acc52508f09 b1
2088 │ ○ │ e6b0ec9f7a4d a1
2089 │ ├─╯
2090 ○ │ ae61a031221a d1
2091 │ │ ○ 47a79ab4bbc6 c2
2092 │ ├─╯
2093 │ ○ 9b24b49f717e c1
2094 ├─╯
2095 │ ○ 65b6f1fe6b41 b2
2096 │ ○ 6a9343b8797a b1
2097 ├─╯
2098 │ ○ e9b68b6313be a4
2099 │ ○ 5fb83d2b58d6 a3
2100 │ ○ 7bfd9fbe959c a2
2101 │ ○ 5d93a4b8f4bd a1
2102 ├─╯
2103 ◆ 000000000000
2104 [EOF]
2105 ");
2106 work_dir.run_jj(["op", "restore", &setup_opid]).success();
2107
2108 // Duplicate multiple commits with an ancestry relationship between
2109 // commits without a direct relationship to the duplicated commits.
2110 let output = work_dir.run_jj(["duplicate", "a1", "a3", "--after", "c1", "--before", "d2"]);
2111 insta::assert_snapshot!(output, @r"
2112 ------- stderr -------
2113 Duplicated 5d93a4b8f4bd as wxzmtyol 09fb22cd a1
2114 Duplicated 5fb83d2b58d6 as musouqkq 12fcbea6 a3
2115 Rebased 1 commits onto duplicated commits
2116 Working copy (@) now at: nmzmmopx 2a7ef48b d2 | d2
2117 Parent commit (@-) : xznxytkn ae61a031 d1 | d1
2118 Parent commit (@-) : musouqkq 12fcbea6 a3
2119 Added 3 files, modified 0 files, removed 0 files
2120 [EOF]
2121 ");
2122 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2123 @ 2a7ef48b82d2 d2
2124 ├─╮
2125 │ ○ 12fcbea66d19 a3
2126 │ ○ 09fb22cdc78e a1
2127 ○ │ ae61a031221a d1
2128 │ │ ○ 47a79ab4bbc6 c2
2129 │ ├─╯
2130 │ ○ 9b24b49f717e c1
2131 ├─╯
2132 │ ○ 65b6f1fe6b41 b2
2133 │ ○ 6a9343b8797a b1
2134 ├─╯
2135 │ ○ e9b68b6313be a4
2136 │ ○ 5fb83d2b58d6 a3
2137 │ ○ 7bfd9fbe959c a2
2138 │ ○ 5d93a4b8f4bd a1
2139 ├─╯
2140 ◆ 000000000000
2141 [EOF]
2142 ");
2143 work_dir.run_jj(["op", "restore", &setup_opid]).success();
2144
2145 // Duplicate multiple commits with an ancestry relationship between a commit
2146 // which is an ancestor of one of the duplicated commits and a commit
2147 // without a direct relationship.
2148 let output = work_dir.run_jj(["duplicate", "a3", "a4", "--after", "a2", "--before", "c2"]);
2149 insta::assert_snapshot!(output, @r"
2150 ------- stderr -------
2151 Duplicated 5fb83d2b58d6 as quyylypw 1e04ee7b a3
2152 Duplicated e9b68b6313be as prukwozq f86d4e2b a4
2153 Rebased 1 commits onto duplicated commits
2154 [EOF]
2155 ");
2156 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2157 @ 3e122d6a4b70 d2
2158 ○ ae61a031221a d1
2159 │ ○ 19896c7c8a53 c2
2160 │ ├─╮
2161 │ │ ○ f86d4e2b2759 a4
2162 │ │ ○ 1e04ee7badf2 a3
2163 │ ○ │ 9b24b49f717e c1
2164 ├─╯ │
2165 │ ○ │ 65b6f1fe6b41 b2
2166 │ ○ │ 6a9343b8797a b1
2167 ├─╯ │
2168 │ ○ │ e9b68b6313be a4
2169 │ ○ │ 5fb83d2b58d6 a3
2170 │ ├─╯
2171 │ ○ 7bfd9fbe959c a2
2172 │ ○ 5d93a4b8f4bd a1
2173 ├─╯
2174 ◆ 000000000000
2175 [EOF]
2176 ");
2177 work_dir.run_jj(["op", "restore", &setup_opid]).success();
2178
2179 // Duplicate multiple commits with an ancestry relationship between a commit
2180 // which is a a descendant of one of the duplicated commits and a commit
2181 // with no direct relationship.
2182 let output = work_dir.run_jj(["duplicate", "a1", "a2", "--before", "a3", "--after", "c2"]);
2183 insta::assert_snapshot!(output, @r"
2184 ------- stderr -------
2185 Duplicated 5d93a4b8f4bd as vvvtksvt 3b8c0610 a1
2186 Duplicated 7bfd9fbe959c as yvrnrpnw ff33d0be a2
2187 Rebased 2 commits onto duplicated commits
2188 [EOF]
2189 ");
2190 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2191 @ 3e122d6a4b70 d2
2192 ○ ae61a031221a d1
2193 │ ○ fbedc3581fd2 a4
2194 │ ○ 724ff9ca6f25 a3
2195 │ ├─╮
2196 │ │ ○ ff33d0be8372 a2
2197 │ │ ○ 3b8c061087d5 a1
2198 │ │ ○ 47a79ab4bbc6 c2
2199 │ │ ○ 9b24b49f717e c1
2200 ├───╯
2201 │ ○ 7bfd9fbe959c a2
2202 │ ○ 5d93a4b8f4bd a1
2203 ├─╯
2204 │ ○ 65b6f1fe6b41 b2
2205 │ ○ 6a9343b8797a b1
2206 ├─╯
2207 ◆ 000000000000
2208 [EOF]
2209 ");
2210 work_dir.run_jj(["op", "restore", &setup_opid]).success();
2211
2212 // Duplicate multiple commits with an ancestry relationship between descendant
2213 // commits.
2214 let output = work_dir.run_jj(["duplicate", "a3", "a4", "--after", "a1", "--before", "a2"]);
2215 insta::assert_snapshot!(output, @r"
2216 ------- stderr -------
2217 Warning: Duplicating commit e9b68b6313be as an ancestor of itself
2218 Warning: Duplicating commit 5fb83d2b58d6 as an ancestor of itself
2219 Duplicated 5fb83d2b58d6 as sukptuzs fcd8320b a3
2220 Duplicated e9b68b6313be as rxnrppxl 606e5abb a4
2221 Rebased 3 commits onto duplicated commits
2222 [EOF]
2223 ");
2224 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2225 @ 3e122d6a4b70 d2
2226 ○ ae61a031221a d1
2227 │ ○ 47a79ab4bbc6 c2
2228 │ ○ 9b24b49f717e c1
2229 ├─╯
2230 │ ○ 65b6f1fe6b41 b2
2231 │ ○ 6a9343b8797a b1
2232 ├─╯
2233 │ ○ 66a8bcd2e874 a4
2234 │ ○ 19653d63dcb6 a3
2235 │ ○ 675587f177c2 a2
2236 │ ○ 606e5abbb07b a4
2237 │ ○ fcd8320b69d9 a3
2238 │ ○ 5d93a4b8f4bd a1
2239 ├─╯
2240 ◆ 000000000000
2241 [EOF]
2242 ");
2243 work_dir.run_jj(["op", "restore", &setup_opid]).success();
2244
2245 // Duplicate multiple commits with an ancestry relationship between ancestor
2246 // commits.
2247 let output = work_dir.run_jj(["duplicate", "a1", "a2", "--after", "a3", "--before", "a4"]);
2248 insta::assert_snapshot!(output, @r"
2249 ------- stderr -------
2250 Warning: Duplicating commit 7bfd9fbe959c as a descendant of itself
2251 Warning: Duplicating commit 5d93a4b8f4bd as a descendant of itself
2252 Duplicated 5d93a4b8f4bd as rwkyzntp 2e22df69 (empty) a1
2253 Duplicated 7bfd9fbe959c as nqtyztop 4a1cab80 (empty) a2
2254 Rebased 1 commits onto duplicated commits
2255 [EOF]
2256 ");
2257 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2258 @ 3e122d6a4b70 d2
2259 ○ ae61a031221a d1
2260 │ ○ 47a79ab4bbc6 c2
2261 │ ○ 9b24b49f717e c1
2262 ├─╯
2263 │ ○ 65b6f1fe6b41 b2
2264 │ ○ 6a9343b8797a b1
2265 ├─╯
2266 │ ○ edfcd526983a a4
2267 │ ○ 4a1cab80c404 a2
2268 │ ○ 2e22df6994f9 a1
2269 │ ○ 5fb83d2b58d6 a3
2270 │ ○ 7bfd9fbe959c a2
2271 │ ○ 5d93a4b8f4bd a1
2272 ├─╯
2273 ◆ 000000000000
2274 [EOF]
2275 ");
2276 work_dir.run_jj(["op", "restore", &setup_opid]).success();
2277
2278 // Duplicate multiple commits with an ancestry relationship between an ancestor
2279 // commit and a descendant commit.
2280 let output = work_dir.run_jj(["duplicate", "a2", "a3", "--after", "a1", "--before", "a4"]);
2281 insta::assert_snapshot!(output, @r"
2282 ------- stderr -------
2283 Duplicated 7bfd9fbe959c as nwmqwkzz 34a2b296 a2
2284 Duplicated 5fb83d2b58d6 as uwrrnrtx a9fed94a a3
2285 Rebased 1 commits onto duplicated commits
2286 [EOF]
2287 ");
2288 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2289 @ 3e122d6a4b70 d2
2290 ○ ae61a031221a d1
2291 │ ○ 47a79ab4bbc6 c2
2292 │ ○ 9b24b49f717e c1
2293 ├─╯
2294 │ ○ 65b6f1fe6b41 b2
2295 │ ○ 6a9343b8797a b1
2296 ├─╯
2297 │ ○ a7d82e5f8a74 a4
2298 │ ├─╮
2299 │ │ ○ a9fed94ac9fe a3
2300 │ │ ○ 34a2b296eced a2
2301 │ ○ │ 5fb83d2b58d6 a3
2302 │ ○ │ 7bfd9fbe959c a2
2303 │ ├─╯
2304 │ ○ 5d93a4b8f4bd a1
2305 ├─╯
2306 ◆ 000000000000
2307 [EOF]
2308 ");
2309 work_dir.run_jj(["op", "restore", &setup_opid]).success();
2310
2311 // Should error if a loop will be created.
2312 let output = work_dir.run_jj(["duplicate", "a1", "--after", "b2", "--before", "b1"]);
2313 insta::assert_snapshot!(output, @r"
2314 ------- stderr -------
2315 Error: Refusing to create a loop: commit 65b6f1fe6b41 would be both an ancestor and a descendant of the duplicated commits
2316 [EOF]
2317 [exit status: 1]
2318 ");
2319}
2320
2321// https://github.com/jj-vcs/jj/issues/1050
2322#[test]
2323fn test_undo_after_duplicate() {
2324 let test_env = TestEnvironment::default();
2325 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
2326 let work_dir = test_env.work_dir("repo");
2327
2328 create_commit(&work_dir, "a", &[]);
2329 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2330 @ 7d980be7a1d4 a
2331 ◆ 000000000000
2332 [EOF]
2333 ");
2334
2335 let output = work_dir.run_jj(["duplicate", "a"]);
2336 insta::assert_snapshot!(output, @r"
2337 ------- stderr -------
2338 Duplicated 7d980be7a1d4 as mzvwutvl 346a7abe a
2339 [EOF]
2340 ");
2341 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2342 @ 7d980be7a1d4 a
2343 │ ○ 346a7abed73c a
2344 ├─╯
2345 ◆ 000000000000
2346 [EOF]
2347 ");
2348
2349 let output = work_dir.run_jj(["undo"]);
2350 insta::assert_snapshot!(output, @r"
2351 ------- stderr -------
2352 Undid operation: a6a20a8e5a46 (2001-02-03 08:05:11) duplicate 1 commit(s)
2353 [EOF]
2354 ");
2355 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2356 @ 7d980be7a1d4 a
2357 ◆ 000000000000
2358 [EOF]
2359 ");
2360}
2361
2362// https://github.com/jj-vcs/jj/issues/694
2363#[test]
2364fn test_rebase_duplicates() {
2365 let test_env = TestEnvironment::default();
2366 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
2367 let work_dir = test_env.work_dir("repo");
2368
2369 create_commit(&work_dir, "a", &[]);
2370 create_commit(&work_dir, "b", &["a"]);
2371 create_commit(&work_dir, "c", &["b"]);
2372 // Test the setup
2373 insta::assert_snapshot!(get_log_output_with_ts(&work_dir), @r"
2374 @ dffaa0d4dacc c @ 2001-02-03 04:05:13.000 +07:00
2375 ○ 123b4d91f6e5 b @ 2001-02-03 04:05:11.000 +07:00
2376 ○ 7d980be7a1d4 a @ 2001-02-03 04:05:09.000 +07:00
2377 ◆ 000000000000 @ 1970-01-01 00:00:00.000 +00:00
2378 [EOF]
2379 ");
2380
2381 let output = work_dir.run_jj(["duplicate", "c"]);
2382 insta::assert_snapshot!(output, @r"
2383 ------- stderr -------
2384 Duplicated dffaa0d4dacc as yostqsxw fc2e8dc2 c
2385 [EOF]
2386 ");
2387 let output = work_dir.run_jj(["duplicate", "c"]);
2388 insta::assert_snapshot!(output, @r"
2389 ------- stderr -------
2390 Duplicated dffaa0d4dacc as znkkpsqq 14e2803a c
2391 [EOF]
2392 ");
2393 insta::assert_snapshot!(get_log_output_with_ts(&work_dir), @r"
2394 @ dffaa0d4dacc c @ 2001-02-03 04:05:13.000 +07:00
2395 │ ○ 14e2803a4b0e c @ 2001-02-03 04:05:16.000 +07:00
2396 ├─╯
2397 │ ○ fc2e8dc218ab c @ 2001-02-03 04:05:15.000 +07:00
2398 ├─╯
2399 ○ 123b4d91f6e5 b @ 2001-02-03 04:05:11.000 +07:00
2400 ○ 7d980be7a1d4 a @ 2001-02-03 04:05:09.000 +07:00
2401 ◆ 000000000000 @ 1970-01-01 00:00:00.000 +00:00
2402 [EOF]
2403 ");
2404
2405 let output = work_dir.run_jj(["rebase", "-s", "b", "-d", "root()"]);
2406 insta::assert_snapshot!(output, @r"
2407 ------- stderr -------
2408 Rebased 4 commits to destination
2409 Working copy (@) now at: royxmykx fa60711d c | c
2410 Parent commit (@-) : zsuskuln 594e9d32 b | b
2411 Added 0 files, modified 0 files, removed 1 files
2412 [EOF]
2413 ");
2414 // Some of the duplicate commits' timestamps were changed a little to make them
2415 // have distinct commit ids.
2416 insta::assert_snapshot!(get_log_output_with_ts(&work_dir), @r"
2417 @ fa60711d6bd1 c @ 2001-02-03 04:05:18.000 +07:00
2418 │ ○ e320e3d23be0 c @ 2001-02-03 04:05:18.000 +07:00
2419 ├─╯
2420 │ ○ f9c10a3b2cfd c @ 2001-02-03 04:05:18.000 +07:00
2421 ├─╯
2422 ○ 594e9d322230 b @ 2001-02-03 04:05:18.000 +07:00
2423 │ ○ 7d980be7a1d4 a @ 2001-02-03 04:05:09.000 +07:00
2424 ├─╯
2425 ◆ 000000000000 @ 1970-01-01 00:00:00.000 +00:00
2426 [EOF]
2427 ");
2428}
2429
2430#[test]
2431fn test_duplicate_description_template() {
2432 let test_env = TestEnvironment::default();
2433 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
2434 let work_dir = test_env.work_dir("repo");
2435
2436 create_commit(&work_dir, "a", &[]);
2437 create_commit(&work_dir, "b", &["a"]);
2438 create_commit(&work_dir, "c", &["b"]);
2439
2440 // Test the setup
2441 insta::assert_snapshot!(get_log_output(&work_dir), @r"
2442 @ dffaa0d4dacc c
2443 ○ 123b4d91f6e5 b
2444 ○ 7d980be7a1d4 a
2445 ◆ 000000000000
2446 [EOF]
2447 ");
2448
2449 // Test duplicate_commits()
2450 test_env.add_config(r#"templates.duplicate_description = "concat(description, '\n(cherry picked from commit ', commit_id, ')')""#);
2451 let output = work_dir.run_jj(["duplicate", "a"]);
2452 insta::assert_snapshot!(output, @r"
2453 ------- stderr -------
2454 Duplicated 7d980be7a1d4 as yostqsxw d6f0812f a
2455 [EOF]
2456 ");
2457
2458 // Test duplicate_commits_onto_parents()
2459 let output = work_dir.run_jj(["duplicate", "a", "-B", "b"]);
2460 insta::assert_snapshot!(output, @r"
2461 ------- stderr -------
2462 Warning: Duplicating commit 7d980be7a1d4 as a descendant of itself
2463 Duplicated 7d980be7a1d4 as znkkpsqq fe35e4a3 (empty) a
2464 Rebased 2 commits onto duplicated commits
2465 Working copy (@) now at: royxmykx c414af3f c | c
2466 Parent commit (@-) : zsuskuln 6960bbcf b | b
2467 [EOF]
2468 ");
2469
2470 // Test empty template
2471 test_env.add_config("templates.duplicate_description = ''");
2472 let output = work_dir.run_jj(["duplicate", "b", "-d", "root()"]);
2473 insta::assert_snapshot!(output, @r"
2474 ------- stderr -------
2475 Duplicated 6960bbcfd5b1 as kpqxywon 33044659 (no description set)
2476 [EOF]
2477 ");
2478
2479 // Test `description` as an alias
2480 test_env.add_config("templates.duplicate_description = 'description'");
2481 let output = work_dir.run_jj([
2482 "duplicate",
2483 "c",
2484 "-d",
2485 "root()",
2486 // Use an argument here so we can actually see the log in the last test
2487 // (We don't have a way to remove a config in TestEnvironment)
2488 "--config",
2489 "template-aliases.description='\"alias\"'",
2490 ]);
2491 insta::assert_snapshot!(output, @r"
2492 ------- stderr -------
2493 Duplicated c414af3f8d2f as kmkuslsw 3eb4e721 alias
2494 [EOF]
2495 ");
2496
2497 let template = r#"commit_id.short() ++ "\n" ++ description"#;
2498 let output = work_dir.run_jj(["log", "-T", template]);
2499 insta::assert_snapshot!(output, @r"
2500 @ c414af3f8d2f
2501 │ c
2502 ○ 6960bbcfd5b1
2503 │ b
2504 ○ fe35e4a3bf3a
2505 │ a
2506 │
2507 │ (cherry picked from commit 7d980be7a1d499e4d316ab4c01242885032f7eaf)
2508 ○ 7d980be7a1d4
2509 │ a
2510 │ ○ 3eb4e7210ce7
2511 ├─╯ alias
2512 │ ○ 33044659b895
2513 ├─╯
2514 │ ○ d6f0812febab
2515 ├─╯ a
2516 │
2517 │ (cherry picked from commit 7d980be7a1d499e4d316ab4c01242885032f7eaf)
2518 ◆ 000000000000
2519 [EOF]
2520 ");
2521}
2522
2523#[must_use]
2524fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput {
2525 let template = r#"commit_id.short() ++ " " ++ description.first_line()"#;
2526 work_dir.run_jj(["log", "-T", template])
2527}
2528
2529#[must_use]
2530fn get_log_output_with_ts(work_dir: &TestWorkDir) -> CommandOutput {
2531 let template = r#"
2532 commit_id.short() ++ " " ++ description.first_line() ++ " @ " ++ committer.timestamp()
2533 "#;
2534 work_dir.run_jj(["log", "-T", template])
2535}