How to get specific version of folder from tfs wit

2020-02-23 08:43发布

问题:

I would like to get the source code of a project at specific time (changeset). So I need do download whole folder. I would like to do it for different times and handling a different workspace is not very convenient.

I know about TFS Get Specific Version into separate folder (with workspace) and Need command to get a file from TFS without a workspace (one file).

Is there some solution for whole folder without creating a new workspace?

Edit I have found the accepted answer too ambitious. I needed something more simple.

Assumptions:

  • I can access TFS from Visual Studio on my computer
  • I want to get the ChangeSetNumber Changeset from the folder DesiredFolder in TFS project tProj

I run the following batch from a destination folder in Visual Studio Command Prompt

set workspace_name=TemporaryWorkspace%username%
set changeset= ChangeSetNumber                
tf workspace -new %workspace_name% -noprompt
tf workfold -map $/tProj . -workspace:%workspace_name%
tf get $/tProj/DesiredFolder -version:C%changeset% -recursive -noprompt
tf workfold -unmap . -workspace:%workspace_name%
tf workspace -delete %workspace_name% -noprompt

It is necessary to confirm remove source control association when starting the downloaded solution.

回答1:

I use this syntax for temporary workspaces:

tf workspace -new %JOB_NAME%;%user% -noprompt -server:http://%host%:8080/tfs/%project% -login:%user%,%password%
tf workfold -map $/Release/MilestoneX.X . -workspace:%JOB_NAME% -server:http://%host%:8080/tfs/%project% -login:%user%,%password%
tf get . -version:L%TFS_LABEL% -recursive -noprompt -login:%user%,%password%
tf workfold -unmap . -workspace:%JOB_NAME% -login:%user%,%password%
tf workspace -delete %JOB_NAME%;%user% -noprompt -server:http://%host%:8080/tfs/%project% -login:%user%,%password%


回答2:

I've discovered that you can do this through the HTTP api that TFS exposes. The "signature" for the URL is as follows:

http(s)://{server}:{port}/tfs/{collectionName}/{teamProjectName}/_api/_versioncontrol/itemContentZipped?version={versionSpec}&path={escapedPathToFolder}

So, if you have a project named "MyProject" in the DefaultCollection, and want to get the content of a folder called "MyFeature":

http://MyTfsServer:8080/tfs/DefaultCollection/MyProject/_api/_versioncontrol/itemContentZipped?version=C1001&path=%24%2FMyProject%2FMyFeature

I think "version" can be any version spec, which is documented in the TFS API documentation. My example is requesting the version as of change set 1001. I was using the .NET API to get a specific version, which is pretty straightforward, but slow because it can only get one file at a time. I'm trying to figure out if this same functionality is exposed through the .NET API because downloading the files this way is much much faster than getting a single file at a time.

I implemented this as an extension method on Microsoft.TeamFoundation.VersionControl.Client.Item. This returns a stream that contains a zip file. I had used this as part of a custom MSBuild task which then saves the contents of this stream to a file location.

public static class TfsExtensions
{

    const String ItemContentZippedFormat = "/_api/_versioncontrol/itemContentZipped?version={0}&path={1}&__v=3";

    public static Stream DownloadVersion(this Item folder, VersionSpec version)
    {
        if (folder.ItemType != ItemType.Folder)
            throw new ArgumentException("Item must be a folder", "folder");


        var vcs = folder.VersionControlServer;

        var collectionName = vcs.TeamProjectCollection.CatalogNode.Resource.DisplayName;

        var baseUri = folder.VersionControlServer.TeamFoundationServer.Uri;
        if (!baseUri.LocalPath.EndsWith(collectionName, StringComparison.OrdinalIgnoreCase))
            baseUri = new Uri(baseUri, baseUri.LocalPath + "/" + collectionName);


        var apiPath = String.Format(ItemContentZippedFormat, version.DisplayString, WebUtility.UrlEncode(folder.ServerItem));
        var downloadUri = new Uri(baseUri, baseUri.LocalPath + apiPath);

        var req = WebRequest.Create(downloadUri);
        req.Credentials = CredentialCache.DefaultCredentials;
        var response = req.GetResponse();
        return response.GetResponseStream();
    }
}


回答3:

I think you should create a temporary Workspace to retrieve the content you want, then delete the Workspace and keep the local items.

A Workspace in TFS is a local view of what's on the server, for a given Workspace you choose which folder(s) you want to retrieve locally and where you'll store the folders/files.

It's not like SourceSafe you're not bound to only one workspace, you can have as many as you want on a given computer.

So I suggest you to create a dedicated Workspace for the operation you want to do and get rid of it when you judge it appropriate.

Use the TF.exe workspace command to create/delete a Workspace from the Shell. Then TF.exe get to retrieve the files.



回答4:

You can use tf view to get a specific file without creating a workspace.

Retrieves a specific version of a file to a temporary folder on your computer and displays it.

tf vc view [/collection:TeamProjectCollectionUrl]
       [/console] [/recursive] [/output:localfile]
       [/shelveset:shelvesetname[;owner]] [/noprompt] itemspec
       [/version:versionspec] [/login:username,[password]]

Versionspec:
Date/Time         D"any .Net Framework-supported format"
                  or any of the date formats of the local machine
Changeset number  Cnnnnnn
Label             Llabelname
Latest version    T
Workspace         Wworkspacename;workspaceowner