Team Foundation Server - 随历史移动源

发布于 2024-08-20 08:16:36 字数 874 浏览 3 评论 0原文

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

TFS 集成平台 似乎是一种可能的情况。根据文档,它可用于更改流程模板。但是,我很好奇 tf.exe 移动语法是否有效?类似于:

tf.exe move $/ProjectA $/ProjectB

据我了解,此命令的操作非常类似于重命名操作,而使用源代码管理资源管理器中的“移动”上下文菜单项进行移动更像是删除和添加操作。另外,假设 $/ProjectA 是一个项目的根源代码控制文件夹,$/ProjectB 是另一个项目的根源代码控制文件夹,tf.exe 移动路径实际上是否会将文件夹下的代码与相应的团队项目相关联?关键是如果可能的话,能够保留历史。

任何建议或提示将不胜感激!

编辑 - 可以分支到另一个项目来处理这种情况 - 就像 Microsoft 在 分支指南文档?我认为这可能是答案,因为历史可能会与分支一起保存。但是,我目前无法访问 Team Foundation Server 2008 实例来对其进行测试。

I was wondering what the best approach might be in moving source code, with history, from one Team Project to another Team Project. I am not concerned with work items, reporting, or SharePoint sites, as the system we are going to be restoring from did not use these functionalities. The reason for wanting to move to a different Team Project also is driven by the fact that the original implementation (being restored from a backup that was maintained by a third party) were using a third-party process template that we do not wish to use going forward. We want to start utilizing work item tracking and reporting after the migration is complete.

The TFS Integration Platform seems to be one likely scenario. It can be used to change the process template, according to the documentation. However, I was curious if the tf.exe move syntax might work? Something like:

tf.exe move $/ProjectA $/ProjectB

It is my understanding that this command operates much like a rename operation, whereas moving with the "Move" context menu item in Source Control Explorer is more like a delete and add operation. Also, would the tf.exe move path actually associate the code under the folders with the appropriate Team Project, assuming that $/ProjectA is the root source control folder for one project and $/ProjectB is the root source control folder for the other? The key is to be able to preserve the history, if possible.

Any advice or tips would be greatly appreciated!

Edit - Could branching to another project handle this scenario - much like Microsoft discusses in the Branching Guidance documentation? I think that this could be the answer, since the history would likely be preserved with the branch. However, I do not have access to a Team Foundation Server 2008 instance at the moment to test it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

葬シ愛 2024-08-27 08:16:37

关于上面的原始命令:-

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

源名称和目标名称都需要用引号引起来,以防完整路径文件名中存在空格。我发现很难在 $_.ServerItem 上执行此操作,因为用转义的 " 包围它返回整个子对象,而不仅仅是 .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 }

另请注意,它需要使用反引号`来转义“。

Regarding the original command above:-

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

Both the source and target names need to be surrounded by quotes in case there are any spaces in the full pathfilename. I found it difficult to do this on $_.ServerItem as surrounding it with escaped " returns that whole child object and not just the .serverItem string. Or if I did manage to get the string, I got unwanted carriage returns such as

"
$proj/folder/file
"

Eventually I got the command to work with the following, but I found that the history still doesn't get transferred, which was the whole point! So I believe this command is the direct equivalent of just using a right mouse click in source explorer and selecting rename (or move).

$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 }

Also note, it requires use of the backtick ` to escape "

不弃不离 2024-08-27 08:16:36

移动和重命名是别名。在任何版本的 TFS 中,命令行或 UI 绝对没有区别。

两者都保存了历史。至少在 2005/2008 年,无论名称和/或父路径更改的频率或程度如何,您都会在 VersionedItem 表中保留相同的物理项目。实际上,如果您不进行大量手动工作,就无法获得“假”重命名(删除+添加)。

然而,虽然这个版本控制模型在理论上非常纯粹,但它有一些实际问题。由于不同的项目可以在不同的时间点占用相同的名称,因此 TFS 需要全名 + 版本来唯一标识您发送给它的任何输入。通常你不会注意到这个限制,但是一旦你重命名了系统中的项目,如果你说 tf [doSomething] $/newname -version:oldversion 那么它会变得混乱并且抛出错误或对您可能无意的项目进行操作。您必须小心传递有效的组合(新名称+新版本或旧名称+旧版本),以确保命令按照您想要的方式运行。

TFS 2010 稍微改变了情况:它是幕后的分支+删除,导致 itemID 发生变化。即便如此,像 Get 和 History 这样的日常命令还是可以很好地“伪造”的。老客户端兼容率达到95%左右。优点是,当您在系统中进行多个重命名并且基于路径的项目查找开始变得不明确(如上面提到的)时,服务器将简单地接受您指定的名称并使用它运行。这提高了整体系统性能并消除了不熟悉的用户经常陷入的几个陷阱,但代价是不太灵活并且不能以 100% 的精度保留历史记录(例如,当两个分支合并期间出现名称冲突时)。

回到手头的问题......

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

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

[当然,如果 $/ProjectA 下没有太多子项,你可以手动完成]

至于我提到的陷阱,我会在查找后详细说明一个古老的历史对你来说似乎很重要。一旦您签入重命名,tf History $/ProjectA/somefile.cs 将不起作用。默认情况下,tf 命令假定版本 =“最新”。这些替代方案中的任何一个都将是您想要的完整历史记录:

  • tf History $/ProjectA/somefile.cs;1234,其中变更集 1234 在移动之前
  • tf History $/ProjectB/somefile.cs;5678 变更集 5678 位于移动之后。或者您可以省略版本。

完整性和完整性的最终替代方案调试目的:

  • tf History $/ProjectA/somefile.cs -slotmode。您只会看到移动之前发生的更改;但是,您还会看到可能存在于 $/ProjectA/somefile.cs“槽”中的项目之前或之后的任何其他项目的历史记录。

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

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

