使用PowerShell从Azure DevOps Git存储库中尝试下载文件

3

我将在Azure DevOps中创建一个Git代码库,其URL类似于以下:

https://[$server]/tfs/[$company]/[$project]/_git/[$repoName]

我可以通过在此基础上追加类似于以下内容来访问库中的单个文件:

?path=/[$folder]/[$fileName]

我想使用PowerShell从该代码库下载特定文件,并将其下载到对应的位置和文件名,如下所示:
$sourcePath = "https://[$server]/tfs/[$company]/[$project]/_git/[$repoName]?path=/[$folder]/[$fileName]&download=true"
$filePath = "C:\Documents\[$folder]\[$fileName]"
Invoke-RestMethod -Uri $sourcePath -Method Get -Headers @{Authorization=("Basic {0}" -f [$AuthInfo])} -OutFile $filePath

这样做的作用是将本地文件的内容替换为响应正文的内容,而不是使用来自存储库的文件替换本地文件。我发现很奇怪,所有我已经搜索过的谷歌都建议这样做,即使Microsoft关于Invoke-RestMethod的文章实际上解释了这就是-OutFile的功能。
注意,我也尝试过Invoke-WebRequest...同样的事情。
那么,如何将实际文件从存储库下载到我想要的本地目标(或者用存储库文件的内容替换本地目标文件的内容)?
此外,有没有一种方法指定从哪个分支获取文件?也许我应该以某种方式使用Git PowerShell命令?我所做的关于从git存储库下载文件的其他搜索结果都是关于GitHub的。
谢谢!

1
这是 Git 的解决方案,但我也很想看看如何在 Powershell 中实现- https://dev59.com/Al4c5IYBdhLWcg3wD2nC - OwlsSleeping
是的,@OwlsSleeping - 这不仅是 Git 的方式,而且看起来它是将文件下载到您克隆存储库的位置,而不是指定要下载到的位置(这是我需要能够做到的)。谢谢! - Andy
1
这不是真正的Git问题。Git的全部关注点在于提交(commit),作为存储库(repository)的一部分。提交(commit) 持有(hold) 文件(每个提交(commit)都至少是文件的存档),这里的技巧在于,但是从服务器中含有Git存储库的服务器上 获取(get) 一个文件*来自(from)*提交(commit)的方式,要取决于该服务器。这就是为什么您找到了所有这些特定于GitHub的答案。您需要一个特定于Azure的答案。 - torek
2个回答

3
请使用以下模板使用rest api:
GET https://{tfs_url}/{collection_name}/{project}/_apis/git/repositories/{repositoryId}/items?path={path}
请查看文档:Items - GetExample - Download 我在构建管道中使用以下代码(使用System.Net.WebClient)来复制文件:
$user = ""
$token = $env:SYSTEM_ACCESSTOKEN
$teamProject = $env:SYSTEM_TEAMPROJECT
$orgUrl = $env:SYSTEM_COLLECTIONURI
$repoName = "REPO_NAME"

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))

    function InvokeGetFileRequest ($GitFilePath, $OutFilePath)
    {
        Write-Host "Download file" $GitFilePath "to" $OutFilePath
     
        $uriGetFile = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/items?scopePath=$GitFilePath&download=true&api-version=6.1-preview.1"
    
       Write-Host "Url:" $uriGetFile
    
        $wc = New-Object System.Net.WebClient
        $wc.Headers["Authorization"] = "Basic {0}" -f $base64AuthInfo
        $wc.Headers["Content-Type"] = "application/json";
        $wc.DownloadFile($uriGetFile, $OutFilePath)
    }

嗯...不幸的是,这样做的结果是一样的——本地文件的内容被请求的内容替换了。谢谢你的帮助! - Andy
可能仅仅是因为我的代码库在“tfs” URL中,而不是像你的示例那样的“repositories” URL,所以才会出现这种情况吗?即使它们在技术上都是Azure DevOps,但对于这种情况,它们的行为方式也有所不同吗? - Andy
@Andy 对于TFS来说,应该是相同的$tfs_coolection_url/$team_project_name/_apis/git/repositories/$repoName/items?scopePath=$GitFilePath&download=true&api-version=5.0。请检查支持您的TFS的API版本:https://learn.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-rest-6.1#api-and-tfs-version-mapping。 - Shamrai Aleksander
问题实际上出在我使用的URL上,你给了我提示。我将"https://[$server]/tfs/[$company]/[$project]/_git/[$repoName]?path=/[$folder]/[$fileName]"改为"https://[$server]/tfs/[$company]/[$project]/_apis/git/repositories/[$repoName]/items?path=/[$folder]/[$fileName]"。然后就可以了!如果你想更新你的答案并指明URL的差异,我会将其标记为答案。谢谢! - Andy

0

我需要做这件事,但这里看到的方法都不起作用,所以我写了自己的代码:

param( 
    [Parameter(Mandatory=$true)] 
    [string] $GitFilePath,
    [Parameter(Mandatory=$true)] 
    [string] $OutFilePath,
    [Parameter(Mandatory=$true)] 
    [string] $RepoName,
    [string] $token,
    [string] $orgUrl,
    [string] $teamProject
)

if([String]::IsNullOrEmpty($token))
{
    if($env:SYSTEM_ACCESSTOKEN -eq $null)
    {
        Write-Error "you must either pass the -token parameter or use the BUILD_TOKEN environment variable"
        exit 1;
    }
    else
    {
        $token = $env:SYSTEM_ACCESSTOKEN;
    }
}


if([string]::IsNullOrEmpty($teamProject)){
    if($env:SYSTEM_TEAMPROJECT -eq $null)
    {
        Write-Error "you must either pass the -teampProject parameter or use the SYSTEM_TEAMPROJECT environment variable"
        exit 1;
    }
    else
    {
        $teamProject = $env:SYSTEM_TEAMPROJECT
    }
}

if([string]::IsNullOrEmpty($orgUrl)){
    if($env:SYSTEM_COLLECTIONURI -eq $null)
    {
        Write-Error "you must either pass the -orgUrl parameter or use the SYSTEM_COLLECTIONURI environment variable"
        exit 1;
    }
    else
    {
        $teamProject = $env:SYSTEM_COLLECTIONURI
    }
}

# Base64-encodes the Personal Access Token (PAT) appropriately  
$User='' 
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User,$token)));  
$header = @{Authorization=("Basic {0}" -f $base64AuthInfo)};  
#---------------------------------------------------------------------- 

Write-Host "Download file" $GitFilePath "to" $OutFilePath
     
$uriGetFile = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/items?scopePath=$GitFilePath&download=true&api-version=6.1-preview.1"
    
Write-Host "Url:" $uriGetFile
    
$filecontent = Invoke-RestMethod -ContentType "application/json" -UseBasicParsing -Headers $header -Uri $uriGetFile
$filecontent | Out-File -Encoding utf8 $OutFilePath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接