Git For Builds

Today's post is simply a handful of git commands you can use to perform tasks that often show up in automated builds.

Versioning

# What's the branch name? main
git rev-parse --abbrev-ref=strict HEAD

# What's the full commit hash? 72395e5237fb7261c9bf561c13602e633c788217
git rev-parse HEAD

# What's the short commit hash? 72395e52
git rev-parse --short=8 HEAD

# What's the hash of the commit that last edited a file? 82773e3b43010f94a8b329af076aee5b4453ae05
git log -n1 --pretty=format:%H -- README.md

# How many commits since a prior one? 20
git rev-list --first-parent --count 82773e3b43010f94a8b329af076aee5b4453ae05..HEAD

# What is the top-level directory of git repo for the current dir? C:/my/repo
git -C . rev-parse --show-toplevel

# What is the branch name, without using git? ref: refs/heads/main
type .git\HEAD

When using PowerShell, you can get the output of any of the above with something like $hash = & git rev-parse HEAD

The type command is a useful thing to know if you're using MSBuild and want to use something like ReadLinesFromFile. Note that you'll need to refer to the output as @(whatever) to use it as a string, because ReadLinesFromFile returns a string array. You can use string methods to check for ref: and get the parts you care about.

You can do something similar with CMake, with something like file(READ .git/HEAD GIT_HEAD) (see file docs). With that value, you can do processing with the string command with REGEX MATCH for example. You can set variables as you wish, and then run configure_file to replace the values you generated.

To automatically build version information, you can use branches for policy, hashes for specific references and commit counts as revision numbers. This information can go in code files, version resource blocks, documentation, tags, etc.

Note that a lot of this generation is meant to be done in an automated environment, changing every build, and so these files that are generated or updated on-the-fly typically do not get committed. This means they won't get properly source-indexed, which in turn means you want to keep them as small as possible - ideally just some global definitions that can get used elsewhere. I wrote a lot about this in my code generations strategies post recently.

Patching

As an alternative to diff and patch, you may choose to use the git diff and git apply commands around them instead.

For example, to create patches for your working tree changes, use git diff > my-repo-changes.patch. Note that it won't pick up additions and removals.

To apply them later, you might use git apply my-repo-changes.patch --ignore-space-change --ignore-whitespace

I typically ignore spaces and whitespace because working across different git configurations and editors can make it a pain to keep those always lined up. You might also want to git reset --hard before applying the changes if you want to make it reproducible - but remember to alert your developers, as it will lose changes otherwise!

Happy building!

Tags:  coding

Home