Using CVS in CS 23

CVS is a system that helps you maintain a semblance of order over the source code in a project that multiple people work on. It is based on an older control system named RCS, which was excellent for controlling source when there was only one developer. CVS does a nice job of making the world safe for multiple developers.

These notes borrow heavily from Bradley Kuszmaul's CVS instructions.

Outline

Repositories: the model behind CVS

CVS is a system for controlling versions of your source files, and it works well with multiple users. You can create files and maintain different versions of files. CVS knows how to recreate every revision of each file under its control.

CVS uses a special directory, called a repository, in which it keeps all versions of each file. The repository can have subdirectories, which correspond to subdirectories that you have.

You work in your own directory, distinct from the repository. We'll call your own directory the sandbox.

When you are working on files, you can easily get the latest versions from CVS into your sandbox. When you're ready to check in your changes from your sandbox, CVS will determine whether your changes conflict with changes to the same file(s) made by others and give you an opportunity to resolve the changes.

The main thing you should find is that, after a little bit of initial setup, CVS is pretty easy to use and very nice to have around.

You can get detailed information about CVS from the CVS man pages. man cvs will tell you more than you want to know. Perhaps a better source is the info function of emacs. You can get all sorts of information about CVS in emacs by the following sequence: C-h i g (cvs) . In other words, type control-h, then i, then g, then left paren, then c, then v, then s, then right paren, then press the return key.

