CVS: An Introduction
If you have downloaded software from the Internet, especially from SourceForge, you probably noticed the letters CVS. CVS stands for Concurrent Versions System and is a tool that allows developers to keep track of their projects. It also allows developers to collaborate on projects.
While CVS may be used on large projects with many developers over a network, this article focuses on its usefulness for individuals on local systems. A common occurrence with CVS might begin with making changes to a script or configuration file and then moving on to other tasks. After some time has passed, you find your changes aren't working, and you don't have a backup of the original file, and you can't quite remember all the changes you made. CVS can help prevent this situation because it keeps track of changes made to files and allows you to revert to working versions of them.
Files under the control of CVS are stored in a special directory called a repository, and each file has a revision number maintained by CVS. To make a change to a file, you first must get a copy of it from the repository. You can get a copy of the latest revision of a file or any earlier revision stored in CVS. When you are through working with the file, you put it back into the repository, and its revision number increases incrementally. Each time you commit a file to the repository you can supply a log message that helps keep track of which changes were made to the file over time.
CVS differs from other version control systems in that it doesn't lock files; different developers can check out a file and work on it at the same time. CVS makes sure one developer's edits don't conflict with edits made by another developer when the file is put back into the repository. If conflicts are found, CVS places markers in the second developer's copy of the file, allowing him or her to find and resolve the conflicts. Once the conflicts are resolved, the developer then commits the file to the repository.
There is nothing tricky involved in installing CVS. You can either download and compile the source or install an RPM package or its equivalent.
Once CVS is installed you will have to decide where to locate the repository. It should be in a partition that has a good amount of free space and one to which you have write permission. Once you have decided on a location for the repository, you have to create it and populate it with CVS administration files. This is done using the CVS init command. If you want your repository to be in /usr/local/cvsstuff, you would execute the CVS command shown below:
cvs -d /usr/local/cvsstuff init
The CVSROOT environment variable, or -d switch, tells CVS commands which repository to act upon. The CVSROOT variable can be set by adding the following line to your .bash_profile:
To put existing projects into the repository, use the import command. For example, say you have the directory structure shown below and will add other client directories in the future.
html_projects/ client1/ images/ client2/ images/
To place html_projects and everything under it into the repository, you would use the following commands:
cd html_projects cvs import -m "Put html_projects in the repository" html_projects vendor releaseThe -m option supplies a log message for the transaction; if you don't use it CVS starts your default editor so you can type a message, then finishes the operation when you exit the editor. The vendor and release tags aren't used by CVS but are required nonetheless. A typical vendor tag could be your company name, and “start” makes a good release tag. If your project contains binary files, such as pictures, read up on the -k option to ensure they are copied into the repository correctly.
If you were to now look in your repository, you should find a directory called html_projects containing copies of all the files in the original html_projects directory.
Creating a new project under CVS is simply a matter of creating an empty directory structure and then importing it into the repository via the import command. As you create the files for the new project, use the CVS add command to put them in the repository.
The basic steps for using CVS are as follows: check a project out of the repository, make changes to project files and verify whether they work, commit the modified files back into the repository and supply notes on the changes you made.
You have to check out files from CVS before you can edit them. By default CVS checks out the latest revision of a project, but you can specify earlier revisions if you wish. When you check out a project from the repository, CVS copies the project's files to the current directory, creating subdirectories as necessary. You can check out project files by specifying a directory name (e.g., html_projects) or by specifying a specific project file (e.g., html_projects/client1/index.html). Specifying a file still creates the project's directory structure in your working directory, but only the specified file is copied from the repository.
To check out client1's files, move to a directory where you can work, such as your home directory, and then issue the CVS checkout command shown below. You can easily end up with several copies of a project scattered about if you don't switch to the same starting directory each time you run the checkout command.
cvs checkout html_projects/client1
Next, switch to the client1 directory (cd ~/html_projects/client1) and make changes to the files using your favorite editing tool. Make sure your changes work before committing a file back into the repository. A common mistake when using version control software is to check in files too soon. This causes the repository to contain many versions of the file, most of which don't work.
To put the changed file into the repository, use the following command:
cvs commit -m "made some changes" index.html
CVS will let you know if the file was successfully placed in the repository and what its new revision number is.
You can retrieve earlier revisions of a file by specifying a revision number or a date with the checkout command. For example, if index.html is currently at revision 1.3 and you want to retrieve yesterday's version, which was 1.2, you can do so with either of the following commands:
cvs checkout -r 1.2 html_projects/client1/index.html
cvs checkout -D yesterday html_projects/client1/index.htmlThe -r switch allows you to specify a revision number, while the -D switch allows you to specify a date. You can specify an ISO standard date such as 2000-03-23 or a relative date such as “yesterday”.
To add a file to an existing project, check out the project then create the new file in the project's working directory. Add it to the repository using the following commands:
cvs add newfile cvs commit -m "Added newfile to the project" newfile
Removing files is very similar to adding them. First check out the project, and then delete the files you wish to remove from the working directory. Remove them from the repository with:
cvs remove newfile cvs commit -m "Removed newfile from project" newfile
One way to deal with a repository full of project directories is to take advantage of the ability to use aliases in place of directory names in CVS commands. Aliases allow you to use short, meaningful names for projects instead of long directory names. An alias can also be used to group separate projects under a single name so they can all be checked out with one command. Finally, an alias can list specific project files, such as documentation or header files, allowing you to check out small pieces of a project. To use aliases you must edit the modules file in the CVSROOT directory of the repository. This is explained in the CVS documentation.
CVS allows you to supply a symbolic or logical name (e.g., release-1 or beta) to all the files in a project with the tag command. Since each file in a project might have a different revision number, a tag provides a way to take a snapshot of the project at a given moment. You can then use the tag with the -r switch when checking out a project to retrieve that snapshot, without having to remember the version numbers of each file in the project. One thing to note is that tags can't contain spaces or periods.
CVS allows you to create branches of a project where each branch contains project code in different states, such as a bug-fix branch and a new features branch. You can work on different branches without affecting the other branches and then you can merge the changes from one branch into another automatically.
For the sake of example, let's assume you're working on a project called FaxMan and have released version 1.0. You tagged the source files in the repository as rel-1-0 upon release, then started working on version 2.0. Then you get complaints of bugs in version 1.0 that have to be fixed. To create a branch of the FaxMan project containing version 1.0 you can use:
cvs rtag -b -r rel-1-0 rel-1-0-bugfix FaxMan
The rtag command assigns a new tag (rel-1-0-bugfix) to the code in the repository. The -b flag means the tag is a new branch, and -r rel-1-0 means this branch contains the code previously tagged as rel-1-0.
To check out and work on the version 1.0 code you would use the following command:
cvs checkout -r rel-1-0-bugfix FaxMan
To merge the bug fixes with the current FaxMan code you first check out the latest code and then tell CVS to merge the rel-1-0-bugfix code with it. This is done using:
cvs checkout FaxMan cvs update -j rel-1-0-bugfix
There are several CVS clients available so you don't have to manipulate CVS from the command line. TkCVS is currently at version 6.4 and requires Tcl/Tk 8.1 or better. Pharmacy, which is currently at version 0.2.1, is part of the GNOME project, while Cervisia, at version 1.0 stable, uses the Qt and KDE libraries. Another client that uses the Qt toolkit is LinCVS, version 0.3. See the Resources section for pointers to these projects.
While CVS is a very powerful tool that allows far-flung developers to collaborate on projects over the Internet, it is also easy to configure and use on a local machine. If you frequently update files and need to keep track of the changes, CVS allows you to build a record of what changes were made.