##// END OF EJS Templates
test-revert: add case where the file is removed between "base" and "parent"
Pierre-Yves David -
r22136:a29574cb default
parent child Browse files
Show More
@@ -1,690 +1,705 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 > # removed: file exist in base but is removed from parent
445 > 'removed': ['base', None],
444 446 > }
445 447 >
446 448 > # content of file in working copy
447 449 > wccontent = {
448 450 > # clean: wc content is the same as parent
449 451 > 'clean': lambda cc: cc[1],
450 452 > }
451 453 >
452 454 > # build the combination of possible states
453 455 > combination = []
454 456 > for ctxkey in ctxcontent:
455 457 > for wckey in wccontent:
456 458 > filename = "%s_%s" % (ctxkey, wckey)
457 459 > combination.append((filename, ctxkey, wckey))
458 460 >
459 461 > # make sure we have stable output
460 462 > combination.sort()
461 463 >
462 464 > # retrieve the state we must generate
463 465 > target = sys.argv[1]
464 466 >
465 467 > # compute file content
466 468 > content = []
467 469 > for filename, ctxkey, wckey in combination:
468 470 > cc = ctxcontent[ctxkey]
469 471 > if target == 'filelist':
470 472 > print filename
471 473 > elif target == 'base':
472 474 > content.append((filename, cc[0]))
473 475 > elif target == 'parent':
474 476 > content.append((filename, cc[1]))
475 477 > elif target == 'wc':
476 478 > content.append((filename, wccontent[wckey](cc)))
477 479 > else:
478 480 > print >> sys.stderr, "unknown target:", target
479 481 > sys.exit(1)
480 482 >
481 483 > # write actual content
482 484 > for filename, data in content:
483 485 > if data is not None:
484 486 > f = open(filename, 'w')
485 487 > f.write(data + '\n')
486 488 > f.close()
487 489 > elif os.path.exists(filename):
488 490 > os.remove(filename)
489 491 > EOF
490 492
491 493 check list of planned files
492 494
493 495 $ python gen-revert-cases.py filelist
494 496 added_clean
495 497 clean_clean
496 498 modified_clean
499 removed_clean
497 500
498 501 Script to make a simple text version of the content
499 502 ---------------------------------------------------
500 503
501 504 $ cat << EOF >> dircontent.py
502 505 > # generate a simple text view of the directory for easy comparison
503 506 > import os
504 507 > files = os.listdir('.')
505 508 > files.sort()
506 509 > for filename in files:
507 510 > if os.path.isdir(filename):
508 511 > continue
509 512 > content = open(filename).read()
510 513 > print '%-6s %s' % (content.strip(), filename)
511 514 > EOF
512 515
513 516 Generate appropriate repo state
514 517 -------------------------------
515 518
516 519 $ hg init revert-ref
517 520 $ cd revert-ref
518 521
519 522 Generate base changeset
520 523
521 524 $ python ../gen-revert-cases.py base
522 525 $ hg addremove --similarity 0
523 526 adding clean_clean
524 527 adding modified_clean
528 adding removed_clean
525 529 $ hg status
526 530 A clean_clean
527 531 A modified_clean
532 A removed_clean
528 533 $ hg commit -m 'base'
529 534
530 535 (create a simple text version of the content)
531 536
532 537 $ python ../dircontent.py > ../content-base.txt
533 538 $ cat ../content-base.txt
534 539 base clean_clean
535 540 base modified_clean
541 base removed_clean
536 542
537 543 Create parent changeset
538 544
539 545 $ python ../gen-revert-cases.py parent
540 546 $ hg addremove --similarity 0
541 547 adding added_clean
548 removing removed_clean
542 549 $ hg status
543 550 M modified_clean
544 551 A added_clean
552 R removed_clean
545 553 $ hg commit -m 'parent'
546 554
547 555 (create a simple text version of the content)
548 556
549 557 $ python ../dircontent.py > ../content-parent.txt
550 558 $ cat ../content-parent.txt
551 559 parent added_clean
552 560 base clean_clean
553 561 parent modified_clean
554 562
555 563 Setup working directory
556 564
557 565 $ python ../gen-revert-cases.py wc | cat
558 566 $ hg addremove --similarity 0
559 567 $ hg status
560 568
561 569 $ hg status --rev 'desc("base")'
562 570 M modified_clean
563 571 A added_clean
572 R removed_clean
564 573
565 574 (create a simple text version of the content)
566 575
567 576 $ python ../dircontent.py > ../content-wc.txt
568 577 $ cat ../content-wc.txt
569 578 parent added_clean
570 579 base clean_clean
571 580 parent modified_clean
572 581
573 582 $ cd ..
574 583
575 584 Test revert --all to parent content
576 585 -----------------------------------
577 586
578 587 (setup from reference repo)
579 588
580 589 $ cp -r revert-ref revert-parent-all
581 590 $ cd revert-parent-all
582 591
583 592 check revert output
584 593
585 594 $ hg revert --all
586 595
587 596 Compare resulting directory with revert target.
588 597
589 598 The diff is filtered to include change only. The only difference should be
590 599 additional `.orig` backup file when applicable.
591 600
592 601 $ python ../dircontent.py > ../content-parent-all.txt
593 602 $ cd ..
594 603 $ diff -U 0 -- content-parent.txt content-parent-all.txt | grep _
595 604 [1]
596 605
597 606 Test revert --all to "base" content
598 607 -----------------------------------
599 608
600 609 (setup from reference repo)
601 610
602 611 $ cp -r revert-ref revert-base-all
603 612 $ cd revert-base-all
604 613
605 614 check revert output
606 615
607 616 $ hg revert --all --rev 'desc(base)'
608 617 removing added_clean
609 618 reverting modified_clean
619 adding removed_clean
610 620
611 621 Compare resulting directory with revert target.
612 622
613 623 The diff is filtered to include change only. The only difference should be
614 624 additional `.orig` backup file when applicable.
615 625
616 626 $ python ../dircontent.py > ../content-base-all.txt
617 627 $ cd ..
618 628 $ diff -U 0 -- content-base.txt content-base-all.txt | grep _
619 629 [1]
620 630
621 631 Test revert to parent content with explicit file name
622 632 -----------------------------------------------------
623 633
624 634 (setup from reference repo)
625 635
626 636 $ cp -r revert-ref revert-parent-explicit
627 637 $ cd revert-parent-explicit
628 638
629 639 revert all files individually and check the output
630 640 (output is expected to be different than in the --all case)
631 641
632 642 $ for file in `python ../gen-revert-cases.py filelist`; do
633 643 > echo '### revert for:' $file;
634 644 > hg revert $file;
635 645 > echo
636 646 > done
637 647 ### revert for: added_clean
638 648 no changes needed to added_clean
639 649
640 650 ### revert for: clean_clean
641 651 no changes needed to clean_clean
642 652
643 653 ### revert for: modified_clean
644 654 no changes needed to modified_clean
645 655
656 ### revert for: removed_clean
657 removed_clean: no such file in rev * (glob)
658
646 659
647 660 check resulting directory againt the --all run
648 661 (There should be no difference)
649 662
650 663 $ python ../dircontent.py > ../content-parent-explicit.txt
651 664 $ cd ..
652 665 $ diff -U 0 -- content-parent-all.txt content-parent-explicit.txt | grep _
653 666 [1]
654 667
655 668 Test revert to "base" content with explicit file name
656 669 -----------------------------------------------------
657 670
658 671 (setup from reference repo)
659 672
660 673 $ cp -r revert-ref revert-base-explicit
661 674 $ cd revert-base-explicit
662 675
663 676 revert all files individually and check the output
664 677 (output is expected to be different than in the --all case)
665 678
666 679 Misbehavior:
667 680
668 681 - fails to report no change to revert for
669 682 |
670 683 | - clean_clean
671 684
672 685 $ for file in `python ../gen-revert-cases.py filelist`; do
673 686 > echo '### revert for:' $file;
674 687 > hg revert $file --rev 'desc(base)';
675 688 > echo
676 689 > done
677 690 ### revert for: added_clean
678 691
679 692 ### revert for: clean_clean
680 693
681 694 ### revert for: modified_clean
682 695
696 ### revert for: removed_clean
697
683 698
684 699 check resulting directory againt the --all run
685 700 (There should be no difference)
686 701
687 702 $ python ../dircontent.py > ../content-base-explicit.txt
688 703 $ cd ..
689 704 $ diff -U 0 -- content-base-all.txt content-base-explicit.txt | grep _
690 705 [1]
General Comments 0
You need to be logged in to leave comments. Login now