May 1st, 2006

Compare the content changes in a shelveset with any checked-in version

Buck Hodges
Director of Engineering

I wrote this snippet recently to compare the edited files in a shelveset with an arbitrary checked-in version of the same files.  It’s another example of how to use the API to show differences.  See How to compare (diff) trees at different versions using the API for a different example of comparing checked-in files.

If you are just getting started with the version control API, you’ll want to start with the basic example.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.VersionControl.Common;

namespace DiffShelveset
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                Console.Error.WriteLine(“This command shows the differences between the shelved edits”);
                Console.Error.WriteLine(“and the specified version of the same files.”);
                Console.Error.WriteLine(”  Usage: diffshelveset shelvset[;shelvesetOwner] versionSpec”);
                Console.Error.WriteLine(”  Example: diffshelveset BugFix;Alice C123″);
                Environment.Exit(1);
            }

            // Determine the server by using the local workspace cache.
            WorkspaceInfo wsInfo = Workstation.Current.GetLocalWorkspaceInfo(Environment.CurrentDirectory);
            if (wsInfo == null)
            {
                Console.Error.WriteLine(“The current directory is not part of a workspace.”);
                Environment.Exit(1);
            }

            TeamFoundationServer tfs = new TeamFoundationServer(wsInfo.ServerUri.AbsoluteUri);
            VersionControlServer versionControl = (VersionControlServer) tfs.GetService(typeof(VersionControlServer));

            try
            {
                DiffShelvedChanges(versionControl, args[0], args[1]);
            }
            catch (VersionControlException e)
            {
                Console.Error.WriteLine(e.Message);
                Environment.Exit(1);
            }
        }

        static void DiffShelvedChanges(VersionControlServer versionControl,
                                       String shevlesetArg, String versionArg)
        {
            // A TeamFoundationServer object is always the “parent” of a VersionControlServer
            // object.
            TeamFoundationServer tfs = versionControl.TeamFoundationServer;

            // The shelvesetName;shelvesetOwner format is exactly the same as
            // workspaceName;workspaceOwner, so the same class is used for parsing both.
            String shelvesetName, shelvesetOwner;
            WorkspaceSpec.Parse(shevlesetArg, RepositoryConstants.AuthenticatedUser,
                                out shelvesetName, out shelvesetOwner);

            // To improve performance, the PendingChange objects do not normally contain the URLs for
            // downloading the file content.  In this case, we know that we are going to be downloading
            // the file contents, so we set the last parameter to true.  Since we want all changes in
            // the shelveset, we specify null for the ItemSpecs.
            PendingSet[] pendingSets = versionControl.QueryShelvedChanges(shelvesetName, shelvesetOwner,
                                                                          nulltrue);
            if (pendingSets.Length == 0)
            {
                Console.Error.WriteLine(“No shelveset matched.”);
                Environment.Exit(1);
            }
            else if (pendingSets.Length > 1)
            {
                Console.Error.WriteLine(“More than one shelveset matched.”);
                Environment.Exit(1);
            }

            PendingChange[] shelvedChanges = pendingSets[0].PendingChanges;
            if (shelvedChanges.Length == 0)
            {
                Console.Error.WriteLine(“You don’t have permission to any of the files involved.”);
                Environment.Exit(1);
            }

            // Convert the string argument into a ChangesetVersionSpec, LabelVersionSpec, DateVersionSpec,
            // or WorkspaceVersionSpec (all derive from the abstract VersionSpec class).
            VersionSpec versionSpec = VersionSpec.ParseSingleSpec(versionArg,
                                                                  RepositoryConstants.AuthenticatedUser);

            // Now we can diff each change against the version specified.
            foreach (PendingChange shelvedChange in shelvedChanges)
            {
                // We only want files that are being edited, but there’s nothing to diff if 
                // the file is guaranteed not to exist at a different version.
                if (shelvedChange.ItemType != ItemType.File ||
                    !shelvedChange.IsEdit || shelvedChange.IsAdd || shelvedChange.IsBranch)
                {
                    continue;
                }

                DiffItemShelvedChange diffChange = new DiffItemShelvedChange(shelvesetName,
                                                                             shelvedChange);

                // We could have directly created a DiffItemVersionedFile, however it wouldn’t
                // take into account the fact that the file may have had a different name.
                // The CreateTargetDiffItem() will take care of all the arcane details, whereas
                // the constructor assumes you are specifying exactly what you want.
                IDiffItem diffVersion = Difference.CreateTargetDiffItem(versionControl,
                                                                        shelvedChange,
                                                                        versionSpec);

                // Since the VisualDiff*() methods do not block, we call the more specific
                // method so that we can have the call block until the external tool exits.
                // If you want to see an example of producing textual diff output instead,
                // see the diff call in
                // http://blogs.msdn.com/buckh/archive/2006/04/06/project_diff.aspx.
                DiffOptions diffOpts = new DiffOptions();
                diffOpts.UseThirdPartyTool = true;
                Difference.DiffFiles(versionControl, diffVersion, diffChange, diffOpts,
                                     String.Empty, true);
            }
        }
    }
}

Author

Buck Hodges
Director of Engineering

Director of Engineering, Azure DevOps

0 comments