How to set up a repository and start using CVS

  1. Choose a team member whose account will contain the repository. Let's say this team member has the login "gump". gump chooses a name for a directory in her account for the repository. Let's say that this directory is ~gump/cs23/repository, but it does not have to have such a path name. I do recommend that the directory name be "repository," however, just to eliminate confusion.
  2. gump creates the repository. setenv CVSROOT ~/cs23/repository cvs init
  3. gump makes the repository accessible only by her project team's UNIX group. Let's say that the team's UNIX group is "bozos". cd ~/cs23 chgrp -R bozos repository chmod -R g+w repository
  4. All team members need to set a shell environment variable named CVSROOT to the name of the repository. (gump has already done this, but only for this login session.) From tcsh, you can type setenv CVSROOT ~gump/cs23/repository But that takes care of only this login session. What you really want is that this environment variable is set upon every login. So each team member, including gump, adds the following line to the end of their ~/.environset file: setenv CVSROOT ~gump/cs23/repository
  5. When you check in a file, you will want to record what changes you made, why you made them, or some other pertinent info. Your life will be nicer if you can use an existing emacs session to do so. To make that happen, each team member adds a line to the end of their ~/.environset file (it doesn't matter whether it goes before or after the setenv CVSROOT line). If you are using xemacs, add the line setenv CVSEDITOR gnuclient If you are using "regular" emacs (not xemacs), add the line setenv CVSEDITOR emacsclient (You might want to type that directly into your tcsh window the very first time so that it takes effect immediately.) Each team member will also need to add one or two lines to the end of their .emacs file. If using xemacs: (gnuserv-start) (setq gnuserv-frame t) If using emacs rather than xemacs: (server-start) To make this "server start" business take effect immediately in emacs, from xemacs enter the commands M-x gnuserv-start and M-x set-var gnuserv-frame t, and from regular emacs enter M-x server-start. In fact, you may find that the "server" shuts itself down automatically every now and then, and you'll need to M-x gnuserv-start or M-x server-start occasionally to restart it, even though you have the (gnuserv-start) or (server-start) line in your .emacs file. I have no idea why this happens.
  6. Each team member creates a sandbox. (Note that even gump, who "owns" the repository, does this step.) Let's say that a team member has the login "vezina". (So vezina might actually be gump.) Assuming that vezina already has a ~vezina/cs23 directory, she might do something like cd ~/cs23 mkdir sandbox
  7. Each team member does a checkout of the files. Yes, I know there aren't any files yet. Indulge me. cd sandbox cvs checkout -l . Note that the last two tokens of the command line are a "minus ell" and a "dot". (As opposed to "minus one" and the dot being construed as a period ending a sentence.)

How to make changes to files that are under control

Adding a new file or directory

Suppose you want to put a brand new file under CVS's control. First you create it, presumably using emacs. Let's say that you have created ~vezina/cs23/sandbox/bozo.cc, and let's assume that your current directory in the shell is ~vezina/cs23/sandbox.

You inform CVS that you're putting bozo.cc under its control with the command

cvs add bozo.cc Note that this command does not actually create a version of bozo.cc in the repository. You'll do that later with the cvs commit command.

CVS can control entire directories. If you want to put a directory under CVS's control, you create it and add it. For example, if we're in ~vezina/cs23/sandbox,

mkdir gui cvs add gui CVS might ask you a question. If it does, answer "y".

When you create a subdirectory, CVS immediately updates the repository. It deals with directories a little differently than files.

Getting ready to make changes

Before you make changes to a file, you need to get the most recent copy from the repository.

If you need an entire directory, and you were not the one who added it to the repository, and you are about to use it for the first time, you need to check it out. You can do so in one of two ways.

  1. If you want the directory "gui" and everything in it, recursively: cvs checkout gui
  2. If you want the directory "gui" without descending recursively: cvs checkout -l gui

Once you've checked out what you need for the first time, there's a really good way to get the latest version of everything in the current directory and all subdirectories beneath it:

cvs update The cvs update command is definitely your friend. You'll also use it to check in changes. In this situation, where you want the latest version of everything before you start working, it modifies the files in your sandbox to reflect the changes that others have made behind your back.

The way that cvs update modifies your files is a little weird sometimes, but it also keeps the original, unmodified file around, but under a different name (see below).

When you run cvs update, you'll get a list of the files it has updated, along with an indication to the left of each one. cvs update doesn't know whether you're trying to get the latest version of everything or you're trying to check in changes. Interpret the indications as follows:

A filename
You are adding the file named filename.
U filename
Someone else modified the file named filename.
M filename
You modified the file named filename.
? filename
The file named filename exists in the sandbox, but you never told CVS about it.
C filename
You modified the file named filename, and so did someone else. The file has been modified using the rcsmerge command to bring in the changes that they made. The format that shows the changes is rather confusing. However, the original, unmodified file is stored in the same directory as the original under the name .#filename.version, where version is the version number of the file you started from.

If all goes correctly, when you use cvs update to check out your files, you should not see the M and C indications. Seeing the M indication isn't so bad; it just means that you hadn't checked in the file. Seeing the C indication can be bad, however, since it means that two of you are editing the same file. It's a good idea to stop and coordinate at this point.

Anyway, once you run cvs update, you should have the latest version of everything you've told CVS about, and you are ready to edit.

By the way, if you want to, you can check out individual files rather than all the files (as cvs update does). If you want to check out bozo.cc from the repository, just type

cvs checkout bozo.cc

Checking in your changes

Checking in your changes is the same as putting your files back into the repository.

First, you run cvs update to make sure you're coordinated with everyone else. Watch out for those C indications, though.

Next, you run

cvs commit You should get a new buffer appearing in your emacs window, and you should type a log message into this buffer, explaining your changes. When you are done typing in your log message, you must type C-x # (control-x pound) to indicate that you're done. Emacs will ask whether to save a file whose name starts with /tmp. (All files in the directory /tmp are considered temporary files by UNIX and are removed periodically.) Just type a "y". The commit procedure will proceed from there.

Unfortunately, CVS seems to use a different /tmp file each time you do a cvs commit, and the buffers for these files don't automatically go away in emacs. But you can get rid of these buffers safely any time after you save them. (From emacs, C-x C-b gives you a list of all your buffers. Type a "d" next to each one you want to get rid of, then type "x" to "expunge" them, i.e., actually get rid of them. Then you can click on the name of whichever buffer you want to go back to.)

Change logs

You can put a change log directly in your file. It's really easy. All you have to do is put a comment whose contents is $Log$ in your file. In a .h or .cc file, put a line // $Log$ In a .tcl file, put a line # $Log$ and the change log should go right in your file. Everytime someone makes a change, you'll be able to see who did it, when, and what their log message was! It'll be right in that comment.

Changing file names

If you want to change a file name, e.g., bozo.cc to clown.cc, the best way is to simply rename the file, remove the old file from CVS's control, and add the new file: mv bozo.cc clown.cc cvs remove bozo.cc cvs add clown.cc CVS keeps all removed files around to be accessible again until the next cvs commit command. To get back a removed file, say bozo.cc, type cvs add bozo.cc But once you have run cvs commit following a cvs remove command, you'll find it tough to get the file back. (It can be done, but it's a pain, so don't do it.)

I would recommend not using cvs remove during your project.

Ignoring files

If you create a file named .cvsignore (note the dot in front) that contains a list of file names, the cvs update command will ignore these files. Of course, if any of these files have been added via a cvs add command, then cvs update will not ignore them.

By default, cvs update ignores files whose names end in ~ (backup files produced by emacs) and .o (object files). Strangely enough, cvs update does not know enough to ignore the .cvsignore file! So you will probably want to include .cvsignore as one of the files listed in .cvsignore.

The file names you list in .cvsignore may include * and ?, which expand in the usual way that the shell matches file names.

Using CVS remotely

You won't need to use CVS remotely for this project, but it's nice to know that you can. What I mean is that your repository can be on a machine at some other site.

For example, when I work on revisions for Introduction to Algorithms, I work on my machine at Dartmouth, but the repository is on the machine theory.lcs.mit.edu in the directory /a/clr/repository. I just have to set the following environment variables:

setenv CVSROOT theory.lcs.mit.edu:/a/clr/repository setenv CVS_RSH ssh MIT requires that I login via ssh for security reasons.

Using CVS from OS X on a Mac

A CS 23 student, Jan Wellford, reports that after some effort, he was able to use CVS from his Mac running OS X. He said that he needed to do the following:

How to avoid typing in your password every time when using ssh

If you use ssh as your way to login to another machine, you can set it up so that you don't have to type in your password each and every time:
  1. Type in the command ssh-keygen -t rsa

  2. It should ask you whether you want to save the key in the file XX/.ssh/id_rsa, where XX indicates your home directory. Just hit the return key.

  3. It should then ask you for a passphrase. Just hit the return key.

  4. It then asks for the same passphrase again. Hit the return key.

  5. Type in the commands cd ~/.ssh cp id_rsa.pub authorized_keys

As long as you're on CS department machines, you won't need to type in your password any more when connecting via ssh. If you're connecting to a remote machine, copy ~/.ssh/authorized_keys to a file by the same name in your account on the remote machine.
Thomas H. Cormen <thc@cs.dartmouth.edu>
Last modified: Fri Feb 15 09:13:41 2002