I'm working on a side project that has required some on-device troubleshooting. I find myself loading a build on my phone and using it for several days. There's been a lot of trial-and-error debugging in this project, so I often run code from an experimental branch for extended periods of time. It's easy to lose track of what source configuration I have loaded on my phone at any given time.
I wanted to get a way to get the current Git revision and branch into the app. I figured a good start would be the following:
- The branch name (using
git rev-parse --abbrev-ref HEAD
) - The abbreviated hash of the current commit (using
git rev-parse --short HEAD
) - Whether the working copy was clean or not. I got this by checking the output of
git status -s
. If the working copy is clean (i.e., no untracked files and no changes to tracked files), that command prints nothing. If the working copy is dirty, the command prints something.
I wanted to get this information into each build, not just release builds. Getting this information from a shell script into a build is tricky. One of the problems is that you can't modify the working copy. Doing so would change the "is clean" flag. The build would always show dirty and a commit would be needed to clean it, changing the commit hash.
The approach I settled on was to write an untracked Swift file as part of the build process.
First, add generate-git-revision.sh
(see below) to your project's bin
directory (or wherever you keep your project's scripts).
#!/usr/bin/env bash
set -euo pipefail
cat <<SWIFT
//
// GitRevision.swift
//
// This file was automatically generated. Do not edit manually. It will be overwritten on every build.
//
// IMPORTANT: This file must be added to .gitignore or it will dirty the working tree every time there is a build.
//
/// Information about the current Git revision.
struct GitRevision {
/// The name of the current branch.
static let branch = "$(git rev-parse --abbrev-ref HEAD)"
/// The abbreviated hash of the current commit.
static let commit = "$(git rev-parse --short HEAD)"
/// Whether the working tree is clean. If false, indicates that there are uncommitted or untracked files in the working tree.
static let clean = $([[ -z $(git status -s) ]] && echo 'true' || echo 'false')
/// Build timestamp. Set when this file was generated at the beginning of the build process.
static let timestamp = "$(date +%Y-%m-%dT%H:%M:%S)"
/// A string summarizing the current Git revision.
static var description: String {
return "\(commit)\(clean ? "" : "-dirty") \(branch) \(timestamp)"
}
}
SWIFT
Next, in Xcode add a new Run Script build phase at the top of the list of Build Phases (directly under Dependencies). Call the new build phase Generate GitRevision.swift. Make the body of the build phase script:
"${PROJECT_DIR}/path/to/generate-git-revision.sh" > "${PROJECT_DIR}/path/to/GitRevision.swift"
Build the project. This causes the script to run and generate GitRevision.swift
.
Now, add the new GitRevision.swift
file to the project. Also add GitRevision.swift
to the project's .gitignore
file.
That's it. The generated GitRevision.swift
file will look something like this:
//
// GitRevision.swift
//
// This file was automatically generated. Do not edit manually. It will be overwritten on every build.
//
// IMPORTANT: This file must be added to .gitignore or it will dirty the working tree every time there is a build.
//
/// Information about the current Git revision.
struct GitRevision {
/// The name of the current branch.
static let branch = "development"
/// The abbreviated hash of the current commit.
static let commit = "3c747d5"
/// Whether the working tree is clean. If false, indicates that there are uncommitted or untracked files in the working tree.
static let clean = false
/// Build timestamp. Set when this file was generated at the beginning of the build process.
static let timestamp = "2020-05-10T23:03:15"
/// A string summarizing the current Git revision.
static var description: String {
return "\(commit)\(clean ? "" : "-dirty") \(branch) \(timestamp)"
}
}
If you leave that file open in Xcode when you build, you can see the property values change as the file gets regenerated.
You can now reference GitRevision.description
from your app's code to show the commit, branch, and build time.