To-The-Point Instructions for Using CVS Bradley C. Kuszmaul bradley@mit.edu MIT Computer Science and Artificial Intelligence Laboratory $Date: 2004/09/07 18:25:44 $ CVS is a version-control system useful for projects that multiple people work on. CVS is based on RCS. RCS, by itself, is useful for projects that one person works on alone. This paper is about CVS, not RCS. This paper explains how to use CVS. You may eventually need to read the CVS and RCS man pages, but you will hopefully be able to get along for a while with just this document. I find the CVS man pages to be long, disorganized, and, at first, difficult to understand. (The CVS info pages are better than the man pages, but I find them stil to be too much all-at-once.) After you understand CVS, the info pages will become more useful. Your system administrator should install CVS before you try using this document. (This has gotten much easier with the advent of standard Linux distributions that have everything on them.) I expect you to be able to use UNIX and EMACS to do reasonable things. These things include simple customizations to your shell scripts and .emacs startup files. You may be able to find the cvs info pages by doing, in emacs c-h i g ( c v s ) Organization: The model behind CVS. (What is a repository?) How to set up a new CVS repository. How to make changes to the files that are under version control. Mnemomic version names (tags) Change logs Changing filenames without losing version control info Ignoring files Remote CVS Remote CVS Hacks CVS Weaknesses Administrivia The model behind CVS. (What is a repository?) CVS is a version-control system. You can create files, and maintain different versions of the file. Conceptually CVS keeps every version of your file that you ever created. CVS has a special directory called a repository in which all the versions of every file are kept. The repository can have subdirectories. The way that CVS keeps all the versions, is that, for each of your files CVS keeps a single RCS file (with a ",v" suffix). The RCS file contains the most up-to-date verison of the file, along with diffs that go all the way back to the beginning of time. The RCS file also contains other information, such a change logs, version numbers, and dates. When you want to edit a file you use CVS to "check out" the file. When a file is checked out, a copy is created in your own subdirectory. (Your working directory is distinct from the shared repository directory. I call your working directory your sandbox.) You then edit the file to your hearts content. Eventually you put the file back into the repository by "committing" your changes. CVS guarantees that the commits happen in some serial order. If someone else commits changes to the repository while you are working, you will be given the opportunity (almost forced, really) to accept the changes they made, and incorporate them into your version before you can successfully commit your changes. If you check out the entire repository, your sandbox will be a complete mirror image of the repository (including subdirectories), except that you will have the actual files that comprise the most up-to-date versions, rather than the RCS files containing all the diffs. My experience is that, at first, people complain about everyone having their own copy of a large system. After a while, people seem to stop worrying about all the disk space that this scheme occupies. How to set up a new CVS repository. The CVS man pages do not seem to explain how to set up a new repository. Here is how I do it. (1) Choose the name of your new repository. For example, /f/bradley/test-repository (2) Do the following two commands: setenv CVSROOT /f/bradley/test-repository cvs init (That works in csh. In bash you might have to do CVSROOT=/f/bradley/test-repository export CVSROOT cvs init ) Don't worry if you run "cvs init" more than once. The cvs init command won't hurt an existing repository. You are all set. Now to create a working directory you need to do the following: (4) You should set your CVSROOT environment variable to the name of the repository. In csh I do setenv CVSROOT /f/bradley/test-repository/ You should probably update your .cshrc file to make this happen every time you login. [If you use multiple repositories for different projects, you may need to change your CVSROOT variable depending on the context.] (5) Create the working directory, and cd to it, and do a checkout of the files. (There aren't any files, but do the checkout anyway.) For example mkdir /f/cel/test-sandbox/ cd /f/cel/test-sandbox/ cvs checkout -l . Note that there is a subdirectory called "CVS" in your test-sandbox. This is where bookkeeping information is kept. You should not modify the CVS subdirectory directly yourself, because CVS needs that information. Now you will be able to create files and add them to the system. If someone has already created a subdirectory or a subfile that you want, then check them out. For example, if the repository contains "foo.c" and you want it then do cvs checkout foo.c If the repository contains a directory called "chess" then you might do cvs checkout chess (That will checkout everything in the chess directory, recursively descending into the directory structure. If you don't want to recursively descend, then do cvs checkout -l chess Note the "-l" in the "cvs checkout -l ." above. It was necessary, but if you forget it it won't screw things up too much. How to make changes to the files that are under version control. cvs add To add a new file to the system, simply create the file in your sandbox. emacs filename And inform CVS of the new file: cvs add filename This does not actually create a version in the repository. It simply updates the local bookkeeping information to inform CVS that you intend to put the file in. Eventually you must commit the file. More on commitment later. To add a new subdirectory to the system, simply create the subdirectory in your sandbox mkdir new-subdirectory and inform CVS of your intent. cvs add new-subdirectory (If it asks a question then answer "y".) Note that when you add a subdirectory, it actually immediately updates the CVS repository. CVS does not quite do version control on directories the same way as on files. cvs commit (including setting up emacs) When you are ready to actually put your files into the repository, you need to commit them. First you need to get your editor working. It will work fine if you have setenv EDITOR emacs in your startup files. It works even better if you do setenv EDITOR emacsclient If you use the emacsclient, you need to do, in emacs m-x server-start You can put a (server-start) in your .emacs file. (Some users report that you must occasionally restart the emacs server. Next do cvs update It will show you all your new files with "A"'s in front of them. If you see other letters you are further along than this, and you should read about cvs update a few paragraphs down from here. Next do cvs commit Your editor will start up, and you will be asked to create a log message. After you do so, all your files will be commited into the directory. If you use the emacsclient, it will start a new buffer in an existing emacs on the same machine. (This won't work if you forget to do "m-x start-server") When done editing, save the buffer, and do "c-x #" (control-x sharp) to end the client edit. The emacsclient is nice because it does not go through the overhead of creating a new emacs process, avoiding the startup files, and avoiding cluttering up your display with lots of windows. Instead it clutters up your emacs with lots of buffers. I find it easier to manage buffers in emacs than windows with twm. cvs remove To remove a file, delete it from your sandbox, and then do "cvs remove". For example rm foo.c cvs remove foo.c You will need to "cvs commit" the removal before the removal will really happen in the repository. When you do a "cvs update", you will see a little "R" in front of every uncommited removal. cvs update The CVS "update" command does two things. I find it frustrating sometimes, because it does two things instead of providing two commands. The update command does the following: (a) Tell you what files you have changed, added, or removed, as well as what files other people may have changed behind your back. (b) It actually modifies the files in your sandbox to reflect the changes that others have made behind your back. The actual modification is what is frustrating. Fortunately, the original unmodified file still exists (but I didn't know about it until recently, which is what frustrates me.) The update will show you the following A filename (you are adding this file) U filename (someone else modified the file) M filename (you modified the file) ? filename (the file exists in the sandbox, but you never told CVS about it.) C filename (you modified the file, and someone else did too. The file has been modified using the rcsmerge(1) command to bring in the changes that they made. I find this file format to be quite confusing. Fortunately, your original unmodified file is sitting in your directory as .#filename.version where the version is the version number of the file you started from.) Mnemomic version names (tags) Every file has a version number. Something like "1.23". Different files will have different version numbers depending on how many times they have been modified and commited. You can also give files a symbolic version number, using the "cvs tag" command. This works as, for example, as follows cvs tag chess_version_2_0 [You cannot put a "." in the tag, so you end up having to use underlines or something.] After you have commited your changes, if you want the commited version to be tagged with a particular name do the cvs tag operation. I find it helpful to keep a separate file in the repository, called README.CVS which lists all the CVS tags that you have used, along with brief descriptions of what the tags correspond to. For the StarTech chess program, I had over 60 tags that I used over a period of about two years. I am not afraid to tag a version. Change logs How to set up a change log in your file. Put a token that is spelled dollar-L-o-g-dollar (see the end of this file for an example) in your file. How to change the comment leaders. Newer versions of CVS guess the comment syntax by looking at the line containing the dollar-L-o-g-dollar, and assuming that you did it right. Older versions of CVS try to use the filename to figure out how to put comment syntax in front of change log entries. For example old versions use "% " for any file of the form *.tex Older versions of CVS do not always guess right. For example. a *.sty file also should be commented with "% " but older CVS defaults to using a "# ". You can tell cvs to change the comment string as follows cvs admin "-c% " foo.sty Changing filenames without losing version control info If you want to change a filename e.g., foo.c to bar.c you could move the file, do "cvs remove foo.c", and then "cvs add bar.c". That would be OK, because all removed files are kept somewhere to be accessable again. the file bar.c will start with version 1.1 An alternative, which is sometimes ok is to change the name of the file in the repository. I find this to be scary. I am afraid of modifying the repository directly. Ignoring files If you create a file named .cvsignore that contains a list of files, they will be ignored by "cvs update". By default, "cvs update" ignores files of the form *~ and *.o You might want it to ignore a particular executable, for example. The file format for .cvsignore is a list of filenames (with "*"'s allowed and maybe "?"'s also) separated by whitespace (newlines are equivalent to a space.) Remote CVS CVS is "network ready". If you are on machine foo.X.edu and your repository is on machine bar.Y.edu you can do the following you@bar.Y.edu> setenv CVSROOT foo.X.edu:/your/repository If your username at foo.X.edu is different than at foo.Y.edu you can specify your remote username (say it is "alterego" as) you@bar.Y.edu> setenv CVSROOT alterego@foo.X.edu:/your/repository You also have to set things up so that "rsh foo.X.edu" works without requiring a password. Typically this means setting up a .rhosts file, but since I use ssh instead of rsh, I set up a .ssh/authorized_keys file and things are much much much much more secure. ssh is a big win over rsh (and it seems much easier to maintain than other approaches such as Kerberos-authenticated rsh). Read about ssh at http://www.cs.hut.fi:80/ssh/index.html After setting things up so that rsh works without a password, you can do normal CVS commands, such as you@bar.y.edu> cvs checkout mystuff Remote CVS Hacks Charles had the following problem, and here was bradley's suggestion: Charles: Also, I'm finding that Web traffic makes it almost impossible to use telnet except for very simple things. Any suggestion as to how I might resolve changes so that I can batch my net traffic as much as possible? I've thought of keeping a sandbox on theory and make a copy here at NUS. I can put things back in the sandbox, but the resolution procedure would work best if I run it on theory. Unfortunately, that's hard to do. Any ideas? Bradley: Here is my suggestion: You create a sandbox on theory, copy it it iscs.nus.sg, modify it at iscs, copy it back to theory, and then check it in. (1) Create a sandbox on theory with everything you want in it. cel@larry% mkdir outgoing-sandbox cel@larry% cd outgoing-sandbox cel@larry% cvs checkout . (2) Copy the entire sandbox directory from theory to iscs.nus.sg There are three ways to do it: tar+ftp or rcp or rsync. For limited-bandwidth applications, rsync is probably best. (a) tar+ftp (in this case I stuck a "| gzip" into the pipe too, since you asked about minimizing network traffic) cel@larry% tar cf - . | gzip > ../outgoing-sandbox.tar cel@larry% ftp iscs.nus.sg (you know the rest) (b) alternate (much easier, but less secure) rcp to push an entire directory from theory to iscs.nus.sg. cel@larry% rcp -pr . iscs.nus.sg:/whereever/you/want/to/put/it To use the rcp you will need to put a file in your home directory on iscs.nus.sg called .rhosts with the following contents cel@iscs% cat ~/.rhosts larry.lcs.mit.edu cel Note that you must give a fully qualified hostname in your .rhosts file. Note that .rhosts files are the source of many security problems. Use ssh, since it includes plug-compatible versions of rcp that are secure. (c) another possibility is to use rcp at the other end to suck stuff from theory to iscs.nus.sg cel@larry% cat ~/.rhosts iscs.nus.sg cel cel@iscs% rcp -pr theory.lcs.mit.edu:/f/cel/outgoing-sandbox incoming-sandbox (d) The rsync command is even better. If you have a sandbox on one machine and a older version of the sandbox on the other machine, you can do cel@theory% rsync -av -e ssh --delete outgoing-sandbox iscs.nus.sg:/f/cel/incoming-sandbox The rsync command copies a directory to another machine by only sending the diffs. (This is a little counter-intuitive. Q: How can you compute the diffs without having both directories on the same machine? A: rsync is clever. Read the docs if you are interested.) (3) Modify it locally, editing your changes. (4) Copy the directory back to theory. For example cel@iscs% rcp -pr . theory.lcs.mit.edu:/f/cel/incoming-sandbox or cel@theory% cp -pr outgoing-sandbox incoming-sandbox cel@iscs% rsync -av -e ssh --delete incoming-sandbox theory.lcs.mit.edu:/f/cel/incoming-sandbox (5) Check it in cel@larry% cd /f/cel/incoming-sandbox cel@larry% cvs update ...reports all the stuff... cel@larry% cvs commit CVS includes enough information that if you copy a directory (including all its recursive components) by value, then CVS will still be able to operate on the directory. This copy must include all the .* files as well as the CVS specific files, or you will get the wrong answer. The copy can be made by tar+gzip or by rcp or by simply mv'ing a directory (in which case you are not copying by value, but rather copying by reference or something...) CVS weaknesses Directories are not version controlled. Removing files can be a little strange. You should use tagging rather than dates to recover things. No way to quote dollar-L-o-g-dollar. This is probably not a problem. Acknowledgements Tom Cormen wrote a CVS howto for his class, based partly on this document. He suggested some improvements. For Tom's version see, http://www.cs.dartmouth.edu/~cs23/CVS.html Stefan Monnier made many suggestions. Administrivia Please send comments about this document to bradley@mit.edu This file is under version control in bradley.csail.mit.edu:/usr/repository/ in the doc subdirectory. $Id: cvs-instructions,v 1.6 2004/09/07 18:25:44 bradley Exp $ $Log: cvs-instructions,v $ Revision 1.6 2004/09/07 18:25:44 bradley Move to CSAIL Revision 1.5 1999/03/10 20:24:54 bradley A few modifications Revision 1.4 1999/01/29 08:22:06 bradley Bring many things up to date. The cvs info are better than the man apges The "cvs init" command is better than an explicit mkdir. The "Remote CVS Hacks" section is impoved. Revision 1.3 1997/10/07 18:29:20 bradley Add an edited version of Monnier's comments about remote cvs. Revision 1.2 1996/11/19 19:42:45 bradley Update Revision 1.1 1996/06/11 03:19:01 bradley Move cvs-instructions from theory.lcs.mit.edu to arch.cs.yale.edu % Revision 1.8 1995/08/24 15:21:41 bradley % Added "Remote CVS" section. % % Revision 1.7 1995/06/07 05:09:01 bradley % More comment hacking. % % Revision 1.6 1995/06/07 05:08:10 bradley % More comment hacking % % Revision 1.5 1995/06/07 05:07:16 bradley % More comment hacking. % % Revision 1.4 1995/06/07 05:05:57 bradley % Fixed up comment notes. % % Revision 1.3 1995/06/07 05:03:52 bradley % Well filled out now. % % Revision 1.2 1995/06/07 03:48:19 bradley % The intro and model sections are written. % % Revision 1.1 1995/06/07 03:31:26 bradley % Skeleton.