9

I want to export TFS source files of a particular changeset and/or multiple changesets in a series. Files should be exported to say D:\myTFSExport folder. This is not the existing mapped folder.

The purpose: I want to extract and review the CODEs of Build that contains these changesets after the Code are uploaded into TFS.

The following command of TFS Power Tool does not have any option for mentioning Destination folder.

tfpt getcs /changeset:changesetNo

Thanks in advance

Saikat Sur
  • 109
  • 2
  • 9

2 Answers2

16

How to extract a list of changesets

I had exactly this requirement in order to create patches for releases. I couldn't find anything in tfs or tfs power tools to do this, so I wrote my own.

To use, the syntax is a follows:

GetTfsChangeSet.exe TfsServerUrl changsetIdList fileOutputPath [merge]

where:

  • TfsServerUrl: The TFS server Url
  • changsetIdList : comma separated list of changesets
  • fileOutputPath: Output path (does not need to be mapped)
  • merge: With Merge param, combines all changesets into one folder. Without the param, each change set is output to a different folder.

e.g.

GetTfsChangeSet.exe http://asdpwiap017:8080/tfs 1233,4555,3332 c:\deploy merge

Create a console application solution.

Add these assembly references:

  • Microsoft.TeamFoundation.Client
  • Microsoft.TeamFoundation.Common
  • Microsoft.TeamFoundation.VersionControl.Client

Program.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;

namespace GetTfsChangeSet
{
    class Program
    {
        static void Main(string[] args)
        {

            if (args.Length < 3)
            {
                Console.WriteLine("Usage:");
                Console.WriteLine("GetTfsChangeSet.exe TfsServerUrl changsetIds fileOutputPath [merge]");
                Console.WriteLine();
                Console.WriteLine("where:");
                Console.WriteLine("- changsetIdList : comma separated list of changesets");
                Console.WriteLine("- merge: With Merge param, combines all changesets into one folder. Without the param, each change set is output to a different folder.");
                Console.WriteLine();
                Console.WriteLine("e.g.");
                Console.WriteLine(@"GetTfsChangeSet.exe http://asdpwiap017:8080/tfs 1233,4555,3332 c:\deploy merge");

                //Console.ReadKey();
                return;
            }

            string teamProjectCollectionUrl = args[0]; // "http://asdpwiap017:8080/tfs";
            var changesets = args[1].Split(',');
            string outputDir = args[2];
            bool mergeChangeSets = args.Length >= 4 && args[3].ToLower().Equals("merge");

            if (mergeChangeSets)
            {
                Console.WriteLine("Merge changesets " + args[1]);
            }

            TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(teamProjectCollectionUrl));
            string downloadPath = "";

            if (mergeChangeSets)
            {
                downloadPath = args[1].Replace(',', '-');
                if (downloadPath.Length > 30)
                {
                    downloadPath = downloadPath.Substring(0, 15) + "..." + downloadPath.Substring(downloadPath.Length-15);
                }
                downloadPath = Path.Combine(outputDir, downloadPath);
            }


            foreach (var changesetStr in changesets.OrderBy(c=>c))
            {
                var changeset = Convert.ToInt32(changesetStr);
                if (!mergeChangeSets)
                {
                    downloadPath = Path.Combine(outputDir, changeset.ToString());
                }

                var files = GetFilesAssociatedWithBuild(teamProjectCollection, changeset, downloadPath);

                Console.WriteLine(string.Format("ChangeSet {0}: {1} files extracted.", changeset, files.Count));
            }

            Console.WriteLine("Done.");
            //Console.ReadKey();
        }

        private static List<string> GetFilesAssociatedWithBuild(TfsTeamProjectCollection teamProjectCollection, int changesetId, string downloadPath)
        {
            List<string> files = new List<string>();
            VersionControlServer versionControlServer = teamProjectCollection.GetService(typeof(VersionControlServer)) as VersionControlServer;
            Changeset changeset = versionControlServer.GetChangeset(changesetId);
            if (changeset.Changes != null)
            {
                foreach (var changedItem in changeset.Changes)
                {
                    var item = changedItem.Item;
                    if (item.ItemType != ItemType.File || item.DeletionId != 0)
                        continue;

                    var outFilename = Path.Combine(downloadPath, item.ServerItem.Replace("$/", "").Replace("/", @"\"));
                    item.DownloadFile(outFilename);

                    files.Add(outFilename);
                }
            }
            return files;
        }
    }
}
AntonK
  • 2,303
  • 1
  • 20
  • 26
  • 5
    I wish I could upvote this answer a hundred of times. Thank you very much Anton ! – AFract Mar 30 '17 at 07:54
  • 2
    Glad I could help. – AntonK Apr 06 '17 at 07:13
  • 4
    To used this code on **VS2017** you need to NuGet: **Microsoft.TeamFoundationServer.ExtendedClient** Example NuGet Console command would be: `Install-Package Microsoft.TeamFoundationServer.ExtendedClient -Version 15.112.1` – Andrew Marais Aug 03 '17 at 10:38
  • 1
    If you get the error *"Unable to retrieve the registration information for ISCCProvider"*, you must add the collection to the URL, e.g. `http://asdpwiap017:8080/tfs/DefaultCollection` – DavidC Apr 02 '18 at 23:22
  • 1
    Oh this one saved my life – User2012384 Jun 02 '20 at 01:50
0

You can simply add another workspace that maps to the D:\myTFSExport folder and use

tf get $/MyProject /version:Cnnnn /recursive

Where nnnn is the desired changeset number.

Giulio Vian
  • 8,248
  • 2
  • 33
  • 41
  • One hint: you can use temporary workspace, that you delete immediately. Then use tf get or tfpt getcs – MichalMa May 22 '15 at 15:02