Managing Application Releases with CVS

Author: David Garcia Garzon

Because CVS documentation is so large and sparse, and, becasue it gives you too much freedom on how you use it, often is not that easy to choose the suited life cycle to follow for your CVS project.

This tutorial, first presents a model for project life cycle, and then, shows how it can be implemented using CVS. The reader will be guided to create a dummy project example and perform on it the key steps of such life cycle.

Index

  1. The project releases policy
    1. Version numbers
    2. Kinds of releases
    3. Development progress
    4. Experimental development
  2. An example of CVS implementation
    1. Create a testing module
    2. Do some 'development'
    3. Release an snapshot
    4. Issue an official release
    5. Fixing a bug on a released version
    6. Merge the fix on the main branch
    7. Fixing and merging a second fix
    8. Backporting fixes from the main branch
    9. Creating an experimental branch
    10. Exporting tagged releases as source tarballs
  3. Other CVS documentation
  4. Multilingual terms glossary

The project releases policy

This section describes a typical release policy which includes most of the events a project may consider. Projects vary a lot on their release needs so take it just as an example.

Version numbers

A distributed team of programmers is going to develop an aplication named 'theapp'. They have choosen a 'M.m.r' version numbering schema being:

Major version number (M):
Will change when the release implies incompatibility with previous version or an important architectural change.
'theapp 2.4.1' -> 'theapp 3.0.0'
Minor version number (m):
Will change when some features have been added but there is no major changes.
'theapp 2.4.1' -> 'theapp 2.5.0'
Release (minor-minor) version number (r):
Will change when only bug fixes have been added without adding any user detectable feature.
'theapp 2.4.1' -> 'theapp 2.4.2'

Kinds of releases

The team can do differents kinds of releases for the project:

  • A Public release (a.k.a. Official release) is a release that you publicly offer to users and is expected to be supported.
    • A Featured release groups all those official releases that shares the same features, that is the 'M.m' part of the release name.
    • A Bugfixed release is an official release that has the minor-minor version number different to 0. So only bugfixing have been done from the previous one.
  • A Development release (a.k.a. Snapshot) is an unsuported release between two official releases. They are used for:
    • being reference points on the development, giving advancements to companion applications developers, and, alpha and beta testing.
    • Snapshots are named appending an ISO date (YYYYMMDD) and a number (the snapshot order within the day) to the official release version that is being developed.

For example, if you are developing towards '2.4.1' and you get an snapshot of it, it will be named 'theapp 2.4.1 20011124-1'. Another snapshot the same day will be 'theapp 2.4.1 20011124-2' and so.

Development progress

Achieving millestones
Evolutive development on the main branch

The features to be reached at the next featured version (i.e. '2.4.0') are previously specified. The development team develops towards this millestone. When those features are reached (or abandoned), 'theapp' is released as 'theapp 2.4.0' and the the next millestone (2.5.0 or 3.0.0) starts to be developed.

Once you have started the development of the next featured version (say 2.5.0), you may detect bugs on 2.4.0. You can do the bug fixing on the 2.4.0 base code and then release that as 2.4.1.

Bugfixing released versions
Corrective development on the bug fixing branch

The bug fixing can be done on the 2.4.1 line and then applied back to 2.5.0 line or the reverse process, that is fixing on 2.5.0 and applying back to 2.4.1. This mechanism will keep the 2.4.0 user bug fixed without having to wait new featured versions.

Experimental development

Another issue we have to deal are experimental development lines. Experimental development appears when you are trying to implement features that you don't know whether it will be part of any official release.

Experimental branches
Experimental development

The same mechanism as for the experimental development is used to develop forward releases. That is, advancing the development of some features that they will not be present on the current featured version but in the next one. For example, you may want to start the implementation of 3.0.0 features while you are still developing 2.5.0

Rationale: One can think that the better way to manage an experiment is outside the repository (CVS) control. This is far from true. By evolving it in a branch you could get the benefits of frequent commits for change tracking, and it is also easier to make diffs and merges with the main trunk.

Notice: Experimental branches should have a very short life. As the code diverges from the main branch, the merge will be harder. To lighten this you should limit the files or folders under experimentation and do frequent merges from the main branch to the experimental one.

An example of CVS implementation

Now, I am going to guide you on creating a dummy CVS project and applying to it some of the key steps of the life cycle explained before.

