text: It is always helpful to know which version you are running of some software, even more so when running development versions. So it’s good if software is able to tell you its version, for example by calling it with
  --version. For release versions, maintaining this information by hand is feasible, but in order for development versions to show exact revision information, you need some automation, otherwise updating it will be forgotten, leaving you with wrong information.
  This blog post shows different techniques that can be used to embed a Git commit hash into programs written in the Go programming language. Finally, it will also show a Git feature that is useful for other languages as well.
  Linker Flags
  One option is to set variables using linker flags. Just define a string variable somewhere in the code like this:
  var Commit string
  This variable can then be set to a specific value by specifying extra linker flags:
  go build -ldflags="-X main.Commit=$(git rev-parse HEAD)"
  Note that
  main specifies the package name that contains the variable, so if you want to set a variable in a different package, you have to specify the import path of that package instead.
  go generate
  Another option is to use
  go generate, which allow you to run arbitrary commands to update auto-generated files. This can be used to generate Go source code later included in the build, or, starting from Go 1.16, you can also write arbitrary files that can then be embedded into the binary using the
  embed package. So consider the following Go code:
  //go:generate sh -c "printf %s $(git rev-parse HEAD) > commit.txt" //go:embed commit.txt var Commit string
  The
  //go:generate directive instructs Go to run a command that writes the current commit hash to a file called
  commit.txt (the extra
  printf %s is only there to strip the trailing newline character, this could also be done by stripping it when using the variable) and the
  //go:embed directive instructs it to set the variable
  Commit to the contents of this file.
  However, these commands are not run automatically, so to build the binary, you now have to invoke two commands:
  go generate go build
  But if you happen to use
  go generate anyways to generate other files, this gives you a nice method of adding Git version information basically for free. Also keep in mind that you have to run this every time, otherwise you might end up using a file from a previous build with outdated information.
  Build Information (Go 1.18+)
  Go 1.18 added a nice feature: when building a Go project from within a Git checkout, some commit information is added to the binary automatically when running
  go build without requiring any additional flags (but you can control the behavior in more detail with the
  -buildvcs flag if you want to). This makes it a very nice solution as it requires no additional build scripts that supply the additional information.
  This information can be read from the Go code like this:
  import "runtime/debug" var Commit = func() string { if info, ok := debug.ReadBuildInfo(); ok { for _, setting := range info.Settings { if setting.Key == "vcs.revision" { return setting.Value } } } return "" }()
  The amount of information available is quite limited though. In case of Git, the following attributes are available besides
  vcs.revision:
  vcs.time: Timestamp of the commit.
  vcs.modified: Set to true (as a string) if the binary was built from a working directory containing uncommitted changes.
  git archive
  For situations where you’re not building from a Git checkout, there is a convenient Git feature that allows you to substitute placeholders in files when exporting the repository, for example as a .tar.gz file. The placeholders look like this:
  const Commit = "$Format:%H$"
  This variable will be set to the full commit hash, for a list of available placeholders, you can check the
  git-log(1) man page. This replacement is not done automatically, but only on files that have the attribute
  export-subst set in
  .gitattributes (next to
  .gitignore) like this:
  /commit.go export-subst
  When this repository is now exported using
  git archive, the resulting file looks something like this:
  $ git archive HEAD | tar -x --to-stdout commit.go package main const Commit = "31fbe21f80912bb2040027c3239ce6c86f7e109c"
  Of course, this substitution only takes place when exporting an archive, which also includes downloads from GitHub. In all other cases, the variable still includes the template string, so any code using such a variable should be aware that this can happen, check if the replacement happened, and treat the commit information as unavailable otherwise.
  If you want to see a full working example combining the last two techniques, you can have a look at this pull request for Icinga DB which among other things adds Git commit information to the output of
  icingadb --version.