Partial Merges in TFS – A Guide

Ladislau Szomoru (CSS TFS Escalation Engineer, Hungary) is at it again today, building on a previous post around TFS merge…


On April 15th 2009 we posted an interesting article written by Philip Kelley from the Team Foundation Server development team on how to track down merge history using tf merge and tf merges. In case you did not have the chance to read I would recommend you go over it before reading this post.

One topic that was not discussed by Philip were partial merges. A partial merge is recorded when only some changes from a changeset are merged into the target. In this post I will try to describe some of the more common scenarios in which you can end up with partial merges.


Consider we have two branches Main and Dev and they both contain two files. The files have been edited in the Dev branch and we are about to perform a merge operation from Dev to Main.

First we get the merge candidates

C:\Samples >tf merge Dev Main /recursive /candidate

Changeset    Author Date
------------------ ------------------- ----------------
138 lszomoru 4/30/2009

Performing the merge operation will add a pending change for each of the two files. For some reason we decide that we do not want to merge the changes in File2.txt so we undo the pending change in the “Pending Changes” window. We go ahead and we check-in the merge.

Now if we take a look at the merge history of Main we will see the following:

C:\Samples >tf merges Dev Main /recursive

Changeset    Merged in Changeset Author Date
------------------ ---------------------------- ------------------- ----------------
138* 139 lszomoru 4/30/2009

Note: It is important to note that in Team Foundation Server 2008, you need to specify both the source and the target for the tf merges command, in order to see the partial merges. This was a decision made by the product group in order to improve the performance of tf merges.

In the output you will see an asterisk (*) next to changeset 138 which indicates that it is a partial merge. That means that only part of changeset 138 has been merged into changeset 139. If we take a look at the merge candidates from Dev to Main, we will see that even though we already merged changeset 138 to Main, it is still a merge candidate. This is caused by the fact that the merge engine detected that there are still some changes in changeset 138 which were not propagated from Dev to Main.

C:\Samples >tf merge Dev Main /recursive /candidate

Changeset    Author Date
------------------ ------------------- ----------------
138 lszomoru 4/30/2009


Scenario 2

Consider that you have two branches Main and Dev, each of them has two folders (Feature1 and Feature2) and each feature folder contains one file. We edit both files from the feature folders (Dev\Feature1\feature1.txt and Dev\Feature2\feature2.txt) and check-in the changes.

There are many scenarios in which a merge operation is performed at the feature level first and not from the top of the branch. Let’s see what happens if we perform the merge at the Feature1 level. Let’s get the candidates first:

C:\Samples>tf merge Dev\Feature1 Main\Feature1 /candidate /recursive

Changeset    Author Date
------------------ ------------------- ----------------
142 lszomoru 4/30/2009


Now perform the merge operation at the Feature1 level. You will notice in the Pending Changes window that only the edit done in the Feature1 folder will be merged. Complete the merge.

If you take a look at the merge history of the Feature1 folder you will see that all changes from changeset 142 have been merged into changeset 143.

C:\ Samples >tf merges Dev\Feature1 Main\Feature1 /recursive

Changeset    Merged in Changeset Author Date
------------------ ---------------------------- ------------------- ----------------
142 143 lszomoru 4/30/2009

However if you take a look at the merge history of Main you will see that only parts of changeset 142 have been merged into changeset 143. This is normal as changeset 142 has some changes - the edit of the file in the Feature2 folder - which were not delivered.

C:\ Samples >tf merges Dev Main /recursive

Changeset    Merged in Changeset Author Date
------------------ ---------------------------- ------------------- ----------------
142* 143 lszomoru 4/30/2009



In case of a partial merge, how do we figure what changes have been merged and what changes from the changeset were left out. The only way to achieve this is to diff the contents of the changeset that was partially merged, and the contents of the changeset that was generated as the result of the merge.

In case of our second scenario we need to check the details of changeset 142 and 143…

C:\Samples >tf changeset 142 /i

C:\Samples >tf changeset 143 /i

Changeset: 142

User: lszomoru

Date: Thursday, April 30, 2009 7:21:07 AM



  edit $/Samples/dev/feature1/file1.txt

  edit $/Samples/dev/feature2/file2.txt

Changeset: 143

User: lszomoru

Date: Thursday, April 30, 2009 7:28:27 AM



  merge, edit $/Samples/main/feature1/file1.txt

Check-in Notes:

  Code Reviewer:

  Performance Reviewer:

  Security Reviewer:

If you diff the list of files under Items, you will see that only the chances for file1.txt have been propagated. In case we choose to perform the merge either at the Feature2 folder level or from the top of the branch the changes made on file2.txt will be merged.

A frequent question that we get from our customers is “Why is changeset xxx listed as a merge candidate when the changeset has already been merged”? The answer is that if changeset xxx is marked as a merge candidate it means that it contains some changes that were not merged from the source to the target. It is possible that only parts of the changeset have been merged.


Comments (6)

  1. Matt Mitrik says:

    Ladislau Szomoru, a CSS Engineer for TFS, just posted a great blog post about partial merges on the CSS

  2. Mohamed Mahmoud on How to: Query all labels on a folder recursively Brian Harry on Power Tool for Profiling

  3. Before setting up my own blog, I have been posting on the Developer Support Team Foundation Server blog.

  4. Nick says:

    What about finding changesets that are *still* partial merged? Someone could have partial merged a changeset and then merged the rest of it at a later time, the entire changeset was merged but still shows an asterisk when you run tf merges.

  5. Mirko says:


    greate post. We have some of your "problems" in our work and we have one other problem that we could not explain. Maybe you have any idea.

    1. We have 2 branches Main and Dev and 2 Files BLClass and AssemblyInfo.cs

    2. We make 1 changes in the Dev branch in both files.

    3. We merge from the root of the Dev branch all changed items to the main branch and CheckIn.

    4. Now we check both changesets. Every changeset have both files in the items and the hole changed code is taken.

    5. We don´t have any more merge candidates from Dev to Main.

    6. But the first CheckIn at the Dev Branch is marked as partial in the track changeset history

    7. But the Merge CheckIn at the Main branch is a merge candidate to Dev (where you comes from!)

    I couldn´t understand this scenario. Have anyone a idear for me?


  6. Sean says:

    So what is the best way to fix a partial merge? I several issues I cannot seem to fix and not sure how to.

Skip to main content