TFS2010:检索与分支关联的所有更改集(完全递归)

时间:2012-02-14 11:04:35

标签: c# tfs2010 branch tfs-workitem changelog

这是关于TFS 2010的my previous question以及创建更改日志的可能性。

我以前使用标签来识别程序的版本,但由于标签不是固定的时间点,现在我正在使用分支。

以下是分支层次结构的样子:

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_AAPP_B,因此APP_AAPP_B个应用都会收到Main trunk
  6. 从修改后的APP_A分支创建一个新分支:APP_A_1.3
  7. 从修改后的APP_B分支创建一个新分支:APP_B_1.3
  8. 我的目标是能够在APP_A_1.3APP_A_1.2之间生成更改日志。

    通过changelog我的意思是WorkItems列表。签入的每个变更集都与一个或多个WorkItem(例如Bug项)相关联。 我希望能够获取与已影响APP_A_1.3 的变更集相关联的所有工作项列表:这些变更集可能来自Main trunk(上面的第1步) ),APP_A branch(上面的第3步)或甚至是APP_A_1.3分支本身(如果在创建分支后签入了修补程序)。

    要获取此工作项列表,我尝试获取APP_A_1.2 “链接”的所有变更集的列表(“已链接”=已检查的代码变更集中的-in现在位于分支APP_A_1.2 )以及“链接”到APP_A_1.3的所有变更集的列表。

    然后,我将能够知道哪些变更集“链接”到APP_A_1.3而不是“链接”到APP_A_1.2。从这个变更集子集中,我将获得所有相关的WorkItems,从而获得我的更改日志。

    这是我的问题:如何获取与指定分支“链接”的所有变更集列表?我正在使用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 个答案:

答案 0 :(得分:3)

首先让我先问一个问题。在帖子的顶部你写道: “我的目​​标是能够在APP_A_1.3和APP_A_1.2之间生成更改日志。”

但是当你写下具体的改变时,你正在寻找你的名单: 更改集应用于APP_A_1.2分支本身 在创建APP_A_1.2之前在APP_A分支上应用的更改集 在主干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你不需要在QueryMergesExtended中指定选项FollowRenames,因为你在分支的根上查询合并 - 当您获得源更改列表(来自APP_A)时,您需要检查每个变更集以查看它包含合并更改。如果是这样,您需要在app_a上查询这些变更集的合并。递归执行,直到您走完整个分支层次结构。

在旁边的主题中,您可以稍后查看QueryMergeRelationships(http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.versioncontrolserver.querymergerelationships.aspx),它为您提供了在tfs 2010中引入的分支对象列表(这是在Source Control Explorer中选择文件夹并单击转换为分支时会发生的情况)。但是,如果你能以不同的方式发现你的分支(硬编码)而不是不需要它。

希望这有帮助!

答案 1 :(得分:2)

我终于提出了一个简单的解决方案。我对它并不十分满意,因为它实际上看起来像是一种蛮力算法,但至少它有效。

我的工作是:

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能够告诉我是否在我指定为函数参数的分支上应用了指定的变更集(它将在这些分支上返回目标变更集ID)。如果在目标分支(在我的情况下为APP_A_1.3)而不是源分支(APP_A_1.2)中应用了变更集,那么这意味着它在我的APP_A_1.3分支上肯定是新的。< / p>

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 :(得分:1)

是的,我自己也在解决这个问题。无论如何,当你正在分辨标签时,我发现了一个解决它的codeplex项目。

看看这是否有帮助:http://tfslabeldiff.codeplex.com/SourceControl/changeset/view/7075#158224

我很惊讶这很难找到,但TFS的文档充其量是缺乏的。看起来它应该是显而易见的!