20
Feb
2011
 

Revisiting git tags and building

by Fraser Hess

A couple of years ago I posted my scripts for tagging and building. The build script doesn’t work so well for the App Stores and the Build and Archive-based submission process, so here’s an updated approach that works inside Xcode. (Same as my last article, I’m still using git, the tag.sh script, and Apple Generic Versioning (agv).)

  1. In your Xcode project, create a Shell Script target called GenGitVersion.
  2. Insert the following script in GenGitVersion’s Run Script phase, replacing the path to your git executable if need be:
    git=/usr/local/git/bin/git
    version=`$git describe`
    echo "#define GIT_VERSION $version" > InfoPlist.h
    touch Info.plist
  3. Make GenGitVersion a dependency of your main target.
  4. Add “InfoPlist.h” to your .gitignore file.
  5. In your main target’s build settings:
    1. Turn on Preprocess Info.plist File
    2. Set Info.plist Preprocessor Prefix File to InfoPlist.h
  6. In your app’s Info.plist set the Bundle versions string, short to GIT_VERSION

Now each time you build the main target, the version will be populated in the build’s Info.plist.

Examples

  • If you tag a commit, the version returned by git describe is the tag name.
  • If the current commit isn’t tagged, you’ll get the most recent tag plus the number of additional commits and an abbreviated commit name. Here’s a 1.0b1 tag with 2 additional commits: 1.0b1-2-g3925f3b. This can be a good way to identify a private developer build.
  • You can optionally add --dirty to git describe and the version will have -dirty appended if there are uncommitted changes to your working tree.
  • git describe will fail if there are no tags in the current working tree.

Comments

dkf2112 says:

On XCode 4 it doesn’t appear necessary to create the secondary target and dependency. I just simply added a build phase to my main target to runt the script.

Fraser Hess says:

I tried that approach in 3.2.5 but the Info.plist was processed before the script was run. I haven’t tested it in 4.

anlumo says:

Note that the CFBundleVersion is required to conform to a specific format (from the docs: “This value is a monotonically increased string, comprised of one or more period-separated integers.”). Not following this will break a few things in the system, like the Finder’s ability to know which version is the newer one.

I just used my own Info.plist-key, which I can easily read in the app and display in the about box.

Also, something I ran into here with the SUFeedURL key: If you have // somewhere in your Info.plist file (like a URL), it will get filtered out when you enable the preprocessor (since it’s a comment), breaking the xml format. I solved this by letting the preprocessor think that it’s a string by surrounding the URL with .

[…] lots of subtle but clever tricks in this article on build numbers: http://www.cimgf.com/2011/02/20/revisiting-git-tags-and-building/ # No comments Digg […]

aglemann says:

I’ve been using a script based on the BetaBuilder Rakefile.. basically it increments the version number, tags it, does the build, generates release notes (based on commit logs since the previous tag) and uploads it to the brilliant TestFlight. The only problem I have is how to find out what the derived data folder is for Xcode4 Workspaces – so the script can find the buildfile – any ideas? (BTW would be happy to share the Rakefile if you were interested)

aglemann says:

Figured it out with help from #iphonedev :)

derived_data_dir = ls -dUt1 $HOME/Library/Developer/Xcode/DerivedData/{workspace_name}* | head -n 1 | tr -d '\n'