August 31st, 2011

Merge enhancements in TFS 11

Brian Harry
Corporate Vice President

Here’s the next post in my series of “Developers are raving fans” enhancements coming in TFS 11.  My last post was on workspace improvements.

One of the things we consistently get customer feedback on in TFS 2010 is that merging is still too complicated and/or too limited.  We’ve made several significant improvements in the coming release:

A new diff/merge experience – The one we’ve been shipping for the past 5 years is the original SourceSafe diff/merge tools – built while we were One Tree Software circa 1994.  It had been enhanced over the years to support globalization, Unicode, etc but it was, in essence, the same diff tool.  Well not any more, it’s gone!  We’ve built a new diff/merge experience based on the VS editor.  And before you say “but wait, I really love kdiff!”, don’t worry – it’s still configurable and you can use any tool you like but the out of the box one is now WAY better.  How is it better you say?

  • It supports both “inline” and “side by side” modes and you can choose the one you like best.
  • It has syntax highlighting (as supported in the VS editor).
  • Individual changes within a line are highlighted.
  • When both diffing and merging, you can edit with the full power of the VS editor, including undo, Intellisense and everything!
  • Diff has a nice “mini-map”.
  • You can now take more actions from the views (like history, etc).
  • Diff uses the new provisional tab feature in VS to avoid cluttering your document well.
  • An improved way of manually selecting merge resolutions.
  • An interactive way of turning on/off ignoring whitespace.

Here are some screen shots to demonstrate.  You can observe many of the points I made above:

Side by side diff view in the provisional tab (all the way to the right) with a change highlighting gutter on the left, in line change highlighting, VS style class/method navigation, syntax coloring and more.  Yes the text with the file names above the source looks dumb – that’s a bug.

Image 2671 DiffSxS thumb 1AA85A52

Same diff using inline mode:

Image 7558 DiffInline thumb 40FA17D0

And here are some screenshots of the merge experience.  I’ve included all three of the views you can choose from:

Image 4747 MergeTool thumb 15F203FE

Image 6888 MergeTool2 thumb 3317AC08

Image 7080 MergeTool3 thumb 24F8BD0B

Overall, it’s a much better default diff and merge experience than we’ve had before!

Minimal conflicts when merging – Probably the biggest complaint that we hear about merging is that it’s way too cumbersome.  We spent a bunch of time trying to get to the bottom of this feedback and concluded that the primary issue is that when you do a merge, you get way too many reported conflicts that actually don’t require you to make meaningful decisions.  People want it to just “handle” all the obvious merge cases and only draw their attention to places where they have real work to do.

To demonstrate the difference between TFS 2010 and TFS 11, I have run a sample scenario.  It’s simple and contrived but it demonstrates the difference.  I took a big folder full of TFS source code and branched it.  I then global renames of two methods in the two branches and merged the results.  The result was 48 files changed in the source branch and 90 files changed in the destination branch.  The resulting reported con flicts were:

  • TFS 2010: 38 conflicts
  • TFS 11: 12 conflicts

The difference is that TFS 11 automatically resolved 26 of the conflicts without requiring user interaction.

I always hear that Git is the “gold standard” for this behavior.  So, we did a head-to-head comparison between Git and TFS merge behavior and we found that the change necessary to our code to get pretty close to the Git experience was actually pretty small.  So I did a head-to-head to compare the new TFS merge behavior to Git.  I’m not going to claim that it’s an exhaustive test or that I caught everything but I believe it covers most of the common scenarios and, when you get your hands on it, if you find anything we missed, please let me know.

For this scenario, I wanted to compare the behavior with different kinds of conflicts.  I created a folder with 9 files in it, branched it and then arranged a specific pattern of changes to evoke conflicts.  Here are the changes:

File Source change Destination change Comment
file1.txt unchanged unchanged Trivial case, nothing to merge and nothing in the destination
file2.txt edit line 3 unchanged Just merge the change into the destination
file3.txt unchanged edit line 3 Nothing to merge over and the change in the destination should affect it
file4.txt edit line 3 edit line 7 Distinct changes in source and destination
file5.txt edit line 5 same edit line 5 Same change in both files should merge well
file6.txt edit line 5 different edit line 5 This is a conflict that will require user interaction to resolve
file7.txt delete file unchanged Delete the file in the source an no changes in the destination
file8.txt delete file edit line 5 A file delete in the source conflicting with an edit in the destination
file9.txt rename file unchanged Should not really be any conflict here

