iOS app versioning with git tag

Wouldn't it be great if your iOS or OS X projects just take their version and build number automatically from git? Well, it can!

Using a script in your build phase, you can run a shell script to determine the version number and inject this into the Info.plist of a build.

It will change your plist based on the last git tag that you have. If that is the current SHA it will show the version as 0.9.2, otherwise it will show how many commits since the last tag and the short version of the current SHA (0.9.2-2-d955863).

If you have uncommited changes (besides the plist) it will add a -dirty tag to the end of the version.

It will also update the build number with the number of commits in that branch, because of that remember to always release your builds from the same branch to prevent duplicated build numbers.

The last thing it will do is adding a GitSHA to your plist, I think that's very usefull when submitting bug reports from within the app.

You can add this script as a build phase in your Xcode project:

# Update build version with number of commits
BUILD_NUMBER=$(git rev-list HEAD | wc -l | tr -d ' ')

# Set git SHA for this build
GIT_SHA=$(git rev-parse --short HEAD)

# Update version string with build number
LINES_CHANGED=$(git status --porcelain | wc -l | tr -d ' ')
PLIST_CHANGED=$(git status --porcelain | grep "${INFOPLIST_FILE}" | wc -l | tr -d ' ')
if [ "$LINES_CHANGED" == "1" -a "$PLIST_CHANGED" == "1" ]; then
    GIT_RELEASE_VERSION=$(git describe --tags --always)
    GIT_RELEASE_VERSION=$(git describe --tags --always --dirty)

# Update plist with new values
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${GIT_RELEASE_VERSION#*v}" "${PROJECT_DIR}/${INFOPLIST_FILE}"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "${PROJECT_DIR}/${INFOPLIST_FILE}"
/usr/libexec/PlistBuddy -c "Set :GitSHA $GIT_SHA" "${PROJECT_DIR}/${INFOPLIST_FILE}"

If you don't want to change your plist you can change only the product plist by replacing the last lines with this:

defaults write "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH%.*}" "CFBundleShortVersionString" "${GIT_RELEASE_VERSION#*v}"
defaults write "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH%.*}" "CFBundleVersion" "${BUILD_NUMBER}"
defaults write "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH%.*}" "GitSHA" "${GIT_SHA}"