We are using version in following format:


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:, 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., 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 into trunk (which is currently, maybe something should happens with version too, not just increment it Not sure what though.


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.

  • Can you confirm that you are increasing minor version whenever a version is branched off? Apr 17, 2018 at 10:41
  • @JonathanvandeVeen, yes, I forgot to explain that explicitly. With new branch last two numbers are reset to 0 (in trunk Test is always set, so it's started from 1)
    – Sinatr
    Apr 17, 2018 at 11:46
  • Side comment: IMHO it's not a great idea to merge release branches back into trunk: once the 1.1.X release branch is pulled trunk evolves into the 1.2.X release branch, changes in 1.1.X may be incompatible with the trunk. Changes in release branches should only be cherry-picked and verified that they are indeed compatible with the the trunk before being double-committed to the trunk. Apr 26, 2018 at 7:41
  • @DanCornilescu, you are using git-terminology I think. This is TFS. There are merge conflicts sometimes (what you call incompatible?), but this is only some inconvenience: auto-merge is disabled and we have to resolve conflicts manually. Not a big deal.
    – Sinatr
    Apr 26, 2018 at 8:28

5 Answers 5


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 when you decide to create the 1.2 release branch, then the first build on that release branch would be (and the next on Trunk

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..

  • is lacking, as it doesn't have meta information as to which release it belong. The number will grow to thousands in few years. That's the reason why we don't want to use auto-incremented build number in the version anymore.
    – Sinatr
    Apr 17, 2018 at 11:37
  • @Sinatr: I understand. I mostly wanted to have it mentioned as a possibility for others who stumble upon the question. Apr 17, 2018 at 12:02
  • I like your second idea. Indeed: the new branch should not receive new number before it's stabilized. Though this solution has same issue as per @DocBrown answer: if trunk is, then branch will never become 1.2
    – Sinatr
    Apr 17, 2018 at 12:36

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

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

Typically version is growing up

1.1.1 --- --- --- --- ... --- 1.2

And we will start differently and do reset at the end

1.1.1 --- --- --- --- ... --- 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").

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

Your stabilizing process in the "release" branch then increments,,, 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,, 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 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.

  • Good idea, that would solve collisions. But if we start branch with, then we don't release "two-numbered" version ever, e.g. 1.3, 1.4, etc., right?
    – Sinatr
    Apr 17, 2018 at 11:27
  • @Sinatr: yes, I think you are correct. If your trunk is at "1.4", which is identical to "", you probably won't make the next release until you did some development in trunk first, which yields a version number like "". And so your next release branch will start with that version number.
    – Doc Brown
    Apr 17, 2018 at 11:52
  • Hmm.. you are right, we will need to stabilize newly born branch version before release, I miss that. Though it would be really cool to present e.g. 1.4 version after 1.3.5 to the customers, but I can't imagine how.
    – Sinatr
    Apr 17, 2018 at 12:02
  • @Sinatr: simple, don't (ab)use the last digit(s) for marketing purposes. In your marketing documents/presentations/whatever, speak about the "1.4" line of your product, even if in the "Show version number" box a number like "" will be shown.
    – Doc Brown
    Apr 17, 2018 at 13:16
  • So you suggest to call as simply 1.4. The problem is that trunk version will also become 1.4. Version will be also shown in product, in setup and it will also be an executable attribute. All of those should be the same, so "hiding" is tricky.. We should only hide last zeroes, it's clear what and 1.4 are the same. If and are both 1.4 that's the problem.
    – Sinatr
    Apr 17, 2018 at 13:25

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.

  • Could you give an example for linux kernel versioning? I am not sure how adding +1 somewhere will solve the collision problem. It will simply occurs later.
    – Sinatr
    Apr 17, 2018 at 12:40
  • 1
    @Sinatr: The stable released versions of the Linux kernel were 2.2, 2.4, 2.6, etc. Version 2.5 would be an unstable (trunk) version. The trick is in bumping the version number twice between release branches. Apr 17, 2018 at 13:09

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 or

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 set as any assembly versioning, and the build process would get the code, set the version to 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.