Contents:
CVS (Concurrent Versions System) provides the following functionality:
CVS works as follows. There is a "repository" containing the master version of the files, including a history of all previous versions. Each user "checks out" a working copy of the files.
Each user can edit his or her copy of the files arbitrarily, without affecting other users or the master version.
Over many years of teaching 6.170, we have observed that on average 2 students' computers will either die or be stolen during the semester. Therefore, you should either work on Athena, or commit your work to the repository often. Committing often
You always edit your own personal copy of files that are under CVS control. Before you can make such edit, you must "check out" your own copies of the repository's master files. You only need to do this step once at the beginning of the term and once when you begin your final project. If you are tempted to use this command at other times, you most likely want CVS's "update" command. In the case that you plan to work at both Athena and home, you will need to do these setup steps for both your Athena account and your home computer.
A CVS repository groups its master files into "modules." When checking out files, you need to specify which module's files you wish to check out.
The following instructions assume you wish to check out a module named psets from a repository that is located at /mit/$USER/6.170/cvsroot such that your local copies of the files appear in the directory ~/6.170. (This is the configuration that is expected for Problem Set 0).
Execute the following commands on the Athena prompt:
cd ~/6.170 cvs -d /mit/$USER/6.170/cvsroot checkout psets
After running the commands above, logout of athena then log back in.
Use the command line.
The following example will show you how to use Eclipse to check out CVS modules. Before doing so, please check to make sure that you have properly set up the Eclipse environment for 6.170. We will assume that you will check out a CVS module called psets. When you check out the psets module, Eclipse automatically sets up an Eclipse project named "psets" for you. These instructions happen to complete the task assigned to you in ps0.
Host: athena.dialup.mit.edu Repository path: /mit/<your username>/6.170/cvsroot User: Fill in your user name. Password: leave this field blank! Connection type: ext (use extssh if you are on a home computer)


