TFS2010: получить все наборы изменений, связанные с веткой (полная рекурсия) - PullRequest
17 голосов
/ 14 февраля 2012

Далее следует мой предыдущий вопрос о TFS 2010 и возможности создания журнала изменений.

Ранее я использовал ярлыки для определения версии программы, но поскольку ярлыки не являются фиксированными моментами времени, теперь я использую ветки.

Вот как выглядит иерархия ветвей:

branch hierarchy

Как видите, есть два разных приложения, которые являются ветвями магистрали: APP_A (приложение A) и APP_B (приложение B). Оба они почти идентичны, но есть некоторые функциональные различия.

Вот процесс создания новой версии приложения (скажем, версия 1.3):

  1. Изменен Main trunk (добавлены новые функции, исправлены ошибки ...)
  2. Из измененного Main trunk создается новая ветка: Main trunk 1.3
  3. APP_A может быть изменена, поэтому уникальные функции APP_A будут работать с модификацией v1.3
  4. APP_B может быть изменена, поэтому уникальные функции APP_B будут работать с модификацией v1.3
  5. Main trunk 1.3 объединяется с APP_A и APP_B, поэтому приложения APP_A и APP_B получают модификации Main trunk
  6. Из модифицированной ветви APP_A создается новая ветка: APP_A_1.3
  7. Из модифицированной ветки APP_B создается новая ветка: APP_B_1.3

Моя цель - создать журнал изменений между APP_A_1.3 и APP_A_1.2.

Под журналом изменений я подразумеваю список WorkItems. Каждый зарегистрированный набор изменений связан с одним или несколькими WorkItem (например, элементом Bug). Я бы хотел получить список всех рабочих элементов, которые были связаны с набором изменений, повлиявшим на APP_A_1.3: эти наборы изменений могут быть получены из Main trunk (шаг 1 выше), APP_A branch (шаг 3 выше) или даже сама ветка APP_A_1.3 (если исправления возвращаются после создания ветки).

Чтобы получить этот список рабочих элементов, я попытался получить список всех наборов изменений, которые «связаны» с APP_A_1.2 ( «связаны» = код, который был зарегистрирован в набор изменений теперь находится на ветке APP_A_1.2) и список всех наборов изменений, которые «связаны» с APP_A_1.3.

Затем я смогу узнать, какие наборы изменений «связаны» с APP_A_1.3, а не «связаны» с APP_A_1.2. Из этого подмножества наборов изменений я получу все связанные WorkItems и, следовательно, свой список изменений.

Вот моя проблема: как я могу получить список ALL наборов изменений, которые "связаны" с указанной веткой? Я использую TFS 2010 API для кода C #.

Входная информация моей программы (которая будет извлекать все наборы изменений для указанной ветви) будет именем ветви (скажем, APP_A_1.2), а выходные данные будут списком следующих наборов изменений:

  • ревизий, примененных к APP_A_1.2 самой ветви
  • ревизий, примененных к ветке APP_A до создания APP_A_1.2
  • ревизии, примененные к ветке Main trunk 1.2 до ее объединения в APP_A
  • ревизий, примененных к ветке Main trunk до создания Main trunk 1.2

Я написал следующие фрагменты кода, чтобы получить все эти наборы изменений:

// Gets the list of all changesets ID from APP_A_1.2 branch
var branch1ChangeSets = myVersionControlServer.QueryHistory(
    "$/PATH/APP_A_1.2/",
    VersionSpec.Latest,
    0,
    RecursionType.Full,
    null,
    null,
    null,
    int.MaxValue,
    false,
    false).OfType<Changeset>().Select(z => z.ChangesetId).ToList();

Даже если указано RecursionType.Full, приведенный выше код только возвращает наборы изменений, которые были зарегистрированы в самой ветви APP_A_1.2. Это идентично команде «Журнал» в представлении «Исходный код» в Visual Studio.

Затем я попробовал следующий фрагмент кода:

// Gets the list of all changesets ID from APP_A_1.2 branch
var branch1MergedChangeSets = myVersionControlServer.QueryMerges(
    null,
    null,
    "$/PATH/APP_A_1.2/",
    VersionSpec.Latest,
    null,
    null,
    RecursionType.Full).Select(z => z.SourceVersion).ToList();

Возвращает наборы изменений, которые были зарегистрированы в ветви APP_A_1.2 + те, которые были проверены в ветви APP_A до создания APP_A_1.2. Намного лучше, но не достаточно. Я не могу найти способ заставить рекурсию работать с ветками, которые "выше" APP_A (Main trunk в моем случае) ...

У кого-нибудь есть идея?

Кроме того, любые лучшие идеи для получения журнала изменений между двумя ветвями приветствуются ... Thx.

Ответы [ 3 ]

3 голосов
/ 27 февраля 2012

сначала позвольте мне сначала задать один вопрос. В верхней части поста вы пишете: «Моя цель - создать журнал изменений между APP_A_1.3 и APP_A_1.2.»

но потом, когда вы пишете, что конкретно меняется, вы ищете свой список: Изменения, примененные к самой ветви APP_A_1.2 наборы изменений, примененные к ветви APP_A до создания APP_A_1.2 наборы изменений, примененные к ветке Main trunk 1.2, прежде чем они были объединены с APP_A наборы изменений, примененные к ветви главной магистрали до создания главной магистрали 1.2

