2011-02-07 8 views
6

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 redundante se haya ido para siempre, ya que definitivamente nunca será necesario. Estos son proyectos nuevos que se están construyendo a partir de ramas de otros más antiguos que, hasta el momento, nadie está usando.TFS 2008 Source Control: forma rápida de destruir todos los elementos eliminados

Hay una gran cantidad de archivos distribuidos en varias carpetas, así que prefiero evitar tener que hacer cada uno individualmente. También estoy en la línea de comandos, sin usar la API.

Lo sé en última instancia, necesitaré el comando tf destroy.

También sé que tf dir [wildcard] /recursive /deleted devolverá todos los elementos eliminados dentro de una ruta (lamentablemente 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) Tomar la salida del comando dir y encontrar todos los artículos que tienen :Xnnnnnnn después - estos son los elementos eliminados; luego simplemente escupir un montón de tf destruir llamadas, o construir un archivo de respuesta (aunque no estoy seguro de este bit). Esto suena como un uso potencial para Powershell, pero aún no ha hecho nada con eso ...

2) Prepara todos los proyectos, y luego simplemente destrúyelos de TFS y luego vuelve a agregarlos para que solo las cosas requeridas están entonces en TFS. Sin embargo, esto elimina la relación de sucursal, lo que podría ser útil porque durante un tiempo 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 se pueda usar para cualquier carpeta en TFS en el futuro (un par de otros equipos tienen otros proyectos de larga duración que podría hacer con una purga completa!).

Gracias de antemano.

+0

Puede intentar realizar programáticamente la versión 'get specific version: changeset 1' clean, seguida de una get latest. http://www.woodwardweb.com/tfs_top_tip/tfs_top_tip_11.html – user423430

Respuesta

10

Bueno por lo que ha escrito una aplicación de consola (.Net 4):

no hace falta decir que no ofrecen ninguna garantía sobre esto - Se va a destruir ARTÍCULOS EN TFS !!!!

actualización (8ª mayo de 2012) Si ejecuta este en una carpeta que tiene masas y masas (me refiero a miles o miles decenas de) de los elementos eliminados no pueda concluir antes de la línea de comandos TFS se acabó el tiempo. La mayor parte del tiempo que toma este comando es generar el script .tfc. Si lo ejecuta y encontrar que esto suceda, trate de algún niño que apuntan a las carpetas primera

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. E.g: ""$/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 (i.e. when run, it won't actually do the destroy) "); 
     Environment.Exit(0); 
    } 
    } 
} 

Debe pasar la carpeta TFS a borrar por ejemplo '$/carpeta'. Si solo lo pasa, todos los elementos eliminados coincidentes se detectarán y destruirán, uno por uno.

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

La aplicación hace un directorio recursivo en la carpeta, con el interruptor /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 lista.

Una vez completa, la lista se ordena por longitud en orden descendente y los contenidos se escriben en un archivo de respuesta tfc para la línea de comando tf.exe.

Si se especifica la opción preview entonces los comandos tf se escriben con el modificador/vista previa (ver TFS Destroy en MSDN) A continuación, las supresiones no son realmente lleva a cabo.

Finalmente, puede especificar norun que hace que el archivo tfc se cree, pero no se ejecute realmente.

+0

No he probado esto, pero parece prometedor. ¡Gracias por compartir! –

+0

@MattRuwe - Sí, esta pequeña aplicación se ha convertido en un elemento básico para mantener nuestro entorno TFS. Una cosa a tener en cuenta, si su TFS es grande, entonces tiene problemas para trabajar en '$ /' porque lleva tanto tiempo y se desconectará después de 60 minutos. Lo mejor es apuntar a carpetas específicas. También notará que, hacia el final, todos los elementos ya se eliminarán: elimina las carpetas antes que los archivos en general, por lo que esto es normal. –

+0

Muchas gracias, esto fue realmente divertido. – Roubachof

2

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 para limpiar los proyectos de nuestro 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; 
     } 
    } 
} 

He usado Microsoft.TeamFoundationServer.ExtendedClient NuGet package.

+0

eso está bien, gracias por la respuesta –

Cuestiones relacionadas