TFS 2008 Source Control - A Quick Way to Destroy All Deleted Items

I have a bunch of source management folders for which I want to get rid of all the elements that are no longer required. These items were deleted (code was moved or rewritten), and since most of us use the Show Deleted Items option by default, some of these folders now show more deleted items and folders and legal items. I want all this redundant code to go away, forever - since it will definitely never be needed. These are new projects that are built from old branches that are not yet in use.

However, quite a few files are distributed across several folders, so I would prefer not to do each separately. I am also on the command line without using the API.

I know that ultimately I will need the tf destroy command.

I also know that tf dir [wildcard] /recursive /deleted will return all deleted items in the path (unfortunately, along with all legal items).

Can anyone think of a good way to do this quickly?

I thought of two solutions:

1) Take the output of the dir command and find all the elements with :Xnnnnnnn after - these are the deleted elements; then just spit out a bunch of tf to destroy calls or create an answer file (but not sure about this bit). This sounds like a potential use for Powershell, but nothing really has been done with it ...

2) Prepare all the projects, and then simply destroy them from TFS, and then add them again so that only the necessary material is in TFS. However, this removes the branch connection, which may be useful because for some time I will have to support two versions of some of these libraries (before and after the update). Not perfect, but there is nothing I can do about it.

Obviously, option 2 is a trickster, but it will work - I would ideally like to use a reusable script that could be used for any folder in TFS in the future (several other teams have other long-lived projects that can do with full cleaning!) .

Thanks in advance.

+6
version-control c # tfs visual-studio-2008
source share
2 answers

Ok, so I wrote a console application (.Net 4):

THIS DOES NOT HAVE WITHOUT A TELL I DO NOT PROVIDE ANY WARRANTY OF THIS IT - IT WILL DESTROY THE ITEMS IN TFS !!!!

Update (May 8, 2012) If you run this in a folder with masses and masses (I mean thousands or tens of thousands) of deleted items, they may not finish before the TFS command line expires. Most of the time this command takes is to create a .tfc script. If you run it and find that this is happening, try moving some child folders first

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Text.RegularExpressions; using System.Diagnostics; namespace TFDestroyDeleted { class Program { static void Main(string[] args) { if (args.Length < 1 || args.Length > 3) Usage(); bool prepareOnly = false; bool previewOnly = false; if (args.Any(s => StringComparer.InvariantCultureIgnoreCase .Compare(s, "preview") == 0)) previewOnly = true; if (args.Any(s => StringComparer.InvariantCultureIgnoreCase .Compare(s, "norun") == 0)) prepareOnly = true; string tfOutput = null; Process p = new Process(); p.StartInfo = new ProcessStartInfo("tf") { Arguments = string.Format ("dir /recursive /deleted \"{0}\"", args[0]), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true }; p.Start(); tfOutput = p.StandardOutput.ReadToEnd(); p.WaitForExit(); string basePath = null; string nextDelete = null; List<string> toDelete = new List<string>(); using (var ms = new MemoryStream(Encoding.Default.GetBytes(tfOutput))) { using (StreamReader sr = new StreamReader(ms)) { while (!sr.EndOfStream) { nextDelete = null; string line = sr.ReadLine(); if (string.IsNullOrWhiteSpace(line)) basePath = null; else { if (basePath == null) { if (line.EndsWith(":")) basePath = line.Substring(0, line.Length - 1); else continue; } else { nextDelete = Regex.Match(line, @"^.*?;X[0-9]+").Value; if (!string.IsNullOrWhiteSpace(nextDelete)) { toDelete.Add( string.Format ( "{0}/{1}", basePath, nextDelete.StartsWith("$") ? nextDelete.Substring(1) : nextDelete )); } } } } } } using (var fs = File.OpenWrite("destroy.tfc")) { fs.SetLength(0); using (var sw = new StreamWriter(fs)) { //do the longest items first, naturally deleting items before their //parent folders foreach (var s in toDelete.OrderByDescending(s => s.Length)) { if (!previewOnly) sw.WriteLine("destroy \"{0}\" /i", s); else sw.WriteLine("destroy \"{0}\" /i /preview", s); } sw.Flush(); } } if (!prepareOnly) { p.StartInfo = new ProcessStartInfo("tf") { Arguments = string.Format("@{0}", "destroy.tfc"), UseShellExecute = false }; p.Start(); p.WaitForExit(); } p.Close(); } static void Usage() { Console.WriteLine(@"Usage: TFDestroyDeleted [TFFolder] (preview) (norun) Where [TFFolder] is the TFS root folder to be purged - it should be quoted if there are spaces. Eg: ""$/folder/subfolder"". norun - Specify this if you only want a command file prepared for tf. preview - Specify this if you want each destroy to be only a preview (ie when run, it won't actually do the destroy) "); Environment.Exit(0); } } } 

You must transfer the TFS folder for deletion, for example '$ / folder'. If you just pass it on, then all relevant deleted items will be detected and destroyed one by one.

For some reason - if you accidentally transfer a folder that doesnโ€™t actually exist, the operation is done forever. Of course, CTRL + C will stop it.

An application executes a recursive directory in a folder using the /deleted switch.

Then it goes through each line in the output, looking for a delete hint, i.e. elements c ;Xnnnnnnn . If found, it adds the full tfs list for this item to the list.

After completion, the list is sorted by length in descending order and the contents recorded in the tfc response file for the tf.exe command line.

If the preview parameter is specified, then tf commands are written using the / preview switch (see TFS Destroy on MSDN). Then deletions are not actually performed.

Finally, you can specify norun , which causes the tfc file to be created, but is not actually executed.

+10
source share

I know this is an old question, but I think it might be helpful.

We have an old collection with 20+ team projects under VSO and it is really necessary to clean our team projects. This code worked great for us.

 using Microsoft.TeamFoundation.Client; using Microsoft.TeamFoundation.VersionControl.Client; static void Main(string[] args) { TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri("COLLECTION_URL")); //Example: https://xxxx.visualstudio.com var versionControl = tfs.GetService<VersionControlServer>(); ItemSpec spec = new ItemSpec("$/", RecursionType.Full); var folderItemSet = versionControl.GetItems(spec, VersionSpec.Latest, DeletedState.Deleted, ItemType.Folder, true); DestoryItemSet(versionControl, folderItemSet); //Delete remaining files var fileItemSet = versionControl.GetItems(spec, VersionSpec.Latest, DeletedState.Deleted, ItemType.File, true); DestoryItemSet(versionControl, fileItemSet); } private static void DestoryItemSet(VersionControlServer versionControl, ItemSet itemSet) { foreach (var deletedItem in itemSet.Items) { try { versionControl.Destroy(new ItemSpec(deletedItem.ServerItem, RecursionType.Full, deletedItem.DeletionId), VersionSpec.Latest, null, Microsoft.TeamFoundation.VersionControl.Common.DestroyFlags.None); Console.WriteLine("{0} destroyed successfully.", deletedItem.ServerItem); } catch (ItemNotFoundException) //For get rid of exception for deleting the nested objects { } catch (Exception) { throw; } } } 

I used the Microsoft.TeamFoundationServer.ExtendedClient NuGet package.

+2
source share

All Articles