Itâs the simple things in life: One of the best workflow changes I made for Loose Leaf was to use git to manage the version number of my app. To release a new version, just add a tag in git, and the version in my appâs Info.plist would automatically update to match. Thereâs a number of different ways to set something like this up, and Iâve pieced my particular strategy together from various Stack Overflow posts, and I thought itâd be helpful to put an end-to-end post together to describes the how and why in 1 place.
Long and Short Versions
There are two version stringâs youâll need to specify in your Info.plist: the Bundle Version and the Short Bundle Version. Despite their similar name, these two version numbers can be used for different things. They let you specify two different version numbers for two different uses:
- Short Bundle Version: This is the version number your users see and care about. â1.0â or â2.0â etc
- Bundle Version: This is the version number for you as a developer to care about. Itâll tell you exactly which git commit it was built from.
This post is going to show you how to use git tags to automatically
Step 1: Defining the Bundle Version
To create a new version of the app, simply add a git tag with the appropriate version number:
$ git tag -a -m "a new release" 1.0.0
Thatâs it! Now that weâve saved our version info into git, we need a way at build time to ask git which tag weâre currently working on. To retrieve our most recent tag info, we can simply use:
$ git describe
This gets us pretty close â If weâre currently on the exact commit of that tag, then weâll see â1.0.0â printed to the command line, but if weâre on a subsequent commit, weâll see something like â1.0.0-24-g89ea736â. Letâs parse out just the version prefix:
$ git describe --tags | awk '{split($0,a,"-"); print a[1]}'
Perfect! that command will ask git for the tagged description, then parse out the prefix before the first â-â. In our case, thatâll print out â1.0.0â for every commit after that 1.0.0 tag.
Step 2: Defining the Short Bundle Version
The short bundle version should be a monotonically increasing number that specifies exactly which commit was used for a particular build. The command to do that is:
$ git rev-list HEAD | wc -l | tr -d ' '
âgit rev-list HEADâ lists out all of the commit hashes from the beginning of our repo until our current commit. âwc -lâ counts those commits, and âtr -d â ââ trims the whitespace. Running this command will print out something like â2434â.
Step 3: Automating Your Build
At this point, we have:
- User-facing build number from Step 1
- Developer-facing build number from Step 2
And now weâre ready to automatically update our Info.plist with these two numbers every build.
Step 3.1: Open up Xcode and select your targetâs Build Phases section
Step 3.2:Â Add a new Run Script phase
Next, weâll add in the script into our build process to automatically update our Info.plist. Select âAdd Run Script Build Phaseâ from the Editor menu.
Important: Make sure that your new Run Script phase is after the Copy Bundle Resources phase.
Step 3.3: The Custom Script
Now weâll use the git commands we found above, and write in their output into the Info.plist. This script modifies the Info.plist in the build target instead of the src directory so that youâre not modifying your source files every time you build.
The script:
# Update the CFBundleShortVersionString in the generated Info.plist using the most recent Git tag.
# Idea taken from http://tinyurl.com/3usjj9d by Joachim Bondo.
# Get the current release description from Git.
GIT_RELEASE_SHORT_VERSION=`git describe --tags | awk '{split($0,a,"-"); print a[1]}'`
GIT_RELEASE_VERSION=`git rev-list HEAD | wc -l | tr -d ' '`
# Set the CFBundleShortVersionString in the generated Info.plist (stripping off the leading "v").
defaults write "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH%.*}" "CFBundleShortVersionString" "$GIT_RELEASE_SHORT_VERSION"
defaults write "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH%.*}" "CFBundleVersion" "$GIT_RELEASE_VERSION"
touch "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH%.*}.plist"
Thatâs it! Now every time you build your app, the version information will be automatically pulled from your git tags. Easy!
Step 3.4: Rename the Script (optional)
I have a number of different build scripts â everything from this version modification to Crashlytics scripts â and itâs nice to be able to see at a glance which script does what. To change the name of the Build Phase, just double click on itâs title to select it, then type in a descriptive name.
Step 4: Bonus Step â Add Version to Settings.bundle
In Loose Leaf, Iâve also added the full version string to the Settings bundle. This helps particularly during QA; itâs much easier for testers to check the app settings to report bugs for a specific version. Even with just a few testers and a few bug-fix builds, itâs nice to be able to quickly verify that someoneâs on a particular build when testing.
The end result of this step is a additional field in your Settings bundle that displays the full version string for that build.
To achieve this, first add in a title field into the Root.plist of your Settings bundle. After your done it should look like this:
The default value can be anything (itâs set as â0.1â here), but our script will update it at build time. Also note in this example Iâve added it as Item 4. It maybe a different index in your plist, so make note of that number, weâll use it again soon. For our example, Iâll be using â4â.
Next, add another Run Script Phase, and copy in the following script:
GIT_RELEASE_SHORT_VERSION=`git describe --tags | awk '{split($0,a,"-"); print a[1]}'`
GIT_RELEASE_VERSION=`git rev-list HEAD | wc -l | tr -d ' '`
VERSION_FOR_SETTINGS="${GIT_RELEASE_SHORT_VERSION} (${GIT_RELEASE_VERSION})"
/usr/libexec/PlistBuddy "$CONFIGURATION_BUILD_DIR/$CONTENTS_FOLDER_PATH/Settings.bundle/Root.plist" -c "set PreferenceSpecifiers:4:DefaultValue $VERSION_FOR_SETTINGS"
In the above script, it specifies âPreferenceSpecifiers:4:âŚâ. If youâre item in the Root plist is a different index, make sure to use that number here too.
Step 5: Enjoy!
Now itâs easy to automatically manage your version numbers for every build. Donât worry about forgetting to update your Info.plist â everything is taken care of automatically with this simple script!




