test-revert.t
652 lines
| 13.8 KiB
| text/troff
|
Tads3Lexer
/ tests / test-revert.t
|
r12106 | $ hg init repo | ||
$ cd repo | ||||
$ echo 123 > a | ||||
$ echo 123 > c | ||||
$ echo 123 > e | ||||
$ hg add a c e | ||||
|
r12156 | $ hg commit -m "first" a c e | ||
|
r14745 | |||
nothing changed | ||||
$ hg revert | ||||
abort: no files or directories specified | ||||
|
r14755 | (use --all to revert all files) | ||
|
r14745 | [255] | ||
|
r14767 | $ hg revert --all | ||
|
r14745 | |||
|
r22099 | Introduce some changes and revert them | ||
-------------------------------------- | ||||
|
r12106 | $ echo 123 > b | ||
$ hg status | ||||
? b | ||||
$ echo 12 > c | ||||
$ hg status | ||||
M c | ||||
? b | ||||
$ hg add b | ||||
$ hg status | ||||
M c | ||||
A b | ||||
$ hg rm a | ||||
$ hg status | ||||
M c | ||||
A b | ||||
R a | ||||
|
r22099 | |||
revert removal of a file | ||||
|
r12106 | $ hg revert a | ||
$ hg status | ||||
M c | ||||
A b | ||||
|
r22099 | |||
revert addition of a file | ||||
|
r12106 | $ hg revert b | ||
$ hg status | ||||
M c | ||||
? b | ||||
|
r22099 | |||
revert modification of a file (--no-backup) | ||||
|
r12106 | $ hg revert --no-backup c | ||
$ hg status | ||||
? b | ||||
|
r22099 | |||
revert deletion (! status) of a added file | ||||
------------------------------------------ | ||||
|
r12106 | $ hg add b | ||
$ hg status b | ||||
A b | ||||
$ rm b | ||||
$ hg status b | ||||
! b | ||||
$ hg revert -v b | ||||
forgetting b | ||||
$ hg status b | ||||
|
r15521 | b: * (glob) | ||
|
r12106 | |||
$ ls | ||||
a | ||||
c | ||||
e | ||||
|
r22099 | Test creation of backup (.orig) files | ||
------------------------------------- | ||||
|
r12106 | |||
$ echo z > e | ||||
$ hg revert --all -v | ||||
saving current version of e as e.orig | ||||
reverting e | ||||
|
r22099 | revert on clean file (no change) | ||
-------------------------------- | ||||
|
r12106 | |||
$ hg revert a | ||||
no changes needed to a | ||||
|
r22099 | revert on an untracked file | ||
--------------------------- | ||||
|
r12106 | |||
$ echo q > q | ||||
$ hg revert q | ||||
file not managed: q | ||||
$ rm q | ||||
|
r22099 | revert on file that does not exists | ||
----------------------------------- | ||||
|
r12106 | |||
$ hg revert notfound | ||||
|
r12156 | notfound: no such file in rev 334a9e57682c | ||
|
r12106 | $ touch d | ||
$ hg add d | ||||
$ hg rm a | ||||
|
r12156 | $ hg commit -m "second" | ||
|
r12106 | $ echo z > z | ||
$ hg add z | ||||
$ hg st | ||||
A z | ||||
? e.orig | ||||
|
r22099 | revert to another revision (--rev) | ||
---------------------------------- | ||||
|
r12106 | |||
$ hg revert --all -r0 | ||||
adding a | ||||
removing d | ||||
forgetting z | ||||
|
r22099 | revert explicitly to parent (--rev) | ||
----------------------------------- | ||||
|
r12106 | |||
$ hg revert --all -rtip | ||||
forgetting a | ||||
undeleting d | ||||
$ rm a *.orig | ||||
|
r22099 | revert to another revision (--rev) and exact match | ||
-------------------------------------------------- | ||||
exact match are more silent | ||||
|
r12106 | |||
$ hg revert -r0 a | ||||
$ hg st a | ||||
A a | ||||
$ hg rm d | ||||
$ hg st d | ||||
R d | ||||
should silently keep d removed | ||||
$ hg revert -r0 d | ||||
$ hg st d | ||||
R d | ||||
$ hg update -C | ||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved | ||||
|
r22099 | |||
revert of exec bit | ||||
------------------ | ||||
|
r16886 | #if execbit | ||
|
r12106 | $ chmod +x c | ||
$ hg revert --all | ||||
reverting c | ||||
$ test -x c || echo non-executable | ||||
non-executable | ||||
$ chmod +x c | ||||
|
r12156 | $ hg commit -m exe | ||
|
r12106 | |||
$ chmod -x c | ||||
$ hg revert --all | ||||
reverting c | ||||
$ test -x c && echo executable | ||||
executable | ||||
|
r16886 | #endif | ||
|
r12106 | |||
$ cd .. | ||||
|
r12399 | Issue241: update and revert produces inconsistent repositories | ||
|
r22099 | -------------------------------------------------------------- | ||
|
r12106 | |||
$ hg init a | ||||
$ cd a | ||||
$ echo a >> a | ||||
$ hg commit -A -d '1 0' -m a | ||||
adding a | ||||
$ echo a >> a | ||||
$ hg commit -d '2 0' -m a | ||||
$ hg update 0 | ||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved | ||||
$ mkdir b | ||||
$ echo b > b/b | ||||
|
r22099 | call `hg revert` with no file specified | ||
--------------------------------------- | ||||
|
r12106 | |||
$ hg revert -rtip | ||||
|
r14542 | abort: no files or directories specified | ||
|
r14726 | (use --all to revert all files, or 'hg update 1' to update) | ||
|
r12316 | [255] | ||
|
r12106 | |||
|
r22099 | call `hg revert` with --all | ||
--------------------------- | ||||
|
r12106 | |||
$ hg revert --all -rtip | ||||
reverting a | ||||
|
r12399 | Issue332: confusing message when reverting directory | ||
|
r22099 | ---------------------------------------------------- | ||
|
r12106 | |||
|
r12156 | $ hg ci -A -m b | ||
|
r12106 | adding b/b | ||
created new head | ||||
$ echo foobar > b/b | ||||
$ mkdir newdir | ||||
$ echo foo > newdir/newfile | ||||
$ hg add newdir/newfile | ||||
$ hg revert b newdir | ||||
|
r15447 | reverting b/b (glob) | ||
forgetting newdir/newfile (glob) | ||||
|
r12106 | $ echo foobar > b/b | ||
$ hg revert . | ||||
|
r15447 | reverting b/b (glob) | ||
|
r12106 | |||
reverting a rename target should revert the source | ||||
|
r22099 | -------------------------------------------------- | ||
|
r12106 | |||
$ hg mv a newa | ||||
$ hg revert newa | ||||
$ hg st a newa | ||||
? newa | ||||
$ cd .. | ||||
$ hg init ignored | ||||
$ cd ignored | ||||
$ echo '^ignored$' > .hgignore | ||||
$ echo '^ignoreddir$' >> .hgignore | ||||
$ echo '^removed$' >> .hgignore | ||||
$ mkdir ignoreddir | ||||
$ touch ignoreddir/file | ||||
$ touch ignoreddir/removed | ||||
$ touch ignored | ||||
$ touch removed | ||||
4 ignored files (we will add/commit everything) | ||||
$ hg st -A -X .hgignore | ||||
I ignored | ||||
I ignoreddir/file | ||||
I ignoreddir/removed | ||||
I removed | ||||
$ hg ci -qAm 'add files' ignored ignoreddir/file ignoreddir/removed removed | ||||
$ echo >> ignored | ||||
$ echo >> ignoreddir/file | ||||
$ hg rm removed ignoreddir/removed | ||||
should revert ignored* and undelete *removed | ||||
|
r22099 | -------------------------------------------- | ||
|
r12106 | |||
$ hg revert -a --no-backup | ||||
reverting ignored | ||||
|
r15447 | reverting ignoreddir/file (glob) | ||
undeleting ignoreddir/removed (glob) | ||||
|
r12106 | undeleting removed | ||
$ hg st -mardi | ||||
$ hg up -qC | ||||
$ echo >> ignored | ||||
$ hg rm removed | ||||
should silently revert the named files | ||||
|
r22099 | -------------------------------------- | ||
|
r12106 | |||
$ hg revert --no-backup ignored removed | ||||
$ hg st -mardi | ||||
|
r16913 | |||
|
r22099 | Reverting copy (issue3920) | ||
-------------------------- | ||||
|
r19129 | someone set up us the copies | ||
$ rm .hgignore | ||||
$ hg update -C | ||||
0 files updated, 0 files merged, 0 files removed, 0 files unresolved | ||||
$ hg mv ignored allyour | ||||
$ hg copy removed base | ||||
$ hg commit -m rename | ||||
copies and renames, you have no chance to survive make your time (issue3920) | ||||
$ hg update '.^' | ||||
1 files updated, 0 files merged, 2 files removed, 0 files unresolved | ||||
$ hg revert -rtip -a | ||||
adding allyour | ||||
adding base | ||||
removing ignored | ||||
$ hg status -C | ||||
A allyour | ||||
ignored | ||||
A base | ||||
removed | ||||
R ignored | ||||
|
r21573 | Test revert of a file added by one side of the merge | ||
|
r22099 | ==================================================== | ||
|
r21573 | |||
|
r22099 | remove any pending change | ||
|
r21573 | |||
$ hg revert --all | ||||
forgetting allyour | ||||
forgetting base | ||||
undeleting ignored | ||||
$ hg purge --all --config extensions.purge= | ||||
|
r22099 | Adds a new commit | ||
|
r21573 | |||
$ echo foo > newadd | ||||
$ hg add newadd | ||||
$ hg commit -m 'other adds' | ||||
created new head | ||||
|
r22099 | merge it with the other head | ||
|
r21573 | |||
$ hg merge # merge 1 into 2 | ||||
2 files updated, 0 files merged, 1 files removed, 0 files unresolved | ||||
(branch merge, don't forget to commit) | ||||
$ hg summary | ||||
parent: 2:b8ec310b2d4e tip | ||||
other adds | ||||
parent: 1:f6180deb8fbe | ||||
rename | ||||
branch: default | ||||
commit: 2 modified, 1 removed (merge) | ||||
update: (current) | ||||
|
r22099 | clarifies who added what | ||
|
r21573 | |||
$ hg status | ||||
M allyour | ||||
M base | ||||
R ignored | ||||
$ hg status --change 'p1()' | ||||
A newadd | ||||
$ hg status --change 'p2()' | ||||
A allyour | ||||
A base | ||||
R ignored | ||||
|
r22099 | revert file added by p1() to p1() state | ||
----------------------------------------- | ||||
|
r21573 | |||
$ hg revert -r 'p1()' 'glob:newad?' | ||||
$ hg status | ||||
M allyour | ||||
M base | ||||
R ignored | ||||
|
r22099 | revert file added by p1() to p2() state | ||
------------------------------------------ | ||||
|
r21573 | |||
$ hg revert -r 'p2()' 'glob:newad?' | ||||
removing newadd | ||||
$ hg status | ||||
M allyour | ||||
M base | ||||
R ignored | ||||
R newadd | ||||
|
r22099 | revert file added by p2() to p2() state | ||
------------------------------------------ | ||||
|
r21573 | |||
$ hg revert -r 'p2()' 'glob:allyou?' | ||||
$ hg status | ||||
M allyour | ||||
M base | ||||
R ignored | ||||
R newadd | ||||
|
r22099 | revert file added by p2() to p1() state | ||
------------------------------------------ | ||||
|
r21573 | |||
$ hg revert -r 'p1()' 'glob:allyou?' | ||||
removing allyour | ||||
$ hg status | ||||
M base | ||||
R allyour | ||||
R ignored | ||||
R newadd | ||||
|
r22124 | Systematic behavior validation of most possible cases | ||
===================================================== | ||||
|
r21573 | |||
|
r22124 | This section tests most of the possible combinations of working directory | ||
changes and inter-revision changes. The number of possible cases is significant | ||||
but they all have a slighly different handling. So this section commits to | ||||
generating and testing all of them to allow safe refactoring of the revert code. | ||||
A python script is used to generate a file history for each combination of | ||||
changes between, on one side the working directory and its parent and on | ||||
the other side, changes between a revert target (--rev) and working directory | ||||
parent. The three states generated are: | ||||
- a "base" revision | ||||
- a "parent" revision | ||||
- the working directory (based on "parent") | ||||
The file generated have names of the form: | ||||
<changeset-state>_<working-copy-state> | ||||
Here, "changeset-state" conveys the state in "base" and "parent" (or the change | ||||
that happen between them), "working-copy-state" is self explanatory. | ||||
All known states are not tested yet. See inline documentation for details. | ||||
Special cases from merge and rename are not tested by this section. | ||||
There are also multiple cases where the current revert implementation is known to | ||||
slightly misbehave. | ||||
Write the python script to disk | ||||
------------------------------- | ||||
$ cat << EOF > gen-revert-cases.py | ||||
> # generate proper file state to test revert behavior | ||||
> import sys | ||||
> | ||||
> # content of the file in "base" and "parent" | ||||
> ctxcontent = { | ||||
> # modified: file content change from base to parent | ||||
> 'modified': ['base', 'parent'], | ||||
> } | ||||
> | ||||
> # content of file in working copy | ||||
> wccontent = { | ||||
> # clean: wc content is the same as parent | ||||
> 'clean': lambda cc: cc[1], | ||||
> } | ||||
> | ||||
> # build the combination of possible states | ||||
> combination = [] | ||||
> for ctxkey in ctxcontent: | ||||
> for wckey in wccontent: | ||||
> filename = "%s_%s" % (ctxkey, wckey) | ||||
> combination.append((filename, ctxkey, wckey)) | ||||
> | ||||
> # make sure we have stable output | ||||
> combination.sort() | ||||
> | ||||
> # retrieve the state we must generate | ||||
> target = sys.argv[1] | ||||
> | ||||
> # compute file content | ||||
> content = [] | ||||
> for filename, ctxkey, wckey in combination: | ||||
> cc = ctxcontent[ctxkey] | ||||
|
r22127 | > if target == 'filelist': | ||
> print filename | ||||
> elif target == 'base': | ||||
|
r22124 | > content.append((filename, cc[0])) | ||
> elif target == 'parent': | ||||
> content.append((filename, cc[1])) | ||||
> elif target == 'wc': | ||||
> content.append((filename, wccontent[wckey](cc))) | ||||
> else: | ||||
> print >> sys.stderr, "unknown target:", target | ||||
> sys.exit(1) | ||||
> | ||||
> # write actual content | ||||
> for filename, data in content: | ||||
> f = open(filename, 'w') | ||||
> f.write(data + '\n') | ||||
> f.close() | ||||
> EOF | ||||
|
r22127 | check list of planned files | ||
$ python gen-revert-cases.py filelist | ||||
modified_clean | ||||
|
r22126 | Script to make a simple text version of the content | ||
--------------------------------------------------- | ||||
$ cat << EOF >> dircontent.py | ||||
> # generate a simple text view of the directory for easy comparison | ||||
> import os | ||||
> files = os.listdir('.') | ||||
> files.sort() | ||||
> for filename in files: | ||||
> if os.path.isdir(filename): | ||||
> continue | ||||
> content = open(filename).read() | ||||
> print '%-6s %s' % (content.strip(), filename) | ||||
> EOF | ||||
|
r22124 | |||
Generate appropriate repo state | ||||
------------------------------- | ||||
$ hg init revert-ref | ||||
$ cd revert-ref | ||||
Generate base changeset | ||||
$ python ../gen-revert-cases.py base | ||||
$ hg addremove --similarity 0 | ||||
adding modified_clean | ||||
$ hg status | ||||
A modified_clean | ||||
$ hg commit -m 'base' | ||||
|
r22126 | (create a simple text version of the content) | ||
$ python ../dircontent.py > ../content-base.txt | ||||
$ cat ../content-base.txt | ||||
base modified_clean | ||||
|
r22124 | Create parent changeset | ||
$ python ../gen-revert-cases.py parent | ||||
$ hg addremove --similarity 0 | ||||
$ hg status | ||||
M modified_clean | ||||
$ hg commit -m 'parent' | ||||
|
r22126 | (create a simple text version of the content) | ||
$ python ../dircontent.py > ../content-parent.txt | ||||
$ cat ../content-parent.txt | ||||
parent modified_clean | ||||
|
r22124 | Setup working directory | ||
$ python ../gen-revert-cases.py wc | cat | ||||
$ hg addremove --similarity 0 | ||||
$ hg status | ||||
$ hg status --rev 'desc("base")' | ||||
M modified_clean | ||||
|
r22126 | (create a simple text version of the content) | ||
$ python ../dircontent.py > ../content-wc.txt | ||||
$ cat ../content-wc.txt | ||||
parent modified_clean | ||||
|
r22124 | $ cd .. | ||
|
r22128 | Test revert --all to parent content | ||
----------------------------------- | ||||
(setup from reference repo) | ||||
$ cp -r revert-ref revert-parent-all | ||||
$ cd revert-parent-all | ||||
check revert output | ||||
$ hg revert --all | ||||
Compare resulting directory with revert target. | ||||
The diff is filtered to include change only. The only difference should be | ||||
additional `.orig` backup file when applicable. | ||||
$ python ../dircontent.py > ../content-parent-all.txt | ||||
$ cd .. | ||||
$ diff -U 0 -- content-parent.txt content-parent-all.txt | grep _ | ||||
[1] | ||||
|
r22129 | |||
Test revert --all to "base" content | ||||
----------------------------------- | ||||
(setup from reference repo) | ||||
$ cp -r revert-ref revert-base-all | ||||
$ cd revert-base-all | ||||
check revert output | ||||
$ hg revert --all --rev 'desc(base)' | ||||
reverting modified_clean | ||||
Compare resulting directory with revert target. | ||||
The diff is filtered to include change only. The only difference should be | ||||
additional `.orig` backup file when applicable. | ||||
$ python ../dircontent.py > ../content-base-all.txt | ||||
$ cd .. | ||||
$ diff -U 0 -- content-base.txt content-base-all.txt | grep _ | ||||
[1] | ||||
|
r22130 | |||
Test revert to parent content with explicit file name | ||||
----------------------------------------------------- | ||||
(setup from reference repo) | ||||
$ cp -r revert-ref revert-parent-explicit | ||||
$ cd revert-parent-explicit | ||||
revert all files individually and check the output | ||||
(output is expected to be different than in the --all case) | ||||
$ for file in `python ../gen-revert-cases.py filelist`; do | ||||
> echo '### revert for:' $file; | ||||
> hg revert $file; | ||||
> echo | ||||
> done | ||||
### revert for: modified_clean | ||||
no changes needed to modified_clean | ||||
check resulting directory againt the --all run | ||||
(There should be no difference) | ||||
$ python ../dircontent.py > ../content-parent-explicit.txt | ||||
$ cd .. | ||||
$ diff -U 0 -- content-parent-all.txt content-parent-explicit.txt | grep _ | ||||
[1] | ||||
|
r22131 | |||
Test revert to "base" content with explicit file name | ||||
----------------------------------------------------- | ||||
(setup from reference repo) | ||||
$ cp -r revert-ref revert-base-explicit | ||||
$ cd revert-base-explicit | ||||
revert all files individually and check the output | ||||
(output is expected to be different than in the --all case) | ||||
$ for file in `python ../gen-revert-cases.py filelist`; do | ||||
> echo '### revert for:' $file; | ||||
> hg revert $file --rev 'desc(base)'; | ||||
> echo | ||||
> done | ||||
### revert for: modified_clean | ||||
check resulting directory againt the --all run | ||||
(There should be no difference) | ||||
$ python ../dircontent.py > ../content-base-explicit.txt | ||||
$ cd .. | ||||
$ diff -U 0 -- content-base-all.txt content-base-explicit.txt | grep _ | ||||
[1] | ||||