Oct 22, 2010

Why does Git Merge Work Better than TFS Merge

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.

10 comments:

  1. TFS and Subversion feels like the stone age of version control compared to git and mercurial :)

    ReplyDelete
  2. TFS doesn't actually create copies of the files when they are branched. It just adds references to the content, so there's no bloat of the database.

    Buck

    ReplyDelete
  3. I think you had this experience because you are not using the good practice for merging.

    If i have a Main structured with two branches, and you need to do RENAME in any file, you should do this in the MAIN branch, doing things this way you will avoid all kind of conflict, not having to depend on 84% certainty, but it will be very accurate.

    Regards

    ReplyDelete
  4. Sorry, I don't see how Git automatically guessing (with a mere 84% certainty) is better than having to hit an extra button "automatically merge" so that you can double-check a possible ambiguity.

    ReplyDelete
  5. Gabriel,

    Many times you don't have the ability to change a file name in the main branch, i.e. you are updating functionality that won't go live for a few weeks, while in the meantime other releases will be pushed live from the main branch that would break things if the filename changed.

    ReplyDelete
  6. I dont see how a merge based on statistics and not end user decision is a better implementation of a version control system when renaming a file. I would prefer the user choice rather than "guessing" done by the version control system. But thats my opinion :-)

    ReplyDelete
  7. Well, In most cases too many options is not an option. Having more human interaction usually equals in more bugs when this type of decision is so common and mistakenly done by us. Hurray for the auto "guessing" mode of Git! HIP HIP HURRAY!

    ReplyDelete
  8. Well, In most cases too many options is not an option. Having more human interaction usually equals in more bugs when this type of decision is so common and mistakenly done by us. Hurray for the auto "guessing" mode of Git! HIP HIP HURRAY!

    ReplyDelete
  9. I wonder if subversion would have had this problem?

    ReplyDelete