Automatic versioning of Android build using git describe with Gradle
Solution 1
A more proper and lean way to achieve the result which gained traction lately would be to use grgit integration, which uses JGit Java libray. As it uses JGit it doesn't even require git to be installed to work (which simplifies things in build pipelines).
Here's a basic example showing a similar (but with some additional information in gitVersionName string) solution:
plugins {
id 'org.ajoberstar.grgit' version '4.1.1'
}
ext {
gitVersionCode = grgit.tag.list().size()
gitVersionName = grgit.describe(tags: true, always: true)
}
android {
defaultConfig {
versionCode gitVersionCode
versionName gitVersionName
}
}
[...]
As you can see in Grgit API documentation the describe operation provides additional information other than most recent tag reachable in history:
Find the most recent tag that is reachable from HEAD. If the tag points to the commit, then only the tag is shown. Otherwise, it suffixes the tag name with the number of additional commits on top of the tagged object and the abbreviated object name of the most recent commit.
Anyhow, it won't tell if the state is dirty or not. This information can be easily added by looking at the clean status of the repo, and appending a string if it's not clean.
Solution 2
Put the following in your build.gradle file for the project. There's no need to modify the manifest directly: Google provided the necessary hooks into their configuration.
def getVersionCode = { ->
try {
def code = new ByteArrayOutputStream()
exec {
commandLine 'git', 'tag', '--list'
standardOutput = code
}
return code.toString().split("\n").size()
}
catch (ignored) {
return -1;
}
}
def getVersionName = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'describe', '--tags', '--dirty'
standardOutput = stdout
}
return stdout.toString().trim()
}
catch (ignored) {
return null;
}
}
android {
defaultConfig {
versionCode getVersionCode()
versionName getVersionName()
}
}
Note that if git is not installed on the machine, or there is some other error getting the version name/code, it will default to what is in your android manifest.
Solution 3
After seeing moveaway00's answer and Avinash R's comment on that answer, I've ended up using this:
apply plugin: 'android'
def getVersionCode = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-list', '--first-parent', '--count', 'master'
standardOutput = stdout
}
return Integer.parseInt(stdout.toString().trim())
}
catch (ignored) {
return -1;
}
}
def getVersionName = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'describe', '--tags', '--dirty'
standardOutput = stdout
}
return stdout.toString().trim()
}
catch (ignored) {
return null;
}
}
android {
defaultConfig {
versionCode getVersionCode()
versionName getVersionName()
}
}
I've edited moveaway00's code to also include Avinash R's comment: the version code is now the number of commits since master
, as this is what the version code is supposed to be.
Note that I didn't need to specify the version code and the version name in the manifest, Gradle took care of it.
Solution 4
Yet another way:
https://github.com/gladed/gradle-android-git-version is a new gradle plugin that calculates android-friendly version names and version codes automatically.
It handles a lot of special cases that are not possible using the accepted solution:
- version tags for multiple projects in the same repo
- expanded version codes like 1002003 for 1.2.3
- gradle tasks for easily extracting version info for CI tools
- etc.
Disclaimer: I wrote it.
Solution 5
Here is another solution that requires statements instead of functions to access the commandline. Warning: *nix only solution
def gitSha = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim()
// Auto-incrementing commit count based on counting commits to master (Build #543)
def commitCount = Integer.parseInt('git rev-list master --count'.execute([], project.rootDir).text.trim())
// I want to use git tags as my version names (1.2.2)
def gitCurrentTag = 'git describe --tags --abbrev=0'.execute([], project.rootDir).text.trim()
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.some.app"
minSdkVersion 16
targetSdkVersion 22
versionCode commitCount
versionName gitCurrentTag
buildConfigField "String", "GIT_SHA", "\"${gitSha}\""
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
Admin
Updated on July 09, 2022Comments
-
Admin almost 2 years
I have searched extensively, but likely due to the newness of Android Studio and Gradle. I haven't found any description of how to do this. I want to do basically exactly what is described in this post, but with Android Studio, Gradle and Windows rather than Eclipse and Linux.
-
Martin Revert over 10 yearsIt doesn't work for me. Git is installed Ok, project is building Ok but name and version is not updated on compilation. How can I debug what's going bad?
-
moveaway00 over 10 yearsTry using gradle directly outside of android studio: try running
gradlew assembleDebug
from inside your project, assuming you used the default gradle wrapper android studio provides. -
Avinash R about 10 years@moveaway00 instead of using
git tag --list | wc -l
isn't it better to just usegit rev-list --first-parent --count master
this gives the number of commits from the initial version, which I believe is actually the version code. Using tags are riskier as tags also has a use case of being use and throw references during rebases/squashes -
Vetalll over 9 yearsIt is good use HEAD instead of branch name. So gradle will use count of revisions of current branch
-
Léo Lam over 9 yearsOf course, you can replace
master
with any branch you want, or evenHEAD
for the current branch. -
Talespin_Kit about 9 yearsSample java code to use the info . PackageInfo packageInfo = this.getPackageManager().getPackageInfo( this.getPackageName(), PackageManager.GET_ACTIVITIES); Log.d(TAG, Integer.toString(packageInfo.versionCode)); Log.d(TAG, packageInfo.versionName);
-
Chad Bingham about 9 years@Talespin_Kit Nice. But easier way is
BuildConfig.VERSION_CODE
orBuildConfig.VERSION_NAME
. Those are static so you don't need context. -
nAkhmedov about 9 yearsIt gives to me error: stackoverflow.com/questions/30026730/…
-
C4F about 9 yearsTo clarify, this goes in Project > app > build.gradle, not the top level build.gradle
-
Pj Dietz over 8 yearsI used the total number of commits to get the build number by changing a couple lines:
commandLine 'git', 'rev-list', 'HEAD', '--count'
andreturn Integer.parseInt(code.toString().trim())
-
Avinash R over 8 years@Vetalll, It's not good to use
HEAD
in this case. This is because if you are developing with a topic branch approach (like git-flow), the topic branch will be having more commits on it, which means that when the branch is merged withmaster
, theversionCode
will be downgraded due to the presence of--first-parent
. So to allow you and your fellow developers not to have to uninstall the app everytime the topic branch is merged to master, take theversionCode
frommaster
(or which ever your release branch is) -
Avinash R over 8 years@LéoLam a pure cross-platform version of this is here
-
Avinash R over 8 yearslink only solution is not a solution. Please add relevant code before someone downvote your answer
-
BitByteDog almost 8 yearsThis is an excellent answer, but the versionCode is an integer, use gitVersionCode = git.tag.list().size() instead.
-
Greg T almost 8 yearsIt's also possible to add the short commit hash to your version name (ex. "8a97512"). Use this: commandLine 'git', 'rev-parse', '--short', 'HEAD'
-
Codeversed over 6 yearsDid this just stop working? I have been using this forever and now with the latest updates for AS and Gradle, seems to not get a value... right directory to exec the command and tested the command outside of Gradle and everything works.
-
Christopher Hunt about 4 yearsThis needs upvoting - I managed to integrate it very easily and I'm very happy with the results. Combine this with the following code to display the version in your app:
version.text = resources.getString(R.string.version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, BuildConfig.BUILD_TYPE)
...where the string resource template is:<string name="version">v%s (%d, %s}</string>
-
Michał Jaroń almost 3 yearsAlso add
--abbrev=0
parameter. Commandgit describe --tags --abbrev=0
prints tag name without suffix.git describe --tags
➤ v0.0.6-1-g7043532git describe --tags --abbrev=0
➤ v0.0.6 -
Daniel Ryan over 2 yearsI made the mistake of using HEAD. I had the exact problem AvinashR explained. I couldn't upload the app on the Play Store. Now using master.