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
    # auto git version noise
    # old skool
    # osx noise

    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.