Getting the most out of CVS in GNOME

Introductory Beginnings

Concurrent Versions System, CVS, is a powerful method of allowing many developers to work on the same source code. It is used extensively within the GNOME project and often proves to be the first hurdle for new developers that are attracted to the GNOME project.

Each developer checks out a copy of the current version of the source code from CVS and then is able to work on their own personal copy separately from other developers. When they have made changes, they commit them back to the CVS repository. The CVS server is then able to merge all the changes that the developer has commit back. Sometimes this merging isn't always successful, the developer is notified and they will have to manually fix any possible conflicts that arise before trying to commit their changes again.

The GNOME project allows both 'read/write' and 'read only' [through its anonymous CVS mirror servers]. Quite often, like any mirror server, the anonymous servers take a little while to get in sync with the main CVS server. Typically, they will be 24 hours behind the main server. This is sometimes a cause of frustration to new developers.

The GNOME project has also set up online browsing and searching of its CVS repository. To browse GNOME CVS, you can use the CVS viewer interface.

If you would like to track the changes that occur in various GNOME CVS modules, subscribe to the cvs-commits-list mailing list, a high volume, read-only list that receives mail every time somebody checks something into the repository. You can filter mail from this list by the title of the modules you are interested in and you may wish to further filter out any changes that only affect translations by looking for the word '(silent)' in the subject and ignoring those messages.

Getting Started

Before getting started, it is useful to remember a key point about CVS GNOME - it a developers work space and has no guarantees that a given project will build right out of the box, or indeed, not dump core on start up. A useful link to check if the current GNOME desktop component builds is Jacob Berkman's excellent tinderbox setup. You should check the build dates before relying on this information, as the tinderbox is quite often out of action.

The first thing to do when you start using CVS is to set up your environment. It is useful to create a developer workspace somewhere on your machine and keep all source code within there. CVS will use the current directory that you are in if you start checking out some source code. You will need to set up the environment variable 'CVSROOT' to either

:pserver:[username]@cvs.gnome.org:/cvs/gnome
in the case of using the main CVS repository [requires password] or
:pserver:anonymous@anoncvs.gnome.org:/cvs/gnome
in the case of using one of the anonymous CVS repository mirrors.

The next thing you will need to do is login to the CVS server. You generally only need to do this once and it will be remembered for the future. You can do this by typing in the following command

cvs login
Now you are ready to check out some source code. This can be done simply by the following command
cvs -z3 co [module]
The -z[n] flag specifies the level of compression. Valid levels are 1 [high speed, low compression] to 9 [low speed, high compression] and 0 to disable compression [which is default]. 3 is most used by most people.

When the check out has been completed, you will start to notice that many projects in CVS GNOME contain similar files

CVS
This directory is present in every directory of a given module. It contains information about version numbers, where the source code came from, etc.. You can ignore it for all purposes, but you should not delete it.
autogen.sh
This is a wrapper script around gettextize, intltoolize, libtoolize, aclocal, autoheader, automake & autoconf which you use to start building the module. For example
./autogen.sh --prefix=/usr/local
will start the build process checking your system, generating all the necessary Makefiles before you are ready to type 'make' and 'make install'.
ChangeLog
This is one of the most useful files for a developer to keep up to date - it lists all the changes that a given module has undergone. In GNOME it is generally of the following form
YYYY-MM-DD  Joe Bloggs <joe.bloggs@gnome.org>

* filename.c: Use gtk_dialog instead of deprecated gnome-dialog. Fixes #878372.
If you are using Emacs, you can automatically generate a template like this as you develop. There are also other scripts available to do this. From eazel-hacking, prepare-ChangeLog.pl
README
This generally gives information about the CVS module in terms of module requirements, where to report bugs etc..
HACKING
This file usually specifies the rules [if any] for development in the module.
MAINTAINERS
This file lists the people who are responsible for the day to day maintenance of the module. Generally these are the people you should send patches to.

CVS allows you to isolate changes onto a separate line of development, known as a branch. Quite often in GNOME, there are stable and unstable branches of development for a given module - as a result, the main trunk [also known as 'HEAD'] may not be suitable for your needs. Stable branches in GNOME CVS are generally a mixture of lowercase alphabetic & numeric characters separated by dashes ie. of the form

[module/project]-[MAJOR]-[MINOR]
where major, minor are version numbers. For example
gnome-2-0
gtk-2-0
You can check out a branch using the following command
cvs -z3 co -r [branch name] [module]
If you wish to have more than one version of a module, you can use the -d flag
cvs -z3 co -d [directory name] [module]
The following example will check out gnome-utils HEAD and 'gnome-2-0' branch, creating 'gnome-utils' and 'gnome-utils-stable' in your current directory
cvs -z3 co gnome-utils
cvs -z3 co -d gnome-utils-stable -r gnome-2-0 gnome-utils

Maintainers 'tag' their module to mark releases in GNOME CVS. Tags in GNOME CVS are generally a mixture of uppercase alphabetic & numeric characters separated by underscores ie. of the form

[MODULE]_[MAJOR]_[MINOR]_[MICRO]
where MAJOR, MINOR and MICRO are version numbers. For example
GTK_2_0_6
GNOME_UTILS_2_0_2

Unfortunately, there is no easy way to view a list of tags and branches for a given CVS module. You can get a list by checking the status of one of the files in the module by the following command

cvs status -v filename
This generally gives you something, using gtk+/ChangeLog as the filename, of the following form
===================================================================
File: ChangeLog        	Status: Needs Patch

Working revision:	1.3338.2.122
Repository revision:	1.3338.2.152	/cvs/gnome/gtk+/ChangeLog,v
Sticky Tag:		gtk-2-0 (branch: 1.3338.2)
Sticky Date:		(none)
Sticky Options:	(none)

