Using Git Versioning inside your XCode Project

  • Twitter
  • Facebook
  • Digg
  • Reddit
  • StumbleUpon
  • del.icio.us
  • Google Bookmarks
March 23rd, 2011 Posted by: (ELC) - 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.

  • http://twitter.com/effzehn effzehn

    Thank you very much for this. Although, all I needed were the steps until the XCode setup – I use XCode 4 which comes with git support. There, you only need to add the repository via File -> Source Control -> Repositories… give the whole thing a name and point to your local directory where .git is located. Select Git as your versioning system. After a restart, you are good to go.

  • http://walkingsmarts.com/ Eimantas

    This is really nice and dandy, but what would you suggest when coding is done by more than 1 developer? What happens with pbxproj file? Running an app requires it to be signed with dev’s signing profile. So if I commit project file with my signing profile, other developer will have to change it after each pull and vice/versa – same will happen to me after other dev pushes to the repo.

  • Dafire

    Having the project file in version control works fine.

    You can set the signing profile to “iPhone Developer” or “iPhone Distribution” and it will autoselect the matching key from the local keychain .. no need to change the settings by every dev.

  • http://profiles.google.com/epologee Eric-Paul Lecluse

    Was this written for Xcode 3 or 4? I’m on 4 now and I can’t find the “Shell Script Target”. Neither in the iOS nor the Mac OS X category. An alternative is to add a script as a build phase, but those scripts are executed *after* the Info.plist is preprocessed, so it doesn’t update the git-described version correctly.

    Any advice? Cheers, Eric-Paul.

  • James Van Metre

    This was written for Xcode 3, however after searching for shell script target, and Xcode 4, I was able to find out where it is located in Xcode 4. You have to add an “Aggregate Target” first, and then you can click on that and Click on the tab “Build Phases”, and on the bottom right you can “Add Build Phase” , which will let you “Add a Run Script”. Everything else is pretty much the same.

  • Raunak Poddar

    Thanks a lot James.

  • http://blindgenius.wordpress.com/ Blind Genius

    Thanks this helped me out a lot.

    With regards to XCode 4 not having run scripts, it does but now they are located under Schemes.

    To get this script to run correctly you must add this script as a pre-build script and dont forget to add #!/bin/sh in the shell text field as it is not added by default as it was in xcode 3.x.

    Thanks again

  • http://blindgenius.wordpress.com/ Blind Genius

    Add the script as a Pre-Action on the build phase of the scheme for your target, then it will be run before the compilation

  • Raunak Poddar

    Hi James,

    The feature doesn’t work on the Distribution version of an iPhone app. When logging CFBundleVersion it prints GIT_VERSION instead of 0.0.5 (or whatever). Works good on the debug and release versions though.

  • Raunak Poddar

    O… It’s working now. The distribution configuration was created after the XCode setup for Git. I just deleted the previous GenGitVersion script and repeated the steps given under XCode setup in this page. Worked like a charm.
    Thanks.

  • http://profiles.google.com/valerii.hiora Valerii Hiora

    James, thanks for sharing.

    There is one short note regarding InfoPlist keys – CFBundleVersion should be GIT_VERSION and CFBundleShortVersionString should be APP_VERSION as the first is supposed to be used by developers and the second one will be shown to users everywhere and git revisions can be confusing :-)

blog comments powered by Disqus
canakkale canakkale canakkale balik tutma search canakkale vergi mevzuati