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 脚本来达到同样的目的。更新脚本和 运行 中的以下参数:

  1. TF 位置
  2. 分行名称
  3. TFS 集合名称
  4. 临时日志文件位置

$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);