How can I extract Git commit hash from VS/msbuild?

The scenario is:

Developers are running a PowerShell script from their machines to publish various Nuget packages to OctopusDeploy via MSBuild. We’d like to make the current git commit’s hash (the base of the Git repo is the same as the .sln directory) part of the generated version number. To do this we presumably need to extract the current commit’s hash and plug it into the version number string we then pass into MSBuild as a parameter.

  • git error: cannot initialize work tree
  • github Diff Truncated error
  • Diff current file version and previous one remote repository
  • Push to heroku through Proxy server
  • How can I fast-forward a single git commit, programmatically?
  • Preserve history of file from before it was moved into the directory being split
  • So the question is, how can we get this from MSBuild or Visual Studio? There’s no guarantee that a developer will have Git commandline installed, but they will have at least VS2015 installed and that has Git support built-in so you’d think there would be some way to get the latest Git commit’s hash from this? You could see the hash if you went into the Visual Studio GUI and looked in the source control section.

    Is there some commandline tool that comes bundled with Visual Studio 2015 or later that will return the current Git commit’s hash?

  • Error: The source control operation failed because the revisions
  • Detach many subdirectories into a new, separate Git repository
  • Have buildbot poll a git repository for new commits?
  • Merge two separate SVN repositories into a single Git repository
  • Is there a way to ask git diff to show the method name instead of the class name?
  • How can I preserve local changes made to an NPM module?
  • One Solution collect form web for “How can I extract Git commit hash from VS/msbuild?”

    Your requirement to not depend on git.exe makes this complicated.
    However if you want to use the library that Visual Studio uses, LibGit2Sharp and have Visual Studio integration you can do something crazy like this.

    Add a new target to your project file. I’m assuming you are using C# so add it to your csproj after

    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

      <PropertyGroup>
        <CodeFile>$(MSBuildProjectDirectory)\HelloGit.cs</CodeFile>
        <CodeFileText>$([System.IO.File]::ReadAllText("$(CodeFile)"))</CodeFileText>
        <CodeFileText>$([MSBuild]::Unescape("$(CodeFileText)"))</CodeFileText>
      </PropertyGroup>
    
      <UsingTask TaskName="HelloGit" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
        <ParameterGroup>
          <Sha1 ParameterType="System.String" Required="False" Output="True" />
          <Repository ParameterType="System.String" Required="True" Output="False" />
        </ParameterGroup>
        <Task>
          <Reference Include="System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
          <Reference Include="C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\LibGit2Sharp.dll" />
          <Using Namespace="System" />
          <Using Namespace="System.IO" />
          <Code Type="Class" Language="cs">
            $(CodeFileText)
          </Code>
        </Task>
      </UsingTask>
    
      <Target Name="RunTask" AfterTargets="BeforeBuild">
    
        <HelloGit Repository="$(MSBuildProjectDirectory)">
          <Output TaskParameter="Sha1" PropertyName="CommitId" />
        </HelloGit>
        <Warning Text="Your commit is: $(CommitId)" />
    
      </Target>
    

    What this does is look in the current project directory for “HelloGit.cs”. The contents of which look like this…

    You could do this with an inline code task (e.g. embedded C# inside XML) but since the task is quite long I wanted to edit it in VS Code as a separate file.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Text;
    using LibGit2Sharp;
    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;
    
    
    namespace GitIntrospection {
        public class HelloGit : Task {
            public override bool Execute() {
                AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
                    if (args.Name.Contains("LibGit2Sharp")) {
                        return Assembly.LoadFrom("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TeamFoundation\\Team Explorer\\LibGit2Sharp.dll");
                    }
                    return null;
                };
    
                GetCommit();
    
                return !Log.HasLoggedErrors;
            }
    
            // [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
            private void GetCommit() {
                Repository repository = new Repository(Repository);
    
                this.Sha1 = repository.Commits.First().Id.Sha;
            }
    
            [Output]
            public string Sha1 { get; set; }
    
            [Required]
            public string Repository { get; set; }
        }
    }
    

    Now when you build your project the latest commit will be extracted and logged as a warning. This works both inside Visual Studio and inside MS Build.

    Works on the command line
    Works on the command line

    Works inside Visual Studio
    Works inside Visual Studio

    The results even seem to agree with git.exe… that’s handy
    The results even seem to agree with git.exe... that's handy

    Alternative 1
    You could just use git.exe and an <Exec> task!

    Alternative 2
    You could use PowerShell to load the LibGit2Sharp assembly and call the same methods.

    Git Baby is a git and github fan, let's start git clone.