15
votes

I have Visual Studio 2008 and TFS.
I can click on specific folder in Source Coontrol Explorer and click view history.

Then I see list of all changesets.

Then I can double click on one change set and see files and folder path that were changed in that changeset (Details for Changeset)

I would like to see list of all files and paths for many changesets for specific folder in Source Control Explorer.

Example:

ChangesetId: 1 User: A Date: today Comment: Fix
ChangesetId: 2 User: B Date: today Comment: Fix2

If I click on Changeset 1 I see this:
Name: class1.vb change: merge, edit Folder C:\work
Name: class2.vb change: merge, edit Folder C:\work

If I click on Changeset 2 I see this:
Name: class3.vb change: merge, edit Folder C:\PetProject
Name: class4.vb change: merge, edit Folder C:\PetProject

What I want to see in one list is this:

ChangesetId: 1 User: A Date: today Comment: Fix Name: class1.vb change: merge, edit Folder C:\work

ChangesetId: 1 User: A Date: today Comment: Fix Name: class2.vb change: merge, edit Folder C:\work

ChangesetId: 2 User: B Date: today Comment: Fix2 Name: class3.vb change: merge, edit Folder C:\PetProject

ChangesetId: 2 User: B Date: today Comment: Fix2 Name: class4.vb change: merge, edit Folder C:\PetProject

Can I query some table in TFS database to get this list or can I see it somewhere in TFS?

3
did you tried tf history or tf changeset?Kiquenet

3 Answers

9
votes

You're probably looking for the tf history command:

tf history /server:http://tfs:8080 "$/path/to/what/you/want" /recursive /noprompt /format:detailed

If you have a lot of changes, you can use /version: to limit, or you can do a /stopafter:xx to limit the results to only 'xx' entries. The data comes back in reverse date order, I believe, so you get all of the newest changes first.

10
votes

you can get this information from the command line. it only does one change at a time, but you could write a script to do this for all of them:

 tf changeset /noprompt 55421

this outputs something like this:

Changeset: 55421
User: dsmith
Date: 09 November 2010 12:41:25

Comment:
  Fix to threading bug in connector

Items:
  edit $/Project/products/App/Dev/Source Code/Utils.cpp
  edit $/Project/products/App/Dev/Source Code/Connector.cpp
  edit $/Project/products/App/Dev/Source Code/Utils.h

Check-in Notes:
  Code Reviewer:
  Performance Reviewer:
  Security Reviewer:

if you have to have the output exactly as you specified it, then you would be best writing some code with the TFS SDK

0
votes

This will give list of files for a specific work item attached to all change sets while checking in. At least it solved the purpose for me.

Reference: http://obscureproblemsandgotchas.com/uncategorized/how-to-get-all-files-modified-for-work/

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

/// <summary>
/// Wrapper class for performing basic TFS queries
/// </summary>
public class TfsUtilities
{
 public string TfsUri { get; private set; }

 TfsTeamProjectCollection Server { get; set; }
 VersionControlServer VersionCS { get; set; }
 WorkItemStore Store { get; set; }

 /// <summary>
 /// Initialize this class to work with the specified Server (URI)
 /// </summary>
 /// <param name="tfsUri">The URI for the desired TFS server</param>
 public TfsUtilities(string tfsUri)
 {
  TfsUri = tfsUri;

  Server = GetServer();

  VersionCS = Server.GetService(typeof(VersionControlServer)) as VersionControlServer;

  Store = new WorkItemStore(Server);
 }

