Вставить git commit хэш в a.Net dll
Я создаю приложение на 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 );
}
}
обратите внимание, что это должно быть сделано в построить времени, а не runtime, так как мой развернутый исполняемый файл не будет иметь доступ к репозиторию git.
A смежный вопрос для C++ можно найти здесь.
EDIT
По запросу @mattanja я публикую скрипт git hook, который я использую в своих проектах. Настройка:
- крючки-это скрипты оболочки linux, которые помещаются под: path_to_project.githooks
- если вы используете msysgit на крючки папка уже содержит некоторые примеры сценариев. Для того, чтобы сделать ГИТ позвони им, убери '.пример ' расширение из имени скрипта.
- имена скриптов hook соответствуют событию, которое их вызывает. В моем случае, я изменил post-commit и после слияния.
- мой AssemblyInfo.cs файл находится непосредственно под путем проекта (тот же уровень, что и .ГИТ). Он содержит 23 строки, и я использую git для создания 24-го.
Как мой linux-обстрел немного ржавый, скрипт просто читает первые 23 строки AssemblyInfo.cs во временный файл, повторяет хэш 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
надеюсь, что это помогает.
12 ответов:
мы используем теги в Git для отслеживания версий.
git tag -a v13.3.1 -m "version 13.3.1"вы можете получить версию с хэшем от git через:
git describe --longнаш процесс сборки помещает хэш git в атрибут AssemblyInformationalVersion объекта AssemblyInfo.cs файл:
[assembly: AssemblyInformationalVersion("13.3.1.74-g5224f3b")]после компиляции вы можете просмотреть версию из Проводника windows:
вы также можете получить его программно через:
var build = ((AssemblyInformationalVersionAttribute)Assembly .GetAssembly(typeof(YOURTYPE)) .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false)[0]) .InformationalVersion;где YOURTYPE-это любой тип сборка, имеющая атрибут AssemblyInformationalVersion.
Вы можете вставить версия.txt файл в исполняемый файл, а затем прочитать версия.txt из исполняемого файла. Чтобы создать версия.txt используйте
git describe --longвот шаги:
используйте событие сборки для вызова git
Правой Кнопкой Мыши на проекте и выберите Свойства
в событиях сборки добавьте предварительную сборку событие, содержащее (обратите внимание на кавычки):
"C:\Program файлы\Git\bin\git.exe "describe --long >" $(ProjectDir)\version.txt"
это создаст версия.txt файл в каталоге проекта.
добавьте версию.txt в исполняемом файле
- щелкните правой кнопкой мыши на проекте и выберите Добавить существующий элемент
- добавить версия.txt (изменить фильтр выбора файлов, чтобы вы могли видеть все файлы)
- после версия.txt добавляется, щелкните правой кнопкой мыши на нем в обозревателе решений и выберите Свойства
- изменить действие при построении значение внедренный ресурс
- изменить копировать в выходной каталог значение всегда копировать
- добавить версия.txt на .gitignore file
чтение встроенного текстового файла строка версии
вот пример кода для чтения строки версии встроенного текстового файла:
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(); } } }
Я создал простой пакет nuget, который вы можете включить в свой проект, который позаботится об этом для вас:https://www.nuget.org/packages/MSBuildGitHash/
этот пакет nuget реализует "чистое" решение MSBuild. Если вы не хотите зависеть от пакета nuget, вы можете просто скопировать эти цели в свой файл csproj, и он должен включать хэш git в качестве атрибута пользовательской сборки:
<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-хэш в свойство MSBuild с именем BuildHash, it только делает это, если BuildHash еще не определен. Это позволяет передать его в MSBuild в командной строке, если вы предпочитаете. Вы можете передать его в MSBuild следующим образом:
MSBuild.exe myproj.csproj /p:BuildHash=MYHASHVALвторая цель, "WriteGitHash", запишет хэш-значение в файл во временной папке" obj "с именем" CustomAssemblyInfo.цезий." Этот файл будет содержать строку, которая выглядит например:
[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; } }некоторые преимущества этого дизайна заключается в том, что он не касается каких-либо файлов в папке проекта, все мутированные файлы находятся в папке "obj". Ваш проект также будет построен идентично в Visual Studio или в командной строке. Он также может быть легко настроен для вашего проекта и будет контролироваться исходным кодом вместе с вашим файлом csproj.
другой способ сделать это-использовать NetRevisionTool С некоторыми на борту Visual Studio magic. Я продемонстрирую это здесь для Visual Studio 2013 Professional Edition, но это будет работать и с другими версиями.
Итак, сначала загрузите NetRevisionTool. Вы включаете NetRevisionTool.exe в ваш путь или проверить его в свой репозиторий и создать визуальную студию перед построением и после построения действий и изменить свою файле AssemblyInfo.цезий.
An пример, который добавит ваш git-хэш в вашу AssemblyInformationVersion, будет следующим: В настройках Вашего проекта:
в AssemblyInfo.cs вашего проекта вы меняете / добавляете строку:
[сборка: AssemblyInformationalVersion ("1.1.{dmin: 2015}.{chash: 6}{!}- {branch}")]
на показанном скриншоте я проверил NetRevisionTool.exe в папке External/bin
после сборки, если вы затем щелкните правой кнопкой мыши двоичный файл и заходим в свойства, то вы должны увидеть примерно следующее:
надеюсь, что это поможет кому-то там
Я думаю, что этот вопрос стоит дать полный шаг за шагом ответ. Стратегия здесь заключается в запуске сценария powershell из событий предварительной сборки, который принимает файл шаблона и создает AssemblyInfo.cs-файл с включенной информацией о количестве фиксаций git tag+.
Шаг 1: сделать AssemblyInfo_template.cs-файл в папке Project\Properties, основанный на исходном AssemblyInfo.cs но содержащий:
[assembly: AssemblyVersion("$FILEVERSION$")] [assembly: AssemblyFileVersion("$FILEVERSION$")] [assembly: AssemblyInformationalVersion("$INFOVERSION$")]Шаг 2: Создайте сценарий powershell с именем InjectGitVersion. ps1, источником которого является:
# 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
Шаг 4: добавьте следующую строку в события предварительной сборки проекта
powershell -ExecutionPolicy ByPass -File $(SolutionDir)\BuildScripts\InjectGitVersion.ps1 $(ProjectDir)Шаг 5: создайте свой проект.
Шаг 6: дополнительно добавьте AssemblyInfo.cs в ваш файл git ignore
поскольку другой ответ уже упоминает бит git, как только у вас есть SHA, вы можете рассмотреть возможность создания
AssemblyInfo.csфайл вашего проекта в крючке предварительной сборки.один из способов сделать это является создание
AssemblyInfo.cs.tmplфайл шаблона, с местозаполнителем для вашего ша, скажем, $$GITSHA$$, например,[assembly: AssemblyDescription("$$GITSHA$$")]ваш крючок предварительной сборки затем должен заменить этот заполнитель и вывести AssemblyInfo.cs-файл для компилятора C#, чтобы забрать.
чтобы увидеть, как это можно сделать использование SubWCRev для SVN см. ответ. Это не должно быть трудно сделать что-то подобное для Git.
другие способы были бы" сделать этап", как уже упоминалось, т. е. написать задачу MSBuild, которая делает что-то подобное. Еще один способ может заключаться в том, чтобы как-то обработать DLL (ildasm+ilasm say), но я думаю, что упомянутые выше варианты, вероятно, проще всего.
для полностью автоматизированной и гибкой проверки метода https://github.com/Fody/Stamp. мы успешно использовали это для наших проектов Git (а также эта версия для проектов SVN)
вы можете использовать однострочную оболочку powershell для обновления всех файлов assemblyinfo с помощью хэша фиксации.
$hash = git describe --long --always;gci **/AssemblyInfo.* -recurse | foreach { $content = (gc $_) -replace "\[assembly: Guid?.*", "$&`n[assembly: AssemblyMetadata(`"commithash`", `"$hash`")]" | sc $_ }
Я использую комбинацию принятого ответа и небольшого дополнения. У меня установлено расширение Th AutoT4 (https://marketplace.visualstudio.com/items?itemName=BennorMcCarthy.AutoT4) для повторного запуска шаблонов перед сборкой.
получение версии от GIT
у меня есть
git -C $(ProjectDir) describe --long --always > "$(ProjectDir)git_version.txt"в моем предварительном событии в свойствах проекта. Добавление git_version.txt и VersionInfo.cs to .gitignore-это довольно хорошая идея.внедрение версии в метаданные
я добавил
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")); } #>Теперь у меня есть мой git тег + хэш в "ProductVersion".
ссылаясь на другой ответ (https://stackoverflow.com/a/44278482/4537127) я также использовал
VersionInfo.ttтекстовый шаблон для созданияAssemblyInformationalVersionбез AutoT4.(по крайней мере, работает в моем приложении C# WPF)
проблема заключалась в том, что события предварительной сборки запускались после преобразований шаблона, поэтому после клонирования
git_version.txtфайл не был там и построить не удается. После его создания вручную, чтобы разрешить преобразование пройти один раз, он был обновлен после превращения, так и было всегда один коммит за.мне пришлось внести две корректировки .csproj файл (это относится, по крайней мере, для Visual Studio Community 2017)
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 describerun перед преобразованиями шаблона (так что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
другой способ-создать версию.cs-файл с этапа предварительной сборки. Я исследовал это в небольшом проекте proof-of-concept, который печатает свой текущий хэш фиксации.
Tha проект загружен на https://github.com/sashoalm/GitCommitHashPrinter.
пакетный код, который создает версию.cs файл это:
@echo off echo "Writing Version.cs file..." @rem Pushd/popd are used to temporarily cd to where the BAT file is. pushd $(ProjectDir) @rem Verify that the command succeeds (i.e. Git is installed and we are in the repo). git rev-parse HEAD || exit 1 @rem Syntax for storing a command's output into a variable (see https://stackoverflow.com/a/2340018/492336). @rem 'git rev-parse HEAD' returns the commit hash. for /f %%i in ('git rev-parse HEAD') do set commitHash=%%i @rem Syntax for printing multiline text to a file (see https://stackoverflow.com/a/23530712/492336). ( echo namespace GitCommitHashPrinter echo { echo class Version echo { echo public static string CommitHash { get; set; } = "%commitHash%"; echo } echo } )>"Version.cs" popd
- Я надеюсь, что вы знаете, как вызывать внешние программы и перехватывать вывод во время сборки.
- Я надеюсь, что вы знаете, как иметь в рабочем каталоге git игнорировать неверсионные файлы.
как отметил @learath2, выход
git rev-parse HEADдаст вам простой хэш.если вы используете теги в Git-репозитории (и вы используете теги, разве это не более описательно и читаемо, чем
git rev-parse), вывод может быть получен изgit describe(в то время как также успешно используется позже вgit checkout)вы можете вызвать rev-parse / описать в:
- некоторые делают этап
- в post-commit hook
- в фильтре smudge, если вы выберете растушевка/очистить фильтры способ применения



Comments