如何在我的PS脚本中获取Git提交哈希?

3
我正在使用PowerShell脚本调用msbuild并向OctopusDeploy传递版本号,如下所示:
msbuild "Xyz.sln" /t:Rebuild /p:Configuration=Release /p:RunOctoPack=true /p:OctopackPackageVersion=$versionNumber

...其中$versionNumber是在PS脚本中生成的。我希望做的是将Git提交哈希的前16个字符添加到版本字符串的末尾,以便它最终看起来像:

2.yyyyMMdd.HHmmss-git-6d34e44340f95c2a

我该如何做到这一点?考虑到它们现在内置了Git支持,我是否可以让msbuild或Visual Studio以某种方式返回当前的git提交哈希值?


如果你想使用git和.Net进行版本控制,可以看一下GitVersion https://github.com/GitTools/GitVersion,它可以帮助你进行语义化版本控制(这是一个好习惯!)。甚至还有一个msbuild任务...时间戳不是一个很好的做法,你应该优先考虑git拓扑结构(GitVersion可以帮助你轻松实现)。 - Philippe
3个回答

14

您实际上可以直接在msbuild中执行此操作,以便它能在VS和大多数CI系统中无需任何额外步骤(如PowerShell脚本)运行,甚至可以在跨平台的dotnet CLI和mono上运行。

您可以在项目或解决方案(>影响所有项目)目录中创建一个名为Directory.Build.targets的文件,并使用以下内容(假设MSBuild 15 / VS 2017. 如果较低,则需要手动导入或将此目标插入每个项目):

<Project>
  <Target Name="DetermineOctopackVersion" BeforeTargets="Build" Condition=" '$(RunOctoPack)' == 'true' ">
    <Exec Command="git rev-parse HEAD" ConsoleToMSBuild="true" StandardOutputImportance="low">
      <Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" />
    </Exec>
    <PropertyGroup>
      <VersionDatePart>$([System.DateTime]::get_Now().ToString(yyyyMMdd.HHmmss))</VersionDatePart>
      <OctopackPackageVersion>2.$(VersionDatePart)-git-$(GitCommitHash.Substring(0,16))</OctopackPackageVersion>
    </PropertyGroup>
  </Target>
</Project>

如果您希望在每次构建时设置属性,而不仅仅是在 RunOctoPacktrue 时进行设置,则只需删除 Condition 属性。

但如果您需要在 PowerShell 中执行此操作,可以调用 git 命令并捕获其输出:

$commitHash = (git rev-parse HEAD).Substring(0,16)
$versionDatePart = [System.DateTime]::Now.ToString('yyyyMMdd.HHmmss')
$version = "1.$versionDatePart-git-$commitHash"

如果你真的想避免调用 git(尽管没有一个像样的构建系统设置可以完全没有 git 安装..),你还可以在 PowerShell 或 MSBuild 中使用 [System.IO.File]::ReadAllText(".git\refs\heads\master") 从 git 目录中读取(在分离状态下,.git\HEAD 将包含哈希值,当使用分支时,它将包含要查找哈希值的文件位置)。


我想问一下,你的两个解决方案都需要在机器上安装 git.exe 吗?在这种情况下,我不能做出这样的假设。 - Jez
2
最佳实践是使用设置构建的git版本。您可以像其他版本一样加载libgit#,或者自己查找文件,但我强烈建议使用git.exe方法,因为它是最跨平台的方法(个人而言,我认为没有安装git的环境不算是开发或构建环境)。 - Martin Ullrich
如果您使用 dotnet msbuild,那么没有办法下载和解析在主机运行时保证可用的 LibGit# 版本(因为不需要安装 VS,而且您可能正在 Linux 上运行)。 - Martin Ullrich
你说的“设置构建”的git版本是什么意思? - Jez

1

由于您想避免调用 git.exe,并且希望在 PowerShell 中进行提交处理,因此您可以将 C# 解决方案转换为 PowerShell,方法如下:

[System.Reflection.Assembly]::LoadFrom("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TeamFoundation\\Team Explorer\\LibGit2Sharp.dll") | Out-Null

$repo = [LibGit2Sharp.Repository]::new("C:\MyRepo")
$repo.Commits | Select-Object -First 1

这将返回包含以下数据的LibGit2Sharp提交对象。
Message      : Further harden mutex closing process

MessageShort : Further harden mutex closing process
Encoding     : UTF-8
Author       : 
Committer    : 
Tree         : {.gitattributes, .gitignore, Build, Doc...}
Parents      : {fe26fc1a476f18bfa8a70c315fdbd96f1434d29c}
Notes        : {}
Id           : 1ba7bce90444a323fa9079cb06e5921afd0c3cd8
Sha          : 1ba7bce90444a323fa9079cb06e5921afd0c3cd8
Repository   : LibGit2Sharp.Repository

您需要使用32位(x86)的PowerShell.exe来调用此功能。


为什么这需要32位版本,有没有不需要的方法? - Jez
请注意,使用VS 2017时,每个安装的版本可能会因VS的版本(社区版、企业版等)和发布/预览而有所不同,所有这些版本都可以并行安装。 - Martin Ullrich
1
因为这个版本的Visual Studio是32位的。 - Michael Baker

0
最终我所做的就是将NGit与我的Powershell脚本捆绑在一起(文件NGit.dllSharpen.dllICSharpCode.SharpZipLib.dll),然后使用类似以下代码来生成带有git哈希后缀的版本号:
[System.Reflection.Assembly]::LoadFrom("Ngit.dll") | Out-Null
[System.Reflection.Assembly]::LoadFrom("Sharpen.dll") | Out-Null
[System.Reflection.Assembly]::LoadFrom("ICSharpCode.SharpZipLib.dll") | Out-Null

# *** Git repo base path (should contain .sln file) ***
$repoPath = "C:\Path\To\Repo"

# *** OctopusDeploy API key for publishing ***
$octoApiKey = "API-[PublishKey]"

#######################################################

# *** Get and process current Git commit hash ***
$sharpenRepoPath = New-Object -TypeName Sharpen.FilePath -ArgumentList "$($repoPath)\.git"
$repoBuilder = New-Object -TypeName NGit.RepositoryBuilder
$repo = $repoBuilder.SetGitDir($sharpenRepoPath).Build()
$headHash = $repo.Resolve("HEAD").Name.Substring(0,12)

# *** Version when pushing to OctopusDeploy NuGet ***
$versionNumber = "2." + [datetime]::now.tostring("yyyyMMdd.HHmmss") + "-git-" + $headHash

# *** Pause before publish ****
Write-Host "About to publish to OctopusDeploy NuGet with version number:"
Write-Host "    $($versionNumber)"
cmd /c pause

# *** OctopusDeploy build and push ***
msbuild "$repoPath\MySolution.sln" /t:Rebuild /p:Configuration=Release /p:RunOctoPack=true /p:OctopackPackageVersion=$versionNumber /p:OctoPackPublishPackageToHttp=https://my.nuget.server/nuget/packages /p:OctoPackPublishApiKey=$octoApiKey

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