Это недопустимый список, потому что он предоставит вам все изменения, внесенные в APP_A_1.3, APP_A_1.2, 1.1 и т. Д. В начало хранилища.

Я не могу сейчас проверить свой подход, но вот что я бы сделал: - QueryHistory, чтобы все изменения были зарегистрированы непосредственно в ветке 1.3 - использовать QueryMergesExtended для отслеживания слияний в этой ветке. QueryMergesExtended (http://msdn.microsoft.com/en-us/library/ff736485.aspx) был добавлен в TFS 2010 специально для того, чтобы быть гораздо более производительным и надежным, чем QueryMerges и QueryMergesWithDetails, для поддержки инструментов визуализации ветвей - afaik вам не нужно указывать опцию FollowRenames в QueryMergesExtended, потому что вы запрашиваете слияния в корне ветви - когда вы получаете список изменений источника (из APP_A), вам нужно проверить каждый набор изменений, чтобы увидеть, содержит ли он изменения слияния. Если это так, вам нужно запросить слияния в app_a для этих наборов изменений. Делайте это рекурсивно, пока не пройдете всю иерархию ветвей.

В дополнительном разделе вы можете взглянуть позже на QueryMergeRelationships (http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.versioncontrolserver.querymergerelationships.aspx), в котором представлен список объектов ветвей, представленный в tfs 2010 (это происходит, когда в Source Control Explorer вы выбираете папку и нажимаете «Преобразовать в ветвь»). Однако, если вы можете обнаружить свою ветку другим способом (жестко закодировать их), это не нужно.

Надеюсь, это поможет!

2 голосов
/ 02 марта 2012

Я наконец-то нашел простое решение. Я не совсем доволен этим, так как на самом деле он выглядит как алгоритм перебора, но, по крайней мере, он работает.

Что я делаю:

1) Получить список каждого набора изменений , который применяется к самому корню моих ветвей TFS (то есть "родительский путь" Main Trunk):

var allChangesets = vcs.QueryHistory(
    "MySourcePath",
    VersionSpec.Latest,
    0,
    RecursionType.Full,
    null,
    firstPossibleChangeset,
    VersionSpec.Latest,
    int.MaxValue,
    true,
    false).OfType<Changeset>().ToList();

2) Для каждого полученного набора изменений я звоню TrackMerges, чтобы узнать, влияет ли набор изменений на мои ветви. TrackMerges может сообщить мне, применен ли указанный набор изменений к ветвям, которые я указал в качестве параметра функции (он вернет целевой идентификатор набора изменений для этих ветвей). Если набор изменений применяется к целевой ветви (в моем случае APP_A_1.3), а не к исходной ветви (APP_A_1.2), то это означает, что это определенно что-то новое в моей APP_A_1.3 ветви.

List<int> newChangesets = new List<int>();
foreach (var z in allChangesets.Where(y => y.ChangesetId > firstPossibleChangesetId))
{
    var zz = vcs.TrackMerges(
        new int[] { z.ChangesetId },
        new ItemIdentifier("THE TRUNK PATH"),   // The root of all branches
        new ItemIdentifier[] { new ItemIdentifier(fromBranchPath), new ItemIdentifier(toBranchPath) },
        null);

    var targetInFromBranch = zz.Where(t => t.TargetItem.Item == fromBranchPath).FirstOrDefault();
    var targetInToBranch = zz.Where(t => t.TargetItem.Item == toBranchPath).FirstOrDefault();

    if (targetInToBranch != null && targetInFromBranch == null)
    {
        // Then the changeset is only applied on the ToBranch
        newChangesets.Add(z.ChangesetId);
    }
}

3) Теперь очень просто получить мой список изменений (список рабочих элементов) из списка "новых наборов изменений":

// Now, gets associated work items!
Dictionary<int, WorkItem> dico = new Dictionary<int, WorkItem>();
foreach (int changesetId in newChangesets)
{
    foreach (WorkItem zz in vcs.GetChangeset(changesetId).WorkItems)
    {
        this.AddWorkItemToDicRecursive(wis, dico, zz);
    }
}

private void AddWorkItemToDicRecursive(WorkItemStore wis, Dictionary<int, WorkItem> dico, WorkItem workItem)
{
    if (!dico.ContainsKey(workItem.Id))
    {
        dico.Add(workItem.Id, workItem);

        foreach (WorkItemLink associatedItem in workItem.WorkItemLinks)
        {
            this.AddWorkItemToDicRecursive(wis, dico, wis.GetWorkItem(associatedItem.TargetId));
        }
    }
}

Я не думаю, что это лучший из возможных подходов, но он отлично работает и остается простым. Кроме того, мне не пришлось ничего жестко кодировать (имена ветвей / иерархия), так что это не так уж плохо для IMO. Надеюсь, это кому-нибудь поможет.

1 голос
/ 29 февраля 2012

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

Посмотрите, поможет ли это: http://tfslabeldiff.codeplex.com/SourceControl/changeset/view/7075#158224

Я был довольно удивлен, насколько сложно это было найти, но документация для TFS в лучшем случае отсутствует.Казалось, что это должно быть очевидно!

...