代码之家  ›  专栏  ›  技术社区  ›  Joseph Ferris

Team Foundation服务器-具有历史记录的移动源

  •  57
  • Joseph Ferris  · 技术社区  · 15 年前

    我想知道在将源代码从一个团队项目移动到另一个团队项目时,最好的方法是什么。我不关心工作项、报告或SharePoint站点,因为我们要从中恢复的系统没有使用这些功能。想要转移到另一个团队项目的原因也是因为原始实现(从第三方维护的备份中恢复)使用了第三方过程模板,而我们不希望继续使用。我们希望在迁移完成后开始使用工作项跟踪和报告。

    这个 TFS Integration Platform 似乎是一种可能的情况。它可用于根据文档更改流程模板。但是,我很好奇tf.exe move语法是否可以工作?类似:

    tf.exe移动$/projecta$/projectb

    据我所知,此命令的操作与重命名操作非常相似,而在源代码管理资源管理器中使用“移动”上下文菜单项进行移动更像是删除和添加操作。另外,如果$/projecta是一个项目的根源代码管理文件夹,而$/projectb是另一个项目的根源代码管理文件夹,tf.exe move path是否会将文件夹下的代码与相应的团队项目实际关联?关键是如果可能的话,能够保存历史。

    任何建议或提示都将非常感谢!

    编辑-可以分支到另一个项目处理此方案-与Microsoft在 Branching Guidance 文档?我认为这可能是答案,因为历史很可能与该分支一起保存。但是,目前我无法访问Team Foundation Server 2008实例来测试它。

    4 回复  |  直到 10 年前
        1
  •  38
  •   Richard Berg    15 年前

    移动和重命名是别名。在任何版本的tfs中,与命令行或用户界面都没有绝对的区别。

    它们都保存着历史。至少在2005/2008年,无论名称和/或父路径更改的频率或程度如何,都要在versionEditem表中保留相同的物理项。实际上,如果没有大量的手工操作,就无法获得“假”重命名(删除+添加)。

    然而,虽然这个版本化模型在理论上是非常纯粹的,但它有一些实际的问题。因为不同的项可以在不同的时间点占用相同的名称,所以TFS需要全名+版本来唯一标识您发送的任何输入。通常你不会注意到这个限制,但是一旦你在系统中重命名了项目,如果你说 tf[dosomething]$/newname-版本:oldversion 然后它将变得混乱,或者抛出一个错误,或者对一个您可能没有打算的项目进行操作。必须小心传递有效的组合(newname+newversion或oldname+oldversion),以确保命令的行为符合您的需要。

    TFS2010稍微改变了这个故事:它是一个分支+在封面下的删除操作,导致itemID发生变化。即使如此,像get和history这样的日常命令也非常好地“伪造”;旧客户机大约95%兼容。其优点是,当系统中有多个重命名时,基于路径的项查找开始变得模糊不清,正如上面提到的那样,服务器将只接受您指定的名称并用它运行。这提高了系统的整体性能,并消除了一些不熟悉的用户经常遇到的陷阱,代价是没有那么灵活,并且没有以100%的精度保存历史(例如在合并两个分支时发生名称冲突)。

    回到手头的问题上…

    这不像说的那么简单 tf重命名$/projecta$/projectb . 源代码管理树中的顶级文件夹是为团队项目创建向导保留的;不能对它们运行标准tf命令。你需要的是这样一个脚本:

    Get-TfsChildItem $/ProjectA |
        select -Skip 1 |  # skip the root dir
        foreach {
            tf rename $_.serveritem $_.serveritem.replace("$/ProjectA", "$/ProjectB")
        }
    

    [当然,如果美元/项目A下没有太多的孩子,你可以手工完成]

    至于我提到的“哥德查”,我现在将详细介绍一个,因为查找旧的历史对您来说很重要。签入重命名后, tf history美元/projecta/somefile.cs 不起作用。默认情况下,tf命令假定version=“latest.”这些选项中的任何一个都将是您想要的完整历史记录:

    • tf history$/projecta/somefile.cs;1234 变更集1234在移动之前的位置
    • tf历史$/projectb/somefile.cs;5678 移动后的变更集5678。或者你可以省略这个版本。

    完整性和调试目的的最终备选方案:

    • tf history$/projecta/somefile.cs-槽模式 . 您将只看到移动之前发生的更改;但是,您还将看到在您移动到b下的项目之前或之后,$/projecta/somefile.cs“slot”中可能存在的任何其他项目的历史记录。

    (在TFS 2010中,“槽模式”是默认行为;有一个-itemmode选项可以请求您的查找像2008年一样在历史记录中进行跟踪,而不是基于路径进行跟踪。)

    不,分支不是一个很好的选择。虽然分支确实在系统中留下了足够的元数据来跟踪从ProjectB到ProjectB的完整历史记录,但在2008年,它对用户不太友好。计划花很多时间学习 TF合并 命令(没有等效的UI)。2010大大提高了您跨多个分支可视化更改的能力,但它仍然不是从重命名中获得的干净统一的体验。

        2
  •  17
  •   solublefish    14 年前

    理查德的回答写得很好,很好地解释了情况。不过,我确实有一些更实际的补充。

    在tfs2010中,默认行为使 似乎 就像移动一个文件会导致你在移动之前丢失所有的历史记录。我的用户可能使用的命令(并且,看起来,由VS2010 GUI使用的命令)是:

    tf history $/ProjectB/somefile.cs
    

    我的用户打算在移动之前和之后获取somefile.cs的所有历史记录。他们想要“当前存储在$/projectb/somefile.cs中的代码的历史记录”,而不管文件名在任何时间点。也许其他人的看法不同。

    第一个问题是,在VS2010中使用TFS2010显示的GUI最初只显示了自迁移以来的历史记录。列表中最近的项是重命名操作。它可以通过一个细微的下拉箭头进行扩展。下面是以前位置的历史记录。如果你不知道要找这个,你的历史可能会消失。

    第二个问题是,如果您以后删除ProjectA(因为您已经完成了到ProjectB的迁移,比如说),那么历史就真的不复存在了。扩展$/projectb/somefile.cs历史记录中的下拉列表不会生成旧的历史记录。

        3
  •  2
  •   dave walker    11 年前

    另一个选择(我认为更简单)是导入到Git,然后使用 the Git-TF 命令行工具。

    • 从二进制、Choclatey或源代码安装git tf。

    • 克隆TFS文件夹:

    git tf clone https://myAcc.visualstudio.com/mycollection $/TeamProjectA/Main --deep

    • 通过删除 .Git/tf 文件夹和 .Git/git-tf 文件。

    • 配置新的git repo以连接到 空的 TFS文件夹。

    git tf configure https://myAcc.visualstudio.com/mycollection $/TeamProjectB/Main --deep

    • 别忘了 --deep

    git tf pull

    此时应该会收到一条消息:“git tf:这是一个新配置的存储库。没有要从tfs中提取的内容。”

    git commit -a -m "merge commit"

    git tf checkin --deep

        4
  •  0
  •   Philip Beck    10 年前

    关于上述原始命令:

    Get-TfsChildItem $/ProjectA |
    select -Skip 1 |  # skip the root dir
    foreach {
        tf rename $_.serveritem $_.serveritem.replace("$/ProjectA", "$/ProjectB")
    }
    

    如果完整路径文件名中有空格,则源名称和目标名称都需要用引号括起来。我发现很难在上面做这个 $Server项 用转义的“返回整个子对象,而不仅仅是.serverItem字符串。或者如果我真的得到了绳子,我得到了不想要的回车,比如


    $proj/文件夹/文件

    最终我得到了命令来处理下面的内容,但我发现历史仍然没有被转移,这就是重点!所以我认为这个命令直接相当于在源资源管理器中单击鼠标右键并选择重命名(或移动)。

    $tfsServerString = "http://machine:8080/tfs/DefaultCollection"
    $tfs = Get-TfsServer $tfsServerString
    Get-TfsChildItem -server $tfs "$/Dest Project/MyTestProject" | select -Skip 1 | foreach { $sourceName = $_.serveritem; $targetName = $_.serveritem.replace("$/Dest Project/MyTestProject/", "$/Dest Project/Source/StoreControllers/dSprint/dSprint2/") ; ./tf rename `"$sourceName`" `"$targetName`" /login:myUser }
    

    还要注意的是,它需要使用反勾号“进行转义”