Once of the main complaints about the CVS version control system is that it’s difficult to move or rename files as your project structure changes.

While you can easily remove files and re-add them under a new name or location, this method loses the precious nuggets of wisdom contained in the file’s history — you do enter meaningful commit messages, don’t you? 😉

Although recent CVS versions (CVSNT 2.0.55 and later) include support for a new rename command, the feature is classified as “experimental” and it’s not well-supported by common clients nor well-documented in the manual.

However, it can be done — the key is to understand that rename operations are properties of directories, not of the files inside. So when you move or rename a file, it is essential to commit the folder containing the file — and (if you moved the file) the new folder as well.

Note: Before using the rename command, you may want to back up your local working copy (sandbox) just to be on the safe side if anything goes wrong — and if it does, please don’t blame me!

The steps below outline the basic process.

To move (rename) an existing file in CVS:

  1. If you’ll be moving a file to a new location that is not already under version control, create NewFolderName and add it to CVS with cvs add.

  2. At the command line, navigate to current location of the file you want to move (let’s call this OldFolderName) and enter:

    cvs rename OldFileName ../NewFolderName/NewFileName

    (the file is moved to NewFolderName and renamed to NewFileName)

  3. This is the important part! — Still in OldFolderName, enter:

    cvs commit

  4. If you moved the file to a different folder, cd to NewFolderName and repeat the commit command:

    cvs commit

    At this point, the repository knows about the changes to OldFolderName and NewFolderName.

    Now, for good measure, we will update our local sandbox to be sure we have a pristine copy of the project. In fact, to really make sure the repository “gets it”, we’ll remove NewFolderName and verify that it returns on update.

  5. So take a deep breath, and delete NewFolderName.

  6. Then, finally, navigate to your project’s root folder and enter:

    cvs update -P -d

    (In this command, the -P option tells CVS to “prune” (remove) any empty folders in your working copy, and -d creates any missing folders like NewFolderName.)

That’s it. You’re done! — NewFolderName should reappear, and inside it, NewFileName will be waiting for you with its history intact!

What? It isn’t? — well, you do have that backup, don’t you?