Let's do the development from one featured version to another to be the main CVS branch. We will place CVS tags on snapshots points and create branches whenever a new featured version is reached. Bugfixed version will be performed on such branches and merged back to the main branch if necessary. Experimental development also takes part on a separated branch and it can be merged to the main branch anytime.

After the tutorial your cvs repository will get a look similar to this one:

CVS content after some releases
CVS content after some releases.

The tutorial suposes that you have already an available cvs repository and that you have the CVSROOT environment variable pointing to it. It also suposes that you know the basic of CVS usage. That is:

  • creating a working copy,
  • performing changes and committing them back,
  • updating your working copy to the repository state, and
  • solving merging conflicts.

I recommend you to create a directory named 'cvstutorial' or something like that where to place all the stuff of this tutorial. Consider that all the paths are relatives to that directory.

Create a testing module

Let's create our dummy project named 'theapp' and let's add it as a new module named 'mymodule' on the cvs.

Note: It's common to put to the same name for the module and the application, but because this can be not your case, we will use different names for you to know which one we are talking about each time.

The steps are:

  • Create a directory named 'initial'
  • Create some files and directories inside of it. Those files will be your project content.
  • Let one of those files be named 'RELEASE'. It will contain data about the project progress. You will simulate development by adding lines to this file.
  • Place in the RELEASE file the text: 'Project starting point'
  • Be sure your shell is placed at the 'initial' directory and import its content as been the 'mymodule' CVS module by executing:

Then run

cvs import -m 'MyApp project started' mymodule theapp_main theapp_unreleased

The '-m' option specifies a comment for the CVS action. If you don't put this option on any CVS command that requires it a text editor will appear. Using the editor is more easy for real usage.

Once the repository has been created you can forget about the initial directory.

Do some 'development'

Now we will start the development of 'theapp 1.0.0'.

  • Place your shell at cvstutorial directory
  • Create a working copy of the repository:
    cvs checkout mymodule
    
    This will create the directory 'mymodule' containing the working copy.
  • You'd better to rename the directory 'mymodule' as 'workcopy' to avoid overwritting it when you will do another checkout.
  • Modify the 'RELEASE' file in order to get this content:
    1.0.0
    * First feature
    Project starting point
    
  • Now that you have added the first feature, commit the change to the repository.
    cvs commit -m 'First feature added'
    

Release an snapshot

Now that you have implemented the first feature it could be a good idea to get a development release.

  • Place an snapshot tag on the main branch
    cvs rtag -Fa theapp_1_0_0_20011124-1 mymodule
    
    Unless '-Fa' options are not needed here, I always use them beause the same command line can be used to move the tag later if you were wrong placing it here.
  • Now, you can add a '* Second feature' line to the RELEASE file, commit it and tag the module status as 'theapp_1_0_0_20011124-2'.

Issue an official release

First of all we will do the 1.0.0 release

  • Ensure you have committed all the changes from working copies you want to include in the 1.0.0 release
  • Create a tag for the release
    cvs rtag -Fa theapp_1_0_0_release mymodule
    
    This will tag all the files in the main branch of your module with the tag 'theapp_1_0_0_release'.

Now, let's prepare the bug fixing branch for 1.0

  • Create an sticky tag for the 1.0 bug fixing branch
    cvs rtag -Fa -b -r theapp_1_0_0_release theapp_1_0 mymodule
    

Now you have two branches: the main branch, ready for the development of the 1.1.0 release and the 1.0 bugfixing branch ready for the development of the 1.0.1 release.

Fixing a bug on a released version

The workcopy is assigned to the main branch so further development on this working copy aplies to the 1.1.0 development. If you want to fix a bug for the 1.0.1 version, you must create a new working copy from the 1.0 branch.

  • Checkout a new repository with the 1.0 branch sticky tag.

    cvs checkout -r theapp_1_0 mymodule
    
  • Rename this working copy as 'workcopy1.0' and go to this directory.

  • Simulate some fixing by adding those lines at the top of the RELEASE file:

    1.0.1
    
    * First fix
    
  • Commit these changes

    cvs commit -m 'Fix: Something weird fixed'
    
  • When you are satisfied with the fixes, then, you can create a tag for the release 1.0.1

    cvs rtag -Fa -r theapp_1_0 theapp_1_0_1_release mymodule
    

    Notice: By adding '-r theapp_1_0' you are tagging only the 1.0 branch.

