##// END OF EJS Templates
test-revert: add case where file exists neither in "base" nor in "parent"
Pierre-Yves David -
r22137:2cfe5ec4 default
parent child Browse files
Show More
@@ -1,705 +1,714 b''
1 1 $ hg init repo
2 2 $ cd repo
3 3 $ echo 123 > a
4 4 $ echo 123 > c
5 5 $ echo 123 > e
6 6 $ hg add a c e
7 7 $ hg commit -m "first" a c e
8 8
9 9 nothing changed
10 10
11 11 $ hg revert
12 12 abort: no files or directories specified
13 13 (use --all to revert all files)
14 14 [255]
15 15 $ hg revert --all
16 16
17 17 Introduce some changes and revert them
18 18 --------------------------------------
19 19
20 20 $ echo 123 > b
21 21
22 22 $ hg status
23 23 ? b
24 24 $ echo 12 > c
25 25
26 26 $ hg status
27 27 M c
28 28 ? b
29 29 $ hg add b
30 30
31 31 $ hg status
32 32 M c
33 33 A b
34 34 $ hg rm a
35 35
36 36 $ hg status
37 37 M c
38 38 A b
39 39 R a
40 40
41 41 revert removal of a file
42 42
43 43 $ hg revert a
44 44 $ hg status
45 45 M c
46 46 A b
47 47
48 48 revert addition of a file
49 49
50 50 $ hg revert b
51 51 $ hg status
52 52 M c
53 53 ? b
54 54
55 55 revert modification of a file (--no-backup)
56 56
57 57 $ hg revert --no-backup c
58 58 $ hg status
59 59 ? b
60 60
61 61 revert deletion (! status) of a added file
62 62 ------------------------------------------
63 63
64 64 $ hg add b
65 65
66 66 $ hg status b
67 67 A b
68 68 $ rm b
69 69 $ hg status b
70 70 ! b
71 71 $ hg revert -v b
72 72 forgetting b
73 73 $ hg status b
74 74 b: * (glob)
75 75
76 76 $ ls
77 77 a
78 78 c
79 79 e
80 80
81 81 Test creation of backup (.orig) files
82 82 -------------------------------------
83 83
84 84 $ echo z > e
85 85 $ hg revert --all -v
86 86 saving current version of e as e.orig
87 87 reverting e
88 88
89 89 revert on clean file (no change)
90 90 --------------------------------
91 91
92 92 $ hg revert a
93 93 no changes needed to a
94 94
95 95 revert on an untracked file
96 96 ---------------------------
97 97
98 98 $ echo q > q
99 99 $ hg revert q
100 100 file not managed: q
101 101 $ rm q
102 102
103 103 revert on file that does not exists
104 104 -----------------------------------
105 105
106 106 $ hg revert notfound
107 107 notfound: no such file in rev 334a9e57682c
108 108 $ touch d
109 109 $ hg add d
110 110 $ hg rm a
111 111 $ hg commit -m "second"
112 112 $ echo z > z
113 113 $ hg add z
114 114 $ hg st
115 115 A z
116 116 ? e.orig
117 117
118 118 revert to another revision (--rev)
119 119 ----------------------------------
120 120
121 121 $ hg revert --all -r0
122 122 adding a
123 123 removing d
124 124 forgetting z
125 125
126 126 revert explicitly to parent (--rev)
127 127 -----------------------------------
128 128
129 129 $ hg revert --all -rtip
130 130 forgetting a
131 131 undeleting d
132 132 $ rm a *.orig
133 133
134 134 revert to another revision (--rev) and exact match
135 135 --------------------------------------------------
136 136
137 137 exact match are more silent
138 138
139 139 $ hg revert -r0 a
140 140 $ hg st a
141 141 A a
142 142 $ hg rm d
143 143 $ hg st d
144 144 R d
145 145
146 146 should silently keep d removed
147 147
148 148 $ hg revert -r0 d
149 149 $ hg st d
150 150 R d
151 151
152 152 $ hg update -C
153 153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154 154
155 155 revert of exec bit
156 156 ------------------
157 157
158 158 #if execbit
159 159 $ chmod +x c
160 160 $ hg revert --all
161 161 reverting c
162 162
163 163 $ test -x c || echo non-executable
164 164 non-executable
165 165
166 166 $ chmod +x c
167 167 $ hg commit -m exe
168 168
169 169 $ chmod -x c
170 170 $ hg revert --all
171 171 reverting c
172 172
173 173 $ test -x c && echo executable
174 174 executable
175 175 #endif
176 176
177 177 $ cd ..
178 178
179 179
180 180 Issue241: update and revert produces inconsistent repositories
181 181 --------------------------------------------------------------
182 182
183 183 $ hg init a
184 184 $ cd a
185 185 $ echo a >> a
186 186 $ hg commit -A -d '1 0' -m a
187 187 adding a
188 188 $ echo a >> a
189 189 $ hg commit -d '2 0' -m a
190 190 $ hg update 0
191 191 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 192 $ mkdir b
193 193 $ echo b > b/b
194 194
195 195 call `hg revert` with no file specified
196 196 ---------------------------------------
197 197
198 198 $ hg revert -rtip
199 199 abort: no files or directories specified
200 200 (use --all to revert all files, or 'hg update 1' to update)
201 201 [255]
202 202
203 203 call `hg revert` with --all
204 204 ---------------------------
205 205
206 206 $ hg revert --all -rtip
207 207 reverting a
208 208
209 209
210 210 Issue332: confusing message when reverting directory
211 211 ----------------------------------------------------
212 212
213 213 $ hg ci -A -m b
214 214 adding b/b
215 215 created new head
216 216 $ echo foobar > b/b
217 217 $ mkdir newdir
218 218 $ echo foo > newdir/newfile
219 219 $ hg add newdir/newfile
220 220 $ hg revert b newdir
221 221 reverting b/b (glob)
222 222 forgetting newdir/newfile (glob)
223 223 $ echo foobar > b/b
224 224 $ hg revert .
225 225 reverting b/b (glob)
226 226
227 227
228 228 reverting a rename target should revert the source
229 229 --------------------------------------------------
230 230
231 231 $ hg mv a newa
232 232 $ hg revert newa
233 233 $ hg st a newa
234 234 ? newa
235 235
236 236 $ cd ..
237 237
238 238 $ hg init ignored
239 239 $ cd ignored
240 240 $ echo '^ignored$' > .hgignore
241 241 $ echo '^ignoreddir$' >> .hgignore
242 242 $ echo '^removed$' >> .hgignore
243 243
244 244 $ mkdir ignoreddir
245 245 $ touch ignoreddir/file
246 246 $ touch ignoreddir/removed
247 247 $ touch ignored
248 248 $ touch removed
249 249
250 250 4 ignored files (we will add/commit everything)
251 251
252 252 $ hg st -A -X .hgignore
253 253 I ignored
254 254 I ignoreddir/file
255 255 I ignoreddir/removed
256 256 I removed
257 257 $ hg ci -qAm 'add files' ignored ignoreddir/file ignoreddir/removed removed
258 258
259 259 $ echo >> ignored
260 260 $ echo >> ignoreddir/file
261 261 $ hg rm removed ignoreddir/removed
262 262
263 263 should revert ignored* and undelete *removed
264 264 --------------------------------------------
265 265
266 266 $ hg revert -a --no-backup
267 267 reverting ignored
268 268 reverting ignoreddir/file (glob)
269 269 undeleting ignoreddir/removed (glob)
270 270 undeleting removed
271 271 $ hg st -mardi
272 272
273 273 $ hg up -qC
274 274 $ echo >> ignored
275 275 $ hg rm removed
276 276
277 277 should silently revert the named files
278 278 --------------------------------------
279 279
280 280 $ hg revert --no-backup ignored removed
281 281 $ hg st -mardi
282 282
283 283 Reverting copy (issue3920)
284 284 --------------------------
285 285
286 286 someone set up us the copies
287 287
288 288 $ rm .hgignore
289 289 $ hg update -C
290 290 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
291 291 $ hg mv ignored allyour
292 292 $ hg copy removed base
293 293 $ hg commit -m rename
294 294
295 295 copies and renames, you have no chance to survive make your time (issue3920)
296 296
297 297 $ hg update '.^'
298 298 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
299 299 $ hg revert -rtip -a
300 300 adding allyour
301 301 adding base
302 302 removing ignored
303 303 $ hg status -C
304 304 A allyour
305 305 ignored
306 306 A base
307 307 removed
308 308 R ignored
309 309
310 310 Test revert of a file added by one side of the merge
311 311 ====================================================
312 312
313 313 remove any pending change
314 314
315 315 $ hg revert --all
316 316 forgetting allyour
317 317 forgetting base
318 318 undeleting ignored
319 319 $ hg purge --all --config extensions.purge=
320 320
321 321 Adds a new commit
322 322
323 323 $ echo foo > newadd
324 324 $ hg add newadd
325 325 $ hg commit -m 'other adds'
326 326 created new head
327 327
328 328
329 329 merge it with the other head
330 330
331 331 $ hg merge # merge 1 into 2
332 332 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
333 333 (branch merge, don't forget to commit)
334 334 $ hg summary
335 335 parent: 2:b8ec310b2d4e tip
336 336 other adds
337 337 parent: 1:f6180deb8fbe
338 338 rename
339 339 branch: default
340 340 commit: 2 modified, 1 removed (merge)
341 341 update: (current)
342 342
343 343 clarifies who added what
344 344
345 345 $ hg status
346 346 M allyour
347 347 M base
348 348 R ignored
349 349 $ hg status --change 'p1()'
350 350 A newadd
351 351 $ hg status --change 'p2()'
352 352 A allyour
353 353 A base
354 354 R ignored
355 355
356 356 revert file added by p1() to p1() state
357 357 -----------------------------------------
358 358
359 359 $ hg revert -r 'p1()' 'glob:newad?'
360 360 $ hg status
361 361 M allyour
362 362 M base
363 363 R ignored
364 364
365 365 revert file added by p1() to p2() state
366 366 ------------------------------------------
367 367
368 368 $ hg revert -r 'p2()' 'glob:newad?'
369 369 removing newadd
370 370 $ hg status
371 371 M allyour
372 372 M base
373 373 R ignored
374 374 R newadd
375 375
376 376 revert file added by p2() to p2() state
377 377 ------------------------------------------
378 378
379 379 $ hg revert -r 'p2()' 'glob:allyou?'
380 380 $ hg status
381 381 M allyour
382 382 M base
383 383 R ignored
384 384 R newadd
385 385
386 386 revert file added by p2() to p1() state
387 387 ------------------------------------------
388 388
389 389 $ hg revert -r 'p1()' 'glob:allyou?'
390 390 removing allyour
391 391 $ hg status
392 392 M base
393 393 R allyour
394 394 R ignored
395 395 R newadd
396 396
397 397 Systematic behavior validation of most possible cases
398 398 =====================================================
399 399
400 400 This section tests most of the possible combinations of working directory
401 401 changes and inter-revision changes. The number of possible cases is significant
402 402 but they all have a slighly different handling. So this section commits to
403 403 generating and testing all of them to allow safe refactoring of the revert code.
404 404
405 405 A python script is used to generate a file history for each combination of
406 406 changes between, on one side the working directory and its parent and on
407 407 the other side, changes between a revert target (--rev) and working directory
408 408 parent. The three states generated are:
409 409
410 410 - a "base" revision
411 411 - a "parent" revision
412 412 - the working directory (based on "parent")
413 413
414 414 The file generated have names of the form:
415 415
416 416 <changeset-state>_<working-copy-state>
417 417
418 418 Here, "changeset-state" conveys the state in "base" and "parent" (or the change
419 419 that happen between them), "working-copy-state" is self explanatory.
420 420
421 421 All known states are not tested yet. See inline documentation for details.
422 422 Special cases from merge and rename are not tested by this section.
423 423
424 424 There are also multiple cases where the current revert implementation is known to
425 425 slightly misbehave.
426 426
427 427 Write the python script to disk
428 428 -------------------------------
429 429
430 430 $ cat << EOF > gen-revert-cases.py
431 431 > # generate proper file state to test revert behavior
432 432 > import sys
433 433 > import os
434 434 >
435 435 > # content of the file in "base" and "parent"
436 436 > # None means no file at all
437 437 > ctxcontent = {
438 438 > # clean: no change from base to parent
439 439 > 'clean': ['base', 'base'],
440 440 > # modified: file content change from base to parent
441 441 > 'modified': ['base', 'parent'],
442 442 > # added: file is missing from base and added in parent
443 443 > 'added': [None, 'parent'],
444 444 > # removed: file exist in base but is removed from parent
445 445 > 'removed': ['base', None],
446 > # file exist neither in base not in parent
447 > 'missing': [None, None],
446 448 > }
447 449 >
448 450 > # content of file in working copy
449 451 > wccontent = {
450 452 > # clean: wc content is the same as parent
451 453 > 'clean': lambda cc: cc[1],
452 454 > }
453 455 >
454 456 > # build the combination of possible states
455 457 > combination = []
456 458 > for ctxkey in ctxcontent:
457 459 > for wckey in wccontent:
458 460 > filename = "%s_%s" % (ctxkey, wckey)
459 461 > combination.append((filename, ctxkey, wckey))
460 462 >
461 463 > # make sure we have stable output
462 464 > combination.sort()
463 465 >
464 466 > # retrieve the state we must generate
465 467 > target = sys.argv[1]
466 468 >
467 469 > # compute file content
468 470 > content = []
469 471 > for filename, ctxkey, wckey in combination:
470 472 > cc = ctxcontent[ctxkey]
471 473 > if target == 'filelist':
472 474 > print filename
473 475 > elif target == 'base':
474 476 > content.append((filename, cc[0]))
475 477 > elif target == 'parent':
476 478 > content.append((filename, cc[1]))
477 479 > elif target == 'wc':
478 480 > content.append((filename, wccontent[wckey](cc)))
479 481 > else:
480 482 > print >> sys.stderr, "unknown target:", target
481 483 > sys.exit(1)
482 484 >
483 485 > # write actual content
484 486 > for filename, data in content:
485 487 > if data is not None:
486 488 > f = open(filename, 'w')
487 489 > f.write(data + '\n')
488 490 > f.close()
489 491 > elif os.path.exists(filename):
490 492 > os.remove(filename)
491 493 > EOF
492 494
493 495 check list of planned files
494 496
495 497 $ python gen-revert-cases.py filelist
496 498 added_clean
497 499 clean_clean
500 missing_clean
498 501 modified_clean
499 502 removed_clean
500 503
501 504 Script to make a simple text version of the content
502 505 ---------------------------------------------------
503 506
504 507 $ cat << EOF >> dircontent.py
505 508 > # generate a simple text view of the directory for easy comparison
506 509 > import os
507 510 > files = os.listdir('.')
508 511 > files.sort()
509 512 > for filename in files:
510 513 > if os.path.isdir(filename):
511 514 > continue
512 515 > content = open(filename).read()
513 516 > print '%-6s %s' % (content.strip(), filename)
514 517 > EOF
515 518
516 519 Generate appropriate repo state
517 520 -------------------------------
518 521
519 522 $ hg init revert-ref
520 523 $ cd revert-ref
521 524
522 525 Generate base changeset
523 526
524 527 $ python ../gen-revert-cases.py base
525 528 $ hg addremove --similarity 0
526 529 adding clean_clean
527 530 adding modified_clean
528 531 adding removed_clean
529 532 $ hg status
530 533 A clean_clean
531 534 A modified_clean
532 535 A removed_clean
533 536 $ hg commit -m 'base'
534 537
535 538 (create a simple text version of the content)
536 539
537 540 $ python ../dircontent.py > ../content-base.txt
538 541 $ cat ../content-base.txt
539 542 base clean_clean
540 543 base modified_clean
541 544 base removed_clean
542 545
543 546 Create parent changeset
544 547
545 548 $ python ../gen-revert-cases.py parent
546 549 $ hg addremove --similarity 0
547 550 adding added_clean
548 551 removing removed_clean
549 552 $ hg status
550 553 M modified_clean
551 554 A added_clean
552 555 R removed_clean
553 556 $ hg commit -m 'parent'
554 557
555 558 (create a simple text version of the content)
556 559
557 560 $ python ../dircontent.py > ../content-parent.txt
558 561 $ cat ../content-parent.txt
559 562 parent added_clean
560 563 base clean_clean
561 564 parent modified_clean
562 565
563 566 Setup working directory
564 567
565 568 $ python ../gen-revert-cases.py wc | cat
566 569 $ hg addremove --similarity 0
567 570 $ hg status
568 571
569 572 $ hg status --rev 'desc("base")'
570 573 M modified_clean
571 574 A added_clean
572 575 R removed_clean
573 576
574 577 (create a simple text version of the content)
575 578
576 579 $ python ../dircontent.py > ../content-wc.txt
577 580 $ cat ../content-wc.txt
578 581 parent added_clean
579 582 base clean_clean
580 583 parent modified_clean
581 584
582 585 $ cd ..
583 586
584 587 Test revert --all to parent content
585 588 -----------------------------------
586 589
587 590 (setup from reference repo)
588 591
589 592 $ cp -r revert-ref revert-parent-all
590 593 $ cd revert-parent-all
591 594
592 595 check revert output
593 596
594 597 $ hg revert --all
595 598
596 599 Compare resulting directory with revert target.
597 600
598 601 The diff is filtered to include change only. The only difference should be
599 602 additional `.orig` backup file when applicable.
600 603
601 604 $ python ../dircontent.py > ../content-parent-all.txt
602 605 $ cd ..
603 606 $ diff -U 0 -- content-parent.txt content-parent-all.txt | grep _
604 607 [1]
605 608
606 609 Test revert --all to "base" content
607 610 -----------------------------------
608 611
609 612 (setup from reference repo)
610 613
611 614 $ cp -r revert-ref revert-base-all
612 615 $ cd revert-base-all
613 616
614 617 check revert output
615 618
616 619 $ hg revert --all --rev 'desc(base)'
617 620 removing added_clean
618 621 reverting modified_clean
619 622 adding removed_clean
620 623
621 624 Compare resulting directory with revert target.
622 625
623 626 The diff is filtered to include change only. The only difference should be
624 627 additional `.orig` backup file when applicable.
625 628
626 629 $ python ../dircontent.py > ../content-base-all.txt
627 630 $ cd ..
628 631 $ diff -U 0 -- content-base.txt content-base-all.txt | grep _
629 632 [1]
630 633
631 634 Test revert to parent content with explicit file name
632 635 -----------------------------------------------------
633 636
634 637 (setup from reference repo)
635 638
636 639 $ cp -r revert-ref revert-parent-explicit
637 640 $ cd revert-parent-explicit
638 641
639 642 revert all files individually and check the output
640 643 (output is expected to be different than in the --all case)
641 644
642 645 $ for file in `python ../gen-revert-cases.py filelist`; do
643 646 > echo '### revert for:' $file;
644 647 > hg revert $file;
645 648 > echo
646 649 > done
647 650 ### revert for: added_clean
648 651 no changes needed to added_clean
649 652
650 653 ### revert for: clean_clean
651 654 no changes needed to clean_clean
652 655
656 ### revert for: missing_clean
657 missing_clean: no such file in rev * (glob)
658
653 659 ### revert for: modified_clean
654 660 no changes needed to modified_clean
655 661
656 662 ### revert for: removed_clean
657 663 removed_clean: no such file in rev * (glob)
658 664
659 665
660 666 check resulting directory againt the --all run
661 667 (There should be no difference)
662 668
663 669 $ python ../dircontent.py > ../content-parent-explicit.txt
664 670 $ cd ..
665 671 $ diff -U 0 -- content-parent-all.txt content-parent-explicit.txt | grep _
666 672 [1]
667 673
668 674 Test revert to "base" content with explicit file name
669 675 -----------------------------------------------------
670 676
671 677 (setup from reference repo)
672 678
673 679 $ cp -r revert-ref revert-base-explicit
674 680 $ cd revert-base-explicit
675 681
676 682 revert all files individually and check the output
677 683 (output is expected to be different than in the --all case)
678 684
679 685 Misbehavior:
680 686
681 687 - fails to report no change to revert for
682 688 |
683 689 | - clean_clean
684 690
685 691 $ for file in `python ../gen-revert-cases.py filelist`; do
686 692 > echo '### revert for:' $file;
687 693 > hg revert $file --rev 'desc(base)';
688 694 > echo
689 695 > done
690 696 ### revert for: added_clean
691 697
692 698 ### revert for: clean_clean
693 699
700 ### revert for: missing_clean
701 missing_clean: no such file in rev * (glob)
702
694 703 ### revert for: modified_clean
695 704
696 705 ### revert for: removed_clean
697 706
698 707
699 708 check resulting directory againt the --all run
700 709 (There should be no difference)
701 710
702 711 $ python ../dircontent.py > ../content-base-explicit.txt
703 712 $ cd ..
704 713 $ diff -U 0 -- content-base-all.txt content-base-explicit.txt | grep _
705 714 [1]
General Comments 0
You need to be logged in to leave comments. Login now