3.1. Concurrent Versions System (CVS)
Concurrent Versions System (CVS) is a centralized version control system based on RCS format with a client-server architecture. It was the first version control system and the predecessor for Subversion (SVN).
This section discusses the various elements of CVS, both the good and the bad.
CVS was developed when network connectivity was unreliable and would often drop out. This meant that if several files were committed at once and the network dropped out, the commit would fail. This can still occur now if a network is unreliable but is less common with modern networking infrastructure. If it happens, the CVS administrator has two options to resolve the problem. The first is to use the admin command to remove stall locked files and back out the changed files. The second option is to reissue the commit command.
CVS uses one central location for making back-ups, which is useful for an unstable network. It allows the enforcement of a commit policy through manually prepared triggers (automated tests, builds, Access Control Lists (ACLs), integration with a bug tracking system) due to centralized architecture. This offers one central location for making back-ups.
To create more detailed commits to the backup, CVS can also expand keywords that are marked by the at-sign (@) to record commit details (committer name, commit message, commit time, for example) into a committed file.
In order to keep track of these commits, CVS uses a server to track the changes for each file separately and in reverse time order. By doing so, the latest version is stored directly and can be retrieved quickly, where older versions must be recomputed by the server. Each changed, committed file is tracked separately with an independent revision identifier. This can make it difficult to discover which files have been changed by the commit when multiple changed files are committed. To counter this, users need to tag the repository state whenever a need exists to refer back and view the changes.
The CVS repository can be accessed by two methods. If the repository is on the same machine as the client (:local: access method) then the client spawns the server on its behalf. If the repository is on a remote machine, the server can be started with rsh/SSH (CVS_RHS environment variable) by a client or by an inet daemon (/etc/xinetd.d/cvs) and different authentication methods (:gserver: access method integrates Kerberos authentication, for example) can be used.
Finally, for security a client-server approach is used with CVS. This means that the client is dependent on connectivity to the server and cannot perform any operation (committing, or reading the commit log) without permission to access the server.
This is a sequence of commands demonstrating CVS repository creation in the $CVSROOT directory (using an absolute path to signal :local: access method), importing sources from $SOURCES, checking them out from the repository into $WORKDIR, modifying some files, and committing the changes.
Procedure 3.1. Using CVS
Initialize CVS storage.
$ mkdir "$CVSROOT"
$ cvs -d "$CVSROOT" init
This creates the CVSROOT subdirectory under $CVSROOT with repositories configuration.
Import code from $SOURCES directory into CVS as $REPOSITORY, tagged with $VENDOR_TAG and $RELEASE_TAG with a commit $MESSAGE.
$ cd "$SOURCES"
$ cvs -d "$CVSROOT" import -m "$MESSAGE" "$REPOSITORY" \
"$VENDOR_TAG" "$RELEASE_TAG"
The $SOURCES content should be imported into CVS under $CVSROOT/$REPOSITORY. It is possible to have more repositories in one CVS storage, though this example just uses the one. The $VENDOR_TAG and $RELEASE_TAG are tags for implicit repository branches.
Different developers can now check the code out into $WORKDIR.
$ cd "$WORKDIR"
$ cvs -d "$CVSROOT" checkout "$REPOSITORY"
Do not check out into the original $SOURCES. This could cause data corruption on the client side and CVS will print errors on various CVS invocations.
The latest version of the CVS repository has been transfered into the $REPOSITORY subdirectory. The developer can also check out multiple repositories from one server.
$ cd $REPOSITORY
To schedule adding a new $FILE use:
$ vi "$FILE"
$ cvs add "$FILE"
The developer can modify an $EXISTING_FILE.
$ vi "$EXISTING_FILE"
Finally, the developer can commit these changes with a $COMMIT_MESSAGE.
$ cvs commit -m "$COMMIT_MESSAGE"
It is possible to export the $CVSROOT value as a CVSROOT environment variable and the cvs tool will respect it. This can free the developer from needing to repetitively supply the -d "$CVSROOT" option. The value is stored in the CVS helper subdirectory at initial check-out, and the CVS tool takes the value from there automatically.