This project has moved. For the latest updates, please go here.

Branch Scheme for Future Releases Using Reparenting

Dec 26, 2012 at 2:40 PM
Edited Dec 26, 2012 at 7:05 PM

Our development process includes simultaneous development on multiple release paths: while one team is working on the current major release another team is working on the next major and a third team may be work on the one after that.  Of course the standard branches for ServicePack and HotFix work on the current production version also exist.  Our problem is that we want to provide a simple merge path from main through all of the development branches.  We are focusing on trying to (1) minimize the number of merges required for each check in and (2) protect main from becoming polluted with accidental merges from future release branches.  The recommended advanced branching pattern suggests creating all of the future release branches at the same time with MAIN as the root:

MAIN
---| RELEASE_1
---| RELEASE_2
---| RELEASE_3

My primary issue with this scheme is that changes checked into RELEASE_1 then have to be merged forward into RELEASE_2 and RELEASE_3 through MAIN.  It quickly becomes difficult to track what items haven't been merged forward and to which branches.  Plus it is difficult to protect MAIN from accidental reverse integration merges from RELEASE_2 and RELEASE_3 while RELEASE_1 is still active.

I am proposing a modified hierarchical branch structure where RELEASE_2 is a child of RELEASE_1 and RELEASE_3 is a child of RELEASE_2.  

MAIN
---| RELEASE_1
------| RELEASE_2
---------| RELEASE_3

Then as each version is released to production, its child branches could be reparented to MAIN and that branch could be locked to prevent further checkins.  This allows for a straightforward, sequential merge path and gives us the ability to protect main by denying reverse integration merges on all of the release branches.  We can easily monitor what changes haven't been merged into the future releases (everything should always merge forward).  By denying reverse integration merges on the release branches, we protect MAIN and ensure that it is only receiving changes from the current release branch.  The only hiccup with this plan that I can see (and it seems minor to me) is that after reparenting, we will have to re-merge every change that was checked into RELEASE_2 back into MAIN.  But as long as we manage our forward integration merges and make sure that the merge list is clear before performing the reparent, this should be a simple overwrite merge (any conflicts should have been resolved by the merge from RELEASE_1 -> RELEASE_2).

Thoughts?  Comments?  What am I missing?

Dec 26, 2012 at 4:04 PM
Under your original plan, Why would you ever merge release 2 or release three Into the main branch until release one is deployed into production?

Sent from my iPhone

On Dec 26, 2012, at 9:40 AM, LostArchitect <notifications@codeplex.com> wrote:

From: LostArchitect

Our development process includes simultaneous development on multiple release paths: while one team is working on the current major release another team is working on the next major and a third team may be work on the one after that. Of course the standard branches for ServicePack and HotFix work on the current production version also exist. Our problem is that we want to provide a simple merge path from main through all of the development branches. We are focusing on trying to (1) minimize the number of merges required for each check in and (2) protect main from becoming polluted with accidental merges from future release branches. The recommended advanced branching pattern suggests creating all of the future release branches at the same time with MAIN as the root:

MAIN
|- RELEASE_1
|- RELEASE_2
|- RELEASE_3

My primary issue with this scheme is that changes checked into RELEASE_1 then have to be merged forward into RELEASE_2 and RELEASE_3 through MAIN. It quickly becomes difficult to track what items haven't been merged forward and to which branches. Plus it is difficult to protect MAIN from accidental reverse integration merges from RELEASE_2 and RELEASE_3 while RELEASE_1 is still active.

I am proposing a modified hierarchical branch structure where RELEASE_2 is a child of RELEASE_1 and RELEASE_3 is a child of RELEASE_2.

MAIN
|- RELEASE_1
|- RELEASE_2
|- RELEASE_3

Then as each version is released to production, its child branches could be reparented to MAIN and that branch could be locked to prevent further checkins. This allows for a straightforward, sequential merge path and gives us the ability to protect main by denying reverse integration merges on all of the release branches. We can easily monitor what changes haven't been merged into the future releases (everything should always merge forward). By denying reverse integration merges on the release branches, we protect MAIN and ensure that it is only receiving changes from the current release branch. The only hiccup with this plan that I can see (and it seems minor to me) is that after reparenting, we will have to re-merge every change that was checked into RELEASE_2 back into MAIN. But as long as we manage our forward integration merges and make sure that the merge list is clear before performing the reparent, this should be a simple overwrite merge (any conflicts should have been resolved by the merge from RELEASE_1 -> RELEASE_2).

