home > cvs > managing common code in websites using cvs
Sometimes when you are developing websites you’ll find you need the same script over and over again – for example a logging script, a mail script, or a form library. If you use CVS, you don’t really want to create copies of this file for every website, because then you’ll have to maintain the code in multiple locations.
A much better way to manage this situation is to “share” this code, so that changes made can be committed back to a central CVS project in the repository, and udpates will be received by each of the sites that use the common code when you run a CVS update.
Note: If your project sudddenly stops working with a new version of the shared code, you can always check out a particular revision of the code, or a version of the code as of a given date. Future updates will leave the code at the requested revision / date as this sets a sticky tag / date for the files. See getting snapshots.
The key to doing this is the CVS administrative file modules. Don’t click that link straight away – the documentation is a little confusing, which is why I wrote this document. Read on.
The first step is to check out the CVSROOT administration directory, so we can work with adminstrative files. This is just like checking out any project.
cvs checkout CVSROOT
Next we edit the CVSROOT/modules file.
What we are going to do is to combine two CVS “projects” into one. This is a two stage process:
1. We define a “module” for each project using the -d option to specify that when checked out using their new module names, both projects will use the same root directory. This keeps things tidy by allowing us to store all the files for a particular website in a single root directory.
2. We use an alias module to combine the two projects into one.
For the purposes of this example, I’m going to assume that we have one project called mySite which contains all of the files and directories that are specific to the website we are developing. The common files that we want to share are also in a CVS project called forms. To make life a bit more interesting, lets say that we only want to use the files in the forms/lib directory in our mySite project.
A simple entry for a “Regular Module” in the modules file takes the form
The CVS manual tells us that:
This defines all the files in directory dir as module mname. dir is a relative path (from $CVSROOT) to a directory of source in the source repository. In this case, on checkout, a single directory called mname is created as a working directory; no intermediate directory levels are used by default, even if dir was a path involving several directory levels.
To specify that both projects should be checked out into a common root directory, we use the -d option which allows us to specify that instead of creating the working directory as mname in the example above, we can specify it in the format:
mname -d newName dir
So, to set the root directory as “ms” for all of our files, we add these two lines to the modules file:
mysitemain -d ms mySite mysiteformlib -d ms/lib/forms forms/lib
Now, if we check out mysitemain, a directory called ms will be created containing all the files and directories in the mySite project.
If subsequently check out mysiteformlib, the contents of forms/lib will be checked out into ms/lib/forms.
Note: you need to commit your changes to the modules file before they will take effect.
So that we only need to do one checkout, we now combine the two modules using an alias:
ms -a mysitemain mysiteformlib
Now, by checking out ms, we get all the files we want together. Running cvs update in the future will update our working copy with the latest versions of our files stored in mySite and forms/lib.
Note: the order in which the modules are specified in the alias module is important. If we switch the order round so that mysiteformlib comes first, CVS will generate an error, something like this:
cvs server: existing repository /usr/local/cvsrep/mySite does not match /usr/local/cvsrep/forms/lib
To see why, we need to think about what happens in this case:
1. CVS initially has to create the directories ms and lib before it can create the forms subdirectory. When it does this, it will associate these directories with the forms project.
2. When CVS tries to check out things into the ms directory from mySite, it notices that it is associated with the forms project and throws its hands up in horror.It won’t let you do this.
By placing mysitemain first in the alias definition, CVS associates the ms directory with the mySite project instead. Since the forms directory is not included in the mySite project it is not created until CVS reaches the mysiteformlib module reference and it gets correctly associated with the forms project, and everything works fine.
In my testing I’ve run into problems if I try to checkout using the -d flag to specify an alternative directory name, e.g.
checkout -d mynewdir ms
generates a “does not match” error.