Existing Tags:
	GTK_2_0_6                	(revision: 1.3338.2.147)
	GTK_2_0_5                	(revision: 1.3338.2.120)
	GTK_2_0_4                	(revision: 1.3338.2.115)
	GTK_2_0_3                	(revision: 1.3338.2.68)
	GTK_MULTIHEAD_MERGEPOINT_19_04_02	(revision: 1.3347)
	gtk-2-0                  	(branch: 1.3338.2)
					
Lines that being with "revision:..." in the righthand column above are normal tags, the one that starts with "branch:..." is a branch tag -- it will always point to the latest version of the file on that branch. Notice also the status of file indicates that there is a newer revision in the CVS repository and that the current version of the file is taken from the gtk-2-0 branch.

CVS was designed so that whenever there were any changes in the source code, you didn't need to remove your sources and re-check out. The following command syncs up your code with what is stored in the CVS repository

cvs update -dP
This command will use the -d flag to notice new directories added to the CVS repository and the -P flag to purge any empty directories.

When you update, you will notice a letter leading each file that is updated or not. These letters have the following meaning

U
Updated from the server and sent as a completely new file
P
Updated from the server and sent as a diff which your client used to patch the file
A
File was added
R
File was removed
C
There is a conflict
M
File has been locally modified
?
File in local repository CVS knows nothing about.
If you have conflicts, you must resolve these, in general, before being able to rebuild the source code.

Moving Forward

Now that you have successfully checked out a GNOME CVS module and hopefully managing to build it, you are ready to move forward and become a GNOME contributor.

GNOME contributors send 'patches' [sometimes called 'diffs'] to each other and attach them to bug reports in bugzilla.gnome.org. A 'patch' describes changes in a file. This generally gives you something of the following form

Index: gcalc.c
===================================================================
RCS file: /cvs/gnome/gnome-utils/gcalc/gcalc.c,v
retrieving revision 1.41.2.1
diff -u -r1.41.2.1 gcalc.c
--- gcalc.c     12 Aug 2002 22:57:12 -0000      1.41.2.1
+++ gcalc.c     19 Aug 2002 18:37:30 -0000
@@ -33,6 +33,7 @@
	gchar *authors[] = {
		"George Lebl ",
		"Bastien Nocera  (fixes)",
+               "Joe Bloggs ",
		NULL
	};
	gchar *documenters[] = {
				
Here you can see the lines added prepended with a '+'. If you had removed [or edited] a line of code, you would have been likely to see a line prepended with '-'. Notice it also shows you the revision of the file you are creating a patch against.

Once you make changes to a given file you can generate a patch very easily using the following command

cvs diff -u [filename] > [patch]
This makes a patch of all the changes between your local changes and the file that currently resides in the CVS repository. The -u flag is important. This creates a 'unified' diff which is easier for a developer to look at and understand.

If you are the one that gets sent a 'patch', then you need to merge that patch into your sources. For this you will need to use the following command

patch -p[n] < [patch]
where n is the number of leading components to strip from the path. This number is relative to where the patch was generated from - you can experiment to get the correct number. If you need to reverse a patch, you can use the following command
patch -R < [patch]

Increased Trust

As you supply more and more patches to a given maintainer, or attach them to bugs in bugzilla.gnome.org, the maintainer may ask you to obtain your own CVS account to make your own source code check ins.

To obtain a GNOME CVS account you will need to email accounts@gnome.org with some details. Please see the requesting accounts page for more information.

Tricky features

Moving files around within a CVS module requires some help from the server administrators. Simply removing the files from their original location (with 'cvs remove') and adding them at the new location is usually insufficient, since it loses all of the history and log messages attached to the file up to that point.

The correct procedure is to contact one of the CVS administrators and ask them to copy the appropriate files from the old location to the new location. Then you can 'cvs remove' them from their original location and everything will be fine.

Some of the directories within a CVS module may not belong to that module at all. Rather, they may be imported from another module to provide common functionality. For example, the CVS repository contains a module called 'vicious-extensions' that contains code to provide common functionality that may be missing from some platforms. This module is imported into other modules so that it looks like it belongs to those modules. However, maintainers of modules that use vicious-extensions must be careful not to change the vicious-extensions, since their changes will affect everybody who uses that module.

To include another module in your module, you need to check out the file CVSROOT/modules from the GNOME CVS repository and add a line for your module that looks like:

mymodule   mymodule   &vicious-extensions
This means that when somebody checks out 'mymodule', they will get the code from the 'mymodule' directory as well as the code from the 'vicious-extensions' directory (which will just appear as another directory inside 'mymodule').

Final Steps

With an increased amount of trust and responsibility, you may even be asked to start maintaining a module within GNOME CVS - or indeed, one or your own that you imported.

One of the first things you will have to perform is to make releases on a given module. The following steps are required, in most cases, to make a release

At some point, you might find that it will be necessary to branch your module for a stable set of releases, while continuing development on HEAD. To branch your module the following command is used

cvs tag -b [module/project]-[MAJOR]-[MINOR]
where MAJOR, MINOR are version numbers.

There is no easy way of dealing with branches. Quite often you will need to merge code from the HEAD to the stable branch - generally for bug fixes that apply to both branches. In this case, you have to be careful what you merge over so as not to merge unstable changes into a stable branch.

The following command merges all changes to a given file from HEAD

cvs update -j HEAD [filename]
Sometimes you will be required to reverse a given change made by mistake. You can do this simply by the following command
cvs update -j [new_revision] -j [old_revision]
This will reverse the changes made in bringing the source up to 'new_revision'.

References

This document was written by Glynn Foster and licensed under the GPL, copyright 2003, Sun Microsystems Inc.