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

таким образом мой предыдущий вопрос о 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 совместимость с модификация В1.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.

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

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

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

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

вход моей программы (которая будет извлекать все наборы изменений для указанной ветви) будет именем ветви (скажем 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 ветка + те, которые были checked - in на APP_A филиала перед APP_A_1.2 был создан. Намного лучше, но недостаточно. Я не могу найти способ заставить рекурсию работать с ветвями, которые находятся "выше"APP_A (Main trunk в моем случае)...

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

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

3 ответов


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

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

надеюсь, что это помогает!


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

что я делаю:

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) Теперь очень просто получить мой журнал изменений (список workitems) из списка " new changesets":

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


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

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

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