Using Git Versioning inside your XCode Project

March 23rd, 2011 Posted by: - posted under:Featured » Tutorials

This tutorial will show you how to automatically fill in CFBundleVersion and CFBundleShortVersionString, when using Git.
This has been tested in Xcode 3.2.5 (Updates for Xcode 4 at the bottom)

Git Setup
First off you need a project that is checked into git, and is also tagged with an initial version number.

If you already have git setup for your project, skip down to XCode Setup

To locally setup up git, without a remote repository, after installing git, issue the following commands
cd into your project directory
and type “git init”
create a file in this directory called “.gitignore” and add the following lines to it

# xcode noise
build/*
*.pbxuser
*.mode1v3
xcuserdata
 
# auto git version noise
InfoPlist.h
 
# old skool
.svn
 
# osx noise
.DS_Store
profile

Then you can type:

git add *
git add .gitignore
git commit -a -m "Initial Version"

To make the first commit.

Type the following to give us our initial version tag

git tag -a "0.0.1" -m "Version 0.0.1"

When tagging, for this script to work, you should be using the form X.Y.Z, where X,Y, and Z are all numbers.

XCode Setup
Now that we have a local Git Project, or if you are already used to git and skipped to here, we can set up our project to auto generate our CFBundleVersion and CFBundleShortVersionString

Right click on Targets, and select Add -> New Target
Choose Shell Script Target
Enter a name. I chose GenGitVersion
Close the Target “GenGitVersion” Info screen that popped up, and expand the GenGitVersion under Targets in the Groups & Files view.
Double click on Run Script to open the “Run Script Phase for “GenGitVersion” Info” Screen.

Paste the following into the “Script” Section

Change Info.plist to the name of your Info.plist, and also the git= string to the location of git on your system.
This script will use the “git describe” command to take the name of the latest tag you have committed of the form 0.0.0 and create a short version string of the form 0.0.1-X-abcdefgh-dirty, where the 0.0.1 is the latest tag, -X is the number of commits since that tag, and the -dirty is whether you have committed all your latest changes or not. The version string created by this script will just be the latest tag name, for example 0.0.1.

If you used my .gitignore, then you already have InfoPlist.h added, otherwise add InfoPlist.h to your .gitignore
Right click on your main Target and choose Get Info
Under the General Tab, you want to add the GenGitVersion Target as a Direct Dependent of your main Target
You would do this by clicking the + sign under the Direct Dependencies section and choosing GenGitVersion, and then clicking Add Target.

Under the Build tab, you also need to select, Under Packaging, the checkbox for “Preprocess Info.plist File”, and right above that make sure to enter in InfoPlist.h as the “Info.plist Preprocessor Prefix File”

The last thing you need to do is change your Info.plist file to use the following for CFBundleVersion and CFBundleShortVersionString
CFBundleVersion = APP_VERSION
CFBundleShortVersionString = GIT_VERSION

Now when you use the following in your application, you will have git populating the strings, based on the version numbers of the latest tag and commits.

NSString *shortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
 
NSLog(@"Short: %@", shortVersion);
NSLog(@"Version: %@", version);

Xcode 4 Changes
There is not a Shell Script Target anymore in Xcode 4, unless you are opening an Xcode 3 project inside Xcode 4, however what I found to work is to create a new Aggregate Target, and in this target you can, under Build Phases, Add A Build Phase of the type, “Add a Run Script”. This gives you a “Run Script” section to place the script. You then set this aggregate target as a Target Dependency of your main Target, which will run the script before your main target is built.