Merge enhancements in TFS 11
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.
Same diff using inline mode:
And here are some screenshots of the merge experience. I’ve included all three of the views you can choose from:
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
- 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:
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:
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:
and the status output:
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:
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:
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:
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:
and here you can see I can pick AlternateDestination. And if I do, and hit OK, I go back to the wizard:
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.