When using Emacs, the majority of CVS commands ("add", "commit", and "remove") are accessed through Emacs's CVS mode. (The notable exception is "checkout".)
Switch Emacs into CVS mode by running Alt-x cvs-examine or Alt-x cvs-update. When prompted for CVS Examine (directory), enter the directory in which the files you wish to manipulate are located. This is called your "working directory." For example, ~/6.170/psets/ps0/. This step will bring up a new buffer that lists all the new and modified files in your working directory. Note that unmodified, non-new files are not shown.
In this CVS buffer, you can move the keyboard cursor over a directory or file and issue one of the following commands:
Note that issuing a command to a directory will apply that command, recursively, to all files and sub-directories within that directory.
If you wish to perform the same command on several files or directories, you can "mark" each file and directory. To mark a file or directory, move the keyboard cursor over the file or directory and press the 'm' key. Doing so will place a '*' next to the file or directory to show that it has been marked. Marking a directory, will recursively mark all of its files and sub-directories. You may unmark a file by pressing the 'u' key. Once you have marked all the files and directories you wish to operate on, you can issue a command, to be applied to all marked files, by pressing 'a', 'r', or 'c'.
Alt-x cvs-update is the same as Alt-x cvs-examine except that it updates all the files in the directory you are examining before displaying the directory's files.
If you create a new file in a directory which is under CVS control, CVS will not automatically add it to the repository. This behavior is to avoid extraneous files from being added to CVS control. (You can tell when a directory is under CVS control when it contains a CVS sub-directory with files such as Entries, Repository, and Root, none of which you should directly modify.)
You should not place compiler-generated or other auto-generated files under CVS control. This includes .class files and Javadoc files. If you place those filenames or patterns (e.g., *.class) in a .cvsignore file, then CVS will ignore those files. This simplifies CVS's update output in the presence of generated files (see this section).
To make CVS place a file under its control, first follow these instructions, then commit the file.
With Eclipse you do not need to worry about this step. Eclipse will automatically ask you if you want to add or ignore specific files when you run commit on the directory that contains the new files.
However, if you create a file or folder in an Eclipse project but via the command line (or any mechanism outside Eclipse), then you will need to "refresh" the package explorer for Eclipse to recognize the change. To do this, right click on the project name in the package explorer and select the "refresh" item.
You will be asked to enter a description of the file(s) added. Do so, then press "enter".
When adding a file, you must indicate to CVS whether it is a text/ASCII file (such as a .java file) or a binary file (such as a .jpg image) when invoking the cvs add filename command.
If you're are attempting to add a file to the directory ~/6.170/psets/psN/ directory, first you should cd to that directory:
cd ~/6.170/psets/psN
Now you can add a text/ASCII file as follows:
cvs add RandomHello.java
But if the file is binary, then you need to use a -kb flag:
cvs add -kb doc/screenshot.jpg
CVS's "update" command updates your local copy of files to reflect changes made to the repository by other people (or by you when working on a different computer system).
In the first half of the class, the only changes made by people other than you will be made by the 6.170 staff when we are adding new psets to your repositories. During the final project, you will need to use update to see the changes your teammates make to your shared repository. If you work at home and on Athena, you will need to use update to propagate your changes between the two locations.
CVS usually does a good job of merging changes made to multiple checkouts (say, by different people or by you on your home computer and you on Athena), even if those changes are to different parts of the same file. However, if both people change the same line of a file, then CVS cannot decide which version should take precedence. In this case, CVS will signal a conflict during CVS update, and you must resolve the conflict manually. This can be an unpleasant task.
To minimize the possibility of conflicting changes being made simultaneously, you should update frequently and commit frequently.
In the Package Explorer window, right-click on a file or directory, and select Team » Update. If the selected item is not a directory, just that file will be updated; otherwise, everything inside the directory will be updated.
Run Alt-x cvs-update, and enter ~/6.170/psets/psN when asked which directory to update or enter ~/6.170/psets if you are attempting to gain access to a new pset.
To update your local copy, go to the root of your repository (~/6.170/psets) and run:
cvs update
This will display a list of files that have been updated. You should pay attention to the character that shows up in front of each file, as it indicates what sort of change was made to the file:
| ? | Indicates that this file has not been added to the repository, so CVS has not edited it. This is an indication that the file should probably either be added to the repository or to a .cvsignore file in that directory. |
| U | Indicates that this file has been updated successfully to match the latest copy in the repository. |
| M | Indicates that your working copy of the file is different from the repository's latest version, but that merging the repository's copy with yours is successful. |
| C | Indicates that there was a conflict when trying to merge your local copy of the file with the one in the repository. (See Resolving Conflicts for more information.) |
| P | Indicates that this file has been patched which for all practical purposes is the same as updated. (The change to the file was "small enough" that a full update wasn't necessary.) |
After making changes to, adding, or removing files, you must "commit" your changes to CVS. This step will cause CVS to record your changes to the repository, so that your changes are backed-up and available to other people working on the repository, or to you when working on a different computer system.
In general, you should "update" your files before committing them. (And, if the update results in any conflicts, you should resolve them before committing.) If you forget to update, CVS will abort and remind you to update first.
It is a good idea to commit your changes frequently. It backs up your work, thus enabling you to revert to an earlier version of your code if you find yourself going down a wrong path. Also, when you are working with others, it minimizes conflicts.
Note: It is not possible for a commit to change the name of a file. If you want to change the name of one of your files, copy the file, cvs remove the old one, then cvs add the renamed file.
After adding the files, you will be prompted to provide a message. Provide a descriptive log message, then type Ctrl-c Ctrl-c.
First, enter the directory in which the file(s) you wish to commit are located. For example:
cd ~/6.170/psets/psN
Then, you can commit a group of filename(s) to CVS by running:
cvs commit -m "a descriptive log message" filename(s)
If you omit the message flag -m "a descriptive log message" from your commit command, CVS will throw you into an editor where you can enter a message.
If you omit the filename(s) from your commit command, then CVS will recursively commit everything in the current directory. Be careful not to inadvertently commit files that you don't want to commit.

Enter a descriptive commit comment, and click Finish. The lower panel shows you the list of files that you have modified and that will be committed to the CVS repository.

When multiple people (or the same person on multiple machines) are working on the same file concurrently, CVS tries to merge the changes made by each person together as each person calls CVS update. However, sometimes CVS is unable to merge the files together when multiple people change the same line of a file. In this case, CVS will signal a conflict during the update. That person (possibly with help of the other parties) will be required to resolve the conflicts.
If some of your changes conflict with others' changes, cvs update will tell you so, and the source file will be changed to include both versions of any conflicting portions (yours and the one from the repository), in this format:
<<<<<<< filename YOUR VERSION ======= REPOSITORY'S VERSION >>>>>>> repository version's revision number
You must resolve the conflict by editing the file, removing the markers, and leaving whichever version of the code you prefer (or merging them by hand). (Searching for "<<<" until you've resolved all the conflicts is generally a good idea.)
CVS is no replacement for management! Coordination of work is important, even if you're working separately. You should minimize working on the same file at the same time if possible. If you do work on the same file, work on different portions. Modularizing code into multiple files often makes parallelizing work more efficient. You should always pass major design decisions by your teammates before implementing them, particularly if they involve interfaces that will affect their code.
When and how often should you commit? If you commit too often without sufficient testing, you may introduce bugs into the repository that will affect your teammates' work. However, if you commit too rarely, your teammates will be using outdated code, which may cause wasted effort and merge conflicts later.
There is no hard and fast rule, but one good rule of thumb is to make sure everything at least compiles before you check in. If you check in non-compiling code, your teammates will be very annoyed when they update (which is good practice) and they cannot compile the code any longer.
Another good rule of thumb (though this one is far more malleable) is that you should minimize leaving something uncommitted when you quit for the day. A lot can happen while you're not coding, and it's generally better to get your changes in working order and commit it before you leave. Large amounts of uncommitted code being committed all at once will result in much more conflicts than small amounts of code being committed often. Since the previous rule (of never checking in non-working code) is more important, this can be hard to accomplish if you're making big changes. Thus, it's often good to tackle one feature at a time, so you can finish each piece quickly and keep the repository up-to-date.
Coordinating your efforts with your teammates is, of course, the true key to minimizing merging hassles. Again, CVS is no replacement for management!
There will often be files that you do not wish to check into CVS. These will include .class files and Javadoc files. However, CVS will, annoyingly, point out the existence of these files whenever you update. A solution is to tell CVS to ignore these files using a .cvsignore file. To do so, create a file named .cvsignore in the directory where the files to be ignored exist. Then, add the names of the files to be ignored to the .cvsignore file. Each file name should go on a separate line. You can also use * to match any file. For example, to ignore all the class files in the directory, add *.class to your .cvsignore file.
If you follow the steps above, you would need a .cvsignore file in every directory in which you want to ignore files. However, there may be certain types of files that you always want to ignore. You can do this by editing a global cvsignore file in your repository. To ignore all .class files, for instance, create the file ~/6.170/cvsroot/CVSROOT/cvsignore (with no dot preceding the file name), and write the pattern *.class in it.
You can add a sub-directory with:
mkdir dirname cvs add dirname
cvs adding a sub-directory happens immediately, without the need to commit.
You cannot remove a sub-directory with CVS. (cvs remove cannot be used on a directory.) The best you can do is to cvs remove -f everything in that directory, then run cvs update -P to get rid of any empty sub-directories in your working directory (-P stands for "prune empty sub-directories"). Note that the -P option to update is added to your cvs commands by default via the ~/.cvsrc file created by the student-setup.pl script.
Eclipse conveniently marks files and directories that have changed since the last cvs update by preceding their names with a > sign in the Package Explorer. In addition, there are two features that allow you to track changes between your working copy and the repository's latest copy: Compare and Synchronize.
To compare a file with its latest version, right-click it in the Package Explorer and select Compare With » Latest from Head. If the files are different, a window will appear showing a side-by-side comparison of the two files.
To see a summary of differences between the local copy and the repository, right-click a file or directory in the Package Explorer and select Team » Synchronize with Repository. A window will appear that summarizes which files (if you selected a directory) have outgoing changes (changes you've made after updating), which have incoming changes (new revisions committed by others to CVS), and which have conflicts. Double-clicking one of these summarized items will bring up a Compare window for that file.
To view CVS commit logs and previous revisions to a file, right click it in the Package Explorer and select Team » Show Revision History. You will see a CVS Resource History window at the bottom panel. Double-clicking a row will allow you to read the corresponding revision.
To see differences between the working copy and the repository's latest copy: Open the file whose history you are interested in then type C-x v =.
Another powerful way to see differences in Eamcs is Alt-x ediff-revisions. It can show changes you have made locally, or the differences between arbitrary versions of a file.
To see the change log, which is a list of the messages used when checking in changes:
cvs log filename
To see differences between the working copy and the repository's latest copy:
cvs diff [filename]
Omit filename to see differences for all files. Use the -r1.xx flag to compare with a particular revision, and use two -r flags to compare two versions with each other.
Some tips on avoiding common problems while using CVS:
You should not need this until the final project.
You may wish your group to be notified whenever a group member commits. You can tell cvs to send email to the group, along with the files committed and the commit message.
cvs -d /mit/6.170/groups/seMMN/cvsroot co CVSROOT
You may need to change the "-d" argument to your own cvs root. This will create a CVSROOT directory in the current directory containing the cvs configuration files for your repository.
cd CVSROOT
DEFAULT /mit/6.170/bin/commit_prep -r
This tells cvs to run the commit_prep script after each file has been committed to the repository.
DEFAULT /mit/6.170/bin/log_accum.pl -s -m 'someone@somewhere.com' %s
Change the "-m" argument to the address you want to send mail to. This tells cvs to run the log_accum.pl script after all the files have been committed. log_accum.pl will mail all the commit messages to the address specified with the "-m" arguments. You can pass multiple -m arguments, or you can just send it to your groups' mailing list ("seMMN@mit.edu").