TFS UNDO others checkout - 对所有用户递归
TFS UNDO others checkout - recursively for all users
作为 TFS 管理员,我不得不一次又一次地 archive/move 将分支分支到其他文件夹,以确保我们的 TFS 文件夹不会被旧的未使用的分支弄得乱七八糟。但是,当我尝试移动分支时,如果任何开发人员已从其工作区中的该分支签出文件,则 TFS 不允许我完成该操作。在移动分支之前,我必须撤消所有这些结帐(所有用户)。
TFS Power 工具在这里提供了一些缓解。它可以帮助您从 Visual studio(或命令行)中撤消其他结帐。右键单击分支 -> 查找 -> 按通配符查找。您可以看到下面的屏幕截图:
但问题是它一次只能为一个用户执行 UNDO 操作。所以在一个大型组织中,如果你有 100-200 名开发人员在一个分支机构工作,这意味着如果 100 名开发人员每人从分支机构签出 1 个文件,那么我将不得不按 UNDO 按钮 100 次以使分支签出免费。
我进行了广泛的搜索,但找不到任何开箱即用的解决方案。最后,我为此提出的解决方案是创建一个 powershell 脚本,该脚本查询 TFS(针对特定分支)以查找签出给用户的文件列表,然后遍历用户列表并撤消所有已检查的文件-到分支下的那个用户。
有人有 better/easier 解决方案吗?我会等待输入,如果没有看到太多响应,我会在此处添加脚本,以便处于类似情况的人可以使用它。
您应该使用 TFS Sidekicks。他们能够轻松发现和撤消这些更改。
http://www.attrice.info/cm/tfs/
然而,我会质疑 'moving' 分支机构的可行性,因为 TFS 在幕后 'branch+delete'。您最好删除分支并使用 'show deleted items' 切换来查看旧内容...
如@MrHinsh 所述,您可以安装 TFSideKicks 来解决问题。谢谢 MrHinsh。
如果您不想安装额外的工具,您可以使用以下powershell 脚本来达到同样的目的。更新脚本和 运行 中的以下参数:
- TF 位置
- 分行名称
- TFS 集合名称
- 临时日志文件位置
$tfLocation = "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE"
$tfsBranchName = “{enter your TFS branch/folder/file location}“
$tfsCollectionName = "http://tfsserver:8080/tfscollection”
$logFile = “{log file location}“
Function GetUserFileList($tfsBranchName)
{
try{
# Array to hold the object (user/file/workspace) objects
$arrayFileUserMapping = @();
If (Test-Path $logFile)
{
Remove-Item $logFile;
}
Set-Location $tfLocation;
.\tf.exe status $tfsBranchName /collection:$tfsCollectionName /user:* /format:detailed /recursive >> $logFile;
Set-Location $PSScriptRoot;
foreach ($line in Get-Content $logFile)
{
If($line.StartsWith("$"))
{
$objCurrFile = New-Object System.Object;
$splitStringFile = $line -Split ";";
$objCurrFile | Add-Member -type NoteProperty -name FileName -value $splitStringFile[0];
}
Else
{
foreach ($singleLine in $line){
If($singleLine.StartsWith(" User"))
{
$splitStringUser = $singleLine -Split ":";
$objCurrFile | Add-Member -type NoteProperty -name User -value $splitStringUser[1];
}
ElseIf($singleLine.StartsWith(" Workspace"))
{
$splitStringWS = $singleLine -Split ":";
$objCurrFile | Add-Member -type NoteProperty -name Workspace -value $splitStringWS[1];
}
}
}
$arrayFileUserMapping += $objCurrFile;
}
$uniqueWorkspaceArray = $arrayFileUserMapping | Group Workspace
$uniqueUserArray = $arrayFileUserMapping | Group User
for($i=0;$i -lt $uniqueUserArray.count; $i++)
{
$workspaceWOSpace = $uniqueWorkspaceArray[$i].Name.Trim()
$userWOSpace = $uniqueUserArray[$i].Name.Trim()
$workspace = $workspaceWOSpace + ";" + $userWOSpace;
Set-Location $tfLocation;
.\tf.exe undo $tfsBranchName /collection:$tfsCollectionName /workspace:""$workspace"" /recursive /noprompt;
Set-Location $PSScriptRoot;
}
}
Catch [system.exception]
{
"Oops, something's wrong!!!"
}
}
GetUserFileList($tfsBranchName);
作为 TFS 管理员,我不得不一次又一次地 archive/move 将分支分支到其他文件夹,以确保我们的 TFS 文件夹不会被旧的未使用的分支弄得乱七八糟。但是,当我尝试移动分支时,如果任何开发人员已从其工作区中的该分支签出文件,则 TFS 不允许我完成该操作。在移动分支之前,我必须撤消所有这些结帐(所有用户)。
TFS Power 工具在这里提供了一些缓解。它可以帮助您从 Visual studio(或命令行)中撤消其他结帐。右键单击分支 -> 查找 -> 按通配符查找。您可以看到下面的屏幕截图:
但问题是它一次只能为一个用户执行 UNDO 操作。所以在一个大型组织中,如果你有 100-200 名开发人员在一个分支机构工作,这意味着如果 100 名开发人员每人从分支机构签出 1 个文件,那么我将不得不按 UNDO 按钮 100 次以使分支签出免费。
我进行了广泛的搜索,但找不到任何开箱即用的解决方案。最后,我为此提出的解决方案是创建一个 powershell 脚本,该脚本查询 TFS(针对特定分支)以查找签出给用户的文件列表,然后遍历用户列表并撤消所有已检查的文件-到分支下的那个用户。
有人有 better/easier 解决方案吗?我会等待输入,如果没有看到太多响应,我会在此处添加脚本,以便处于类似情况的人可以使用它。
您应该使用 TFS Sidekicks。他们能够轻松发现和撤消这些更改。
http://www.attrice.info/cm/tfs/
然而,我会质疑 'moving' 分支机构的可行性,因为 TFS 在幕后 'branch+delete'。您最好删除分支并使用 'show deleted items' 切换来查看旧内容...
如@MrHinsh 所述,您可以安装 TFSideKicks 来解决问题。谢谢 MrHinsh。
如果您不想安装额外的工具,您可以使用以下powershell 脚本来达到同样的目的。更新脚本和 运行 中的以下参数:
- TF 位置
- 分行名称
- TFS 集合名称
- 临时日志文件位置
$tfLocation = "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE"
$tfsBranchName = “{enter your TFS branch/folder/file location}“
$tfsCollectionName = "http://tfsserver:8080/tfscollection”
$logFile = “{log file location}“
Function GetUserFileList($tfsBranchName)
{
try{
# Array to hold the object (user/file/workspace) objects
$arrayFileUserMapping = @();
If (Test-Path $logFile)
{
Remove-Item $logFile;
}
Set-Location $tfLocation;
.\tf.exe status $tfsBranchName /collection:$tfsCollectionName /user:* /format:detailed /recursive >> $logFile;
Set-Location $PSScriptRoot;
foreach ($line in Get-Content $logFile)
{
If($line.StartsWith("$"))
{
$objCurrFile = New-Object System.Object;
$splitStringFile = $line -Split ";";
$objCurrFile | Add-Member -type NoteProperty -name FileName -value $splitStringFile[0];
}
Else
{
foreach ($singleLine in $line){
If($singleLine.StartsWith(" User"))
{
$splitStringUser = $singleLine -Split ":";
$objCurrFile | Add-Member -type NoteProperty -name User -value $splitStringUser[1];
}
ElseIf($singleLine.StartsWith(" Workspace"))
{
$splitStringWS = $singleLine -Split ":";
$objCurrFile | Add-Member -type NoteProperty -name Workspace -value $splitStringWS[1];
}
}
}
$arrayFileUserMapping += $objCurrFile;
}
$uniqueWorkspaceArray = $arrayFileUserMapping | Group Workspace
$uniqueUserArray = $arrayFileUserMapping | Group User
for($i=0;$i -lt $uniqueUserArray.count; $i++)
{
$workspaceWOSpace = $uniqueWorkspaceArray[$i].Name.Trim()
$userWOSpace = $uniqueUserArray[$i].Name.Trim()
$workspace = $workspaceWOSpace + ";" + $userWOSpace;
Set-Location $tfLocation;
.\tf.exe undo $tfsBranchName /collection:$tfsCollectionName /workspace:""$workspace"" /recursive /noprompt;
Set-Location $PSScriptRoot;
}
}
Catch [system.exception]
{
"Oops, something's wrong!!!"
}
}
GetUserFileList($tfsBranchName);