Search code examples
tfstfs-power-tools

TFS UNDO others checkout - recursively for all users


As a TFS admin, time and again I have to archive/move the branches to other folders to make sure that our TFS folders are not cluttered with old un-used branches. But when I try to MOVE the branches, if any of the developers have checked-out a file from that branch in their workspace then TFS doesn't allow me complete the operation. I have to undo all those checkouts (by all the users) before I can MOVE the branch.

The TFS Power tools provides some relief here. It helps you to undo others checkout from within Visual studio (or command line). Right click the branch -> Find -> Find by Wildcard. You can see the screenshots below:

enter image description here

enter image description here

But the catch is that it can only perform the UNDO operation for one user at a time. So in a large organization if you have 100-200 developers working in a branch, that means if 100 developers have each checked out 1 file each from the branch, then I will have to press UNDO button 100 times to make the branch checkout free.

I searched extensively and couldnt find any out of the box solution. Finally the solution that I came up for this it to create a powershell script which queries the TFS (for a specific branch) to find the list of files checked out to users, then it loops through the user list and UNDO all the files checked-out to that user under the branch.

Does anyone have a better/easier solution? I will wait for inputs and if I dont see much response, I will add the script here so people who are in the similar situation can make use of it.


Solution

  • As @MrHinsh mentioned, you can install TFSSideKicks to solve the problem. Thank you MrHinsh.

    If you do not want to install additional tools, you can achieve the same by using the following powershell script. Update the following parameters in the script and run it:

    1. TF Location
    2. Branch Name
    3. TFS Collection Name
    4. Temp Log file location

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