Release Management in Open Source Projects

During my work in open source projects, I observed several ways of dealing with software releases, ranging from chaos up to well-defined release processes.

In this article, I'm going to describe two common patterns of dealing with releases from a technical perspective. This article has been written with subversion in mind, but applies to other revision control systems as well, as long as they support tagging and branching. The general idea is to use the revision control system to keep track of past releases for being able to exactly reproduce any released artifact for later reference.

The first pattern can often be observed in smaller open source projects: All development takes place in the trunk, with branches mainly used for experimental code. From time to time, a release is made, which works like this:

  1. Make sure the trunk contains all the changes for the release
  2. Execute the test suite one last time
  3. Prepare change log and other release information
  4. Increment version number
  5. Commit
  6. Create a tag for the trunk's current state
  7. Create the release artifact (tarball, EAR, Deb-File, RPM)

The process is very easy to execute and to understand, but the downside of this approach is its inflexibility. If bugs are found and a new release has to be created quickly, the trunk might have evolved quite a bit since the last release. You would typically have to work around this problem by creating a branch based on the last release's tag and fix the bugs there.

In larger projects, a more powerful pattern is usually used. It supports multiple development lines, where releases can be made on each of them. The development of new features is done on the trunk, while maintenance work is done on branches. We'll go through a few typical situations to illustrate how this works.

After a period of development, you decide the time is right for a release (version 1.0.0, for example). You would then do the following:

  1. Create a branch called RELEASE-1.0 (a snapshot of the trunk) and prepare the release from there
  2. Execute the test suite
  3. Prepare change log and other release information
  4. Increment version number to 1.0.0
  5. Commit
  6. Create a tag for the branch's current state (RELEASE-1.0.0)
  7. Create the release artifact (tarball, EAR, Deb-File, RPM)

Note that no release is ever created from the trunk directly (developer snapshots might be an exception). All release preparations and the tagging is done on the RELEASE-1.0 branch.

After the branch has been created, development on the trunk may continue as usual. If bugs are found in the 1.0.0 release or a maintenance release is desired, the following would be done:

  1. Check out the RELEASE-1.0 branch and apply all necessary changes there
  2. Prepare the release as usual and tag it as RELEASE-1.0.1
  3. Optionally merge your changes into the trunk if applicable

The trunk and other branches are unaffected by this release process and different teams can work on the individual branches without getting in each other's way.

Multiple development lines have a disadvantage, too: The increased complexity. Care has to be taken to make sure all relevant changes from a branch are merged back into the trunk (and into other relevant branches as well) or otherwise regressions will occur. This requires the ability to merge branches (not entirely trivial, even with subversion!) and good commit logs for all your changes. Otherwise it might not always be clear which changes to merge.

social