##// END OF EJS Templates
uncommit: added interactive mode(issue6062)...
Taapas Agrawal -
r41892:64d519ca default draft
parent child Browse files
Show More
This diff has been collapsed as it changes many lines, (969 lines changed) Show them Hide them
@@ -0,0 +1,969 b''
1 ================================================
2 || The test for `hg uncommit --interactive` ||
3 ================================================
4
5 Repo Setup
6 ============
7
8 $ cat >> $HGRCPATH <<EOF
9 > [ui]
10 > interactive = true
11 > [experimental]
12 > evolution.createmarkers=True
13 > evolution.allowunstable=True
14 > uncommitondirtywdir = true
15 > [extensions]
16 > uncommit =
17 > amend =
18 > drawdag=$TESTDIR/drawdag.py
19 > EOF
20 $ glog() {
21 > hg log -G --template '{rev}:{node|short}@{branch}({separate("/", obsolete, phase)}) {desc|firstline}\n' "$@"
22 > }
23
24 $ hg init repo
25 $ cd repo
26
27 $ touch a
28 $ cat >> a << EOF
29 > 1
30 > 2
31 > 3
32 > 4
33 > 5
34 > EOF
35
36 $ hg add a
37 $ hg ci -m "The base commit"
38
39 Make sure aborting the interactive selection does no magic
40 ----------------------------------------------------------
41
42 $ hg status
43 $ hg uncommit -i<<EOF
44 > q
45 > EOF
46 diff --git a/a b/a
47 new file mode 100644
48 examine changes to 'a'? [Ynesfdaq?] q
49
50 abort: user quit
51 [255]
52 $ hg status
53
54 Make a commit with multiple hunks
55 ---------------------------------
56
57 $ cat > a << EOF
58 > -2
59 > -1
60 > 0
61 > 1
62 > 2
63 > 3
64 > foo
65 > bar
66 > 4
67 > 5
68 > babar
69 > EOF
70
71 $ hg diff
72 diff -r 7733902a8d94 a
73 --- a/a Thu Jan 01 00:00:00 1970 +0000
74 +++ b/a Thu Jan 01 00:00:00 1970 +0000
75 @@ -1,5 +1,11 @@
76 +-2
77 +-1
78 +0
79 1
80 2
81 3
82 +foo
83 +bar
84 4
85 5
86 +babar
87
88 $ hg ci -m "another one"
89
90 Not selecting anything to uncommit
91 ==================================
92
93 $ hg uncommit -i<<EOF
94 > y
95 > n
96 > n
97 > n
98 > EOF
99 diff --git a/a b/a
100 3 hunks, 6 lines changed
101 examine changes to 'a'? [Ynesfdaq?] y
102
103 @@ -1,3 +1,6 @@
104 +-2
105 +-1
106 +0
107 1
108 2
109 3
110 discard change 1/3 to 'a'? [Ynesfdaq?] n
111
112 @@ -1,5 +4,7 @@
113 1
114 2
115 3
116 +foo
117 +bar
118 4
119 5
120 discard change 2/3 to 'a'? [Ynesfdaq?] n
121
122 @@ -4,2 +9,3 @@
123 4
124 5
125 +babar
126 discard change 3/3 to 'a'? [Ynesfdaq?] n
127
128 abort: nothing selected to uncommit
129 [255]
130 $ hg status
131
132 Uncommit a chunk
133 ================
134
135 $ hg uncommit -i<<EOF
136 > y
137 > y
138 > n
139 > n
140 > EOF
141 diff --git a/a b/a
142 3 hunks, 6 lines changed
143 examine changes to 'a'? [Ynesfdaq?] y
144
145 @@ -1,3 +1,6 @@
146 +-2
147 +-1
148 +0
149 1
150 2
151 3
152 discard change 1/3 to 'a'? [Ynesfdaq?] y
153
154 @@ -1,5 +4,7 @@
155 1
156 2
157 3
158 +foo
159 +bar
160 4
161 5
162 discard change 2/3 to 'a'? [Ynesfdaq?] n
163
164 @@ -4,2 +9,3 @@
165 4
166 5
167 +babar
168 discard change 3/3 to 'a'? [Ynesfdaq?] n
169
170
171 $ hg log -G --hidden
172 @ changeset: 3:678a59e5ff90
173 | tag: tip
174 | parent: 0:7733902a8d94
175 | user: test
176 | date: Thu Jan 01 00:00:00 1970 +0000
177 | summary: another one
178 |
179 | x changeset: 2:e9635f4beaf1
180 |/ parent: 0:7733902a8d94
181 | user: test
182 | date: Thu Jan 01 00:00:00 1970 +0000
183 | obsolete: pruned using uncommit
184 | summary: temporary commit for uncommiting f70fb463d5bf
185 |
186 | x changeset: 1:f70fb463d5bf
187 |/ user: test
188 | date: Thu Jan 01 00:00:00 1970 +0000
189 | obsolete: rewritten using uncommit as 3:678a59e5ff90
190 | summary: another one
191 |
192 o changeset: 0:7733902a8d94
193 user: test
194 date: Thu Jan 01 00:00:00 1970 +0000
195 summary: The base commit
196
197 The unselected part should be in the diff
198 -----------------------------------------
199
200 $ hg diff
201 diff -r 678a59e5ff90 a
202 --- a/a Thu Jan 01 00:00:00 1970 +0000
203 +++ b/a Thu Jan 01 00:00:00 1970 +0000
204 @@ -1,3 +1,6 @@
205 +-2
206 +-1
207 +0
208 1
209 2
210 3
211
212 The commit should contain the rest of part
213 ------------------------------------------
214
215 $ hg exp
216 # HG changeset patch
217 # User test
218 # Date 0 0
219 # Thu Jan 01 00:00:00 1970 +0000
220 # Node ID 678a59e5ff90754d5e94719bd82ad169be773c21
221 # Parent 7733902a8d94c789ca81d866bea1893d79442db6
222 another one
223
224 diff -r 7733902a8d94 -r 678a59e5ff90 a
225 --- a/a Thu Jan 01 00:00:00 1970 +0000
226 +++ b/a Thu Jan 01 00:00:00 1970 +0000
227 @@ -1,5 +1,8 @@
228 1
229 2
230 3
231 +foo
232 +bar
233 4
234 5
235 +babar
236
237 Uncommiting on dirty working directory
238 ======================================
239
240 $ hg status
241 M a
242 $ hg diff
243 diff -r 678a59e5ff90 a
244 --- a/a Thu Jan 01 00:00:00 1970 +0000
245 +++ b/a Thu Jan 01 00:00:00 1970 +0000
246 @@ -1,3 +1,6 @@
247 +-2
248 +-1
249 +0
250 1
251 2
252 3
253
254 $ hg uncommit -i<<EOF
255 > y
256 > n
257 > y
258 > EOF
259 diff --git a/a b/a
260 2 hunks, 3 lines changed
261 examine changes to 'a'? [Ynesfdaq?] y
262
263 @@ -1,5 +1,7 @@
264 1
265 2
266 3
267 +foo
268 +bar
269 4
270 5
271 discard change 1/2 to 'a'? [Ynesfdaq?] n
272
273 @@ -4,2 +6,3 @@
274 4
275 5
276 +babar
277 discard change 2/2 to 'a'? [Ynesfdaq?] y
278
279 patching file a
280 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
281
282 $ hg diff
283 diff -r 46e35360be47 a
284 --- a/a Thu Jan 01 00:00:00 1970 +0000
285 +++ b/a Thu Jan 01 00:00:00 1970 +0000
286 @@ -1,3 +1,6 @@
287 +-2
288 +-1
289 +0
290 1
291 2
292 3
293 @@ -5,3 +8,4 @@
294 bar
295 4
296 5
297 +babar
298
299 $ hg exp
300 # HG changeset patch
301 # User test
302 # Date 0 0
303 # Thu Jan 01 00:00:00 1970 +0000
304 # Node ID 46e35360be473bf761bedf3d05de4a68ffd9d9f8
305 # Parent 7733902a8d94c789ca81d866bea1893d79442db6
306 another one
307
308 diff -r 7733902a8d94 -r 46e35360be47 a
309 --- a/a Thu Jan 01 00:00:00 1970 +0000
310 +++ b/a Thu Jan 01 00:00:00 1970 +0000
311 @@ -1,5 +1,7 @@
312 1
313 2
314 3
315 +foo
316 +bar
317 4
318 5
319
320 Checking the obsolescence history
321
322 $ hg log -G --hidden
323 @ changeset: 5:46e35360be47
324 | tag: tip
325 | parent: 0:7733902a8d94
326 | user: test
327 | date: Thu Jan 01 00:00:00 1970 +0000
328 | summary: another one
329 |
330 | x changeset: 4:7ca9935a62f1
331 |/ parent: 0:7733902a8d94
332 | user: test
333 | date: Thu Jan 01 00:00:00 1970 +0000
334 | obsolete: pruned using uncommit
335 | summary: temporary commit for uncommiting 678a59e5ff90
336 |
337 | x changeset: 3:678a59e5ff90
338 |/ parent: 0:7733902a8d94
339 | user: test
340 | date: Thu Jan 01 00:00:00 1970 +0000
341 | obsolete: rewritten using uncommit as 5:46e35360be47
342 | summary: another one
343 |
344 | x changeset: 2:e9635f4beaf1
345 |/ parent: 0:7733902a8d94
346 | user: test
347 | date: Thu Jan 01 00:00:00 1970 +0000
348 | obsolete: pruned using uncommit
349 | summary: temporary commit for uncommiting f70fb463d5bf
350 |
351 | x changeset: 1:f70fb463d5bf
352 |/ user: test
353 | date: Thu Jan 01 00:00:00 1970 +0000
354 | obsolete: rewritten using uncommit as 3:678a59e5ff90
355 | summary: another one
356 |
357 o changeset: 0:7733902a8d94
358 user: test
359 date: Thu Jan 01 00:00:00 1970 +0000
360 summary: The base commit
361
362 Push the changes back to the commit and more commits for more testing
363
364 $ hg amend
365 $ glog
366 @ 6:905eb2a23ea2@default(draft) another one
367 |
368 o 0:7733902a8d94@default(draft) The base commit
369
370 $ touch foo
371 $ echo "hey" >> foo
372 $ hg ci -Am "Added foo"
373 adding foo
374
375 Testing uncommiting a whole changeset and also for a file addition
376 ==================================================================
377
378 $ hg uncommit -i<<EOF
379 > y
380 > y
381 > EOF
382 diff --git a/foo b/foo
383 new file mode 100644
384 examine changes to 'foo'? [Ynesfdaq?] y
385
386 @@ -0,0 +1,1 @@
387 +hey
388 discard this change to 'foo'? [Ynesfdaq?] y
389
390
391 $ hg status
392 A foo
393 $ hg diff
394 diff -r 857367499298 foo
395 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
396 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
397 @@ -0,0 +1,1 @@
398 +hey
399
400 $ hg exp
401 # HG changeset patch
402 # User test
403 # Date 0 0
404 # Thu Jan 01 00:00:00 1970 +0000
405 # Node ID 857367499298e999b5841bb01df65f73088b5d3b
406 # Parent 905eb2a23ea2d92073419d0e19165b90d36ea223
407 Added foo
408
409 $ hg amend
410
411 Testing to uncommit removed files completely
412 ============================================
413
414 $ hg rm a
415 $ hg ci -m "Removed a"
416 $ hg exp
417 # HG changeset patch
418 # User test
419 # Date 0 0
420 # Thu Jan 01 00:00:00 1970 +0000
421 # Node ID 219cfe20964e93f8bb9bd82ceaa54d3b776046db
422 # Parent 42cc15efbec26c14d96d805dee2766ba91d1fd31
423 Removed a
424
425 diff -r 42cc15efbec2 -r 219cfe20964e a
426 --- a/a Thu Jan 01 00:00:00 1970 +0000
427 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
428 @@ -1,11 +0,0 @@
429 --2
430 --1
431 -0
432 -1
433 -2
434 -3
435 -foo
436 -bar
437 -4
438 -5
439 -babar
440
441 Not examining the file
442 ----------------------
443
444 $ hg uncommit -i<<EOF
445 > n
446 > EOF
447 diff --git a/a b/a
448 deleted file mode 100644
449 examine changes to 'a'? [Ynesfdaq?] n
450
451 abort: nothing selected to uncommit
452 [255]
453
454 Examining the file
455 ------------------
456 XXX: there is a bug in interactive selection as it is not letting to examine the
457 file. Tried with curses too. In the curses UI, if you just unselect the hunks
458 and the not file mod thing at the top, it will show the same "nothing unselected
459 to uncommit" message which is a bug in interactive selection.
460
461 $ hg uncommit -i<<EOF
462 > y
463 > EOF
464 diff --git a/a b/a
465 deleted file mode 100644
466 examine changes to 'a'? [Ynesfdaq?] y
467
468
469 $ hg diff
470 diff -r 737487f1e5f8 a
471 --- a/a Thu Jan 01 00:00:00 1970 +0000
472 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
473 @@ -1,11 +0,0 @@
474 --2
475 --1
476 -0
477 -1
478 -2
479 -3
480 -foo
481 -bar
482 -4
483 -5
484 -babar
485 $ hg status
486 R a
487 $ hg exp
488 # HG changeset patch
489 # User test
490 # Date 0 0
491 # Thu Jan 01 00:00:00 1970 +0000
492 # Node ID 737487f1e5f853e55decb73ea31522c63e7f5980
493 # Parent 42cc15efbec26c14d96d805dee2766ba91d1fd31
494 Removed a
495
496
497 $ hg prune .
498 hg: unknown command 'prune'
499 (use 'hg help' for a list of commands)
500 [255]
501 $ hg revert --all
502 undeleting a
503
504 $ glog
505 @ 13:737487f1e5f8@default(draft) Removed a
506 |
507 o 10:42cc15efbec2@default(draft) Added foo
508 |
509 o 6:905eb2a23ea2@default(draft) another one
510 |
511 o 0:7733902a8d94@default(draft) The base commit
512
513
514 Testing when a new file is added in the last commit
515 ===================================================
516
517 $ echo "foo" >> foo
518 $ touch x
519 $ echo "abcd" >> x
520 $ hg add x
521 $ hg ci -m "Added x"
522 $ hg uncommit -i<<EOF
523 > y
524 > y
525 > y
526 > n
527 > EOF
528 diff --git a/foo b/foo
529 1 hunks, 1 lines changed
530 examine changes to 'foo'? [Ynesfdaq?] y
531
532 @@ -1,1 +1,2 @@
533 hey
534 +foo
535 discard change 1/2 to 'foo'? [Ynesfdaq?] y
536
537 diff --git a/x b/x
538 new file mode 100644
539 examine changes to 'x'? [Ynesfdaq?] y
540
541 @@ -0,0 +1,1 @@
542 +abcd
543 discard change 2/2 to 'x'? [Ynesfdaq?] n
544
545
546 $ hg exp
547 # HG changeset patch
548 # User test
549 # Date 0 0
550 # Thu Jan 01 00:00:00 1970 +0000
551 # Node ID f7b39cf595081f8e63fe1119953cc7f669663720
552 # Parent 737487f1e5f853e55decb73ea31522c63e7f5980
553 Added x
554
555 diff -r 737487f1e5f8 -r f7b39cf59508 x
556 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
557 +++ b/x Thu Jan 01 00:00:00 1970 +0000
558 @@ -0,0 +1,1 @@
559 +abcd
560
561 $ hg diff
562 diff -r f7b39cf59508 foo
563 --- a/foo Thu Jan 01 00:00:00 1970 +0000
564 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
565 @@ -1,1 +1,2 @@
566 hey
567 +foo
568
569 $ hg status
570 M foo
571
572 $ hg revert --all
573 reverting foo
574
575 Testing between the stack and with dirty working copy
576 =====================================================
577
578 $ glog
579 @ 16:f7b39cf59508@default(draft) Added x
580 |
581 o 13:737487f1e5f8@default(draft) Removed a
582 |
583 o 10:42cc15efbec2@default(draft) Added foo
584 |
585 o 6:905eb2a23ea2@default(draft) another one
586 |
587 o 0:7733902a8d94@default(draft) The base commit
588
589 $ hg up 905eb2a23ea2
590 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
591
592 $ touch bar
593 $ echo "foo" >> bar
594 $ hg add bar
595 $ hg status
596 A bar
597 ? foo.orig
598
599 $ hg exp
600 # HG changeset patch
601 # User test
602 # Date 0 0
603 # Thu Jan 01 00:00:00 1970 +0000
604 # Node ID 905eb2a23ea2d92073419d0e19165b90d36ea223
605 # Parent 7733902a8d94c789ca81d866bea1893d79442db6
606 another one
607
608 diff -r 7733902a8d94 -r 905eb2a23ea2 a
609 --- a/a Thu Jan 01 00:00:00 1970 +0000
610 +++ b/a Thu Jan 01 00:00:00 1970 +0000
611 @@ -1,5 +1,11 @@
612 +-2
613 +-1
614 +0
615 1
616 2
617 3
618 +foo
619 +bar
620 4
621 5
622 +babar
623
624 $ hg uncommit -i<<EOF
625 > y
626 > n
627 > n
628 > y
629 > EOF
630 diff --git a/a b/a
631 3 hunks, 6 lines changed
632 examine changes to 'a'? [Ynesfdaq?] y
633
634 @@ -1,3 +1,6 @@
635 +-2
636 +-1
637 +0
638 1
639 2
640 3
641 discard change 1/3 to 'a'? [Ynesfdaq?] n
642
643 @@ -1,5 +4,7 @@
644 1
645 2
646 3
647 +foo
648 +bar
649 4
650 5
651 discard change 2/3 to 'a'? [Ynesfdaq?] n
652
653 @@ -4,2 +9,3 @@
654 4
655 5
656 +babar
657 discard change 3/3 to 'a'? [Ynesfdaq?] y
658
659 patching file a
660 Hunk #1 succeeded at 1 with fuzz 1 (offset -1 lines).
661 3 new orphan changesets
662
663 $ hg diff
664 diff -r 676366511f95 a
665 --- a/a Thu Jan 01 00:00:00 1970 +0000
666 +++ b/a Thu Jan 01 00:00:00 1970 +0000
667 @@ -8,3 +8,4 @@
668 bar
669 4
670 5
671 +babar
672 diff -r 676366511f95 bar
673 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
674 +++ b/bar Thu Jan 01 00:00:00 1970 +0000
675 @@ -0,0 +1,1 @@
676 +foo
677
678 $ hg exp
679 # HG changeset patch
680 # User test
681 # Date 0 0
682 # Thu Jan 01 00:00:00 1970 +0000
683 # Node ID 676366511f95ca4122413dcf79b45eaab61fb387
684 # Parent 7733902a8d94c789ca81d866bea1893d79442db6
685 another one
686
687 diff -r 7733902a8d94 -r 676366511f95 a
688 --- a/a Thu Jan 01 00:00:00 1970 +0000
689 +++ b/a Thu Jan 01 00:00:00 1970 +0000
690 @@ -1,5 +1,10 @@
691 +-2
692 +-1
693 +0
694 1
695 2
696 3
697 +foo
698 +bar
699 4
700 5
701 $ hg status
702 M a
703 A bar
704 ? foo.orig
705
706 More uncommit on the same dirty working copy
707 =============================================
708
709 $ hg uncommit -i<<EOF
710 > y
711 > y
712 > n
713 > EOF
714 diff --git a/a b/a
715 2 hunks, 5 lines changed
716 examine changes to 'a'? [Ynesfdaq?] y
717
718 @@ -1,3 +1,6 @@
719 +-2
720 +-1
721 +0
722 1
723 2
724 3
725 discard change 1/2 to 'a'? [Ynesfdaq?] y
726
727 @@ -1,5 +4,7 @@
728 1
729 2
730 3
731 +foo
732 +bar
733 4
734 5
735 discard change 2/2 to 'a'? [Ynesfdaq?] n
736
737
738 $ hg exp
739 # HG changeset patch
740 # User test
741 # Date 0 0
742 # Thu Jan 01 00:00:00 1970 +0000
743 # Node ID 62d907d0c4fa13b4b8bfeed05f13751035daf963
744 # Parent 7733902a8d94c789ca81d866bea1893d79442db6
745 another one
746
747 diff -r 7733902a8d94 -r 62d907d0c4fa a
748 --- a/a Thu Jan 01 00:00:00 1970 +0000
749 +++ b/a Thu Jan 01 00:00:00 1970 +0000
750 @@ -1,5 +1,7 @@
751 1
752 2
753 3
754 +foo
755 +bar
756 4
757 5
758
759 $ hg diff
760 diff -r 62d907d0c4fa a
761 --- a/a Thu Jan 01 00:00:00 1970 +0000
762 +++ b/a Thu Jan 01 00:00:00 1970 +0000
763 @@ -1,3 +1,6 @@
764 +-2
765 +-1
766 +0
767 1
768 2
769 3
770 @@ -5,3 +8,4 @@
771 bar
772 4
773 5
774 +babar
775 diff -r 62d907d0c4fa bar
776 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
777 +++ b/bar Thu Jan 01 00:00:00 1970 +0000
778 @@ -0,0 +1,1 @@
779 +foo
780
781 $ hg status
782 M a
783 A bar
784 ? foo.orig
785
786 Interactive uncommit with a pattern
787 -----------------------------------
788
789 (more setup)
790
791 $ hg ci -m 'roaming changes'
792 $ cat > b << EOF
793 > a
794 > b
795 > c
796 > d
797 > e
798 > f
799 > h
800 > EOF
801 $ hg add b
802 $ hg ci -m 'add b'
803 $ echo 'celeste' >> a
804 $ echo 'i' >> b
805 $ hg ci -m 'some more changes'
806 $ hg export
807 # HG changeset patch
808 # User test
809 # Date 0 0
810 # Thu Jan 01 00:00:00 1970 +0000
811 # Node ID be5c67225e80b050867862bbd9f4755c4e9207c5
812 # Parent c280a907fddcef2ffe9fadcc2d87f29998e22b2f
813 some more changes
814
815 diff -r c280a907fddc -r be5c67225e80 a
816 --- a/a Thu Jan 01 00:00:00 1970 +0000
817 +++ b/a Thu Jan 01 00:00:00 1970 +0000
818 @@ -9,3 +9,4 @@
819 4
820 5
821 babar
822 +celeste
823 diff -r c280a907fddc -r be5c67225e80 b
824 --- a/b Thu Jan 01 00:00:00 1970 +0000
825 +++ b/b Thu Jan 01 00:00:00 1970 +0000
826 @@ -5,3 +5,4 @@
827 e
828 f
829 h
830 +i
831
832 $ hg uncommit -i a << DONE
833 > y
834 > y
835 > DONE
836 diff --git a/a b/a
837 1 hunks, 1 lines changed
838 examine changes to 'a'? [Ynesfdaq?] y
839
840 @@ -9,3 +9,4 @@
841 4
842 5
843 babar
844 +celeste
845 discard this change to 'a'? [Ynesfdaq?] y
846
847 $ hg status
848 M a
849 ? foo.orig
850 $ hg diff
851 diff -r c701d7c8d18b a
852 --- a/a Thu Jan 01 00:00:00 1970 +0000
853 +++ b/a Thu Jan 01 00:00:00 1970 +0000
854 @@ -9,3 +9,4 @@
855 4
856 5
857 babar
858 +celeste
859 $ hg export
860 # HG changeset patch
861 # User test
862 # Date 0 0
863 # Thu Jan 01 00:00:00 1970 +0000
864 # Node ID c701d7c8d18be55a92688f4458c26bd74fb1f525
865 # Parent c280a907fddcef2ffe9fadcc2d87f29998e22b2f
866 some more changes
867
868 diff -r c280a907fddc -r c701d7c8d18b b
869 --- a/b Thu Jan 01 00:00:00 1970 +0000
870 +++ b/b Thu Jan 01 00:00:00 1970 +0000
871 @@ -5,3 +5,4 @@
872 e
873 f
874 h
875 +i
876
877 (reset)
878
879 $ cat << EOF > a
880 > -3
881 > -2
882 > -1
883 > 0
884 > 1
885 > 2
886 > 3
887 > foo
888 > bar
889 > 4
890 > 5
891 > babar
892 > celeste
893 > EOF
894 $ hg amend
895
896 Same but do not select some change in 'a'
897
898 $ hg uncommit -i a << DONE
899 > y
900 > y
901 > n
902 > DONE
903 diff --git a/a b/a
904 2 hunks, 2 lines changed
905 examine changes to 'a'? [Ynesfdaq?] y
906
907 @@ -1,3 +1,4 @@
908 +-3
909 -2
910 -1
911 0
912 discard change 1/2 to 'a'? [Ynesfdaq?] y
913
914 @@ -9,3 +10,4 @@
915 4
916 5
917 babar
918 +celeste
919 discard change 2/2 to 'a'? [Ynesfdaq?] n
920
921 $ hg status
922 M a
923 ? foo.orig
924
925 $ hg diff
926 diff -r 28d5de12b225 a
927 --- a/a Thu Jan 01 00:00:00 1970 +0000
928 +++ b/a Thu Jan 01 00:00:00 1970 +0000
929 @@ -1,3 +1,4 @@
930 +-3
931 -2
932 -1
933 0
934
935 $ hg export
936 # HG changeset patch
937 # User test
938 # Date 0 0
939 # Thu Jan 01 00:00:00 1970 +0000
940 # Node ID 28d5de12b225d1e0951110cced8d8994227be026
941 # Parent c280a907fddcef2ffe9fadcc2d87f29998e22b2f
942 some more changes
943
944 diff -r c280a907fddc -r 28d5de12b225 a
945 --- a/a Thu Jan 01 00:00:00 1970 +0000
946 +++ b/a Thu Jan 01 00:00:00 1970 +0000
947 @@ -9,3 +9,4 @@
948 4
949 5
950 babar
951 +celeste
952 diff -r c280a907fddc -r 28d5de12b225 b
953 --- a/b Thu Jan 01 00:00:00 1970 +0000
954 +++ b/b Thu Jan 01 00:00:00 1970 +0000
955 @@ -5,3 +5,4 @@
956 e
957 f
958 h
959 +i
960
961 $ cat b
962 a
963 b
964 c
965 d
966 e
967 f
968 h
969 i
@@ -1,245 +1,450 b''
1 # uncommit - undo the actions of a commit
1 # uncommit - undo the actions of a commit
2 #
2 #
3 # Copyright 2011 Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
3 # Copyright 2011 Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
4 # Logilab SA <contact@logilab.fr>
4 # Logilab SA <contact@logilab.fr>
5 # Pierre-Yves David <pierre-yves.david@ens-lyon.org>
5 # Pierre-Yves David <pierre-yves.david@ens-lyon.org>
6 # Patrick Mezard <patrick@mezard.eu>
6 # Patrick Mezard <patrick@mezard.eu>
7 # Copyright 2016 Facebook, Inc.
7 # Copyright 2016 Facebook, Inc.
8 #
8 #
9 # This software may be used and distributed according to the terms of the
9 # This software may be used and distributed according to the terms of the
10 # GNU General Public License version 2 or any later version.
10 # GNU General Public License version 2 or any later version.
11
11
12 """uncommit part or all of a local changeset (EXPERIMENTAL)
12 """uncommit part or all of a local changeset (EXPERIMENTAL)
13
13
14 This command undoes the effect of a local commit, returning the affected
14 This command undoes the effect of a local commit, returning the affected
15 files to their uncommitted state. This means that files modified, added or
15 files to their uncommitted state. This means that files modified, added or
16 removed in the changeset will be left unchanged, and so will remain modified,
16 removed in the changeset will be left unchanged, and so will remain modified,
17 added and removed in the working directory.
17 added and removed in the working directory.
18 """
18 """
19
19
20 from __future__ import absolute_import
20 from __future__ import absolute_import
21
21
22 from mercurial.i18n import _
22 from mercurial.i18n import _
23
23
24 from mercurial import (
24 from mercurial import (
25 cmdutil,
25 cmdutil,
26 commands,
26 commands,
27 context,
27 context,
28 copies as copiesmod,
28 copies as copiesmod,
29 error,
29 error,
30 node,
30 node,
31 obsolete,
31 obsutil,
32 obsutil,
33 patch,
32 pycompat,
34 pycompat,
33 registrar,
35 registrar,
34 rewriteutil,
36 rewriteutil,
35 scmutil,
37 scmutil,
38 util,
36 )
39 )
37
40
38 cmdtable = {}
41 cmdtable = {}
39 command = registrar.command(cmdtable)
42 command = registrar.command(cmdtable)
40
43
41 configtable = {}
44 configtable = {}
42 configitem = registrar.configitem(configtable)
45 configitem = registrar.configitem(configtable)
43
46
44 configitem('experimental', 'uncommitondirtywdir',
47 configitem('experimental', 'uncommitondirtywdir',
45 default=False,
48 default=False,
46 )
49 )
47
50
51 stringio = util.stringio
52
48 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
53 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
49 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
54 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
50 # be specifying the version(s) of Mercurial they are tested with, or
55 # be specifying the version(s) of Mercurial they are tested with, or
51 # leave the attribute unspecified.
56 # leave the attribute unspecified.
52 testedwith = 'ships-with-hg-core'
57 testedwith = 'ships-with-hg-core'
53
58
54 def _commitfiltered(repo, ctx, match, keepcommit):
59 def _commitfiltered(repo, ctx, match, keepcommit):
55 """Recommit ctx with changed files not in match. Return the new
60 """Recommit ctx with changed files not in match. Return the new
56 node identifier, or None if nothing changed.
61 node identifier, or None if nothing changed.
57 """
62 """
58 base = ctx.p1()
63 base = ctx.p1()
59 # ctx
64 # ctx
60 initialfiles = set(ctx.files())
65 initialfiles = set(ctx.files())
61 exclude = set(f for f in initialfiles if match(f))
66 exclude = set(f for f in initialfiles if match(f))
62
67
63 # No files matched commit, so nothing excluded
68 # No files matched commit, so nothing excluded
64 if not exclude:
69 if not exclude:
65 return None
70 return None
66
71
67 files = (initialfiles - exclude)
72 files = (initialfiles - exclude)
68 # return the p1 so that we don't create an obsmarker later
73 # return the p1 so that we don't create an obsmarker later
69 if not keepcommit:
74 if not keepcommit:
70 return ctx.p1().node()
75 return ctx.p1().node()
71
76
72 # Filter copies
77 # Filter copies
73 copied = copiesmod.pathcopies(base, ctx)
78 copied = copiesmod.pathcopies(base, ctx)
74 copied = dict((dst, src) for dst, src in copied.iteritems()
79 copied = dict((dst, src) for dst, src in copied.iteritems()
75 if dst in files)
80 if dst in files)
76 def filectxfn(repo, memctx, path, contentctx=ctx, redirect=()):
81 def filectxfn(repo, memctx, path, contentctx=ctx, redirect=()):
77 if path not in contentctx:
82 if path not in contentctx:
78 return None
83 return None
79 fctx = contentctx[path]
84 fctx = contentctx[path]
80 mctx = context.memfilectx(repo, memctx, fctx.path(), fctx.data(),
85 mctx = context.memfilectx(repo, memctx, fctx.path(), fctx.data(),
81 fctx.islink(),
86 fctx.islink(),
82 fctx.isexec(),
87 fctx.isexec(),
83 copied=copied.get(path))
88 copied=copied.get(path))
84 return mctx
89 return mctx
85
90
86 new = context.memctx(repo,
91 new = context.memctx(repo,
87 parents=[base.node(), node.nullid],
92 parents=[base.node(), node.nullid],
88 text=ctx.description(),
93 text=ctx.description(),
89 files=files,
94 files=files,
90 filectxfn=filectxfn,
95 filectxfn=filectxfn,
91 user=ctx.user(),
96 user=ctx.user(),
92 date=ctx.date(),
97 date=ctx.date(),
93 extra=ctx.extra())
98 extra=ctx.extra())
94 return repo.commitctx(new)
99 return repo.commitctx(new)
95
100
96 def _fixdirstate(repo, oldctx, newctx, match=None):
101 def _fixdirstate(repo, oldctx, newctx, match=None):
97 """ fix the dirstate after switching the working directory from oldctx to
102 """ fix the dirstate after switching the working directory from oldctx to
98 newctx which can be result of either unamend or uncommit.
103 newctx which can be result of either unamend or uncommit.
99 """
104 """
100 ds = repo.dirstate
105 ds = repo.dirstate
101 ds.setparents(newctx.node(), node.nullid)
106 ds.setparents(newctx.node(), node.nullid)
102 copies = dict(ds.copies())
107 copies = dict(ds.copies())
103 s = newctx.status(oldctx, match=match)
108 s = newctx.status(oldctx, match=match)
104 for f in s.modified:
109 for f in s.modified:
105 if ds[f] == 'r':
110 if ds[f] == 'r':
106 # modified + removed -> removed
111 # modified + removed -> removed
107 continue
112 continue
108 ds.normallookup(f)
113 ds.normallookup(f)
109
114
110 for f in s.added:
115 for f in s.added:
111 if ds[f] == 'r':
116 if ds[f] == 'r':
112 # added + removed -> unknown
117 # added + removed -> unknown
113 ds.drop(f)
118 ds.drop(f)
114 elif ds[f] != 'a':
119 elif ds[f] != 'a':
115 ds.add(f)
120 ds.add(f)
116
121
117 for f in s.removed:
122 for f in s.removed:
118 if ds[f] == 'a':
123 if ds[f] == 'a':
119 # removed + added -> normal
124 # removed + added -> normal
120 ds.normallookup(f)
125 ds.normallookup(f)
121 elif ds[f] != 'r':
126 elif ds[f] != 'r':
122 ds.remove(f)
127 ds.remove(f)
123
128
124 # Merge old parent and old working dir copies
129 # Merge old parent and old working dir copies
125 oldcopies = copiesmod.pathcopies(newctx, oldctx, match)
130 oldcopies = copiesmod.pathcopies(newctx, oldctx, match)
126 oldcopies.update(copies)
131 oldcopies.update(copies)
127 copies = dict((dst, oldcopies.get(src, src))
132 copies = dict((dst, oldcopies.get(src, src))
128 for dst, src in oldcopies.iteritems())
133 for dst, src in oldcopies.iteritems())
129 # Adjust the dirstate copies
134 # Adjust the dirstate copies
130 for dst, src in copies.iteritems():
135 for dst, src in copies.iteritems():
131 if (src not in newctx or dst in newctx or ds[dst] != 'a'):
136 if (src not in newctx or dst in newctx or ds[dst] != 'a'):
132 src = None
137 src = None
133 ds.copy(src, dst)
138 ds.copy(src, dst)
134
139
140
141 def _uncommitdirstate(repo, oldctx, match, interactive):
142 """Fix the dirstate after switching the working directory from
143 oldctx to a copy of oldctx not containing changed files matched by
144 match.
145 """
146 ctx = repo['.']
147 ds = repo.dirstate
148 copies = dict(ds.copies())
149 if interactive:
150 # In interactive cases, we will find the status between oldctx and ctx
151 # and considering only the files which are changed between oldctx and
152 # ctx, and the status of what changed between oldctx and ctx will help
153 # us in defining the exact behavior
154 m, a, r = repo.status(oldctx, ctx, match=match)[:3]
155 for f in m:
156 # These are files which are modified between oldctx and ctx which
157 # contains two cases: 1) Were modified in oldctx and some
158 # modifications are uncommitted
159 # 2) Were added in oldctx but some part is uncommitted (this cannot
160 # contain the case when added files are uncommitted completely as
161 # that will result in status as removed not modified.)
162 # Also any modifications to a removed file will result the status as
163 # added, so we have only two cases. So in either of the cases, the
164 # resulting status can be modified or clean.
165 if ds[f] == 'r':
166 # But the file is removed in the working directory, leaving that
167 # as removed
168 continue
169 ds.normallookup(f)
170
171 for f in a:
172 # These are the files which are added between oldctx and ctx(new
173 # one), which means the files which were removed in oldctx
174 # but uncommitted completely while making the ctx
175 # This file should be marked as removed if the working directory
176 # does not adds it back. If it's adds it back, we do a normallookup.
177 # The file can't be removed in working directory, because it was
178 # removed in oldctx
179 if ds[f] == 'a':
180 ds.normallookup(f)
181 continue
182 ds.remove(f)
183
184 for f in r:
185 # These are files which are removed between oldctx and ctx, which
186 # means the files which were added in oldctx and were completely
187 # uncommitted in ctx. If a added file is partially uncommitted, that
188 # would have resulted in modified status, not removed.
189 # So a file added in a commit, and uncommitting that addition must
190 # result in file being stated as unknown.
191 if ds[f] == 'r':
192 # The working directory say it's removed, so lets make the file
193 # unknown
194 ds.drop(f)
195 continue
196 ds.add(f)
197 else:
198 m, a, r = repo.status(oldctx.p1(), oldctx, match=match)[:3]
199 for f in m:
200 if ds[f] == 'r':
201 # modified + removed -> removed
202 continue
203 ds.normallookup(f)
204
205 for f in a:
206 if ds[f] == 'r':
207 # added + removed -> unknown
208 ds.drop(f)
209 elif ds[f] != 'a':
210 ds.add(f)
211
212 for f in r:
213 if ds[f] == 'a':
214 # removed + added -> normal
215 ds.normallookup(f)
216 elif ds[f] != 'r':
217 ds.remove(f)
218
219 # Merge old parent and old working dir copies
220 oldcopies = {}
221 if interactive:
222 # Interactive had different meaning of the variables so restoring the
223 # original meaning to use them
224 m, a, r = repo.status(oldctx.p1(), oldctx, match=match)[:3]
225 for f in (m + a):
226 src = oldctx[f].renamed()
227 if src:
228 oldcopies[f] = src[0]
229 oldcopies.update(copies)
230 copies = dict((dst, oldcopies.get(src, src))
231 for dst, src in oldcopies.iteritems())
232 # Adjust the dirstate copies
233 for dst, src in copies.iteritems():
234 if (src not in ctx or dst in ctx or ds[dst] != 'a'):
235 src = None
236 ds.copy(src, dst)
237
135 @command('uncommit',
238 @command('uncommit',
136 [('', 'keep', False, _('allow an empty commit after uncommiting')),
239 [('i', 'interactive', False, _('interactive mode to uncommit')),
240 ('', 'keep', False, _('allow an empty commit after uncommiting')),
137 ] + commands.walkopts,
241 ] + commands.walkopts,
138 _('[OPTION]... [FILE]...'),
242 _('[OPTION]... [FILE]...'),
139 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
243 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
140 def uncommit(ui, repo, *pats, **opts):
244 def uncommit(ui, repo, *pats, **opts):
141 """uncommit part or all of a local changeset
245 """uncommit part or all of a local changeset
142
246
143 This command undoes the effect of a local commit, returning the affected
247 This command undoes the effect of a local commit, returning the affected
144 files to their uncommitted state. This means that files modified or
248 files to their uncommitted state. This means that files modified or
145 deleted in the changeset will be left unchanged, and so will remain
249 deleted in the changeset will be left unchanged, and so will remain
146 modified in the working directory.
250 modified in the working directory.
147
251
148 If no files are specified, the commit will be pruned, unless --keep is
252 If no files are specified, the commit will be pruned, unless --keep is
149 given.
253 given.
150 """
254 """
151 opts = pycompat.byteskwargs(opts)
255 opts = pycompat.byteskwargs(opts)
256 interactive = opts.get('interactive')
152
257
153 with repo.wlock(), repo.lock():
258 with repo.wlock(), repo.lock():
154
259
155 if not pats and not repo.ui.configbool('experimental',
260 if not pats and not repo.ui.configbool('experimental',
156 'uncommitondirtywdir'):
261 'uncommitondirtywdir'):
157 cmdutil.bailifchanged(repo)
262 cmdutil.bailifchanged(repo)
158 old = repo['.']
263 old = repo['.']
159 rewriteutil.precheck(repo, [old.rev()], 'uncommit')
264 rewriteutil.precheck(repo, [old.rev()], 'uncommit')
160 if len(old.parents()) > 1:
265 if len(old.parents()) > 1:
161 raise error.Abort(_("cannot uncommit merge changeset"))
266 raise error.Abort(_("cannot uncommit merge changeset"))
162
267
163 with repo.transaction('uncommit'):
268 with repo.transaction('uncommit'):
164 match = scmutil.match(old, pats, opts)
269 match = scmutil.match(old, pats, opts)
165 keepcommit = opts.get('keep') or pats
270 keepcommit = opts.get('keep') or pats
166 newid = _commitfiltered(repo, old, match, keepcommit)
271 newid = _commitfiltered(repo, old, match, keepcommit)
272 if interactive:
273 match = scmutil.match(old, pats, opts)
274 newid = _interactiveuncommit(ui, repo, old, match)
275
167 if newid is None:
276 if newid is None:
168 ui.status(_("nothing to uncommit\n"))
277 ui.status(_("nothing to uncommit\n"))
169 return 1
278 return 1
170
279
171 mapping = {}
280 mapping = {}
172 if newid != old.p1().node():
281 if newid != old.p1().node():
173 # Move local changes on filtered changeset
282 # Move local changes on filtered changeset
174 mapping[old.node()] = (newid,)
283 mapping[old.node()] = (newid,)
175 else:
284 else:
176 # Fully removed the old commit
285 # Fully removed the old commit
177 mapping[old.node()] = ()
286 mapping[old.node()] = ()
178
287
288 scmutil.cleanupnodes(repo, mapping, 'uncommit', fixphase=True)
289
179 with repo.dirstate.parentchange():
290 with repo.dirstate.parentchange():
180 _fixdirstate(repo, old, repo[newid], match)
291 repo.dirstate.setparents(newid, node.nullid)
292 _uncommitdirstate(repo, old, match, interactive)
293
294 def _interactiveuncommit(ui, repo, old, match):
295 """ The function which contains all the logic for interactively uncommiting
296 a commit. This function makes a temporary commit with the chunks which user
297 selected to uncommit. After that the diff of the parent and that commit is
298 applied to the working directory and committed again which results in the
299 new commit which should be one after uncommitted.
300 """
301
302 # create a temporary commit with hunks user selected
303 tempnode = _createtempcommit(ui, repo, old, match)
304
305 diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
306 diffopts.nodates = True
307 diffopts.git = True
308 fp = stringio()
309 for chunk, label in patch.diffui(repo, tempnode, old.node(), None,
310 opts=diffopts):
311 fp.write(chunk)
312
313 fp.seek(0)
314 newnode = _patchtocommit(ui, repo, old, fp)
315 # creating obs marker temp -> ()
316 obsolete.createmarkers(repo, [(repo[tempnode], ())], operation="uncommit")
317 return newnode
318
319 def _createtempcommit(ui, repo, old, match):
320 """ Creates a temporary commit for `uncommit --interative` which contains
321 the hunks which were selected by the user to uncommit.
322 """
181
323
182 scmutil.cleanupnodes(repo, mapping, 'uncommit', fixphase=True)
324 pold = old.p1()
325 # The logic to interactively selecting something copied from
326 # cmdutil.revert()
327 diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
328 diffopts.nodates = True
329 diffopts.git = True
330 diff = patch.diff(repo, pold.node(), old.node(), match, opts=diffopts)
331 originalchunks = patch.parsepatch(diff)
332 # XXX: The interactive selection is buggy and does not let you
333 # uncommit a removed file partially.
334 # TODO: wrap the operations in mercurial/patch.py and mercurial/crecord.py
335 # to add uncommit as an operation taking care of BC.
336 chunks, opts = cmdutil.recordfilter(repo.ui, originalchunks,
337 operation='discard')
338 if not chunks:
339 raise error.Abort(_("nothing selected to uncommit"))
340 fp = stringio()
341 for c in chunks:
342 c.write(fp)
343
344 fp.seek(0)
345 oldnode = node.hex(old.node())[:12]
346 message = 'temporary commit for uncommiting %s' % oldnode
347 tempnode = _patchtocommit(ui, repo, old, fp, message, oldnode)
348 return tempnode
349
350 def _patchtocommit(ui, repo, old, fp, message=None, extras=None):
351 """ A function which will apply the patch to the working directory and
352 make a commit whose parents are same as that of old argument. The message
353 argument tells us whether to use the message of the old commit or a
354 different message which is passed. Returns the node of new commit made.
355 """
356 pold = old.p1()
357 parents = (old.p1().node(), old.p2().node())
358 date = old.date()
359 branch = old.branch()
360 user = old.user()
361 extra = old.extra()
362 if extras:
363 extra['uncommit_source'] = extras
364 if not message:
365 message = old.description()
366 store = patch.filestore()
367 try:
368 files = set()
369 try:
370 patch.patchrepo(ui, repo, pold, store, fp, 1, '',
371 files=files, eolmode=None)
372 except patch.PatchError as err:
373 raise error.Abort(str(err))
374
375 finally:
376 del fp
377
378 memctx = context.memctx(repo, parents, message, files=files,
379 filectxfn=store,
380 user=user,
381 date=date,
382 branch=branch,
383 extra=extra)
384 newcm = memctx.commit()
385 finally:
386 store.close()
387 return newcm
183
388
184 def predecessormarkers(ctx):
389 def predecessormarkers(ctx):
185 """yields the obsolete markers marking the given changeset as a successor"""
390 """yields the obsolete markers marking the given changeset as a successor"""
186 for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
391 for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
187 yield obsutil.marker(ctx.repo(), data)
392 yield obsutil.marker(ctx.repo(), data)
188
393
189 @command('unamend', [], helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
394 @command('unamend', [], helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
190 helpbasic=True)
395 helpbasic=True)
191 def unamend(ui, repo, **opts):
396 def unamend(ui, repo, **opts):
192 """undo the most recent amend operation on a current changeset
397 """undo the most recent amend operation on a current changeset
193
398
194 This command will roll back to the previous version of a changeset,
399 This command will roll back to the previous version of a changeset,
195 leaving working directory in state in which it was before running
400 leaving working directory in state in which it was before running
196 `hg amend` (e.g. files modified as part of an amend will be
401 `hg amend` (e.g. files modified as part of an amend will be
197 marked as modified `hg status`)
402 marked as modified `hg status`)
198 """
403 """
199
404
200 unfi = repo.unfiltered()
405 unfi = repo.unfiltered()
201 with repo.wlock(), repo.lock(), repo.transaction('unamend'):
406 with repo.wlock(), repo.lock(), repo.transaction('unamend'):
202
407
203 # identify the commit from which to unamend
408 # identify the commit from which to unamend
204 curctx = repo['.']
409 curctx = repo['.']
205
410
206 rewriteutil.precheck(repo, [curctx.rev()], 'unamend')
411 rewriteutil.precheck(repo, [curctx.rev()], 'unamend')
207
412
208 # identify the commit to which to unamend
413 # identify the commit to which to unamend
209 markers = list(predecessormarkers(curctx))
414 markers = list(predecessormarkers(curctx))
210 if len(markers) != 1:
415 if len(markers) != 1:
211 e = _("changeset must have one predecessor, found %i predecessors")
416 e = _("changeset must have one predecessor, found %i predecessors")
212 raise error.Abort(e % len(markers))
417 raise error.Abort(e % len(markers))
213
418
214 prednode = markers[0].prednode()
419 prednode = markers[0].prednode()
215 predctx = unfi[prednode]
420 predctx = unfi[prednode]
216
421
217 # add an extra so that we get a new hash
422 # add an extra so that we get a new hash
218 # note: allowing unamend to undo an unamend is an intentional feature
423 # note: allowing unamend to undo an unamend is an intentional feature
219 extras = predctx.extra()
424 extras = predctx.extra()
220 extras['unamend_source'] = curctx.hex()
425 extras['unamend_source'] = curctx.hex()
221
426
222 def filectxfn(repo, ctx_, path):
427 def filectxfn(repo, ctx_, path):
223 try:
428 try:
224 return predctx.filectx(path)
429 return predctx.filectx(path)
225 except KeyError:
430 except KeyError:
226 return None
431 return None
227
432
228 # Make a new commit same as predctx
433 # Make a new commit same as predctx
229 newctx = context.memctx(repo,
434 newctx = context.memctx(repo,
230 parents=(predctx.p1(), predctx.p2()),
435 parents=(predctx.p1(), predctx.p2()),
231 text=predctx.description(),
436 text=predctx.description(),
232 files=predctx.files(),
437 files=predctx.files(),
233 filectxfn=filectxfn,
438 filectxfn=filectxfn,
234 user=predctx.user(),
439 user=predctx.user(),
235 date=predctx.date(),
440 date=predctx.date(),
236 extra=extras)
441 extra=extras)
237 newprednode = repo.commitctx(newctx)
442 newprednode = repo.commitctx(newctx)
238 newpredctx = repo[newprednode]
443 newpredctx = repo[newprednode]
239 dirstate = repo.dirstate
444 dirstate = repo.dirstate
240
445
241 with dirstate.parentchange():
446 with dirstate.parentchange():
242 _fixdirstate(repo, curctx, newpredctx)
447 _fixdirstate(repo, curctx, newpredctx)
243
448
244 mapping = {curctx.node(): (newprednode,)}
449 mapping = {curctx.node(): (newprednode,)}
245 scmutil.cleanupnodes(repo, mapping, 'unamend', fixphase=True)
450 scmutil.cleanupnodes(repo, mapping, 'unamend', fixphase=True)
@@ -1,440 +1,441 b''
1 Test uncommit - set up the config
1 Test uncommit - set up the config
2
2
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [experimental]
4 > [experimental]
5 > evolution.createmarkers=True
5 > evolution.createmarkers=True
6 > evolution.allowunstable=True
6 > evolution.allowunstable=True
7 > [extensions]
7 > [extensions]
8 > uncommit =
8 > uncommit =
9 > drawdag=$TESTDIR/drawdag.py
9 > drawdag=$TESTDIR/drawdag.py
10 > EOF
10 > EOF
11
11
12 Build up a repo
12 Build up a repo
13
13
14 $ hg init repo
14 $ hg init repo
15 $ cd repo
15 $ cd repo
16 $ hg bookmark foo
16 $ hg bookmark foo
17
17
18 Help for uncommit
18 Help for uncommit
19
19
20 $ hg help uncommit
20 $ hg help uncommit
21 hg uncommit [OPTION]... [FILE]...
21 hg uncommit [OPTION]... [FILE]...
22
22
23 uncommit part or all of a local changeset
23 uncommit part or all of a local changeset
24
24
25 This command undoes the effect of a local commit, returning the affected
25 This command undoes the effect of a local commit, returning the affected
26 files to their uncommitted state. This means that files modified or
26 files to their uncommitted state. This means that files modified or
27 deleted in the changeset will be left unchanged, and so will remain
27 deleted in the changeset will be left unchanged, and so will remain
28 modified in the working directory.
28 modified in the working directory.
29
29
30 If no files are specified, the commit will be pruned, unless --keep is
30 If no files are specified, the commit will be pruned, unless --keep is
31 given.
31 given.
32
32
33 (use 'hg help -e uncommit' to show help for the uncommit extension)
33 (use 'hg help -e uncommit' to show help for the uncommit extension)
34
34
35 options ([+] can be repeated):
35 options ([+] can be repeated):
36
36
37 -i --interactive interactive mode to uncommit
37 --keep allow an empty commit after uncommiting
38 --keep allow an empty commit after uncommiting
38 -I --include PATTERN [+] include names matching the given patterns
39 -I --include PATTERN [+] include names matching the given patterns
39 -X --exclude PATTERN [+] exclude names matching the given patterns
40 -X --exclude PATTERN [+] exclude names matching the given patterns
40
41
41 (some details hidden, use --verbose to show complete help)
42 (some details hidden, use --verbose to show complete help)
42
43
43 Uncommit with no commits should fail
44 Uncommit with no commits should fail
44
45
45 $ hg uncommit
46 $ hg uncommit
46 abort: cannot uncommit null changeset
47 abort: cannot uncommit null changeset
47 (no changeset checked out)
48 (no changeset checked out)
48 [255]
49 [255]
49
50
50 Create some commits
51 Create some commits
51
52
52 $ touch files
53 $ touch files
53 $ hg add files
54 $ hg add files
54 $ for i in a ab abc abcd abcde; do echo $i > files; echo $i > file-$i; hg add file-$i; hg commit -m "added file-$i"; done
55 $ for i in a ab abc abcd abcde; do echo $i > files; echo $i > file-$i; hg add file-$i; hg commit -m "added file-$i"; done
55 $ ls
56 $ ls
56 file-a
57 file-a
57 file-ab
58 file-ab
58 file-abc
59 file-abc
59 file-abcd
60 file-abcd
60 file-abcde
61 file-abcde
61 files
62 files
62
63
63 $ hg log -G -T '{rev}:{node} {desc}' --hidden
64 $ hg log -G -T '{rev}:{node} {desc}' --hidden
64 @ 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
65 @ 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
65 |
66 |
66 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
67 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
67 |
68 |
68 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
69 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
69 |
70 |
70 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
71 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
71 |
72 |
72 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
73 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
73
74
74 Simple uncommit off the top, also moves bookmark
75 Simple uncommit off the top, also moves bookmark
75
76
76 $ hg bookmark
77 $ hg bookmark
77 * foo 4:6c4fd43ed714
78 * foo 4:6c4fd43ed714
78 $ hg uncommit
79 $ hg uncommit
79 $ hg status
80 $ hg status
80 M files
81 M files
81 A file-abcde
82 A file-abcde
82 $ hg bookmark
83 $ hg bookmark
83 * foo 3:6db330d65db4
84 * foo 3:6db330d65db4
84
85
85 $ hg log -G -T '{rev}:{node} {desc}' --hidden
86 $ hg log -G -T '{rev}:{node} {desc}' --hidden
86 x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
87 x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
87 |
88 |
88 @ 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
89 @ 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
89 |
90 |
90 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
91 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
91 |
92 |
92 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
93 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
93 |
94 |
94 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
95 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
95
96
96
97
97 Recommit
98 Recommit
98
99
99 $ hg commit -m 'new change abcde'
100 $ hg commit -m 'new change abcde'
100 $ hg status
101 $ hg status
101 $ hg heads -T '{rev}:{node} {desc}'
102 $ hg heads -T '{rev}:{node} {desc}'
102 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde (no-eol)
103 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde (no-eol)
103
104
104 Uncommit of non-existent and unchanged files has no effect
105 Uncommit of non-existent and unchanged files has no effect
105 $ hg uncommit nothinghere
106 $ hg uncommit nothinghere
106 nothing to uncommit
107 nothing to uncommit
107 [1]
108 [1]
108 $ hg status
109 $ hg status
109 $ hg uncommit file-abc
110 $ hg uncommit file-abc
110 nothing to uncommit
111 nothing to uncommit
111 [1]
112 [1]
112 $ hg status
113 $ hg status
113
114
114 Try partial uncommit, also moves bookmark
115 Try partial uncommit, also moves bookmark
115
116
116 $ hg bookmark
117 $ hg bookmark
117 * foo 5:0c07a3ccda77
118 * foo 5:0c07a3ccda77
118 $ hg uncommit files
119 $ hg uncommit files
119 $ hg status
120 $ hg status
120 M files
121 M files
121 $ hg bookmark
122 $ hg bookmark
122 * foo 6:3727deee06f7
123 * foo 6:3727deee06f7
123 $ hg heads -T '{rev}:{node} {desc}'
124 $ hg heads -T '{rev}:{node} {desc}'
124 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde (no-eol)
125 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde (no-eol)
125 $ hg log -r . -p -T '{rev}:{node} {desc}'
126 $ hg log -r . -p -T '{rev}:{node} {desc}'
126 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcdediff -r 6db330d65db4 -r 3727deee06f7 file-abcde
127 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcdediff -r 6db330d65db4 -r 3727deee06f7 file-abcde
127 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
128 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
128 +++ b/file-abcde Thu Jan 01 00:00:00 1970 +0000
129 +++ b/file-abcde Thu Jan 01 00:00:00 1970 +0000
129 @@ -0,0 +1,1 @@
130 @@ -0,0 +1,1 @@
130 +abcde
131 +abcde
131
132
132 $ hg log -G -T '{rev}:{node} {desc}' --hidden
133 $ hg log -G -T '{rev}:{node} {desc}' --hidden
133 @ 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
134 @ 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
134 |
135 |
135 | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
136 | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
136 |/
137 |/
137 | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
138 | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
138 |/
139 |/
139 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
140 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
140 |
141 |
141 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
142 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
142 |
143 |
143 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
144 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
144 |
145 |
145 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
146 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
146
147
147 $ hg commit -m 'update files for abcde'
148 $ hg commit -m 'update files for abcde'
148
149
149 Uncommit with dirty state
150 Uncommit with dirty state
150
151
151 $ echo "foo" >> files
152 $ echo "foo" >> files
152 $ cat files
153 $ cat files
153 abcde
154 abcde
154 foo
155 foo
155 $ hg status
156 $ hg status
156 M files
157 M files
157 $ hg uncommit
158 $ hg uncommit
158 abort: uncommitted changes
159 abort: uncommitted changes
159 [255]
160 [255]
160 $ hg uncommit files
161 $ hg uncommit files
161 $ cat files
162 $ cat files
162 abcde
163 abcde
163 foo
164 foo
164 $ hg commit --amend -m "files abcde + foo"
165 $ hg commit --amend -m "files abcde + foo"
165
166
166 Testing the 'experimental.uncommitondirtywdir' config
167 Testing the 'experimental.uncommitondirtywdir' config
167
168
168 $ echo "bar" >> files
169 $ echo "bar" >> files
169 $ hg uncommit
170 $ hg uncommit
170 abort: uncommitted changes
171 abort: uncommitted changes
171 [255]
172 [255]
172 $ hg uncommit --config experimental.uncommitondirtywdir=True
173 $ hg uncommit --config experimental.uncommitondirtywdir=True
173 $ hg commit -m "files abcde + foo"
174 $ hg commit -m "files abcde + foo"
174
175
175 Uncommit in the middle of a stack, does not move bookmark
176 Uncommit in the middle of a stack, does not move bookmark
176
177
177 $ hg checkout '.^^^'
178 $ hg checkout '.^^^'
178 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
179 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
179 (leaving bookmark foo)
180 (leaving bookmark foo)
180 $ hg log -r . -p -T '{rev}:{node} {desc}'
181 $ hg log -r . -p -T '{rev}:{node} {desc}'
181 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abcdiff -r 69a232e754b0 -r abf2df566fc1 file-abc
182 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abcdiff -r 69a232e754b0 -r abf2df566fc1 file-abc
182 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
183 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
183 +++ b/file-abc Thu Jan 01 00:00:00 1970 +0000
184 +++ b/file-abc Thu Jan 01 00:00:00 1970 +0000
184 @@ -0,0 +1,1 @@
185 @@ -0,0 +1,1 @@
185 +abc
186 +abc
186 diff -r 69a232e754b0 -r abf2df566fc1 files
187 diff -r 69a232e754b0 -r abf2df566fc1 files
187 --- a/files Thu Jan 01 00:00:00 1970 +0000
188 --- a/files Thu Jan 01 00:00:00 1970 +0000
188 +++ b/files Thu Jan 01 00:00:00 1970 +0000
189 +++ b/files Thu Jan 01 00:00:00 1970 +0000
189 @@ -1,1 +1,1 @@
190 @@ -1,1 +1,1 @@
190 -ab
191 -ab
191 +abc
192 +abc
192
193
193 $ hg bookmark
194 $ hg bookmark
194 foo 10:48e5bd7cd583
195 foo 10:48e5bd7cd583
195 $ hg uncommit
196 $ hg uncommit
196 3 new orphan changesets
197 3 new orphan changesets
197 $ hg status
198 $ hg status
198 M files
199 M files
199 A file-abc
200 A file-abc
200 $ hg heads -T '{rev}:{node} {desc}'
201 $ hg heads -T '{rev}:{node} {desc}'
201 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo (no-eol)
202 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo (no-eol)
202 $ hg bookmark
203 $ hg bookmark
203 foo 10:48e5bd7cd583
204 foo 10:48e5bd7cd583
204 $ hg commit -m 'new abc'
205 $ hg commit -m 'new abc'
205 created new head
206 created new head
206
207
207 Partial uncommit in the middle, does not move bookmark
208 Partial uncommit in the middle, does not move bookmark
208
209
209 $ hg checkout '.^'
210 $ hg checkout '.^'
210 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
211 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
211 $ hg log -r . -p -T '{rev}:{node} {desc}'
212 $ hg log -r . -p -T '{rev}:{node} {desc}'
212 1:69a232e754b08d568c4899475faf2eb44b857802 added file-abdiff -r 3004d2d9b508 -r 69a232e754b0 file-ab
213 1:69a232e754b08d568c4899475faf2eb44b857802 added file-abdiff -r 3004d2d9b508 -r 69a232e754b0 file-ab
213 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
214 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
214 +++ b/file-ab Thu Jan 01 00:00:00 1970 +0000
215 +++ b/file-ab Thu Jan 01 00:00:00 1970 +0000
215 @@ -0,0 +1,1 @@
216 @@ -0,0 +1,1 @@
216 +ab
217 +ab
217 diff -r 3004d2d9b508 -r 69a232e754b0 files
218 diff -r 3004d2d9b508 -r 69a232e754b0 files
218 --- a/files Thu Jan 01 00:00:00 1970 +0000
219 --- a/files Thu Jan 01 00:00:00 1970 +0000
219 +++ b/files Thu Jan 01 00:00:00 1970 +0000
220 +++ b/files Thu Jan 01 00:00:00 1970 +0000
220 @@ -1,1 +1,1 @@
221 @@ -1,1 +1,1 @@
221 -a
222 -a
222 +ab
223 +ab
223
224
224 $ hg bookmark
225 $ hg bookmark
225 foo 10:48e5bd7cd583
226 foo 10:48e5bd7cd583
226 $ hg uncommit file-ab
227 $ hg uncommit file-ab
227 1 new orphan changesets
228 1 new orphan changesets
228 $ hg status
229 $ hg status
229 A file-ab
230 A file-ab
230
231
231 $ hg heads -T '{rev}:{node} {desc}\n'
232 $ hg heads -T '{rev}:{node} {desc}\n'
232 12:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
233 12:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
233 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
234 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
234 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
235 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
235
236
236 $ hg bookmark
237 $ hg bookmark
237 foo 10:48e5bd7cd583
238 foo 10:48e5bd7cd583
238 $ hg commit -m 'update ab'
239 $ hg commit -m 'update ab'
239 $ hg status
240 $ hg status
240 $ hg heads -T '{rev}:{node} {desc}\n'
241 $ hg heads -T '{rev}:{node} {desc}\n'
241 13:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
242 13:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
242 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
243 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
243 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
244 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
244
245
245 $ hg log -G -T '{rev}:{node} {desc}' --hidden
246 $ hg log -G -T '{rev}:{node} {desc}' --hidden
246 @ 13:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
247 @ 13:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
247 |
248 |
248 o 12:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
249 o 12:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
249 |
250 |
250 | * 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
251 | * 11:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
251 | |
252 | |
252 | | * 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
253 | | * 10:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
253 | | |
254 | | |
254 | | | x 9:8a6b58c173ca6a2e3745d8bd86698718d664bc6c files abcde + foo
255 | | | x 9:8a6b58c173ca6a2e3745d8bd86698718d664bc6c files abcde + foo
255 | | |/
256 | | |/
256 | | | x 8:39ad452c7f684a55d161c574340c5766c4569278 update files for abcde
257 | | | x 8:39ad452c7f684a55d161c574340c5766c4569278 update files for abcde
257 | | |/
258 | | |/
258 | | | x 7:0977fa602c2fd7d8427ed4e7ee15ea13b84c9173 update files for abcde
259 | | | x 7:0977fa602c2fd7d8427ed4e7ee15ea13b84c9173 update files for abcde
259 | | |/
260 | | |/
260 | | * 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
261 | | * 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
261 | | |
262 | | |
262 | | | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
263 | | | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
263 | | |/
264 | | |/
264 | | | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
265 | | | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
265 | | |/
266 | | |/
266 | | * 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
267 | | * 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
267 | | |
268 | | |
268 | | x 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
269 | | x 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
269 | |/
270 | |/
270 | x 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
271 | x 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
271 |/
272 |/
272 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
273 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
273
274
274 Uncommit with draft parent
275 Uncommit with draft parent
275
276
276 $ hg uncommit
277 $ hg uncommit
277 $ hg phase -r .
278 $ hg phase -r .
278 12: draft
279 12: draft
279 $ hg commit -m 'update ab again'
280 $ hg commit -m 'update ab again'
280
281
281 Phase is preserved
282 Phase is preserved
282
283
283 $ hg uncommit --keep --config phases.new-commit=secret
284 $ hg uncommit --keep --config phases.new-commit=secret
284 $ hg phase -r .
285 $ hg phase -r .
285 15: draft
286 15: draft
286 $ hg commit --amend -m 'update ab again'
287 $ hg commit --amend -m 'update ab again'
287
288
288 Uncommit with public parent
289 Uncommit with public parent
289
290
290 $ hg phase -p "::.^"
291 $ hg phase -p "::.^"
291 $ hg uncommit
292 $ hg uncommit
292 $ hg phase -r .
293 $ hg phase -r .
293 12: public
294 12: public
294
295
295 Partial uncommit with public parent
296 Partial uncommit with public parent
296
297
297 $ echo xyz > xyz
298 $ echo xyz > xyz
298 $ hg add xyz
299 $ hg add xyz
299 $ hg commit -m "update ab and add xyz"
300 $ hg commit -m "update ab and add xyz"
300 $ hg uncommit xyz
301 $ hg uncommit xyz
301 $ hg status
302 $ hg status
302 A xyz
303 A xyz
303 $ hg phase -r .
304 $ hg phase -r .
304 18: draft
305 18: draft
305 $ hg phase -r ".^"
306 $ hg phase -r ".^"
306 12: public
307 12: public
307
308
308 Uncommit leaving an empty changeset
309 Uncommit leaving an empty changeset
309
310
310 $ cd $TESTTMP
311 $ cd $TESTTMP
311 $ hg init repo1
312 $ hg init repo1
312 $ cd repo1
313 $ cd repo1
313 $ hg debugdrawdag <<'EOS'
314 $ hg debugdrawdag <<'EOS'
314 > Q
315 > Q
315 > |
316 > |
316 > P
317 > P
317 > EOS
318 > EOS
318 $ hg up Q -q
319 $ hg up Q -q
319 $ hg uncommit --keep
320 $ hg uncommit --keep
320 $ hg log -G -T '{desc} FILES: {files}'
321 $ hg log -G -T '{desc} FILES: {files}'
321 @ Q FILES:
322 @ Q FILES:
322 |
323 |
323 | x Q FILES: Q
324 | x Q FILES: Q
324 |/
325 |/
325 o P FILES: P
326 o P FILES: P
326
327
327 $ hg status
328 $ hg status
328 A Q
329 A Q
329
330
330 $ cd ..
331 $ cd ..
331 $ rm -rf repo1
332 $ rm -rf repo1
332
333
333 Testing uncommit while merge
334 Testing uncommit while merge
334
335
335 $ hg init repo2
336 $ hg init repo2
336 $ cd repo2
337 $ cd repo2
337
338
338 Create some history
339 Create some history
339
340
340 $ touch a
341 $ touch a
341 $ hg add a
342 $ hg add a
342 $ for i in 1 2 3; do echo $i > a; hg commit -m "a $i"; done
343 $ for i in 1 2 3; do echo $i > a; hg commit -m "a $i"; done
343 $ hg checkout 0
344 $ hg checkout 0
344 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
345 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
345 $ touch b
346 $ touch b
346 $ hg add b
347 $ hg add b
347 $ for i in 1 2 3; do echo $i > b; hg commit -m "b $i"; done
348 $ for i in 1 2 3; do echo $i > b; hg commit -m "b $i"; done
348 created new head
349 created new head
349 $ hg log -G -T '{rev}:{node} {desc}' --hidden
350 $ hg log -G -T '{rev}:{node} {desc}' --hidden
350 @ 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
351 @ 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
351 |
352 |
352 o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
353 o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
353 |
354 |
354 o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
355 o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
355 |
356 |
356 | o 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
357 | o 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
357 | |
358 | |
358 | o 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
359 | o 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
359 |/
360 |/
360 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
361 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
361
362
362
363
363 Add and expect uncommit to fail on both merge working dir and merge changeset
364 Add and expect uncommit to fail on both merge working dir and merge changeset
364
365
365 $ hg merge 2
366 $ hg merge 2
366 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 (branch merge, don't forget to commit)
368 (branch merge, don't forget to commit)
368
369
369 $ hg uncommit
370 $ hg uncommit
370 abort: outstanding uncommitted merge
371 abort: outstanding uncommitted merge
371 [255]
372 [255]
372
373
373 $ hg uncommit --config experimental.uncommitondirtywdir=True
374 $ hg uncommit --config experimental.uncommitondirtywdir=True
374 abort: cannot uncommit while merging
375 abort: cannot uncommit while merging
375 [255]
376 [255]
376
377
377 $ hg status
378 $ hg status
378 M a
379 M a
379 $ hg commit -m 'merge a and b'
380 $ hg commit -m 'merge a and b'
380
381
381 $ hg uncommit
382 $ hg uncommit
382 abort: cannot uncommit merge changeset
383 abort: cannot uncommit merge changeset
383 [255]
384 [255]
384
385
385 $ hg status
386 $ hg status
386 $ hg log -G -T '{rev}:{node} {desc}' --hidden
387 $ hg log -G -T '{rev}:{node} {desc}' --hidden
387 @ 6:c03b9c37bc67bf504d4912061cfb527b47a63c6e merge a and b
388 @ 6:c03b9c37bc67bf504d4912061cfb527b47a63c6e merge a and b
388 |\
389 |\
389 | o 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
390 | o 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
390 | |
391 | |
391 | o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
392 | o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
392 | |
393 | |
393 | o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
394 | o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
394 | |
395 | |
395 o | 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
396 o | 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
396 | |
397 | |
397 o | 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
398 o | 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
398 |/
399 |/
399 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
400 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
400
401
401
402
402 Rename a->b, then remove b in working copy. Result should remove a.
403 Rename a->b, then remove b in working copy. Result should remove a.
403
404
404 $ hg co -q 0
405 $ hg co -q 0
405 $ hg mv a b
406 $ hg mv a b
406 $ hg ci -qm 'move a to b'
407 $ hg ci -qm 'move a to b'
407 $ hg rm b
408 $ hg rm b
408 $ hg uncommit --config experimental.uncommitondirtywdir=True
409 $ hg uncommit --config experimental.uncommitondirtywdir=True
409 $ hg st --copies
410 $ hg st --copies
410 R a
411 R a
411 $ hg revert a
412 $ hg revert a
412
413
413 Rename a->b, then rename b->c in working copy. Result should rename a->c.
414 Rename a->b, then rename b->c in working copy. Result should rename a->c.
414
415
415 $ hg co -q 0
416 $ hg co -q 0
416 $ hg mv a b
417 $ hg mv a b
417 $ hg ci -qm 'move a to b'
418 $ hg ci -qm 'move a to b'
418 $ hg mv b c
419 $ hg mv b c
419 $ hg uncommit --config experimental.uncommitondirtywdir=True
420 $ hg uncommit --config experimental.uncommitondirtywdir=True
420 $ hg st --copies
421 $ hg st --copies
421 A c
422 A c
422 a
423 a
423 R a
424 R a
424 $ hg revert a
425 $ hg revert a
425 $ hg forget c
426 $ hg forget c
426 $ rm c
427 $ rm c
427
428
428 Copy a->b1 and a->b2, then rename b1->c in working copy. Result should copy a->b2 and a->c.
429 Copy a->b1 and a->b2, then rename b1->c in working copy. Result should copy a->b2 and a->c.
429
430
430 $ hg co -q 0
431 $ hg co -q 0
431 $ hg cp a b1
432 $ hg cp a b1
432 $ hg cp a b2
433 $ hg cp a b2
433 $ hg ci -qm 'move a to b1 and b2'
434 $ hg ci -qm 'move a to b1 and b2'
434 $ hg mv b1 c
435 $ hg mv b1 c
435 $ hg uncommit --config experimental.uncommitondirtywdir=True
436 $ hg uncommit --config experimental.uncommitondirtywdir=True
436 $ hg st --copies
437 $ hg st --copies
437 A b2
438 A b2
438 a
439 a
439 A c
440 A c
440 a
441 a
General Comments 0
You need to be logged in to leave comments. Login now