在.Net dll中嵌入git commit hash

bav*_*aza 84 c# git

我正在构建一个C#应用程序,使用Git作为我的版本控制.

有没有办法在构建应用程序时自动将最后一个提交哈希嵌入可执行文件中?

例如,将提交哈希打印到控制台看起来像:

class PrintCommitHash
{
    private String lastCommitHash = ?? // What do I put here?
    static void Main(string[] args)
    {
        // Display the version number:
        System.Console.WriteLine(lastCommitHash );
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这必须在构建时完成,而不是在运行时完成,因为我部署的可执行文件不会访问git repo.

可以在此处找到C++的相关问题.

编辑

Per @ mattanja的请求,我发布了我在项目中使用的git钩子脚本.设置:

  • 钩子是linux shell脚本,位于:path_to_project\.git\hooks下
  • 如果您使用的是msysgit,则hooks文件夹中已包含一些示例脚本.为了让git调用它们,从脚本名称中删除".sample"扩展名.
  • 钩子脚本的名称与调用它们的事件匹配.就我而言,我修改后提交合并后.
  • 我的AssemblyInfo.cs文件直接位于项目路径下(与.git文件夹相同).它包含23行,我使用git生成第24行.

由于我的linux-shelling有点生疏,脚本只是将AssemblyInfo.cs的前23行读取到临时文件,将git散列回到最后一行,然后将文件重命名为AssemblyInfo.cs.我确信有更好的方法可以做到这一点:

#!/bin/sh
cmt=$(git rev-list --max-count=1 HEAD)
head -23 AssemblyInfo.cs > AssemblyInfo.cs.tmp
echo [assembly: AssemblyFileVersion\(\"$cmt\"\)] >> AssemblyInfo.cs.tmp
mv AssemblyInfo.cs.tmp AssemblyInfo.cs
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

Joh*_*sus 68

您可以将version.txt文件嵌入到可执行文件中,然后从可执行文件中读取version.txt.要创建version.txt文件,请使用git describe --long

以下是步骤:

使用构建事件来调用git

  • 右键单击该项目,然后选择"属性"

  • 在Build Events中,添加包含(注意引号)的Pre-Build事件:

    "C:\ Program Files\Git\bin\git.exe"描述--long>"$(ProjectDir)\ version.txt"

    这将在项目目录中创建一个version.txt文件.

将version.txt嵌入可执行文件中

  • 右键单击该项目,然后选择Add Existing Item
  • 添加version.txt文件(更改文件选择器过滤器以便您查看所有文件)
  • 添加version.txt后,在解决方案资源管理器中右键单击它,然后选择"属性"
  • 将构建操作更改为嵌入式资源
  • 将复制更改为输出目录以始终复制
  • version.txt添加到.gitignore文件中

读取嵌入的文本文件版本字符串

这里有一些示例代码来读取嵌入的文本文件版本字符串:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;

namespace TryGitDescribe
{
    class Program
    {
        static void Main(string[] args)
        {
            string gitVersion= String.Empty;
            using (Stream stream = Assembly.GetExecutingAssembly()
                    .GetManifestResourceStream("TryGitDescribe." + "version.txt"))
            using (StreamReader reader = new StreamReader(stream))
            {
                gitVersion= reader.ReadToEnd();
            }

            Console.WriteLine("Version: {0}", gitVersion);
            Console.WriteLine("Hit any key to continue");
            Console.ReadKey();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这种方法运作得相当好.不过,我使用了"git rev-parse --short HEAD". (7认同)
  • 我使用`git describe --dirty`,当开发人员使用脏工作树时,它会添加一个标志. (5认同)
  • 我用`git describe --always`来使用标签或回退到缩写哈希 (3认同)
  • 啊好。我使用了“ git describe”,因为当您有标签时,它对我而言真的很有趣;版本信息包含标签以及标签应用后的提交次数;以前从未在SCM中看到过类似的东西。 (2认同)
  • @TamásSzelei项目命名空间是TryGitDescribe.将version.txt文件嵌入到可执行文件/程序集工件中之后,您需要预先添加命名空间以将其取出. (2认同)
  • 感谢您提供完整的解决方案。就我而言,我使用了GetEntryAssembly来获取程序集。在任何情况下,您都可以调用`GetName()。Name`以避免对名称进行硬编码。 (2认同)

Han*_*man 51

我们在git中使用标签来跟踪版本.

git tag -a v13.3.1 -m "version 13.3.1"
Run Code Online (Sandbox Code Playgroud)

您可以通过git获取带有哈希的版本:

git describe --long
Run Code Online (Sandbox Code Playgroud)

我们的构建过程将git哈希放在AssemblyInfo.cs文件的AssemblyInformationalVersion属性中:

[assembly: AssemblyInformationalVersion("13.3.1.74-g5224f3b")]
Run Code Online (Sandbox Code Playgroud)

编译后,您可以从Windows资源管理器中查看版本:

在此输入图像描述

您也可以通过以下方式以编程方式获取:

var build = ((AssemblyInformationalVersionAttribute)Assembly
  .GetAssembly(typeof(YOURTYPE))
  .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false)[0])
  .InformationalVersion;
Run Code Online (Sandbox Code Playgroud)

其中YOURTYPE是具有AssemblyInformationalVersion属性的程序集中的任何类型.

  • 嗨,我想在一个月前问,但是,我没有足够的代表发表评论.当你说"我们的构建过程将git哈希放在AssemblyInfo.cs的AssemblyInformationalVersion属性中"时,那究竟是什么?你只是做一个视觉工作室构建,或者,你使用像NAnt或其他工具? (10认同)
  • 以下项目[https://github.com/jeromerg/NGitVersion ](https://github.com/jeromerg/NGitVersion)提供了一个完整的解决方案,可以在编译时为C#和C++项目生成`GlobalAssemblyInfo.*`文件:默认情况下,生成的程序集版本包含:提交哈希,表示本地更改的标志,以及计算从存储库根目录到当前提交的提交量的增量. (4认同)
  • @John Jesus - 正如Lazy Badger建议的那样,你也可以在提交/合并等之后使用git hooks来改变AssemblyInfo.cs(这就是我最终做的事情).请参阅https://www.kernel.org/pub/software/scm/git/docs/githooks.html (3认同)
  • 我们使用ruby(rake)来自动构建.我们的rake构建任务之一更新了解决方案中所有项目使用的CommonAssemblyInfo.cs文件.该任务使用albacore生成CommonAssemblyInfo.cs文件 - https://github.com/derickbailey/Albacore任务集之一的AssemblyInfo值之一是AssemblyInformationalVersion. (2认同)

Mar*_*lug 32

我已经创建了一个简单的nuget包,您可以将其包含在您的项目中,它将为您解决此问题:https://www.nuget.org/packages/MSBuildGitHash/

这个nuget包实现了一个"纯粹"的MSBuild解决方案.如果你不想依赖nuget包,你可以简单地将这些Targets复制到你的csproj文件中,它应该包含git hash作为自定义程序集属性:

<Target Name="GetGitHash" BeforeTargets="WriteGitHash" Condition="'$(BuildHash)' == ''">
  <PropertyGroup>
    <!-- temp file for the git version (lives in "obj" folder)-->
    <VerFile>$(IntermediateOutputPath)gitver</VerFile>
  </PropertyGroup>

  <!-- write the hash to the temp file.-->
  <Exec Command="git -C $(ProjectDir) describe --long --always --dirty &gt; $(VerFile)" />

  <!-- read the version into the GitVersion itemGroup-->
  <ReadLinesFromFile File="$(VerFile)">
    <Output TaskParameter="Lines" ItemName="GitVersion" />
  </ReadLinesFromFile>
  <!-- Set the BuildHash property to contain the GitVersion, if it wasn't already set.-->
  <PropertyGroup>
    <BuildHash>@(GitVersion)</BuildHash>
  </PropertyGroup>    
</Target>

<Target Name="WriteGitHash" BeforeTargets="CoreCompile">
  <!-- names the obj/.../CustomAssemblyInfo.cs file -->
  <PropertyGroup>
    <CustomAssemblyInfoFile>$(IntermediateOutputPath)CustomAssemblyInfo.cs</CustomAssemblyInfoFile>
  </PropertyGroup>
  <!-- includes the CustomAssemblyInfo for compilation into your project -->
  <ItemGroup>
    <Compile Include="$(CustomAssemblyInfoFile)" />
  </ItemGroup>
  <!-- defines the AssemblyMetadata attribute that will be written -->
  <ItemGroup>
    <AssemblyAttributes Include="AssemblyMetadata">
      <_Parameter1>GitHash</_Parameter1>
      <_Parameter2>$(BuildHash)</_Parameter2>
    </AssemblyAttributes>
  </ItemGroup>
  <!-- writes the attribute to the customAssemblyInfo file -->
  <WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
</Target>
Run Code Online (Sandbox Code Playgroud)

这里有两个目标.第一个,"GetGitHash",将git哈希加载到名为BuildHash的MSBuild属性中,只有在尚未定义BuildHash的情况下才会执行此操作.如果您愿意,这允许您在命令行上将其传递给MSBuild.您可以将它传递给MSBuild,如下所示:

MSBuild.exe myproj.csproj /p:BuildHash=MYHASHVAL

第二个目标"WriteGitHash"将哈希值写入名为"CustomAssemblyInfo.cs"的临时"obj"文件夹中的文件.该文件将包含如下所示的行:

[assembly: AssemblyMetadata("GitHash", "MYHASHVAL")]

此CustomAssemblyInfo.cs文件将编译到程序集中,因此您可以使用反射来查找AssemblyMetadata运行时.以下代码显示了当AssemblyInfo类包含在同一程序集中时如何执行此操作.

using System.Linq;
using System.Reflection;

public static class AssemblyInfo
{
    /// <summary> Gets the git hash value from the assembly
    /// or null if it cannot be found. </summary>
    public static string GetGitHash()
    {
        var asm = typeof(AssemblyInfo).Assembly;
        var attrs = asm.GetCustomAttributes<AssemblyMetadataAttribute>();
        return attrs.FirstOrDefault(a => a.Key == "GitHash")?.Value;
    }
}
Run Code Online (Sandbox Code Playgroud)

这种设计的一些好处是它不会触及项目文件夹中的任何文件,所有变异文件都在"obj"文件夹下.您的项目也将在Visual Studio或命令行中以相同方式构建.它也可以很容易地为您的项目定制,并将与您的csproj文件一起进行源代码控制.

  • 这是一个工作示例: &lt;Project Sdk="Microsoft.NET.Sdk"&gt; &lt;Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation"&gt; &lt;Exec Command="git describe --long --always --exclude=* - -abbrev=8" ConsoleToMSBuild="True" IgnoreExitCode="False"&gt; &lt;Output PropertyName="SourceRevisionId" TaskParameter="ConsoleOutput"/&gt; &lt;/Exec&gt; &lt;/Target&gt; &lt;PropertyGroup&gt; &lt;Version&gt;0.0.2.0&lt;/Version &gt; &lt;信息版本&gt;$(版本)$(SourceRevisionId)&lt;/信息版本&gt; &lt;/属性组&gt; (5认同)
  • 这工作得很好。我安装了 nuget 包,并能够使用 `Assembly.GetExecutingAssembly()` 提取 git 哈希,然后检查程序集 `CustomAttributes`。 (2认同)
  • @danmiser 我不知道“UseMerge/SingleAssemblyName”是什么,所以我帮不了你。在 https://github.com/MarkPflug/MSBuildGitHash 上创建一个问题,我可能会看看它(这不是承诺)。 (2认同)
  • 感谢您的现代答案 - 非常干净的方法来做到这一点。对于任何未来遇到与我相同问题的读者:为了让这个工作(对于 SDK 项目方法),我还需要 `IncludeSourceRevisionInInformationalVersion` 属性,并且我还必须在InitializeSourceControlInformation 目标,但在使用 `BeforeTargets="InitializeSourceControlInformation"` 声明的单独目标中。 (2认同)
  • 对于那些像我一样努力应用新的(更新的)答案的人:您需要将带有“Target”的部分添加到 csproj 或“Directory.Build.targets”。另外,由于某种原因,名称“InitializeSourceControlInformation”最初对我不起作用。您还可以向 `Target` 标签添加 `Condition` 属性,即限制此目标仅适用于非调试配置 `Condition="'$(ConfigurationName)' != 'Debug'"` (2认同)

sch*_*ick 12

另一种方法是使用NetRevisionTool和一些On-Board Visual Studio魔术.我将在这里展示Visual Studio 2013专业版,但这也适用于其他版本.

首先下载NetRevisionTool.您在PATH中包含NetRevisionTool.exe或将其签入到您的存储库中并创建Visual Studio预构建和构建后操作并更改AssemblyInfo.cs.

将您的git-hash添加到AssemblyInformationVersion的示例如下:在您的项目设置中:

在此输入图像描述

在项目的AssemblyInfo.cs中,您可以更改/添加行:

[assembly:AssemblyInformationalVersion("1.1.{dmin:2015}.{chash:6} {!} - {branch}")]

在显示的屏幕截图中,我在External/bin文件夹中的NetRevisionTool.exe中进行了检查

在构建之后,如果您然后右键单击二进制文件并转到属性,那么您应该看到类似以下内容:

在此输入图像描述

希望这有助于那里的人

  • 问题是NetRevision没有找到我的git可执行文件.原因是因为我们正在使用SourceTree并且git嵌入了它.解决方案是将git.exe和libiconv-2.dll从%USERPROFILE%\ AppData\Local\Atlassian\SourceTree\git_local\bin复制到包含NetRevision.exe的文件夹.我还必须像这样修改事件:预构建事件:cd $(ProjectDir)库NetRevisionTool.exe/patch $(ProjectDir)构建后事件:cd $(ProjectDir)库NetRevisionTool.exe/restore $(ProjectDir) (2认同)

小智 12

我认为这个问题值得给出一个完整的循序渐进的答案.这里的策略是从预构建事件运行powershell脚本,该脚本接收模板文件并生成包含git标签+提交计数信息的AssemblyInfo.cs文件.

步骤1:根据原始AssemblyInfo.cs在Project\Properties文件夹中创建AssemblyInfo_template.cs文件,但包含:

[assembly: AssemblyVersion("$FILEVERSION$")]
[assembly: AssemblyFileVersion("$FILEVERSION$")]
[assembly: AssemblyInformationalVersion("$INFOVERSION$")]
Run Code Online (Sandbox Code Playgroud)

步骤2:创建名为InjectGitVersion.ps1的powershell脚本,其源代码为:

# InjectGitVersion.ps1
#
# Set the version in the projects AssemblyInfo.cs file
#


# Get version info from Git. example 1.2.3-45-g6789abc
$gitVersion = git describe --long --always;

# Parse Git version info into semantic pieces
$gitVersion -match '(.*)-(\d+)-[g](\w+)$';
$gitTag = $Matches[1];
$gitCount = $Matches[2];
$gitSHA1 = $Matches[3];

# Define file variables
$assemblyFile = $args[0] + "\Properties\AssemblyInfo.cs";
$templateFile =  $args[0] + "\Properties\AssemblyInfo_template.cs";

# Read template file, overwrite place holders with git version info
$newAssemblyContent = Get-Content $templateFile |
    %{$_ -replace '\$FILEVERSION\$', ($gitTag + "." + $gitCount) } |
    %{$_ -replace '\$INFOVERSION\$', ($gitTag + "." + $gitCount + "-" + $gitSHA1) };

# Write AssemblyInfo.cs file only if there are changes
If (-not (Test-Path $assemblyFile) -or ((Compare-Object (Get-Content $assemblyFile) $newAssemblyContent))) {
    echo "Injecting Git Version Info to AssemblyInfo.cs"
    $newAssemblyContent > $assemblyFile;       
}
Run Code Online (Sandbox Code Playgroud)

步骤3:将InjectGitVersion.ps1文件保存到BuildScripts文件夹中的解决方案目录

第4步:将以下行添加到项目的预构建事件中

powershell -ExecutionPolicy ByPass -File  $(SolutionDir)\BuildScripts\InjectGitVersion.ps1 $(ProjectDir)
Run Code Online (Sandbox Code Playgroud)

第5步:构建项目.

步骤6:(可选)将AssemblyInfo.cs添加到您的git ignore文件中

  • 与其使用模板和 gitignoring 真正的“AssemblyInfo.cs”,不如就地修改“AssemblyInfo.cs”,构建,然后将“AssemblyInfo.cs”重置为最后提交的版本。所以在 repo 中总会有 `AssemblyInfo.cs`,`$..$` 只替换构建时间。 (2认同)

Cla*_*tus 7

这是一个在 Visual Studio 2019 中工作的简单解决方案,并将 git commit 哈希直接获取到 C# 文件中。将以下 C# 代码添加到您的解决方案中:

namespace MyNameSpace
{

    [System.AttributeUsage(System.AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
    sealed class GitHashAttribute : System.Attribute
    {
        public string Hash { get; }
        public GitHashAttribute(string hsh)
        {
            this.Hash = hsh;
        }
    }
    var hash = Assembly.GetEntryAssembly().GetCustomAttribute<GitHashAttribute>().Hash;
}
Run Code Online (Sandbox Code Playgroud)

如果将以下行添加到文件中,则变量hash将包含所需的字符串.csproj

<Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation">
    <Exec Command="git.exe describe --long --always --dirty --exclude='*' --abbrev=40"
          ConsoleToMSBuild="True" IgnoreExitCode="False">
        <Output PropertyName="SourceRevisionId" TaskParameter="ConsoleOutput" />
    </Exec>
</Target>

<Target Name="SetHash" AfterTargets="InitializeSourceControlInformation">
  <ItemGroup>
    <AssemblyAttribute Include="MyNameSpace.GitHashAttribute">
        <_Parameter1>$(SourceRevisionId)</_Parameter1>
    </AssemblyAttribute>
  </ItemGroup>
</Target>
Run Code Online (Sandbox Code Playgroud)

确保MyNameSpace两个文件中的内容都符合您的需求。这里重要的一点是ItemGroup必须将其嵌入到Target适当的AfterTargets集合中。


krl*_*zlx 5

现在,使用.NET Revision Task for MSBuild并使用 Visual Studio 2019 变得非常容易。

只需安装NuGetUnclassified.NetRevisionTaskAssemblyInfo.cs ,然后按照GitHub 文档中的说明在文件中配置所需的信息。

如果您只想要最后一次提交的哈希值(长度=8):

[assembly: AssemblyInformationalVersion("1.0-{chash:8}")]
Run Code Online (Sandbox Code Playgroud)

构建您的项目/解决方案,您将得到如下内容:

在此输入图像描述