17

这遵循我之前关于 TFS 2010 的问题以及创建变更日志的可能性。

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

分支层次结构如下所示:

分支层次结构

如您所见,有两个不同的应用程序是主干的分支:(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_Aand APP_B,所以APP_AandAPP_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

变更日志是指工作项列表。签入的每个变更集都与一个或多个 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_AMain trunk在我的情况下)......

有人有想法吗?

此外,欢迎任何更好的想法来获取两个分支之间的变更日志......谢谢。

4

3 回答 3

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 中(这是在源代码管理资源管理器中选择文件夹并单击转换为分支时发生的情况)。但是,如果您可以以不同的方式(硬编码它们)发现您的分支,则不需要它。

希望这可以帮助!

于 2012-02-27T10:26:39.033 回答
2

I finally came up with a simple solution. I'm not totally happy with it as it actually looks like a brute-force algorithm, but at least it works.

What I do is:

1) Get the list of every changeset that is applied on the very root of my TFS branches (i.e. the "parent path" of Main Trunk):

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

2) For each retrieved changeset, I call TrackMerges to see if the changeset impacts in some way my branches. TrackMerges is able to tell me if a specified changeset is applied on the branches I specify as parameter of the function (it'll return the target changeset ID on these branches). If a changeset is applied on the destination branch (in my case APP_A_1.3) and not in the source branch (APP_A_1.2), then it means it's definitely something new on my APP_A_1.3 branch.

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 it's very simple to get my changelog (the list of workitems) from the list of "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));
        }
    }
}

I don't think it's the best possible approach, but it works fine and remains simple. Also, I didn't have to hardcode anything (branch names/hierarchy) so it's not too bad IMO. Hope it'll help someone.

于 2012-03-02T16:50:16.737 回答
1

是的,我自己也在解决这个问题。无论如何,当您区分标签时,我找到了一个解决它的 codeplex 项目。

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

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

于 2012-02-29T07:20:55.753 回答