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

ken*_*n2k 17 c# branch changelog tfs2010 tfs-workitem

这是我之前关于TFS 2010的问题以及创建更改日志的可能性.

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

以下是分支层次结构的外观:

分支层次结构

如您所见,有两个不同的应用程序是主干的分支:( APP_A应用程序A)和APP_B(应用程序B).两者几乎完全相同,但存在一些功能差异.

以下是创建应用程序新版本(例如版本1.3)的过程:

  1. Main trunk被修改(新功能的添加,bug修复...)
  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

我的目标是能够在APP_A_1.3和之间生成更改日志APP_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("链接"=变更集中签入的代码现在在分支上APP_A_1.2)以及所有变更集的列表是"联系"的APP_A_1.3.

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

这是我的问题:我如何获得与指定分支"链接" 的所有变更集的列表?我正在使用TFS 2010 API for 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();
Run Code Online (Sandbox Code Playgroud)

即使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();
Run Code Online (Sandbox Code Playgroud)

这将返回在APP_A_1.2分支上签入的变更集+ APP_AAPP_A_1.2创建之前在分支上被取消的变更集.好多了,但还不够.我找不到一种方法来使递归工作与"高于" APP_A(Main trunk在我的情况下)的分支...

有人有想法吗?

此外,欢迎任何更好的想法,以获得两个分支之间的更改日志... Thx.

ken*_*n2k 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();
Run Code Online (Sandbox Code Playgroud)

2)对于每个检索到的变更集,我调用TrackMerges以查看变更集是否以某种方式影响我的分支。TrackMerges能够告诉我指定的变更集是否应用于我指定为函数参数的分支(它将返回这些分支上的目标变更集 ID)。如果变更集应用于目标分支(在我的例子中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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为这不是最好的方法,但它效果很好并且很简单。另外,我不需要对任何东西(分支名称/层次结构)进行硬编码,所以在我看来这还不错。希望它能帮助某人。