Xcode 4: Einfache Versionsnummern mit git

Immer wenn man sein Programm in ein Versions Control System einbetten, steht man vor dem Problem die “normalen” Versionsnummern mit den Revisionen zu verknüpfen.

Für dieses Problem gibt es na nun die Möglichkeit des Tags, aber was wenn man die mal wieder vergisst? Oder was wenn man sich zwischen den Releases befindet und seine Development-Build irgendwie einordnen will.

All dies kann man mit dem netten »git describe« Befehl lösen (sofern man Git benutzt). Hier eine Beispielausgabe:

1
2
$ ~/super-app$ git describe --dirty
1.5.0-14-g2414721-dirty

Hier die Auflösung:

  • 1.5.0 steht für den letzten annotated Tag. Diese benutze ich dreist für die einzelnen Versionsnummern. (Hinweis: die normalen “anderen” Tags werden defaultmäßig ignoriert.)
  • 14 steht für die Anzahl der Commits seit dem genannten Tag.
  • g2414721 steht einerseits für das verwendete VCS, das »g«, und andererseit beinhaltet es den Commithash »2414721«.
  • dirty steht dafür das noch Änderungen vorhanden sind, die nicht comitted wurden.

Die Teile dieser Ausgabe, die nicht notwendig sind, fallen weg. So würde ein Commit der gerade als »1.6.0« getagt wurde, nur folgendes liefern:

1
2
~/super-app$ git describe --dirty
1.6.0

Ziemlich schön, nicht?

Einbinden in Xcode

In Xcode, oder besser gesagt in Mac/iOS Apps, wird die Versionsnummer bekanntlicherweise in der Info.plist angegeben. Auch wenn ich keine Ahnung habe wer bei Apple auf die komische Idee gekommen ist, ist es möglich die PropertyList durch den Preprozessor zu jagen (Was sogar funktioniert!).

Als erstes ersetzen wir die Version in der Info.plist durch ein »GIT_VERSION«, welches dann durch den Preprozessor ersetzt wird.

1
2
3
4
5
6
7
8
<plist version="1.0">
    <dict><key>CFBundleVersion</key>
        <string>GIT_VERSION</string></dict>
</plist>

Nun erstellen wir ein neues »Aggregate« Target mit einer »Run-Script« Phase und gibt dort folgendes als Skript an:

1
2
3
4
VERSION=$(git describe --dirty)

echo "#define GIT_VERSION $VERSION" > Version.h
touch Info.plist

Dies erstellt uns nun bei jedem Build eine neue Version.h-Datei, welche die Aktuelle Version enthält. Zusätzlich berührt sie noch die Info.plist so das Xcode weiß, das er diese neu verarbeiten soll.

Damit das alles Hand in Hand funktioniert, müssen wir das Target noch als Abhängigkeit zu unserem eigentlichen App-Target hinzufügen.

Möge man es Magie nennen =)