You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编程下载TFS工作项附件 完成TFS向GitLab迁移

TFS工作项附件批量下载及迁移实现方案

基于官方.NET客户端的稳定实现(无文件损坏问题)

该方案适配TFS 2017/2018/2019全版本,是经过生产环境迁移验证的可靠方式:

  • 前置准备:在项目中安装与当前TFS大版本匹配的Microsoft.TeamFoundationServer.Client NuGet包,避免版本兼容导致的接口报错
  • 核心注意点:禁止直接用无认证的HTTP客户端请求附件URL,否则会被重定向到TFS登录页,下载到的是HTML内容而非原文件,表现为文件损坏
  • 核心实现代码:
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
using System.IO;

// 初始化TFS连接
var tfsCollectionUrl = new Uri("http://你的TFS服务地址/tfs/目标项目集合名称");
var credentials = new VssBasicCredential(string.Empty, "你申请的TFS个人访问令牌");
using var connection = new Microsoft.VisualStudio.Services.WebApi.VssConnection(tfsCollectionUrl, credentials);
using var workItemClient = connection.GetClient<WorkItemTrackingHttpClient>();

// 拉取所有需要迁移的工作项ID
var queryResult = await workItemClient.QueryByWiqlAsync(new Wiql
{
    Query = "SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = '你的项目名称'"
});
var targetWorkItemIds = queryResult.WorkItems.Select(item => item.Id).ToList();

// 批量拉取工作项完整信息,包含附件关联数据
var workItemDetails = await workItemClient.GetWorkItemsAsync(targetWorkItemIds, expand: WorkItemExpand.Relations);

foreach (var workItem in workItemDetails)
{
    if (workItem.Relations == null) continue;
    // 筛选出附件类型的关联项
    var attachedFiles = workItem.Relations.Where(rel => rel.Rel == "AttachedFile");
    foreach (var attachment in attachedFiles)
    {
        var attachmentId = Guid.Parse(attachment.Url.Split('/').Last());
        var fileName = Path.GetFileName(new Uri(attachment.Url).AbsolutePath);
        // 通过官方客户端方法拉取附件流,自动带认证信息
        using var attachmentStream = await workItemClient.GetAttachmentContentAsync(attachmentId);
        // 按工作项ID分目录存储,方便后续和GitLab议题做映射
        var savePath = Path.Combine("D:\\TFS附件备份", workItem.Id.ToString());
        Directory.CreateDirectory(savePath);
        using var outputFile = File.Create(Path.Combine(savePath, fileName));
        await attachmentStream.CopyToAsync(outputFile);
    }
}

轻量脚本实现方案(无需.NET开发环境)

如果不想编写C#程序,也可以用Python/Shell等脚本直接调用TFS REST API实现,流程完全一致:

  1. 申请拥有工作项读取权限的个人访问令牌作为认证凭证
  2. 调用工作项查询接口获取所有目标工作项的ID列表
  3. 逐个请求工作项详情接口,提取所有关联类型为AttachedFile的附件地址
  4. 请求附件地址时必须在请求头携带认证信息,将返回的二进制流直接保存为对应文件名即可

GitLab迁移配套操作

附件全部备份到本地后,创建GitLab议题时,可将对应工作项目录下的附件调用GitLab上传接口上传,拿到GitLab侧的附件访问地址后,替换原工作项描述中的附件引用,即可完成附件和议题的关联映射,不需要手动逐个上传。

内容的提问来源于stack exchange,提问作者B. Cratty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 15:18:15