Embed git commit hash in a .Net dll

bavaza picture bavaza · Feb 28, 2013 · Viewed 41.8k times · Source

I'm building a C# application, using Git as my version control.

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 build time, not runtime, as my deployed executable will not have the git repo accessible.

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:

  • The hooks are linux shell scripts, which are placed under: path_to_project\.git\hooks
  • If you are using msysgit, the hooks folder 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-commit and post-merge.
  • My AssemblyInfo.cs file is directly under the project path (same level as the .git folder). It contains 23 lines, and I use git to generate the 24th.

As my linux-shelling a bit rusty, the script simply reads the first 23-lines of AssemblyInfo.cs to 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:

#!/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.

Answer

John Jesus picture John Jesus · Feb 28, 2013

You can embed a version.txt file into the executable and then read the version.txt out of the executable. To create the version.txt file, use git describe --long

Here are the steps:

Use a Build Event to call 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.txt file in your project directory.

Embed the version.txt in the executable

  • Right click on the project and select Add Existing Item
  • Add the version.txt file (change the file chooser filter to let you see All Files)
  • After version.txt is 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.txt to your .gitignore file

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();
        }
    }
}