blogs.conchango.com

welcome to the conchango blogging site
Welcome to blogs.conchango.com Sign in | Join | Help
in Search

James Dawson's Blog

Team Foundation Server - Merging Branches Issue?

So last week I had my first official introduction to Visual Studio Team System (VSTS) and Team Foundation Server (TFS) when I attended a 'VSTS Readiness Workshop' that was co-led by Joel.

By Day 2 we'd started looking at the new source control system that ships with TFS and I was keen to see how the new/improved features (database back-end, concurrent check-out, transactional check-ins aka changesets  etc.) might affect our approach to versioning and release management - in particular I was interested to see how much the branch/merge functionality had been improved.

One of the main differences is that creating a branch does not immediately result in a duplicates of each affected object (and thus double the storage requirements) - initially the branch contains links to the files, and only when a file is actually changed in the branch does a new version get created. With this in mind, I set about simulating a typical scenario to put the merge/branch functionality through its paces - and got some 'interesting' results.

The scenario (and resulting issue) is summarised below:

1 ) 'Sprint 1' begins, and development continues for 4 weeks
2 ) At the end of 'Sprint 1', a new branch is created called 'Sprint 2'
3) Consider that 'Sprint 1' functionality is now in production In both branches the file Class1.cs contains the following code: 
    1 public class Class1
    2 {
    3     public Class1()
    4     {
    5         //
    6     }
    7 
    8     public int SomeMethod1(int x, int y)
    9     {
   10         return x + y;
   11     }
   12 }
4) All 2nd Sprint development continues in the 'Sprint 2' branch
5) During the first week of 'Sprint 2' additional methods are added to Class1 as part of functionality on the sprint backlog. The Class1.cs file now looks like this: 
    1 public class Class1
    2 {
    3     public Class1()
    4     {
    5         //
    6     }
    7 
    8     public int SomeMethod1(int x, int y)
    9     {
   10         return x + y;
   11     }
   12 
   13     public int SomeMethod2(int x, int y)
   14     {
   15         return (2 * x) - y;
   16     }
   17 
   18     public int SomeMethod3(int x, int y, int z)
   19     {
   20         return (x ^ y) / z;
   21     }   
   22 }
6) Also during week 1 a production bug comes in, and is fixed in the 'Sprint 1' branch. The Class1.cs in the 'Sprint 1' branch now looks like this: 
    1 public class Class1
    2 {
    3     public Class1()
    4     {
    5         //
    6     }
    7 
    8     public int SomeMethod1(int x, int y)
    9     {
   10         return x + (y - 1);
   11     }
   12 }
7) In week 2 the bug fix is signed-off and needs to be applied to the 'Sprint 2' branch - this is done via a merge operation.

8) The merge is performed from 'Sprint 1' to 'Sprint 2', and happens as you'd expect, with a conflict being detected and being given the opportunity to perform a manual resolution to combine the bug fix from 'Sprint 1' with the new methods in 'Sprint 2', to give a Class1.cs in 'Sprint 2' that looks like this: 

    1 public class Class1
    2 {
    3     public Class1()
    4     {
    5         //
    6     }
    7 
    8     public int SomeMethod1(int x, int y)
    9     {
   10         return x + (y - 1);
   11     }
   12 
   13     public int SomeMethod2(int x, int y)
   14     {
   15         return (2 * x) - y;
   16     }
   17 
   18     public int SomeMethod3(int x, int y, int z)
   19     {
   20         return (x ^ y) / z;
   21     }   
   22 }
9) In week 3 another production bug is discovered and fixed in the 'Sprint 1' branch, and is fixed as shown below: 
    1 public class Class1
    2 {
    3     public Class1()
    4     {
    5         //
    6     }
    7 
    8     public int SomeMethod1(int x, int y)
    9     {
   10         return (2 * x) + (y - 1);
   11     }
   12 }
10) This bug fix is signed-off and then needs to be applied to the 'Sprint 2' branch
11 ) The same merge operation as in step 9 is performed, however, this time no conflict is detected and the merge completes automatically without any prompts.

12) The merged version of Class1.cs in 'Sprint 2' can be checked-in without intervention. Unfortunately, upon inspection of the resulting Class1.cs in 'Sprint 2' we can see the merge has not quite happened as we'd intended: 

    1 public class Class1
    2 {
    3     public Class1()
    4     {
    5         //
    6     }
    7 
    8     public int SomeMethod1(int x, int y)
    9     {
   10         return (2 * x) + (y - 1);
   11     }
   12 }

As you can see above, Class1.cs in 'Sprint 2' has been overwritten by the version in 'Sprint 1' and the all the new methods have been lost. It seems that TFS assumes that a merge operation should result in identical files, which of course is not necessarily the case.

I'd be interested to hear from anyone who cannot recreate the above issue - I also plan to re-test this scenario using the December CTP version of TFS that was recently released to see if it behaves differently.

Published 20 December 2005 20:18 by james.dawson

Comments

 

James Dawson's Blog said:

So after receiving an e-mail from someone asking whether I'd heard anything more regarding the TFS

September 20, 2006 00:22
Anonymous comments are disabled
Powered by Community Server (Personal Edition), by Telligent Systems