TFS 2008 Source Control: forma rápida de destruir todos los elementos eliminados

Tengo un montón de carpetas de control de origen para las que quiero deshacerme de todos los elementos que ya no se necesitan. Estos elementos se han eliminado (el código se ha movido o reescrito) y, como la mayoría de nosotros usamos la opción 'Mostrar elementos eliminados', algunas de estas carpetas ahora muestran más elementos y carpetas eliminados y artículos legítimos. Quiero asegurarme de que todo este código networkingundante se haya ido para siempre, ya que definitivamente nunca será necesario. Estos son proyectos nuevos que se están construyendo a partir de twigs de otros más antiguos que, hasta el momento, nadie está usando.

Sin embargo, hay una gran cantidad de files distribuidos en varias carpetas, así que prefiero evitar tener que hacer cada uno de manera individual. También estoy en la command-line, sin usar la API.

Sé que al final necesitaré el command tf destroy .

También sé que tf dir [wildcard] /recursive /deleted devolverá todos los elementos eliminados dentro de una ruta (desafortunadamente junto con todos los artículos legítimos).

¿Alguien puede pensar en una buena manera de hacer esto rápidamente ?

He pensado en dos soluciones:

1) Tome la salida del command dir y encuentre todos los elementos que tengan :Xnnnnnnn después: estos son los elementos eliminados; luego simplemente escupir un montón de tf destruir llamadas, o build un file de respuesta (aunque no estoy seguro de este bit). Esto parece ser un uso potencial para Powershell, pero aún no ha hecho nada con eso …

2) Prepare todos los proyectos, y luego simplemente destrúyalos de TFS y luego vuélvalos a agregar para que solo los elementos necesarios estén en TFS. Sin embargo, esto elimina la relación de sucursal, lo que podría ser útil porque durante un time tendré que mantener dos versiones de algunas de estas bibliotecas (pre y post actualización). No es ideal, pero no puedo hacer nada al respecto.

Obviamente, la Opción 2 es una trampa, pero funcionará: idealmente me gustaría tener un script reutilizable que pueda usarse para cualquier carpeta en TFS en el futuro (un par de otros equipos tienen otros proyectos de larga duración que podrían hacer con un purga completa!).

Gracias por adelantado.

Bien, entonces escribí una aplicación de console (.Net 4):

VALE SIN DECIR QUE NO OFREZCO NINGUNA GARANTÍA SOBRE ESTO – ¡DESTRUIRÁ ARTÍCULOS EN TFS !!!!

Actualización (8 de mayo de 2012) Si ejecuta esto en una carpeta que tiene masas y masas (quiero decir miles o decenas de miles) de elementos eliminados, puede que no se complete antes de que la command-line TFS expire. La mayor parte del time que toma este command es generar el script .tfc. Si lo ejecuta y descubre que esto está sucediendo, intente primero apuntar a algunas carpetas secundarias

 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 prepanetworking 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); } } } 

Debe pasar la carpeta TFS para eliminar, por ejemplo, '$ / carpeta'. Si acaba de pasar eso, todos los elementos eliminados coincidentes serán detectados y destruidos, uno por uno.

Por alguna razón, si accidentalmente pasa una carpeta que no existe, entonces la operación durará para siempre . Un CTRL + C lo detendrá, por supuesto.

La aplicación hace un directory recursivo en la carpeta, con el /deleted .

A continuación, se ejecuta a través de cada línea en la salida, buscando la sugerencia de eliminación, es decir, elementos con ;Xnnnnnnn . Si se encuentra, agrega la ruta tfs completa para ese elemento a una list.

Una vez completa, la list se ordera por longitud en order descendente y los contenidos se escriben en un file de respuesta tfc para la línea de command tf.exe .

Si se especifica la opción de preview , los commands tf se escriben con el modificador / preview (ver TFS Destroy en MSDN). Entonces las eliminaciones no se realizan realmente.

Finalmente, puede especificar norun que hace que se cree el file tfc, pero no se ejecute en realidad.

Sé que es una vieja pregunta, pero creo que puede ser útil.

Tenemos una colección antigua con más de 20 proyectos de equipo bajo VSO y realmente necesitamos limpiar nuestros proyectos de equipo. Este código funcionó perfectamente para nosotros.

 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; } } } 

Usé el package Microsoft.TeamFoundationServer.ExtendedClient NuGet.