在.net dll中embeddedgit commit hash
我正在构build一个C#应用程序,使用Git作为我的版本控制。
有没有一种方法可以在构build我的应用程序时自动将最后一个提交哈希embedded到可执行文件中?
例如,将提交散列打印到控制台看起来是这样的:
class PrintCommitHash { private String lastCommitHash = ?? // What do I put here? static void Main(string[] args) { // Display the version number: System.Console.WriteLine(lastCommitHash ); } }
请注意,这必须在构build时完成,而不是运行时 ,因为我部署的可执行文件不会有可访问的git仓库。
有关C ++的相关问题可以在这里find。
编辑
Per @ mattanja的请求,我发布我的项目中使用的git钩子脚本。 设置:
- 挂钩是linux shell脚本,放在: path_to_project \ .git \ hooks下
- 如果你使用msysgit , hooks文件夹已经包含了一些示例脚本。 为了让git调用它们,从脚本名称中删除'.sample'扩展名。
- 钩子脚本的名称与调用它们的事件相匹配。 就我而言,我修改了提交 后和合并后 。
- 我的AssemblyInfo.cs文件直接在项目path下(与.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
希望这可以帮助。
我们在git中使用标签来跟踪版本。
git tag -a v13.3.1 -m "version 13.3.1"
你可以通过从git获得哈希版本:
git describe --long
我们的构build过程将git散列放在AssemblyInfo.cs文件的AssemblyInformationalVersion属性中:
[assembly: AssemblyInformationalVersion("13.3.1.74-g5224f3b")]
一旦你编译,你可以从Windows资源pipe理器中查看版本:
你也可以通过编程获得它:
var build = ((AssemblyInformationalVersionAttribute)Assembly .GetAssembly(typeof(YOURTYPE)) .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false)[0]) .InformationalVersion;
其中YOURTYPE是具有AssemblyInformationalVersion属性的程序集中的任何types。
您可以将version.txt文件embedded到可执行文件中,然后从可执行文件中读取version.txt 。 要创buildversion.txt文件,请使用git describe --long
这里是步骤:
使用构build事件来调用git
-
用鼠标右键单击该项目,然后select属性
-
在Build Events中,添加包含Pre-Build的事件(注意引号):
“C:\ Program Files \ Git \ bin \ git.exe”描述–long>“$(ProjectDir)\ version.txt”
这将在您的项目目录中创build一个version.txt文件。
将version.txtembedded到可执行文件中
- 右键单击该项目,然后select添加现有项目
- 添加version.txt文件(更改文件select器筛选器,让您看到所有文件)
- 添加version.txt后,在解决scheme资源pipe理器中右键单击它,然后select属性
- 将生成操作更改为embedded式资源
- 将复制更改为输出目录以始终复制
- 将version.txt添加到.gitignore文件中
阅读embedded的文本文件版本string
下面是一些示例代码来读取embedded的文本文件版本string:
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(); } } }
另一种方法是使用带有一些板上Visual Studio魔术的NetRevisionTool 。 我将在这里为Visual Studio 2013专业版展示这一点,但是这也适用于其他版本。
所以先下载NetRevisionTool。 您可以在您的PATH中包含NetRevisionTool.exe,或将其存入您的存储库,并创build一个Visual Studio预生成和生成后的操作,并更改您的AssemblyInfo.cs。
一个将你的git-hash添加到你的AssemblyInformationVersion的例子如下:在你的项目设置中:
在你的项目的AssemblyInfo.cs中,你改变/添加这一行:
[assembly:AssemblyInformationalVersion(“1.1。{dmin:2015}。{chash:6} {!} – {branch}”)]
在显示的屏幕截图中,我在外部/ bin文件夹中检查了NetRevisionTool.exe
生成后,如果你然后右键点击你的二进制文件,然后去属性,那么你应该看到如下所示:
希望这可以帮助那里的人
我觉得这个问题值得一个完整的一步一步的回答。 这里的策略是从预生成事件中运行一个PowerShell脚本,该事件接受一个模板文件并生成一个包含git标记+ commit数量信息的AssemblyInfo.cs文件。
第1步:根据您的原始AssemblyInfo.cs在Project \ Properties文件夹中生成一个AssemblyInfo_template.cs文件,但包含:
[assembly: AssemblyVersion("$FILEVERSION$")] [assembly: AssemblyFileVersion("$FILEVERSION$")] [assembly: AssemblyInformationalVersion("$INFOVERSION$")]
第2步:创build一个名为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; }
步骤3:将InjectGitVersion.ps1文件保存到BuildScripts文件夹中的解决scheme目录中
第4步:将以下行添加到项目的预生成事件
powershell -ExecutionPolicy ByPass -File $(SolutionDir)\BuildScripts\InjectGitVersion.ps1 $(ProjectDir)
第5步:build立你的项目。
步骤6:或者,将AssemblyInfo.cs添加到你的git忽略文件中
由于其他答案已经提到了git位,一旦你有了SHA,你可以考虑在预生成钩子中生成你的项目的AssemblyInfo.cs
文件。
一种方法是创build一个AssemblyInfo.cs.tmpl
模板文件,其中包含SHA的占位符,例如$$ GITSHA $$,例如
[assembly: AssemblyDescription("$$GITSHA$$")]
然后,您的预编译钩子必须replace此占位符,并输出用于C#编译器的AssemblyInfo.cs文件。
要了解如何使用SubWCRev来完成SVN,请参阅此答案 。 为git做类似的事情不应该很难。
其他的方式就像上面提到的“制作阶段”,即写一个类似的MSBuild任务。 另一种方式可能是以某种方式后处理DLL(ildasm + ilasm说),但我认为上面提到的选项可能是最简单的。
我已经创build了一个简单的nuget包,你可以包含在你的项目中,这将为你处理这个问题: https ://www.nuget.org/packages/MSBuildGitHash/
这个nuget包实现了一个“纯粹的”MSBuild解决scheme。 如果你不想依赖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 > $(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>
这里有两个目标。 第一个“GetGitHash”将git散列加载到名为BuildHash的MSBuild属性中, 只有在BuildHash尚未定义的情况下才会执行此操作。 这可以让你把它传递给命令行上的MSBuild,如果你愿意的话。 你可以把它传递给MSBuild,如下所示:
MSBuild.exe myproj.csproj /p:BuildHash=MYHASHVAL
第二个目标“WriteGitHash”将把散列值写入名为“CustomAssemblyInfo.cs”的临时“obj”文件夹中的文件。 这个文件将包含一个如下所示的行:
[assembly: AssemblyMetadata("GitHash", "MYHASHVAL")]
此CustomAssemblyInfo.cs文件将被编译到您的程序集中,因此您可以使用reflection在运行时查找AssemblyMetadata
。
这个devise的一些好处是它不会触及项目文件夹中的任何文件,所有的变异文件都在“obj”文件夹下。 您的项目也将在Visual Studio中或从命令行进行相同的构build。 它也可以很容易地为您的项目定制,并将与您的csproj文件源控制。
为完全自动化和灵活的方法结帐https://github.com/Fody/Stamp 。 我们已经成功地将它用于我们的Git项目(以及SVN项目的这个版本 )
您可以使用powershell单线程来更新提交散列的所有汇编信息文件。
$hash = git describe --long --always;gci **/AssemblyInfo.* -recurse | foreach { $content = (gc $_) -replace "\[assembly: Guid?.*", "$&`n[assembly: AssemblyMetadata(`"commithash`", `"$hash`")]" | sc $_ }
我正在使用一个接受的答案和一个小的adition的组合。 我已经安装了AutoT4扩展( https://marketplace.visualstudio.com/items?itemName=BennorMcCarthy.AutoT4 )在构build之前重新运行模板。
从GIT获取版本
我有git -C $(ProjectDir) describe --long --always > "$(ProjectDir)git_version.txt"
在项目属性的预生成事件中git -C $(ProjectDir) describe --long --always > "$(ProjectDir)git_version.txt"
。 将git_version.txt和VersionInfo.cs添加到.gitignore是一个不错的主意。
在元数据中embedded版本
我已经添加了一个VersionInfo.tt
模板到我的项目中:
<#@ template debug="false" hostspecific="true" language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <#@ import namespace="System.IO" #> <#@ output extension=".cs" #> using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <# if (File.Exists(Host.ResolvePath("git_version.txt"))) { Write("[assembly: AssemblyInformationalVersion(\""+ File.ReadAllText(Host.ResolvePath("git_version.txt")).Trim() + "\")]"); }else{ Write("// version file not found in " + Host.ResolvePath("git_version.txt")); } #>
现在我在“ProductVersion”中有我的git标签+散列。
参考另一个答案( https://stackoverflow.com/a/44278482/4537127 )我还利用VersionInfo.tt
文本模板生成AssemblyInformationalVersion
没有AutoT4。
(Atleast在我的C#WPF应用程序中工作)
问题在于预生成事件是在模板转换之后运行的,所以在克隆之后, git_version.txt
文件不在那里,生成失败。 在手动创build它以允许转换传递一次之后,它在转换之后被更新,并且始终是一个后面的提交 。
我必须对.csproj文件进行两次调整(至less对于Visual Studio Community 2017至less适用)
1)导入文本转换目标,并使模板转换在每个版本上运行:(Ref https://msdn.microsoft.com/en-us/library/ee847423.aspx )
<PropertyGroup> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <TransformOnBuild>true</TransformOnBuild> <TransformOutOfDateOnly>false</TransformOutOfDateOnly> </PropertyGroup>
并在<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
2)在模板转换之前使git describe
运行(以便在转换git_version.txt
时VersionInfo.tt
在那里):
<Target Name="PreBuild" BeforeTargets="ExecuteTransformations"> <Exec Command="git -C $(ProjectDir) describe --long --always --dirty > $(ProjectDir)git_version.txt" /> </Target>
..和C#代码来获取AssemblyInformationalVersion
(Ref https://stackoverflow.com/a/7770189/4537127 )
public string AppGitHash { get { AssemblyInformationalVersionAttribute attribute = (AssemblyInformationalVersionAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false).FirstOrDefault(); return attribute.InformationalVersion; } }
..并将生成的文件添加到.gitignore
VersionInfo.cs git_version.txt
- 我希望你知道如何在构build时调用外部程序和拦截输出。
- 我希望你知道如何在git的工作目录中忽略未版本化的文件。
正如@ learath2所指出的那样, git rev-parse HEAD
输出会给你简单的哈希。
如果你在Git-repository中使用标签(并且你使用标签,那么它不是比git rev-parse
更具描述性和可读性),输出可以从git describe
(同时也可以在git checkout
)
您可以在以下位置调用rev-parse | describe:
- 一些制作舞台
- 在提交后钩
- 在涂抹filter中,如果您select涂抹/清洁filter的实施方式