I then created the same scenario in TFS 2010, TFS 11 and Git and looked at the results.  In this scenario, I used the command lines for all 3 to really show apples to apples.

Here’s the merge output for TFS 2010:

Image 5822 image thumb 428A980A

Note there are 3 conflicts listed and 4 additional merges.  files 1 and 3 didn’t require any merges.  And here’s the output of tf status:

Image 3362 image thumb 79F0A938

And we see 7 changes pended (to be expected based on what we saw in the merge output).

Here’s the merge output for Git in the same scenario:

Image 8463 GitMergeOutput thumb 113BADAA

and the status output:

Image 4747 GitStatus thumb 2F39BB9E

First thing to note is that Git lists only 2 conflicts – file4 is automatically resolved where it is not in TFS 2010.  The other thing that I not ice is that file5 doesn’t show up at all (remember that’s the one where identical changes were made in source and destination).  Other than that, the merge/conflict results are identical.  Other things I notice is that all the wrapping in TFS’s merge output makes it hard to read, the color coding in Git is nicer and including the conflict information in the status output is very nice.

I then ran the same scenario in TFS 11:

Image 8154 Dev11MergeOutput thumb 5EA82A6A

Image 7870 Dev11Status thumb 2D78C9FD

Now the number of conflicts matches Git.  We still have the difference that we list file5.txt because we way we do debit/credit logic on merges requires that we have a pending change to recognize that the merge has happened.  I’m going to look at this more closely.  The output is the same and I’ve spoken to the team about making a few changes here that can improve readability and reduce verbosity.

When I ran this comparison against Git, I was struck that the number of types of conflicts that we resolved differently in 2010 was not actually all that high.  However, that doesn’t take into account frequency (which is why I did the rename example first).  The one type we didn’t handle as well happens to be the most common type, so that small change has a pretty big effect on the developer experience.

Baseless merge in the UI – Another long standing piece of feedback is people want to be able to initiate baseless merges in the UI.  We’ve supported it in the command line for a long time but much as I said about rollback in my post on the Power Tools, for many people, if it’s not in the UI, it’s not in the product.  Now it’s in the UI.  If you initiate a merge from the Source Control Explorer, the merge wizard now has a browse button that allows you to go find branches to do a baseless merge against.

Let’s look at an example.  I started with a branch structure that looked like this:

Image 2287 Hierarchy thumb 64DEDB2B

As you can see there’s no merge relationship between destination and AlternateDestination.  But let’s imagine that I have some changes in destination that I want in AlternateDestination but I don’t want to go through Source.  I want a baseless merge from destination to AlternateDestination.  I can now go to Source Control Explorer and start the standard merge experience:

Image 5023 MergeWiz thumb 02DCE920

As always, only Source is in the list because it is the only related branch to destination.  However, unlike TFS 2010, there is now a Browse… button for baseless merges.  If you click it, you get:

Image 5824 BrowseBranch thumb 72EDA45B

and here you can see I can pick AlternateDestination.  And if I do, and hit OK, I go back to the wizard:

Image 0243 BaselessMerge thumb 6CC657C0

And it warns me that I’m doing a baseless merge but I can hit next and then finish and proceed with it.  So, now you can do baseless merges in the UI!

Merge on unshelve – From the beginning people have loved shelving as a simple, clean way to package up changes and set them aside.  However, we’ve often heard the complaint that the inability to unshelve into a workspace with pending changes and deal with the merge conflicts was a serious limitation.  No more!  We have now built merging into unshelve operation and it works just like merging does elsewhere in the product.

This post has gotten plenty long so I’m not going to include screenshots of this.  The new thing is that merges are performed, conflicts are filed, etc in this scenario.  All the UI around that is the same as on other scenarios (like merge and get) where merges happen.

Whew!  That was a lot but I’ve got plenty more to tell so I’ll keep writing posts in this series.

Brian

Topics
TFS

Author

Brian Harry
Corporate Vice President

Corporate Vice President for Cloud Developer Services.

0 comments