Move and Rename are aliases. There is absolutely no difference, in any version of TFS, from the command line or the UI.

Both of them preserve history. At least in 2005/2008, you keep the same physical item in the VersionedItem table no matter how often or how drastically the name and/or parent path changes. There is actually no way to get a "fake" rename (delete + add) without a lot of manual work on your part.

However, while this versioning model is very pure in a theoretical sense, it has some practical gotchas. Because different items can occupy the same name at different points in time, TFS needs the full name + version to uniquely identify any inputs you send it. Normally you don't notice this restriction, but once have you renamed items in the system, if you say tf [doSomething] $/newname -version:oldversion then it will get confused and either throw an error or operate on an item you may not have intended. You have to be careful to pass valid combinations (newname+newversion or oldname+oldversion) to ensure commands behave the way you want.

TFS 2010 changes the story somewhat: it's a branch+delete under the covers, causing the itemID to change. Even so, everyday commands like Get and History are "faked" very well; old clients are about 95% compatible. The advantage is that when you have multiple renames in the system and path-based item lookups start to become ambiguous as alluded to above, the server will simply accept the name you specify and run with it. This improves overall system performance and eliminates several traps that unfamiliar users often fell into, at the cost of not being quite as flexible and not preserving history with 100% precision (eg when there are name collisions during a Merge of two branches).

Returning to the problem at hand...

It's not as simple as saying tf rename $/projectA $/projectB. Top level folders in the source control tree are reserved for the Team Project Creation Wizard; you can't run standard tf commands against them. What you need is a script like:

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

[of course, you can do it by hand if there aren't too many children under $/ProjectA]

As far as the gotchas I mentioned, I'll elaborate on one right now since looking up old history seems very important to you. Once you checkin the rename, tf history $/ProjectA/somefile.cs will NOT work. By default, tf commands assume version = "latest." Any of these alternatives will the full history you want:

  • tf history $/ProjectA/somefile.cs;1234 where changeset 1234 was before the move
  • tf history $/ProjectB/somefile.cs;5678 where changeset 5678 was after the move. Or you could just omit the version.

A final alternative for completeness & debugging purposes:

  • tf history $/ProjectA/somefile.cs -slotmode. You will only see the changes that happened prior to the move; however you'll also see the history of any other items that may have lived in the $/ProjectA/somefile.cs "slot" prior to or subsequent to the item you moved underneath B.

(In TFS 2010, "slot mode" is the default behavior; there's an -ItemMode option to request that your lookup be traced across history like it was 2008 rather than path-based.)

EDIT - no, branching is not a great alternative. While branching does leave enough metadata in the system to trace the full history to & from ProjectB, it's not terribly user friendly in 2008. Plan to spend a lot of time learning the tf merges command (no UI equivalent). 2010 dramatically improves your ability to visualize changes across multiple branches, but it's still not the clean unified experience you'd get from a Rename.

人海汹涌 2024-08-27 08:16:36

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

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

tf history $/ProjectB/somefile.cs

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

第一个问题是,使用 TFS2010 在 VS2010 中出现的 GUI 最初仅显示移动以来的历史记录。列表中最近的项目是重命名操作。它可以通过一个微妙的小下拉箭头来扩展。下面是之前位置的历史记录。如果您不知道查找此信息,您的历史记录可能会消失。

第二个问题是,如果您稍后删除 ProjectA(例如,因为您已经完成了到 ProjectB 的迁移),历史记录确实消失了。展开 $/ProjectB/somefile.cs 历史记录中的下拉列表不会生成较旧的历史记录。

Richard's answer above is well written and explains the situation well. I did have a couple more practical gotcha to add, however.

In TFS2010, the default behavior makes it seem like moving a file causes you to lose all history from before the move. The command my users are likely to use (and the one used, it seems, by the VS2010 GUI) is:

tf history $/ProjectB/somefile.cs

My users intend to get all the history of somefile.cs, both before and after the move. They want "the history of the code that is currently stored in $/ProjectB/somefile.cs", regardless of the filename at any point in time. Maybe other people see it differently.

The first gotcha is that the GUI that appears for me in VS2010 using TFS2010 initally shows only the history since the move. The least-recent item in the list is the rename operation. It can be expanded with a subtle little drop-down arrow. Underneath is the history from the previous location. If you don't know to look for this, it can look like your history is gone.

The second gotcha is that if you later delete ProjectA (because you've finished the migration to ProjectB, say), the history really is gone. Expanding the drop-down in the history for $/ProjectB/somefile.cs doesn't produce the older history.

温柔戏命师 2024-08-27 08:16:36

另一种选择(我认为更简单)是导入到 Git,然后使用 Git-TF 命令导出回 TFS线工具。

  • 从二进制、Choclatey 或源代码安装 Git-TF。

  • 克隆 TFS 文件夹:

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

  • 取消关联通过删除 .Git/tf 文件夹和 .Git/git-tf 文件,从 TFS 服务器中删除 Git Repo。

  • 配置新的 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“合并提交”

git tf checkin --deep

Another option (and I think easier) is to import to Git then export back to TFS using the Git-TF command line tools.

  • Install Git-TF from binary, Choclatey or source code.

  • Clone a TFS folder:

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

  • Disassociate the Git Repo from the TFS server by deleting the .Git/tf folder and the .Git/git-tf file.

  • Configure the new Git Repo to connect to an empty TFS folder.

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

  • Don't forget the --deep

git tf pull

You should get a message at this point "git-tf: this is a newly configured repository. There is nothing to fetch from tfs."

git commit -a -m "merge commit"

git tf checkin --deep

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文