Thoughts? Comments? What am I missing?

Dec 26, 2012 at 4:21 PM

It shouldn't happen, but I'm trying to protect against accidents.  In my environment developers swap teams frequently.  A dev who was working on RELEASE_1 yesterday could easily be working on RELEASE_2 tomorrow.  Given that condition, I can easily foresee a situation where a dev get's confused and (thinking that he is working on the current release) accidentally performs a reverse integration merge from RELEASE_2 into MAIN effectively promoting code ahead of schedule.  My second scheme is focused on trying to prevent this.

Dec 26, 2012 at 7:45 PM
If they accidentally merge from rls 3 to rls 1, it will pollute rls 1 just as it would have polluted the main branch. Then when you go to merge rls 1, it has the release 3 stuff in it. I don't see what you gained.

The fact that you have 3 releases going on at one time is disturbing. Especially since you said some of the same people are working on multiple releases. This is highly inefficient. They could be more effective concentrating on finishing the first release. This parallelism provides the illusion of great activity. But it is actually a slower way to get results. There appear to be deeper issues here of release planning and program management. It might be useful to explore your broader problems rather than thinking this is just a branch design issue.

Sent from my iPhone

On Dec 26, 2012, at 11:22 AM, lostarchitect <notifications@codeplex.com> wrote:

From: lostarchitect

It shouldn't happen, but I'm trying to protect against accidents. In my environment developers swap teams frequently. A dev who was working on RELEASE_1 yesterday could easily be working on RELEASE_2 tomorrow. Given that condition, I can easily foresee a situation where a dev get's confused and (thinking that he is working on the current release) accidentally performs a reverse integration merge from RELEASE_2 into MAIN effectively promoting code ahead of schedule. My second scheme is focused on trying to prevent this.

Dec 26, 2012 at 8:24 PM

I addressed that possibility as well in my proposed scheme.  By denying the ability to perform reverse integration merges on the release branches we do not allow for the possibility of merging from RELEASE_3 into RELEASE_2 or RELEASE_2 into RELEASE_1.  This can be simply implemented with a custom check-in policy.  Putting a similar restriction on MAIN with a growing set of separate child branches would be more difficult.  The gains from this scheme are (repeated as listed above):

  1. A sequential merge path from 1 -> 2 -> 3 (as opposed to 1 -> Main, Main -> 2, Main -> 3)
    • This also guarantees that all changes from RELEASE_1 will get merged into future branches, rather than being left behind on the MAIN line and never merged forward
  2. Faster utilization of new features implemented in previous releases (available immediately upon forward integration merge)
  3. Identifying unmerged items for branches RELEASE_2 and RELEASE_3 is very simple (everything should always merge)
  4. It is easier to protect MAIN against accidental reverse integration merges from future release branches

In short, I believe that this offers greater synchronization between the branches with the least amount of effort for both the developers and the build master/TFS admin.

Project management is beyond the scope of the problem which I am addressing here.  I am trying to design a safe and efficient branching structure based on the development environment as it exists.  I believe that this scheme does that, but would appreciate any input that shows flaws in the design or gaps in my logic.

Dec 27, 2012 at 10:38 PM
Edited Dec 28, 2012 at 1:24 AM

Is there a possibility of two versions released at the same time?  I doubt that would happen.  A more managable approach would be to have one Service Pack branch off of main and branch your releases from Service Pack.  Any production bug fixes would be done in Service Pack and the new version would be branched off of there.  When you are ready to reverse integrate, it would be from Service Pack to Main and FI to development.  Any new development versions that are ready to be released are forward integrated from Main to SP and then an immediate branch from SP to Release_x.  Since one version is live at a time, there is little need for each Release branch to have its own SP or hotfix or to branch future releases until they are ready to go live.

  • Main
    • SP
      • Release_1
      • Release_2
      • etc.