A common problem developers encounter when developing applications that use a crash reporting tool like Crashlytics is determinig if a particular crash/bug has been fixed/addressed or not.
For example assume that you get a crash report for a recent release. But you released three times this week already … which release does it apply to?
This is usually solved by reviewing the version code and verison name in Crashlytics. But even then you have to be properly tagging your releases. If you’re doing that you can trace back the release to a particular commit and then investigate.
However … Lets be 100% honest here – not everyone does this. Unfortunately , very few companies do this in my experience and it declines even more when the size of the team deminishes to even a single developer. There’s a lot going on, its easy to miss. Furthremore, chasing down a tag, then finding a commit, well … its kind of a pain. If someone forgot then its all for nothing.
That said, here’s a quick tip that can save you a ton of time when you’re performing crash and bug triage with tools like Crashlytics.
Adding The GIT SHA
In your Android application, open the build.gradle file and add the following above the android block.
// Hat tip to Jake Wharton for this - found it in the u2020 app def gitSha = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim()
Back in the Android block add a git sha build config constant.
android { compileSdkVersion 19 buildToolsVersion "21.1.0" defaultConfig { applicationId "co.your.appname" minSdkVersion 19 targetSdkVersion 19 buildConfigField "String", "GIT_SHA", "\"${gitSha}\"" } }
Now go back to where you’ve set up your Crashlytics instance in your application code (example shown below). Just below the initialization script add the following code:
Crashlytics.setString("git_sha", BuildConfig.GIT_SHA);
What this will do is set a string with the key value being “git_sha” and the value being the short git-sha from your source control.
Now, when your application crashes you’ll get a bug report in Crashlytics and you’ll be able to see what the latest commit was on that code.
Reviewing in Crashlytics
Open Crashlytics and go to one of your crashes. Then click on “more details”. Here you will see (screenshot below) the git_sha that the application was built off of.
Then you’ll see this ..
Remediation
Once you have identified the crash and the git-sha you can checkout that exact version of the code by issuing
git checkout git_sha_goes_here
At this point you’re in a detached head state. You’ll want to see what caused the crash in this state. Then you’ll want to return to your current develop branch or tagged branch to fix/hotfix the issue and release the fix.
The git_sha saves a ton of time and its super easy to set up. You no longer have to dig through git logs, tags, patches, etc to find “what commit is this crash happening on? Did we fix it already? How can I find out?” Simply check the git sha, look for the bug, see if it’s fixed yet. If it is, cool. If not, fix it and be on your way.
I hope that helps!
** Update **
Jake had a great comment in the reddit thread that I wanted to share …
Worth noting that this will break incremental compilation as you commit (and thus cause the value to change). Internally we switched to writing the SHA to a file if it is missing and using the file’s value (we do the same with build timestamp). This means that only a clean build gets fresh values. Since CI builds and making releases are always clean (right? RIGHT?) it keeps developer builds fully incremental yet still gives the right values where it matters. – Jake Wharton
HeQingbao says
Thank you very much.
Thomas Sunderland says
We put the Git SHA in as part of the application version itself. Our format for continuous builds is Major.Minor.J+JenkinsBuildNumber.GitSha(8 chars) (e.g. 1.0.J200.01234ABCD).
For developer builds we use the timestamp along with the Windows/Mac user name rather than the Jenkins build number. (e.g. 1.0.AS20150629123000.jdoe) where AS signifies that build was created directly in Android Studio (or possibily the command line). If the user name is unavailable then we replace it with the literal “Internal”.
def versionCodeJenkinsBuild = System.getenv(“BUILD_NUMBER”) as Integer ?: 0
// Windows uses “USERNAME”, Linux (MAC) uses “USER”
def gitIdentifier = System.getenv(“GIT_COMMIT”) as String ?: System.getenv(“USERNAME”) as String ?:
System.getenv(“USER”) as String ?: ‘Internal’
versionCode versionCodeJenkinsBuild
versionName ‘6.6.’ + ((versionCodeJenkinsBuild == 0) ?
(‘AS’ + getDate()) : (‘J’ + versionCodeJenkinsBuild.toString())) +
‘.’ + gitIdentifier.substring(0, Math.min(gitIdentifier.length(), 8))
Yacong Gu says
Very helpful, thanks!
Sarthak Mittal says
Hello Donn,
why can’t the BuildConfig.VERSION_NAME alone be used instead of finding SHA?
Nate R says
I got a Gradle error while implementing this: “Error:(21, 0) CreateProcess error=2, The system cannot find the file specified”. Gradle was having trouble finding my Git binary, despite Android Studio knowing where it was. Turns out that Git was not on my PATH, so it was an easy fix. I think is fairly common on Windows, so I thought I’d share.
Aashrai Ravooru says
He started out the article by saying that internally companies don’t increment versions while testing they should but most of them don’t hence this is a solution for the same
Martin Sloup says
I use Git SHA and timestamp only in release builds which doesn’t break incremental debug builds.
def gitSha() {
return ‘git rev-parse –short HEAD’.execute([], project.rootDir).text.trim();
}
def buildTime() {
return new Date().format(“yyyy-MM-dd’T’HH:mm:ss.SSSZ”, TimeZone.getTimeZone(‘UTC’));
}
android {
defaultConfig {
buildConfigField ‘String’, ‘GIT_SHA’, ‘null’
buildConfigField ‘String’, ‘BUILD_TIME’, ‘null’
}
buildTypes {
release {
buildConfigField ‘String’, ‘GIT_SHA’, ‘”‘ + gitSha() +'”‘
buildConfigField ‘String’, ‘BUILD_TIME’, ‘”‘ + buildTime() + ‘”‘
}
}
}
Martin Sloup says
Add path to Git bin to your system PATH environment variable.