Table of Contents Good places to look for more info than what's covered here Basic Idea Gotchas Accessing Existing Repositories Creating a Repository Modifying Files in Existing Repositories Other tips Summary of examples Additional examples without explanation Good places to look for more info than what's covered here: http://cvsbook.red-bean.com/cvsbook.html # Good tutorial (lengthy) info cvs # Good reference http://developer.gnome.org/tools/cvs.html # Gnome specific cvs tips http://developer.gnome.org/doc/tutorials/import.html # Gnome specific importing Basic Idea In cvs, you work with a repository and one or more sandboxes. The repository is the place where cvs stores all your files along with a history of changes made to those files. The repository is usually located under some directory on a remote machine, but it can be in a directory on your local machine as well. A sandbox is simply a snapshot of the files from the repository at a given moment in time. Sandboxes don't contain any history of changes to files--they merely contain a certain version of each file (well, with a little more information, like the repository the files came from and the specific version of each file currently in the sandbox). Day-to-day work is done in a sandbox, with various cvs commands used to commit changes to the repository or obtain updates made by others. One makes use of cvs by running the cvs command with various options. The basic syntax is: cvs [global cvs options] [cvs sub-command options] The main trick to learning cvs is to simply learn the most commonly used cvs sub-commands (like 'add', 'commit', 'update') as well as a few of the more common options for each. Gotchas CVS, unfortunately, has a handful of little gotchas or pitfalls that can cause problems for new users. Most of this is due to historical implementational issues combined with the need for backward-compatibility. Other programs like Subversion are suppose to fix these issues, but they aren't used as widely yet. The main gotchas that I can think of are: 1) cvs doesn't handle binary files well a) must mark each binary file as such b) can't do incremental changes to binary files 2) one can't cleanly rename a file or move it to another directory 3) cvs treats files & directories differently a) can't remove directories b) special commands to deal with unused or new directories 4) cvs ignores file permissions 5) branching tags are different than normal tags 6) there seem to be a lot of abbreviations or alternate names for various cvs sub-commands 7) you can't use subdirectories named 'CVS' I'll address some of these issues here, for the rest, see the cvs book at cvsbook.red-bean.com. Accessing Existing Repositories First, let me explain some of the global options to cvs: Global CVS Options: --help -d [:access method:user@cvs.server.domain:]/location/of/cvs/repositories Global CVS Options explained: --help Prints help for the cvs command -d Specifies the location of the repository that you are trying to access (this option isn't required when you have already checked out a sandbox and are working on it). Valid access methods are pserver and ext. Other useful Global commands that I occasionally use (which you may want to read up on after finishing this tutorial): -q -Q -z As an example, I'll use the GNOME repositories, since they are public and I'm familiar with them. To do so, you need the following basic information: access method: pserver user: anonymous cvs server: anoncvs.gnome.org root directory: /cvs/gnome With pservers, you first have to login. To do so, you use the login cvs sub-command as follows: cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome login For the password, just hit enter without typing anything. Next, we can checkout a module with the checkout sub-command. We first have to know the names of the possible modules to choose from. These tend to be on the web somewhere. For GNOME, you can find the modules listed at http://cvs.gnome.org/bonsai/rview.cgi?cvsroot=/cvs/gnome . We'll checkout the module jhbuild. To do so, issue the following command cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome checkout jhbuild That will create a subdirectory called jhbuild below the current directory and fill it. Change to that directory and have a look around. Note in particular that each directory in a sandbox (other than the ones named 'CVS') will have a CVS subdirectory for tracking information about files within that directory. Make some changes to a file (e.g. README) and then issue the following cvs command to get a diff showing your changes: cvs diff -u README The -u option merely puts the diff in a readable format. Note that you could get a list of all your changes in all files by running cvs diff -u You can also check for updates by running cvs update -d The -d option isn't necessary but is a good idea to always include. Using it causes cvs to checkout any new sub-directories as well, whereas without it, cvs won't. Other useful cvs sub-commands I use often (you may want to read up on these): log status Other useful options for cvs sub-commands that I use often (again, you may want to read up on these): checkout -P, -d, -r update -P, -r, -A Creating a Repository From the server (which for now, I'll assume is named somemachine.com) which will hold the cvs repositories, you need to first initialize the directory that will hold the repositories. I'll assume that you want these to be located in /home/user/cvs. On somemachine.com, run the following commands: mkdir -p /home/user/cvs cvs -d /home/user/cvs init Now we have to import some project from a client (which for now, I'll assume is named anothermachine.com) into the repository. We do this from the machine that has the initial project, not from the server (unless the two machines are the same). First, let's create a new test project with a couple files to import. On anothermachine.com, run the following commands: mkdir project cd project ls /tmp > file_a.txt ls -al . > file_b.txt mkdir subdir uptime > subdir/file_c.txt Now, we'll be using the ext method for access, which basically means ssh. Since CVS is old, it (stupidly) defaults to rsh instead of ssh. So you first have to run the following (you may want to add this to your .bash_profile): export CVS_RSH=ssh Now, import our new project to the server by running the following command (make sure you're still in the project directory): cvs -d :ext:user@somemachine.com:/home/user/cvs import -m \ "Initial import" project user start If anothermachine.com and somemachine.com are the same machine, then the above command could be shortened to: cvs -d /home/user/cvs import -m "Initial import" project user start In general, the syntax of an import (which must be launched from within the directory that is being imported) is: cvs -d import -m \ where the was described above under global flags to cvs, the import message is any string you want, and the vendor and release tags are basically unimportant (I've never used them; I've even heard people suggest that you simply make up something to use for those fields! Apparently some kind of advanced use for them, though) Now, importing project into cvs doesn't actually make the project directory a real sandbox. To get a real sandbox, run the following: cd .. rm -rf project cvs -d :ext:user@somemachine.com:/home/user/cvs checkout project again, the last command above could be shortened to cvs -d /home/user/cvs checkout project if anothermachine.com and somemachine.com are the same. Modifying Files in Existing Repositories Let's start modifying the sandbox we have in the directory project. Run the following commands on anothermachine.com: cd project cat file_b.txt | wc -l >> file_a.txt touch file_d echo "Hi there" >> subdir/file_c.txt cvs -q update As you can see, the update command shows that file_a.txt and subdir/file_c.txt have been locally modified and that CVS doesn't know anything about file_d (since it's new). We can commit the changes for file_a.txt and file_c.txt by issuing the following commands: cvs commit -m "Added a line" file_a.txt cvs commit -m "I added a polite message" subdir/file_c.txt To commit the file_d change, though, we first have to add it to the repository: cvs add file_d cvs commit -m "Initial creation" file_d If we now checked for updates: cvs -q update we'd notice that everything was up to date and that CVS doesn't see any local changes. Note that instead of the above individual committing of changes, we could have simply added file_d and then committed all files at once like this: cvs add file_d cvs commit -m "Made some random changes" If you want to tag a specific version of your files, you use the cvs tag command. An example: cvs tag VERSION_1_0 note that tags cannot contain the '.' character, so underscores are usually used instead. Users can than later obtain a certain release of your files by using the -r flag to either the checkout or update sub-commands. Other tips: If you want cvs update to ignore certain files, merely add the filenames or wildcard patters to a file called .cvsignore in the directory of interest. If you find yourself adding the same wildcard patters to a .cvsignore file in every directory, moves those patterns to your ~/.cvsignore file. Summary of examples cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome login cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome checkout jhbuild cvs diff -u README cvs diff -u cvs update -d cvs -d /home/user/cvs init cvs -d :ext:user@somemachine.com:/home/user/cvs import -m \ "Initial import" project user start cvs -d :ext:user@somemachine.com:/home/user/cvs checkout project cvs commit -m "Added a line" file_a.txt cvs commit -m "Made some random changes" cvs tag VERSION_1_0 Additional examples without explanation: cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome \ checkout -d evolution-sandbox -r EVOLUTION_1_4_5 evolution cd evolution-sandbox cvs status ChangeLog cvs status cvs -q update -Pd -r evolution-1-4-branch cvs status ChangeLog cvs -Q update -Pd -A cvs status ChangeLog cvs log README find . -type f | sed -e s%.*/%% | sed -e s/.*\\.// | sort | uniq cvs -d /home/user/cvs import -m "Initial import into CVS" \ -W "*.doc -k 'b'" -W "*.pdf -k 'b'" -W "*.ps -k 'b'" \ project vendorname releasename cvs tag -b stable-1_0-branch cvs update -r stable-1_0-branch