C# 在 .Net dll 中嵌入 git commit hash
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15141338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Embed git commit hash in a .Net dll
提问by bavaza
I'm building a C# application, using Git as my version control.
我正在构建一个 C# 应用程序,使用 Git 作为我的版本控制。
Is there a way to automatically embed the last commit hash in the executable when I build my application?
当我构建我的应用程序时,有没有办法在可执行文件中自动嵌入最后一个提交哈希?
For example, printing the commit hash to console would look something like:
例如,将提交哈希打印到控制台看起来像这样:
class PrintCommitHash
{
private String lastCommitHash = ?? // What do I put here?
static void Main(string[] args)
{
// Display the version number:
System.Console.WriteLine(lastCommitHash );
}
}
Note that this has to be done at buildtime, not runtime, as my deployed executable will not have the git repo accessible.
请注意,这必须在构建时完成,而不是在运行时完成,因为我部署的可执行文件将无法访问 git repo。
A related question for C++ can be found here.
EDIT
Per @mattanja's request, I'm posting the git hook script I use in my projects. The setup:
可以在此处找到 C++ 的相关问题。
编辑
根据@mattanja 的要求,我发布了我在项目中使用的 git 钩子脚本。设置:
- The hooks are linux shell scripts, which are placed under: path_to_project\.git\hooks
- If you are using msysgit, the hooksfolder already contains some sample scripts. In order to make git call them, remove the '.sample' extension from the script name.
- The names of the hook scripts match the event that invokes them. In my case, I modified post-commitand post-merge.
- My AssemblyInfo.csfile is directly under the project path (same level as the .gitfolder). It contains 23 lines, and I use git to generate the 24th.
- 钩子是linux shell脚本,放在:path_to_project\.git\hooks
- 如果您使用的是msysgit,hooks文件夹已经包含一些示例脚本。为了让 git 调用它们,请从脚本名称中删除“.sample”扩展名。
- 钩子脚本的名称与调用它们的事件相匹配。就我而言,我修改了post-commit和post-merge。
- 我的AssemblyInfo.cs文件直接位于项目路径下(与.git文件夹相同级别)。它包含 23 行,我使用 git 生成第 24 行。
As my linux-shelling a bit rusty, the script simply reads the first 23-lines of AssemblyInfo.csto a temporary file, echos the git hash to the last line, and renames the file back to AssemblyInfo.cs. I'm sure there are better ways of doing this:
由于我的 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
Hope this helps.
希望这可以帮助。
采纳答案by Handcraftsman
We use tags in git to track versions.
我们在 git 中使用标签来跟踪版本。
git tag -a v13.3.1 -m "version 13.3.1"
You can get the version with hash from git via:
您可以通过以下方式从 git 获取带有哈希的版本:
git describe --long
Our build process puts the git hash in the AssemblyInformationalVersion attribute of the AssemblyInfo.cs file:
我们的构建过程将 git 哈希放在 AssemblyInfo.cs 文件的 AssemblyInformationalVersion 属性中:
[assembly: AssemblyInformationalVersion("13.3.1.74-g5224f3b")]
Once you compile, you can view the version from windows explorer:
编译后,您可以从 Windows 资源管理器中查看版本:
You can also get it programmatically via:
您还可以通过以下方式以编程方式获取它:
var build = ((AssemblyInformationalVersionAttribute)Assembly
.GetAssembly(typeof(YOURTYPE))
.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false)[0])
.InformationalVersion;
where YOURTYPE is any Type in the Assembly that has the AssemblyInformationalVersion attribute.
其中 YOURTYPE 是程序集中具有 AssemblyInformationalVersion 属性的任何类型。
回答by Lazy Badger
- I hope you know how to call external programs and intercept output at the build-time.
- I hope you know how to have in git's working directory ignore unversioned files.
- 我希望你知道如何在构建时调用外部程序和拦截输出。
- 我希望你知道如何在 git 的工作目录中忽略未版本控制的文件。
As noted by @learath2, output of git rev-parse HEAD
will give you plain hash.
正如@learath2 所指出的, of 的输出git rev-parse HEAD
将为您提供简单的哈希值。
If you use tags in Git-repository (and you use tags, isn't it more descriptive and readable than git rev-parse
), output may be received from git describe
(while also successfully used later in git checkout
)
如果您在 Git-repository 中使用标签(并且您使用标签,它是不是比 更具描述性和可读性git rev-parse
),则可能会收到输出git describe
(同时也可以在稍后成功使用git checkout
)
You can call rev-parse|describe in:
您可以在以下位置调用 rev-parse|describe:
- some make stage
- in post-commit hook
- in smudge filter, if you'll select smudge/clean filtersway of implementation
- 一些制作阶段
- 在提交后挂钩中
- 在污迹过滤器中,如果您选择污迹/清洁过滤器的实现方式
回答by Marcus
As the other answer already mentions the git bit, once you have the SHA you can consider generating the AssemblyInfo.cs
file of your project in a pre-build hook.
由于另一个答案已经提到了 git 位,一旦您拥有 SHA,您就可以考虑AssemblyInfo.cs
在预构建挂钩中生成项目文件。
One way to do this is to create an AssemblyInfo.cs.tmpl
template file, with a placeholder for your SHA in say $$GITSHA$$, e.g.
一种方法是创建一个AssemblyInfo.cs.tmpl
模板文件,在 $$GITSHA$$ 中为您的 SHA 设置一个占位符,例如
[assembly: AssemblyDescription("$$GITSHA$$")]
Your pre build hook then has to replace this placeholder and output the AssemblyInfo.cs file for the C# compiler to pick up.
然后,您的预构建挂钩必须替换此占位符并输出 AssemblyInfo.cs 文件以供 C# 编译器选取。
To see how this can be done using SubWCRev for SVN see this answer. It shouldn't be hard to do something similar for git.
要了解如何使用 SubWCRev for SVN 完成此操作,请参阅此答案。为 git 做类似的事情应该不难。
Other ways would be a "make stage" as mentioned, i.e. write an MSBuild task that does something similar. Yet another way may be to post process the DLL somehow (ildasm+ilasm say), but I think the options mentioned above are probably easiest.
其他方式将是提到的“制作阶段”,即编写一个执行类似操作的 MSBuild 任务。另一种方法可能是以某种方式对 DLL 进行后期处理(ildasm+ilasm 说),但我认为上面提到的选项可能是最简单的。
回答by John Jesus
You can embed a version.txtfile into the executable and then read the version.txtout of the executable. To create the version.txtfile, use git describe --long
您可以将version.txt文件嵌入到可执行文件中,然后从可执行文件中读取version.txt。要创建version.txt文件,请使用git describe --long
Here are the steps:
以下是步骤:
Use a Build Event to call git
使用构建事件调用 git
Right-click on the project and select Properties
In Build Events, add Pre-Build event containing (notice the quotes):
"C:\Program Files\Git\bin\git.exe" describe --long > "$(ProjectDir)\version.txt"
That will create a version.txtfile in your project directory.
右键单击项目并选择属性
在 Build Events 中,添加 Pre-Build 事件包含(注意引号):
"C:\Program Files\Git\bin\git.exe" 描述 --long > "$(ProjectDir)\version.txt"
这将在您的项目目录中创建一个version.txt文件。
Embed the version.txt in the executable
在可执行文件中嵌入 version.txt
- Right click on the project and select Add Existing Item
- Add the version.txtfile (change the file chooser filter to let you see All Files)
- After version.txtis added, right-click on it in the Solution Explorer and select Properties
- Change the Build Action to Embedded Resource
- Change Copy to Output Directory to Copy Always
- Add version.txtto your .gitignorefile
- 右键单击项目并选择添加现有项目
- 添加version.txt文件(更改文件选择器过滤器以让您看到所有文件)
- 添加version.txt后,在解决方案资源管理器中右键单击它并选择属性
- 将构建操作更改为嵌入式资源
- 将复制到输出目录更改为始终复制
- 将version.txt添加到您的.gitignore文件中
Read the embedded text file version string
读取嵌入的文本文件版本字符串
Here's some sample code to read the embedded text file version 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();
}
}
}
回答by schmendrick
Another way to do this is to use the NetRevisionToolwith some On-Board Visual Studio magic. I will showcase this here for Visual Studio 2013 Professional Edition, but this will work with other versions as well.
另一种方法是使用NetRevisionTool和一些 On-Board Visual Studio 魔法。我将在此处为 Visual Studio 2013 专业版展示此功能,但这也适用于其他版本。
So first download the NetRevisionTool. You include the NetRevisionTool.exe in your PATH or check it in into your repository and create a visual studio pre-build and a post-build action and change your AssemblyInfo.cs.
所以首先下载NetRevisionTool。您将 NetRevisionTool.exe 包含在您的 PATH 中或将其签入您的存储库并创建一个 Visual Studio 预构建和一个构建后操作并更改您的 AssemblyInfo.cs。
An example that would add your git-hash to your AssemblyInformationVersion would be the following: In your project settings:
将您的 git-hash 添加到您的 AssemblyInformationVersion 的示例如下:在您的项目设置中:
in the AssemblyInfo.cs of your project you change/add the line:
在您的项目的 AssemblyInfo.cs 中,您更改/添加以下行:
[assembly: AssemblyInformationalVersion("1.1.{dmin:2015}.{chash:6}{!}-{branch}")]
[程序集:AssemblyInformationalVersion("1.1.{dmin:2015}.{chash:6}{!}-{branch}")]
in the shown screenshot i checked in NetRevisionTool.exe in the External/bin folder
在显示的屏幕截图中,我检查了 External/bin 文件夹中的 NetRevisionTool.exe
After build, if you then right-click your binary and go to properties then you should see something like the following:
构建后,如果您然后右键单击您的二进制文件并转到属性,那么您应该会看到如下所示的内容:
Hope this helps somebody out there
希望这可以帮助那里的人
回答by Atilio Jobson
I think this question is worth giving a complete step by step answer. The strategy here to is run a powershell script from the pre-build events that takes in a template file and generates an AssemblyInfo.cs file with the git tag + commit count information included.
我认为这个问题值得一步一步给出完整的答案。这里的策略是从预构建事件中运行 powershell 脚本,该脚本接收模板文件并生成包含 git 标记 + 提交计数信息的 AssemblyInfo.cs 文件。
Step 1:make an AssemblyInfo_template.cs file in the Project\Properties folder, based on your original AssemblyInfo.cs but containing:
步骤 1:在 Project\Properties 文件夹中创建一个 AssemblyInfo_template.cs 文件,基于您原来的 AssemblyInfo.cs 但包含:
[assembly: AssemblyVersion("$FILEVERSION$")]
[assembly: AssemblyFileVersion("$FILEVERSION$")]
[assembly: AssemblyInformationalVersion("$INFOVERSION$")]
Step 2:Create a powershell script named InjectGitVersion.ps1 whose source is:
第 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;
}
Step 3:Save the InjectGitVersion.ps1 file to your solution directory in a BuildScripts folder
步骤 3:将 InjectGitVersion.ps1 文件保存到 BuildScripts 文件夹中的解决方案目录中
Step 4:Add the following line to the project's Pre-Build events
第 4 步:将以下行添加到项目的 Pre-Build 事件
powershell -ExecutionPolicy ByPass -File $(SolutionDir)\BuildScripts\InjectGitVersion.ps1 $(ProjectDir)
Step 5:Build your project.
第 5 步:构建您的项目。
Step 6:Optionally, add AssemblyInfo.cs to your git ignore file
步骤 6:(可选)将 AssemblyInfo.cs 添加到您的 git ignore 文件
回答by roh85
You can use a powershell one-liner to update all assemblyinfo files with the commit hash.
您可以使用 powershell one-liner 使用提交哈希更新所有 assemblyinfo 文件。
$hash = git describe --long --always;gci **/AssemblyInfo.* -recurse | foreach { $content = (gc $_) -replace "\[assembly: Guid?.*", "$&`n[assembly: AssemblyMetadata(`"commithash`", `"$hash`")]" | sc $_ }
回答by mamuesstack
For a fully automated and flexible method checkout https://github.com/Fody/Stamp. We've successfully used this for our Git projects (as well as the this versionfor SVN projects)
对于完全自动化和灵活的方法结帐https://github.com/Fody/Stamp。我们已经成功地将它用于我们的 Git 项目(以及用于 SVN 项目的这个版本)
Update: This is outdated since Stamp.Fody is no longer maintained
更新:这已经过时了,因为 Stamp.Fody 不再维护
回答by jelinek.01
I'm using a combination of the accepted answer and a small adition. I have th AutoT4 extension installed (https://marketplace.visualstudio.com/items?itemName=BennorMcCarthy.AutoT4) to re-run the templates before build.
我正在使用接受的答案和一个小的添加的组合。我安装了 AutoT4 扩展(https://marketplace.visualstudio.com/items?itemName=BennorMcCarthy.AutoT4)以在构建之前重新运行模板。
getting version from GIT
从 GIT 获取版本
I have git -C $(ProjectDir) describe --long --always > "$(ProjectDir)git_version.txt"
in my pre-build event in project properties.
Adding git_version.txt and VersionInfo.cs to .gitignore is quite a good idea.
我git -C $(ProjectDir) describe --long --always > "$(ProjectDir)git_version.txt"
在项目属性中的预构建事件中有。将 git_version.txt 和 VersionInfo.cs 添加到 .gitignore 是一个很好的主意。
embedding version in metadata
在元数据中嵌入版本
I have added a VersionInfo.tt
template to my project:
我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"));
}
#>
Now I have my git tag + hash in "ProductVersion".
现在我在“ProductVersion”中有我的 git tag + hash。
回答by kimmoli
Referring to the another answer (https://stackoverflow.com/a/44278482/4537127) i also utilised the VersionInfo.tt
text template to generate AssemblyInformationalVersion
without AutoT4.
参考另一个答案(https://stackoverflow.com/a/44278482/4537127),我还利用VersionInfo.tt
文本模板在AssemblyInformationalVersion
没有 AutoT4 的情况下生成。
(Atleast works in my C# WPF application)
(至少适用于我的 C# WPF 应用程序)
Problem was that the Pre-build events were run after template transformations, so after cloning, the git_version.txt
file was not there and build fails.
After creating it manually to allow transformation to pass once, it was updated after transformation, and was always one commit behind.
问题是预构建事件是在模板转换之后运行的,所以在克隆之后,git_version.txt
文件不存在并且构建失败。在手动创建它以允许转换通过一次后,它在转换后更新,并且始终落后于.
I had to make two adjustments to the .csproj file (this applies at least for Visual Studio Community 2017)
我不得不对 .csproj 文件进行两次调整(这至少适用于 Visual Studio Community 2017)
1) Import the Text Transformation Targets and make template transformations to run on every build: (Ref https://msdn.microsoft.com/en-us/library/ee847423.aspx)
1) 导入文本转换目标并使模板转换在每个构建上运行:(参考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>
and after <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
之后 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
2) Make the git describe
run before template transformations (so that git_version.txt
is there when VersionInfo.tt
is transformed) :
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>
..And the C# code to get the AssemblyInformationalVersion
(Ref https://stackoverflow.com/a/7770189/4537127)
..和 C# 代码来获取AssemblyInformationalVersion
(参考https://stackoverflow.com/a/7770189/4537127)
public string AppGitHash
{
get
{
AssemblyInformationalVersionAttribute attribute = (AssemblyInformationalVersionAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false).FirstOrDefault();
return attribute.InformationalVersion;
}
}
..And add the generated files to .gitignore
..并将生成的文件添加到 .gitignore
VersionInfo.cs
git_version.txt