Quick Reference Guide
Quick Guide to CVS
A practical reference for setting up and using the Concurrent Versions System (CVS). Commands were originally tested on CVS 1.10. Covers setup, import, checkout, commit, branching, tags, and remote repositories.
Note: This guide was originally published in 2006 and has been updated in May 2026 with additional sections and improved formatting, with assistance from Claude (Anthropic).
CVS is a legacy tool. For new projects, Git is strongly recommended. This guide is useful for working with existing CVS repositories.
Setup
Set the CVSROOT environment variable to point to your repository directory, then initialise it:
setenv CVSROOT ~/cvsroot # csh / tcsh
export CVSROOT=~/cvsroot # bash
cvs init # creates the repository structure
For remote repositories, CVSROOT takes the form :pserver:user@host:/path/to/repo. See the Remote Repositories section below.
Core Workflow
The typical day-to-day CVS cycle for a developer:
| Step | Command | What it does |
| 1. Get latest | cvs update | Pull changes from the repository into your working copy |
| 2. Edit files | your editor | Make your changes locally |
| 3. Review | cvs diff | See what you have changed before committing |
| 4. Commit | cvs commit -m "message" | Save your changes back to the repository |
Importing a Project
To place an existing directory of files under CVS control, cd into the project directory and run:
cd ~/project
cvs import -m "Initial import" myproject vendor start
| Argument | Meaning |
myproject | Repository name — use this name in future checkout commands |
vendor | Vendor tag — can be any label (e.g. your username or organisation) |
start | Release tag — marks this as the initial release |
Checking Out a Project
Checkout creates a working copy of the repository in your current directory:
cvs checkout myproject # full checkout
cvs checkout -r v1.2 myproject # checkout a specific tag
cvs co myproject # shorthand
This creates a myproject/ directory. CVS metadata is stored in CVS/ subdirectories — do not delete or edit these.
Updating Your Working Copy
Run cvs update from inside your working copy to pull changes committed by others:
cvs update # update all files in current directory
cvs update -d # also create any new directories added to repo
cvs update file.c # update a single file
Status codes in the output:
| Code | Meaning |
U | File updated from repository |
M | File modified locally (your changes) |
C | Conflict — your changes clash with someone else’s; must be resolved manually |
? | File exists locally but is not tracked by CVS |
Committing Changes
After editing files, commit them back to the repository:
cvs commit -m "Fix off-by-one error in solver" # commit all changed files
cvs commit -m "Update README" README.md # commit a specific file
If you omit -m, CVS opens an editor for your log message. To change which editor is used:
setenv EDITOR emacs # or vim, nano, etc.
Adding and Removing Files
Adding or removing a file is a two-step process: stage the change with add/remove, then make it permanent with commit:
# Add a new file
cvs add newfile.c
cvs commit -m "Add newfile.c"
# Remove a file (delete it first, then remove from CVS)
rm oldfile.c
cvs remove oldfile.c
cvs commit -m "Remove oldfile.c"
# Add a binary file (prevents line-ending conversion)
cvs add -kb image.png
To add an entire new directory: cvs add dirname followed by cvs add dirname/* and then commit.
Status and Diff
cvs status # show status of all files in working copy
cvs status file.c # status of a specific file
cvs diff # show all local changes as a unified diff
cvs diff -u file.c # unified diff for one file
cvs diff -r 1.3 -r 1.5 file.c # diff between two specific revisions
Always run cvs diff before committing to review exactly what will be saved.
Log and History
cvs log # full commit history for all files
cvs log file.c # history for a specific file
cvs log -r 1.3 file.c # log entry for revision 1.3 only
cvs log -d "2006-01-01<2006-06-01" file.c # log within a date range
CVS uses dotted revision numbers (e.g. 1.1, 1.2, …) per file. Branch revisions use additional components (e.g. 1.2.2.1).
Tags and Branches
Tags
A tag marks the current state of all files with a symbolic name, useful for marking releases:
cvs tag v1_0_release # tag the current working copy state
cvs rtag v1_0_release myproject # tag directly in the repository
Branches
Branches allow parallel lines of development, e.g. a maintenance branch alongside active development:
# Create a branch
cvs tag -b MAINTENANCE_1_0
# Switch your working copy to that branch
cvs update -r MAINTENANCE_1_0
# Switch back to the main trunk
cvs update -A
Changes committed on a branch do not affect the main trunk. Merging branch changes back uses cvs update -j BRANCH_TAG.
Remote Repositories (pserver)
CVS can connect to a remote server over its own pserver protocol. Set CVSROOT to the remote path and log in once:
setenv CVSROOT :pserver:[email protected]:/srv/cvsroot
cvs login # prompts for password; stored in ~/.cvspass
cvs checkout myproject
cvs logout # when done
SSH-tunnelled access is more secure for production use: set CVSROOT to :ext:username@host:/path and CVS_RSH=ssh.
Quick Command Reference
| Command | What it does |
cvs init | Initialise a new repository |
cvs import | Import a directory into CVS for the first time |
cvs checkout | Get a working copy from the repository |
cvs update | Pull latest changes from the repository |
cvs commit | Save local changes to the repository |
cvs add | Schedule a new file for addition (follow with commit) |
cvs remove | Schedule a file for removal (follow with commit) |
cvs status | Show the status of files in the working copy |
cvs diff | Show differences between local and repository versions |
cvs log | Show commit history and revision log |
cvs tag | Apply a symbolic tag to the current state |
cvs tag -b | Create a branch tag |
For a more comprehensive tutorial, see this CVS guide. For new projects, the Quick Guide to Git is a better starting point.