TFS 2008 Source Control - быстрый способ уничтожить все удаленные элементы - PullRequest
7 голосов
/ 07 февраля 2011

У меня есть несколько папок управления исходным кодом, для которых я хочу избавиться от всех ненужных элементов.Эти элементы были удалены (код был перемещен или переписан), и, поскольку большинство из нас по умолчанию использует параметр «Показать удаленные элементы», в некоторых из этих папок теперь отображается больше удаленных элементов, папок и допустимых элементов.Я хочу убедиться, что весь этот избыточный код исчез, навсегда - так как он совершенно определенно не понадобится.Это новые проекты, построенные из веток старых, которые еще никто не использует.

Однако довольно много файлов распределено по нескольким папкам, поэтому я бы предпочел не делать каждый из них.индивидуально.Я тоже в командной строке, не использую API.

Я знаю, что в конечном итоге мне понадобится команда tf destroy.

Я также знаю, что tf dir [wildcard] /recursive /deleted вернет все удаленныепредметы в пути (к сожалению, наряду со всеми законными предметами).

Может кто-нибудь придумать, как сделать это быстро ?

Я подумал о двух решениях:

1) Возьмите выходные данные команды dir и найдите все элементы, которые имеют :Xnnnnnnn после - это удаленные элементы;затем просто выплюните кучу вызовов уничтожения или создайте файл ответов (хотя и не уверен насчет этого бита).Это звучит как потенциальное использование для Powershell, но на самом деле еще ничего с этим не сделано ...

2) Подготовьте все проекты, а затем просто уничтожьте их из TFS и затем снова добавьте их тактогда только требуемый материал находится в TFS.Тем не менее, это устраняет связь между ветвями, что может быть полезно, потому что некоторое время мне придется поддерживать две версии некоторых из этих библиотек (до и после обновления).Не идеально, но я ничего не могу с этим поделать.

Очевидно, что Вариант 2 - это чит, но он будет работать - я просто идеально хотел бы повторно использовать сценарий, который может быть использован для любой папки в TFS в будущем(у пары других команд есть другие долгоживущие проекты, которые можно сделать с полной продувкой!).

Заранее спасибо.

Ответы [ 2 ]

10 голосов
/ 07 февраля 2011

Хорошо, я написал консольное приложение (.Net 4):

ЭТО ИДЕТ БЕЗ ТОГО, ЧТО Я НЕ ПРЕДЛАГАЮ НИКАКИХ ГАРАНТИЙ НА ЭТО - ЭТО УНИЧТОЖАЕТ ПУНКТЫ В TFS !!!!

Обновление (8 мая 2012 г.) Если вы запустите это для папки с массами и массами (я имею в виду тысячи или десятки тысяч) удаленных элементов, она может не завершиться до команды TFS. время ожидания истекло. Большая часть времени, затрачиваемого этой командой, заключается в создании сценария .tfc. Если вы запустите его и обнаружите, что это происходит, попробуйте сначала настроить таргетинг на некоторые дочерние папки

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

Вы должны передать удаляемую папку TFS, например, $ / folder. Если вы просто пройдете это, то все соответствующие удаленные элементы будут обнаружены и уничтожены, один за другим.

По какой-то причине - если вы случайно пропустите папку, которая на самом деле не существует, операция займет навсегда . CTRL + C остановит это, конечно.

Приложение выполняет рекурсивный dir для папки с переключателем /deleted.

Затем он пробегает каждую строку в выходных данных в поисках подсказки для удаления, то есть элементов с ;Xnnnnnnn. Если найдено, он добавляет полный путь TFS для этого элемента в список.

После завершения список сортируется по длине в порядке убывания, а содержимое записывается в файл ответов tfc для командной строки tf.exe.

Если указан параметр preview, то команды tf записываются с параметром / preview (см. TFS Destroy в MSDN) Тогда удаление фактически не выполняется.

Наконец, вы можете указать norun, который вызывает создание файла tfc, но не его запуск.

2 голосов
/ 25 июля 2016

Я знаю, что это старый вопрос, но я думаю, что он может быть полезен.

У нас есть старая коллекция с более чем 20 командными проектами в рамках VSO, и нам действительно нужно было очистить наши командные проекты.Этот код отлично сработал для нас.

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

Я использовал Microsoft.TeamFoundationServer.ExtendedClient Пакет NuGet.

...