Have you ever had to do any forensic work on TFS merges, tracking down what you or a member of your team has done? For example, when changes have been merged into a branch and an attempt is made to merge again with the same source and target, TFS may respond with “No changes to merge”. This may be expected, but you might like to see what TFS already knows with regards to which changesets have already been merged. That is just one example of something you may need to investigate. Recently, Philip Kelley from the TFS dev team provided this little write-up on that type of work. I present it now for your reading pleasure. Hopefully it will help with the sleuthing!
The way to answer questions like this is with the “tf merges” command and the “tf merge /candidate” command.
“tf merges $/Source/file.txt $/Target/file.txt” asks the question, “What changesets have I already merged from $/Source/file.txt to $/Target/file.txt? What changeset was each merge committed in in the target?” You get output a bit like this.
D:\>tf merges $/Source/File.cs $/Target/File.cs
Changeset Merged in Changeset Author Date
——— ——————- ——————————– ———- ———-
437213 500301 REDMOND\asdfasdf 7/19/2008
559688 600202 REDMOND\asdfasdf 10/15/2008
683776 708113 REDMOND\dddddd 1/16/2009
704497 706112 REDMOND\asdfasdf 1/14/2009
714056 727413 REDMOND\dddddd 1/31/2009
786117 788339 REDMOND\asdfasdf 3/17/2009
So here we can see that changeset 437213 to $/Source/File.cs was successfully merged to $/Target/File.cs in changeset 500301 (on 7/19/2008). Etc.
“tf merge /candidate $/Source/file.txt $/Target/file.txt” asks the question, “What changesets in the source have I not merged to the target yet – that is, which ones are eligible for merging?” Here again is some sample output.
D:\>tf merge /candidate $/Source/File.cs $/Target/File.cs
Changeset Author Date
——— ——————————– ———-
751713 REDMOND\lalalal 2/20/2009
Here we see a single changeset eligible for merging to the target. If I say “tf merge $/Source/File.cs $/Target/File.cs” then I will see a merge pended which brings this changeset to the target. If I say “tf merge $/Source/File.cs;C700000 $/Target/File.cs” then I am asking for eligible changesets in the range 1-700000 to be merged and 751713 is outside of this range, so I’ll see “No changes to merge.”
Any time these merge history tables are going to be updated by a change, you will see the “merge” bit pending on the item. This indicates that some sort of credit is being given for a merge. At least one new line will show up in “tf merges” as a result of the changeset.
You can give credit for a merge without actually taking the content changes. This is the purpose of the /discard switch to tf merge – it says, pend a change in the target which gives credit for some changes, but does not actually bring them to the target branch. You can also accomplish the same thing when there’s a conflict by selecting “Keep target version.” This gives credit for the changeset merging over but leaves the content alone. In both cases you’ll see a “merge” change standing alone. In future merges this change will not come over again.
If you’ve given credit for a changeset already and want to merge it “again” – maybe I wanted to bring changeset 786117 from $/Source/File.cs to $/Target/File.cs again – then I could use the /force option to tf merge. The /force says, ignore the merge history that says the change(s) are already in the target. I want you to bring them over again. You can do this for a range of changesets or just a particular one. For just 786117 I would say “tf merge /force $/Source/File.cs;C786117~786117 $/Target/file.cs”.