Question

We are using version in following format:

Major.Minor.Bugfix.Test

Development for upcoming release is going on in the trunk. When enough features are done we are creating a new release branch: 1.1, 1.2 and so on.

After branch is created there is a continuous "stabilizing" process, producing test versions of branches: 1.1.0.1, 1.1.0.2 and so on, until a new bugfix version is ready, those are: 1.1.1, 1.1.2 and so on.

The image below should explain it better:

Upon creating release branch the version in the trunk is increased (since we begin working for next release somehow).

The problem: we also need to use versions in the trunk (those are given for internal tests) and they will collide with the next release branch test versions (marked with red circle).

The question: how to avoid such version collision?

One proposal was to change trunk version after branching to high enough number, e.g. 1.2.0.100, this will make collision unlikely to occur, but is ugly.

Ideally we want to keep numbers "small" (so they are easy to remember and to use).

(Optional) Another thing: after periodic merging from current release branch into trunk it make sense to indicate this somehow in the version too (marked as ? on the picture), could be very useful to indicate that following trunk test builds are have those bugfixes included, e.g. after merging 1.1.1.1 into trunk (which is currently 1.2.0.3), maybe something should happens with version too, not just increment it 1.2.0.4. Not sure what though.

Ideas?


For an easier overview here is an image of one of proposed solutions:

The idea is to inherit (continue) number in release branch. This will solve collision, but will introduce another problem: there is no more 1.1 or 1.2 versions. We'd like to have those if possible.

Was it helpful?

Solution 2

Thanks to other answerers we finally agreed on the versioning system.

The idea is to start test version with release number (e.g. 1.1.0.1 means "test version for 1.1.0 release") and remove Test when testing is finished.

Typically version is growing up

1.1.1 --- 1.1.0.1 --- 1.1.0.2 --- 1.1.0.3 --- ... --- 1.2

And we will start differently and do reset at the end

1.1.1 --- 1.2.0.1 --- 1.2.0.2 --- 1.2.0.3 --- ... --- 1.2

The image:

  • The release branch version will continue from the version of the trunk.
  • The trunk version will be reset to x.x.0.1.
  • After release the test version is reset to x.x.x.1, where x.x.x is next release version.
  • Release versions are obtained by clearing Test number (means "test is finished").

OTHER TIPS

There are two major strategies that address both your problems.

1. Trunk has a "fixed" version number

You could choose to give the Trunk a version number 0.0.0.X, where only the X ever changes. This then makes it clear to everybody that such builds are part of the active development and not part of the stabilization of a release.

In this concept, it does not make sense to track (using version numbers) when bug-fixes from earlier releases are being merged into the trunk.
It also has the advantage that you only have to decide on which version number to release (increment the minor or the major part) when starting the stabilization.

2. Release branch continues where Trunk ended

If you want your working methods as close as possible to what you are currently doing, then you could just continue the test numbers on the release branch.

If Trunk is at version 1.2.0.26 when you decide to create the 1.2 release branch, then the first build on that release branch would be 1.2.0.27 (and the next on Trunk 1.3.0.1)

In this scheme, you can just increment the BugFix part of the version on Trunk when merging bug fixes from earlier releases.

This scheme essentially uses a different mental picture of the branches

------------------------  release 1.1
     \
      \-----------------  release 1.2
            \
             \----------  trunk (to become release 1.3)

When starting stabilization for a release, you rename Trunk to the release branch and then create a new Trunk from that point for the development of the next release..

Lets say your trunk is at 1.3.0.3. Now you create a release branch for the "1.3" line, which means that branch starts with that number, 1.3.0.3. Simultanously, you set your trunk to 1.4.

Your stabilizing process in the "release" branch then increments 1.3.0.4, 1.3.0.5, 1.3.0.6, maybe "1.3.1", and so on - it always keeps the "major.minor" number fixed.

On the other hand, your trunk will be versioned as 1.4.0.1, 1.4.0.2, and so on. So your trunk has always a higher "major.minor" number than every other release branch, which means there is no collision.

If you merge changes from a release branch into the trunk, you increase the trunk's version number just as you do it by a direct change in the trunk. Your VCS (TFS) might support documenting from which revision you merged the changes into the trunk, and if not, you have always the option to write this manually into the history log (simply a comment like "merged the following changes from 1.3.0.6 back into the trunk: ... "). And that is is the place where it belongs, I would not try to map such information into the version number.

The two solutions that I came up with for this:

  1. As per Bart van Ingen Schenau's "Release branch continues where Trunk ended" suggestion - basically the same as what you're doing at the moment, but you don't reset the bugfix and test components of the release number when you create the release branch.

  2. Similar to how the Linux kernel used to be versioned, bump the minor version both before and after you create the release branch. This then means that a specific minor version number exists either on trunk or on a release branch, but not on both. I don't know the exact reasons why the Linux kernel is no longer numbered this way, but it might suggest that they encountered problems with it.

Zero + Concat for non-release branches

I always begin non-release branches like Trunk with 0 and only try to keep it generally around the next release number by concatenating the release major and minor as the trunk minor. So if the current release is 7.6.1, and the next release is 7.7.1, then the trunk would be 0.77.1. The three parts are not a semver thing, I'm only omitting the fourth part as its an auto incremented part. The code in source control would have 7.7.1.0 or 0.77.1.0.

This "zero + concat" gives me non-colliding trunk version numbering that can produce development/alpha artifacts and that is still relatively close enough to a release number to identify the "era" of the code.

Stop over-versioning branches

I dont think you should worry so much about "versioning a branch" and dealing with all the code management churn that comes with updating version numbers in code constantly.

Version numbers are assigned to programs and other compiled code artifacts, not to the raw source code which constitutes the branch. I will sometimes name a branch for the expected release number, but I also dont set a version in the source code except when bumping the Trunk or bumping the release branch (or setting it when the branch is created). I let the build platform handle the incrementation of numbering (and it should start with .1). The build platform also must tag and/or label the specific code changeset/commit that went into that versions build.

Using the above example, the code in the release branch would have 7.7.1.0 set as any assembly versioning, and the build process would get the code, set the version to 7.7.1.1. 7.7.1.2. etc and compile.

Bugfixes/Hotfixes for a release will be merged up and a release build executed, and just the parts (dll's, etc) needed to address the problem get packaged as the fix to test.

Versioning helps artifact identification

Remember why we version things; to be able to more reliably identify deployed software so we can better support and maintain those things. We dont version things just to create another thing to manage.

So this only applies to builds that produce artifacts, and things like feature branches dont usually fall under this as they often only need a gated checkin or similar build. When I have needed to make artifacts for feature branches, it would still carry the 0 major, concat minor, but have a crazy 3rd part like 3333 that has no realistic chance for collision.

Licensed under: CC-BY-SA with attribution
scroll top