##// 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
@@ -28,11 +28,14 b' from mercurial import ('
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 = {}
@@ -45,6 +48,8 b" configitem('experimental', 'uncommitondi"
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
@@ -132,8 +137,107 b' def _fixdirstate(repo, oldctx, newctx, m'
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)
@@ -149,6 +253,7 b' def uncommit(ui, repo, *pats, **opts):'
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
@@ -164,6 +269,10 b' def uncommit(ui, repo, *pats, **opts):'
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
@@ -176,10 +285,106 b' def uncommit(ui, repo, *pats, **opts):'
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"""
@@ -34,6 +34,7 b' Help for uncommit'
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
General Comments 0
You need to be logged in to leave comments. Login now