Merge the fix on the main branch

Hint: This exercise will be more interesting if you perform and commit some development towards 1.1.0 on 'workcopy'.

Now you want to apply the fixes to the main branch.

  • Go to the main branch working copy (workcopy)
  • Execute the command:

    cvs update -j theapp_1_0
    
    This will apply to your working copy all the changes you made on the 1.0 branch from the branching point.
    
  • You'd better tag the 1.0 branch in order to know where the branch was done:

    cvs rtag -Fa -r theapp_1_0 theapp_1_0_merged_to_main mymodule
    
  • Remember to commit the merge.

    cvs commit -m 'Merged the first fix done for 1.0.1'
    

Fixing and merging a second fix

Additional fixings on this branch must be merged in a different way. We will use the tag 'theapp_1_0_merged_to_main' placed on the previous merging, as a reference point in order to specify which changes must be applied.

  • Make the new fixes on the branched working copy and commit them
  • Create a tag for the release 1.0.2 on the branch 1.0

    cvs rtag -Fa -r theapp_1_0 theapp_1_0_2_release mymodule
    
  • From the working copy of the main branch ('workcopy') do:

    cvs update -j theapp_1_0_merged_to_main -j theapp_1_0
    
    This will apply to your working copy all the changes you made on the branch from the branching time.
    
  • Commit the changes:

    cvs commit -m 'Merged fixes done for 1.0.2'
    
  • Move the merging reference to the current state of the branch:

    cvs rtag -Fa -r theapp_1_0 theapp_1_0_merged_to_main mymodule
    

Backporting fixes from the main branch

Often bug fixes are done on the main branch as part of the normal development, and you want to apply this fixes to an older release.

The easiest way to proceed is to delimitate the changes, using dates or tags. In that case, you can apply the same steps used to apply fixes to the main branch but in the inverse sense, from the main branch to the BugFixed branch.

Just because having delimited changes is not always possible, you have to deal with patching files separately, using file revision numbers.

File revisions are very different from application releases. Revisions are the name of differents commitments for a file. So dealing with revision you can isolate the changes done between two commitments of a file.

CVS content after some releases
CVS content after some releases.

Creating an experimental branch

TODO

Exporting tagged releases as source tarballs

When you do a development release or an official release, you may want to offer a tarball containing the project files.

Because a working copy done with a ckeckout has, not only the project files but also some CVS administration files, is not a good idea to tarballing from it.

You can use the CVS 'export' subcommand that creates a clean copy of the project files with a concrete tag. So for a official release you will do:

cvs -d $CVSROOT export -r theapp_1_0_0_release -dtheapp mymodule
tar cvfz theapp1.1.0-src.tar.gz theapp/*

and for a development relese you will do:

cvs -d $CVSROOT export -r theapp_1_0_0_20020110-1 -dtheapp mymodule
tar cvfz theapp1.1.0-20020110-1-src.tar.gz theapp/*

Other CVS documentation

  • The official CVS manual: It provides detailed information about CVS usage. Most CVS distributions bring it on several formats: 'info' pages, html pages, Windows help file... It is also available online.
  • Step-to-step guide to stablish a CVS system: It describes the operations related to the CVS repository creation and administration. It is available on my web site as companion of the tutorial you are reading now.

Multilingual terms glossary

The following table is provided to localize the project management vocabulary used on this tutorial. It is intended to help giving courses based on this tutorial but without abusing of english terms when native terms exists. I will be glad to receive additions, corrections and translations to your own languages.

EnglishSpanishCatalanYour Language Here
RepositoryRepositorioRepositori?
SandboxCopia de trabajoCòpia de treball?
MillestoneHitoFita?
ReleaseEntregaEntrega?
VersionVersiónVersió?
BranchRamaBranca?
TagMarcaMarca?
PolicyPolíticaPolítica?
TeamEquipoEquip?
Life cycleCiclo de vidaCicle de vida?
FeatureCaracterística, FuncionalidadCaracterística, Funcionalitat?
BugFalloFalla?
FixCorrecciónCorrecció?
MergeFusiónFusió?
DevelopDesarrollarDesenvolupar?
SnapshotInstantáneaInstantània?
PathRuta, LocalizaciónCamí, Localització?
CommitConfirmarConfirmar?
UpdateActualizarActualitzar?
CheckoutCrear copia de trabajoCrear còpia de treball?