The question came up during a discussion on our internal mailing list as to why Git’s merge is seen as better than the TFS merge.  What better way to explain it than via a worked example:

TFS Example

Consider the following solution in TFS:

image

Now let’s branch it for two different teams.  Team A and Team B.

image

Now let’s go into TeamA’s code and refactor SomeClass to have a better name.  Here’s the changeset that gets created.  Note that we’ve changed the .csproj and Program.cs as well since they both had references to SomeClass.

image

Meanwhile TeamB adds an extra property for some functionality they are adding:

image

Team A then merges back to trunk.  When merging in Visual Studio you can only merge between branches that are directly related to each other.

image

Team B then wants to merge to trunk, but as Team A checked in first, they decide to follow good practices and pull down the latest changes from Trunk and merge them first.  Because the SomeClass file was renamed we now have a merge conflict as seen here:

image

And until we fix it our solution is broken.

image

Visual Studio asks us what we want to do with the file name and we need to figure out what the right option is.  Giving choice like this to the user is unnecessary and can easily result in a big mess.

Git Example

Let’s do the same thing using git.  We start by creating a new project and making the two team branches.  Note how the branches all point to the same commit instead of creating copies of all the files.

image

Now let’s refactor the TeamA code and add the property to TeamB as we did with the TFS example and commit the changes.  We see the branches now have some changes and are diverging from each other.

image

Now let’s merge the TeamA changes to TeamB.  For consistency with the TFS example we’ll do it by merging TeamA to master, and then master to TeamB

image

Note that the merge from TeamA to master is a fast-forward merge.  This happens because trunk hasn’t changed since TeamA branched so master can just be repositioned to the TeamA commit..

You can see that in the second merge from master to TeamB an auto-merge occurred, and git automatically detected that the changed SomeClass.cs file and the new SomeBetterName.cs file are actually the same file (with an 84% certainty), so it performed a rename for us automatically.

When we reload the solution in Visual Studio, everything looks fine, and we can get on with our development activities.  Here’s what it looks like in the repository viewer:

image

As a note, with git we don’t have to go via the master branch to merge TeamA changes to TeamB, we could have just done git merge TeamA as shown here:

image

For reference, you don’t have to merge from TeamA to TeamB via Trunk in TFS either.  TFS has a baseless merge option that you can run via the command line, though when you do the branch history can get a little messed up.

Here’s hoping that the next version of TFS will have a much better story around rename detection and version control in general.