How do I revert a big change in CVS?

user9876 picture user9876 · Jan 12, 2009 · Viewed 18.6k times · Source

One of my colleagues has totally messed up the contents of a directory in our main CVS repository. I need to just revert the whole module to the state it was in at the end of last year. What's the CVS command to do this please?

He has added and removed hundreds of files, so a simple "copy over files from old checkout and commit" isn't enough.

I have RTFM and STFW, and I tried this:

cvs co modulename  # Note no -P option
cvs up -jHEAD -jMAIN:2008-12-30 modulename

But that doesn't work - the new files he created get removed, but the old files and directories don't get resurrected. (I didn't commit it).

I can probably write a shell script for this, but surely this functionality must be in CVS already?

Update: Some clarifications:

  • I can get a local checkout of the module at a specific date. The question is how to get that back into CVS.

  • I do have backups, but the point using of a revision control system like CVS is that it's supposed to be easy to get any historical state. Next time something like this happens I may not be lucky enough to have backups (e.g. backups are daily, so I may lose up to a day's work).

  • I know that CVS is old, and we should move to something newer. But in a large team with a large number of CVS-based tools (checkout & build scripts, nightly build server, etc) the time cost of such a move is considerable. (Evaluation, updating scripts, testing, migration, training, lost developer time, maintaining both systems in parallel as CVS would still be needed for old branches). Hence this has to be planned & scheduled by management.

Update #2: I'm going to start a bounty on this. To qualify for the bounty you have to explain how to revert using normal CVS commands, not with a hacky shell script.

Update #3: The server is CVS 1.12.13. Access is via pserver. I can use the same version of CVS on a Linux PC, or the CVSNT 2.0.51d client on Windows.

Answer

Ralph picture Ralph · Jun 25, 2009

Actually your initial approach was very close to the solution. The problem is, that joining date-based does not handle removed files and directories correctly. You need to set a tag to the code base you want to join first:

mkdir code_base1 && cd code_base1
cvs co -D "2008-12-30" modulename
cvs tag code_base_2008_12_30

Now do the join tag-based, subtracting all changes between now and 2008-12-30:

cd .. && mkdir code_base2 && cd code_base2
cvs co modulename
cvs update -d -j HEAD -j code_base_2008_12_30  # use -d to resurrect deleted directories

Compare the contents of code_base1 and code_base2. They should be identical except for the CVS meta information. Finally commit the code as it was on 2008-12-30 as new HEAD:

cvs commit -m "Revert all changes this year"

Note that tagging the code you wish to join like this will not work, because rtag also does not handle removed files and directories correctly, when using -D:

cvs rtag -D "2008-12-30" code_base_2008_12_30 modulename