Подтвердить что ты не робот

TFS2010: извлечение всех наборов изменений, связанных с ветвью (полная рекурсия)

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

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

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

branch hierarchy

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

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

  • Изменен Main trunk (добавлены новые функциональные возможности, исправлены ошибки...)
  • Из измененного Main trunk создается новая ветвь: Main trunk 1.3
  • APP_A ветвь может быть изменена, поэтому уникальные функции APP_A будут работать с модификацией версии 1.3 ветвь
  • APP_B может быть изменена, поэтому уникальные функции APP_B будут работать с модификацией v1.3
  • Main trunk 1.3 объединяется в APP_A и APP_B, поэтому приложения APP_A и APP_B получают модификации Main trunk
  • От измененной ветки APP_A создается новая ветвь: APP_A_1.3
  • От измененной ветки 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 и, следовательно, свой журнал изменений.

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

Ввод моей программы (которая будет извлекать все команды изменений для указанной ветки) будет именем ветки (скажем 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 в моем случае)...

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

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

4b9b3361

Ответ 1

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

Что я делаю:

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. Надеюсь, это поможет кому-то.

Ответ 2

сначала позвольте мне сначала задать один вопрос. В верхней части сообщения вы пишете: "Моя цель - создать журнал изменений между 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 вы выбираете папку и нажимаете "Преобразовать в ветвь" ). Однако, если вы можете обнаружить свою ветку по-разному (с жестким кодом), чем она не нужна.

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

Ответ 3

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

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

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