 /// <summary>
 /// Get a reference to the specified server
 /// </summary>
 /// <returns>TFS Server at Collection Level</returns>
 private TfsTeamProjectCollection GetServer()
 {
  return TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(TfsUri));
 }

 /// <summary>
 /// Get items recursively in TFS via a direct TFS path.
 /// </summary>
 /// <param name="tfsPath">A path in the current TFS server</param>
 /// <returns>All items found</returns>
 public ItemSet GetTeamProjectItems(string tfsPath)
 {
  ItemSet items = VersionCS.GetItems(@"$" + tfsPath, RecursionType.Full);
  //ItemSet items = version.GetItems(@"$ProjectNameFileName.cs", RecursionType.Full);

  foreach (Item item in items.Items)
   System.Console.WriteLine(item.ServerItem);

  return items;
 }

 /// <summary>
 /// Query for all or a specific work item in a team project
 /// </summary>
 /// <param name="teamProject">team project name</param>
 /// <param name="workItemID">Optional - work item ID</param>
 /// <returns>Work Item Collection</returns>
 public WorkItemCollection GetWorkItems(string teamProject, int workItemID = 0)
 {
  string strSQL = 
  " SELECT [System.Id], [System.WorkItemType]," +
  " [System.State], [System.AssignedTo], [System.Title] " +
  " FROM WorkItems " +
  " WHERE [System.TeamProject] = '" + teamProject +"' ";

  if (workItemID > 0)
   strSQL += " AND [System.Id] = " + workItemID;

  strSQL += " ORDER BY [System.WorkItemType], [System.Id]";

  WorkItemCollection workItems = Store.Query(strSQL);

  foreach(WorkItem item in workItems)
   Console.WriteLine(item.Id);

  return workItems;
 }

 /// <summary>
 /// Get all of the Files/Items that were modified and associated with a Work Item
 /// </summary>
 /// <param name="teamProject">Name of the Team Project</param>
 /// <param name="workItemID">The work item ID</param>
 /// <returns>List of changes</returns>
 public List<FileItem> GetAllFilesModifiedForWorkItem(string teamProject, int workItemID)
 {
  WorkItemCollection workItems = GetWorkItems(teamProject, workItemID);

  if (workItems.Count == 0)
  {
   Console.WriteLine("No Items found for Work Item ID: " + workItemID);

   return null;
  }

  WorkItem item = workItems[0];

  Console.WriteLine("Work Item {0} has {1} Links", workItemID, item.Links.Count);

  if(item.Links.Count == 0)
   return null;

  List<Changeset> lstChangesets = GetChangesets(item.Links);

  Console.WriteLine("Work Item {0} has {1} Changesets", workItemID, lstChangesets.Count);

  if (lstChangesets.Count == 0)
   return null;

  List<FileItem> lstItems = GetItemsForChangeset(lstChangesets);

  Console.WriteLine("Work Item {0} has {1} Items (changes)", workItemID, lstItems.Count);

  if (lstItems.Count == 0)
   return null;

  return lstItems;
 }

 /// <summary>
 /// Get all of the items, regardless of duplicates, changed for each provided changeset
 /// </summary>
 /// <param name="changesets"></param>
 /// <returns></returns>
 public List<FileItem> GetItemsForChangeset(List<Changeset> changesets)
 {
  List<FileItem> lst = new List<FileItem>();

  foreach (Changeset obj in changesets)
  {
   Console.WriteLine("Changeset {0} has {1} Items", obj.ChangesetId, obj.Changes.Length);

   lst.AddRange(GetItemsForChangeset(obj));
  }

  return lst;
 }

 /// <summary>
 /// Get all of the changed files/items associated with this changeset
 /// </summary>
 /// <param name="changeset"></param>
 /// <returns></returns>
 public List<FileItem> GetItemsForChangeset(Changeset changeset)
 {
  FileItem t = null;

  List<FileItem> lst = new List<FileItem>();

  foreach (Change obj in changeset.Changes)
  {
   t = new FileItem() { CheckinDate = obj.Item.CheckinDate, ChangeType = obj.ChangeType, TfsPath = obj.Item.ServerItem };

   Console.WriteLine("Item {0} : {1} - {2} - {3}", obj.Item.ItemId, t.CheckinDate, t.ChangeType, t.TfsPath);

   lst.Add(t);
  }

  return lst;
 }

 /// <summary>
 /// Get all of the Changesets from a collection of links (Links in a Work Item)
 /// </summary>
 /// <param name="workItemLinks">The links of a work item</param>
 /// <returns>All of the found changesets - can be returned empty</returns>
 public List<Changeset> GetChangesets(LinkCollection workItemLinks)
 {
  Changeset cs = null;

  List<Changeset> lst = new List<Changeset>();

  foreach (Link obj in workItemLinks)
  {
   cs = ConvertToChangeSet(obj);

   if (cs != null)
    lst.Add(cs);
  }

  return lst;
 }

 /// <summary>
 /// Convert the provided Link to a Changeset.
 /// If the conversion cannot be made, null is returned.
 /// </summary>
 /// <param name="workItemLink">Work Item Link</param>
 /// <returns>Changeset or null</returns>
 public Changeset ConvertToChangeSet(Link workItemLink)
 { 
  Changeset cs = null;

  ExternalLink externalLink = workItemLink as ExternalLink;

  if (externalLink != null)
  {
   ArtifactId artifact = LinkingUtilities.DecodeUri(externalLink.LinkedArtifactUri);

   if (String.Equals(artifact.ArtifactType, "Changeset", StringComparison.Ordinal))
   {
    // Convert the artifact URI to Changeset object.
    cs = VersionCS.ArtifactProvider.GetChangeset(new Uri(externalLink.LinkedArtifactUri));
   }
  }

  return cs;
 }

 //http://stackoverflow.com/questions/3619078/what-is-the-fastest-method-of-retrieving-tfs-team-projects-using-the-tfs-sdk-api
 /// <summary>
 /// Get all of the Team Project Names for the current TFS Server's Collection
 /// </summary>
 /// <returns>List of team project names</returns>
 public List<string> GetTeamProjectNames()
 {
  return Server.GetService<VersionControlServer>()
      .GetAllTeamProjects(false)
      .Select(x => x.Name)
      .ToList();
 }
}

//Code for the FileItem class (not entirely necessary)
using System;
using Microsoft.TeamFoundation.VersionControl.Client;

public class FileItem
{
 public DateTime CheckinDate { get; set; }

 public string ChangeTypeString 
 { 
  get { return ChangeType.ToString(); } 
 }

 public ChangeType ChangeType { get; set; }

 public string TfsPath { get; set; }
}