Finding What’s Out of Date In your Workspace

A couple of customers have asked me about this in the past couple of weeks:  “How can I tell in my workspace, how far out of date are my files?”

TFS knows if your file is out-of-date and will tell you simply by showing you a “No” in the Latest column in Source Control Explorer:

Source Control Explorer

But what if you want to know how far out of date your file is?  You can see this by accessing the properties of the file (right-click, select Advanced->Properties):

File properties

As you can see in the above screenshot, I’m one version behind.

Easy, right?

But what if I want to know this for all the files in my workspace?  Using the built-in mechanisms, I’d have to look at the properties of each file that shows “No” in the Latest column.  That could take a while!

As a side note, if I don’t care how far out of date I am, but I at least want to know all the files that are out-of-date, I could use the /preview switch on the command line tf get:

command line

Notice that a.txt and d.txt in the command line correspond with what’s shown as out-of-date in the first screenshot. (BTW, nothing actually happened because I specified /preview.  And the “Replacing” tells me that these files need to be replaced, or “caught up”.

However, let’s assume I want to know the workspace and server versions for all my files that are outdated in my workspace.  There’s not a very convenient manner to do this without several clicks, but it’s surprisingly easy through the TFS API.

Here’s a quick, full sample console application that:

  1. Connects to my TFS server (only works for “on prem” TFS, not TF Service (it will work, but not by using WindowsIdentity))
  2. Grabs your workspace
  3. For each file in your workspace, checks to see if the workspace version is different than the server version.
  4. Spits everything out to the console.

The code isn’t anything special (I’m not a developer by trade), but it works.

 using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;

namespace WorkspaceVersions
{
    class Program
    {
        private const string _TfsUrl = "https://<myTFS>/defaultcollection";
        private const string _TfsProject = "$/<myproject>";
        private const bool _OnlyListOutOfDate = true;

        static void Main(string[] args)
        {
            Print("Connecting to TFS..");
            // Connect to the team project collection and the server that hosts the 
            // version-control repository. 
            TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(
               new Uri(_TfsUrl));
            VersionControlServer vcServer = tpc.GetService<VersionControlServer>();
            
            // Get workspace versions
            ListWorkspaceVersions(vcServer, _TfsProject);

            Print("");
            Print("Finished.");

            Console.ReadLine();
        }

        /// <summary>
        /// Silly convenience method for printing a line of text to the console.
        /// </summary>
        /// <param name="text"></param>
        private static void Print(string text)
        {
            Console.WriteLine(text);
        }
        private static void ListWorkspaceVersions(VersionControlServer vcs, string project)
        {
            Print("Getting workspace..");
            var workspace = vcs.QueryWorkspaces(null, WindowsIdentity.GetCurrent().Name, 
                System.Environment.MachineName).First();

            Print("Getting working folder for the project..");
            var folder = workspace.Folders.First(f => f.ServerItem == project);

            Print("Getting local versions..");
            List<LocalVersion[]> items = workspace.GetLocalVersions(new[] { 
                new ItemSpec(folder.LocalItem, RecursionType.Full) }, 
                false).ToList<LocalVersion[]>();

            if (_OnlyListOutOfDate)
                Print("NOTE: Only listing items which are out-of-date");

            foreach (LocalVersion[] locals in items)
            {
                foreach (LocalVersion item in locals)
                {
                    int serverversion = vcs.QueryHistory(
                        new ItemSpec(workspace.GetServerItemForLocalItem(item.Item),RecursionType.Full),
                        1).First<Changeset>().ChangesetId;
                    if ((_OnlyListOutOfDate && (serverversion != item.Version)) || _OnlyListOutOfDate == false)
                    {
                        Print(item.Item);
                        Print(String.Format("   Server: {0}, Local: {1}", serverversion, item.Version));
                    }
                }
            }
        }
    }
}

If you are comfortable in the command line, this may work out well for you.