Git Commit Info in your App

/ 3 August 2017 / Alexander Celeste

For a while now we have been computing the build number for our iOS apps from the Git commit that the code was at when the project was compiled. This is done using a custom Run Script Build Phase in Xcode. We have recently expanded upon simply rewriting CFBundleVersion in the Info.plist to be that number, to also write out everything we’d need to know in order to know the current branch, the commit hash, and how many changes were made since the last commit (when shipping an app this really should be 0, but when developing it often will be some larger value).

The original version of this, which only wrote out the computed build number, came from a post on Tommy’s Domain. This only reported the build number, and also required manually setting what branch the count would be based on. As such, we have built upon this. We set out first to automatically set the branch based on the current branch, and along the way found ourselves deciding to actually write out a lot more information to the Info.plist as well.

All the code I’ll be discussing in the remainder of this post can be found at the very bottom, embedded from a Github Gist. Feel free to also discuss this post in comments on the Gist.

While you can write entire shell scripts directly in the Run Script Build Phase editor, this has a few pitfalls to be aware of, and so we don’t recommend it. The main pitfalls include a tiny editor space that does not have the autocompletion and other smarts we expect in Xcode, for each target you’ll need to copy and paste the script, which is unfriendly to further editing, and also the script contents is a part of the project file, so unfriendly to Git if ever you need to diff it.

Instead we reccommend writing a shorter shell (no pun intended) script as the Run Script Build Phase that itself calls an external script file that is in your project like any other source file. The build script in the below Gist is what we use, based on a tip about Run Script Build Phases. You only really need the code starting with line 8 and on in your build phases, though take note that the shell to set this build phase to is bash. Also note that it expects the script itself to be in a scripts subfolder, but of course you can do whatever you’d like.

The script in the below Gist is the script that actually does the fun stuff here. It first collects the information from the project directory (reporting it into the build log as it goes) and then writes that out to the Info.plist files. Since we write to the dSYM bundle as well, you’ll need to set your Debug Information Format build setting to DWARF with dSYM File for Debug builds as well as Release builds, which last I checked isn’t the Xcode default. This script also doesn’t need to be included in any of your targets, so when creating the new file you should uncheck all targets. You should also change the TSCommit key to something specific to your environment, as TS is simply Tenseg’s prefix.

If you’re wondering how to expose all this in your app we have also included example code for generating a versionString that you can use in an About view, logged string, or really anything you can dream up. That is in the version-string.swift file in the below Gist.

We hope that this may help you encode important details about your projects into your apps. Since the project is under Git already (if it isn’t, please stop reading this and put it under Git, then come back, also if it isn’t then this post really doesn’t apply to you) the targets might as well include Git-centric records that point back to the exact point in your project’s life they came from. If exposed to the user, or just included in bug and crash reports, having these details at your fingertips in each target can be very handy.

Please feel free to ask questions, leave comments, or just generally discuss in the comments section of this Gist.