I will be covering three things in this blog post:
- Get the history, i.e., all change sets of an item programmatically using the TFS API
- Download the change sets programmatically using the TFS API
- Use WinMerge to compare those change sets programmatically
1. How Do I Get the History of a File Using TFS API?
The VersionControlServer Class exposes the QueryHistory method that gets you all changesets that have impacted a file or folder you are querying for.
public IEnumerable QueryHistory(
string path,
VersionSpec version,
int deletionId,
RecursionType recursion,
string user,
VersionSpec versionFrom,
VersionSpec versionTo,
int maxCount,
bool includeChanges,
bool slotMode
}
Example: Query the history of file TfsRepository.cs placed in the source control at ‘$/Temp_UK_1/Development/Prod/Source/TfsWorkspaceManager/TfsWorkspaceManager/TfsRepository.cs’.
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection
(new Uri("https://tfs2010:8080/defaultcollection"));
var vsStore = tfs.GetService<VersionControlServer>();
var histories =
vsStore.QueryHistory(
"$/Temp_UK_1/Development/Prod/Source/
TfsWorkspaceManager/TfsWorkspaceManager/TfsRepository.cs",
VersionSpec.Latest, 0, RecursionType.OneLevel, null,
null, null, Int32.MaxValue, true, false, true);
foreach (Changeset history in histories)
{
}
Histories
is IEnumerable
, as we enumerate we convert history
to type changeset. Let’s see the results:
There are two overloads:
- bool includeDownloadInfo: A flag that describes whether to get the information necessary to download the change sets from the server
- bool sortAscending: A flag that describes whether to sort the results in ascending order. Specify
false
to not sort the results.
2. Download the Files in the Changeset Programmatically
The Item Class exposes the DownloadFile method that downloads the content for this version of the item.
Example: Download all changesets of the TfsRepository.cs file to Windows Temp folder.
public static void DownloadHistoryChangesetsToTempFolder()
{
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection
(new Uri("https://tfs2010:8080/defaultcollection"));
tfs.EnsureAuthenticated();
var vsStore = tfs.GetService<VersionControlServer>();
var histories =
vsStore.QueryHistory(
"$/Temp_UK_1/Development/Prod/Source/
TfsWorkspaceManager/TfsRepository.cs",
VersionSpec.Latest, 0, RecursionType.OneLevel,
null, null, null, Int32.MaxValue, true, false, true);
foreach (Changeset history in histories)
{
foreach (Change change in history.Changes)
{
change.Item.DownloadFile(System.IO.Path.GetTempPath() + change.Item.ChangesetId +
change.Item.ServerItem.Split('/')
[change.Item.ServerItem.Split('/').Length - 1]);
}
}
}
Screen shot of the windows temp folder:
3. Compare the Downloaded Versions Programmatically using WinMerge
Download and Install WinMerge. WinMerge is an Open Source differencing and merging tool for Windows. WinMerge can compare both folders and files, presenting differences in a visual text format that is easy to understand and handle. You can read more about how to change the default Compare and Merge tool in Team Foundation Server in my earlier blog post here.
Example: Compare the earlier downloaded history versions of TfsRepository.cs from the windows temp folder.
WinMerge command line access with a bunch of useful arguments. You can do WinMergeU.exe /? to get the details of the arguments.
WinMerge[U] [/r] [/e] [/f filter] [/x] [/s] [/ul] [/ur] [/u] [/wl] [/wr] [/minimize] [/maximize] [/dl leftdesc] [/dr rightdesc] leftpath rightpath [outputpath]
WinMerge[U] conflictfile
public static void CompareTwoChangeSets()
{
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection
(new Uri("https://tfs2010:8080/defaultcollection"));
tfs.EnsureAuthenticated();
var vsStore = tfs.GetService<VersionControlServer>();
var histories =
vsStore.QueryHistory(
"$/Temp_UK_1/Development/Prod/Source/TfsWorkspaceManager/
TfsWorkspaceManager/TfsWorkspaceManager/TfsRepository.cs",
VersionSpec.Latest, 0, RecursionType.OneLevel, null,
null, null, Int32.MaxValue, true, false, true);
foreach (Changeset history in histories)
{
foreach (Change change in history.Changes)
{
change.Item.DownloadFile(System.IO.Path.GetTempPath() +
change.Item.ChangesetId +
change.Item.ServerItem.Split('/')[
change.Item.ServerItem.Split('/').Length - 1]);
}
}
var winmerge = Process.Start(@"C:\Program Files
(x86)\WinMerge\WinMergeU.exe",
String.Format("{0}{1} {0}{2}",
System.IO.Path.GetTempPath(),
@"\36TfsRepository.cs",
@"\37TfsRepository.cs"));
}
So, I am starting a Process to consume the WinMergeU.exe and passing the 2 versions of the file that I want to compare. You can also use the following arguments:
/r
compares all files in all subfolders (recursive compare). Unique folders (occurring only on one side) are listed in the compare
result as separate items. Note that including subfolders can increase compare time significantly. Without this parameter, WinMerge lists only files and subfolders at the top level of the two target folders. It does not compare the subfolders. /dl
specifies a description in the left side title bar, overriding the default folder or filename text. For example: /dl "Version 1.0"
or /dl WorkingCopy
. Use quotation marks around descriptions that contain spaces. /dr
specifies a description in the right side title bar, just like /dl
.
Screenshot of execution of the above method: