Update your web app version dynamically with git-describe
Git tags help you to mark a point in your git history, we use this to mark our code/software version.
A little more about tags
In git we have two "kinds" of tags .
Annotated tag — Is store with some information
git tag -a v1.0 -m "First version"
Lightweight — Is an simple commit checksum without any extra information
git tag v1.0
This is important because `git description`treats this “kind”of tags different.
Git-describe
git describe
is a git command that display the last reachable tag , this can be useful if you want to know the exact version of your code.
In your CI for instance, if fail you want to know what was the exact version of your code that failed.
Let’s do to understand
Let's build a very simple calculator.
❯ yarn init . && yarn add assert -D && git init .
Our first version will sum two numbers
// calc.test.js
const assert = require('assert');
const calc = require('./calc');
assert.equal(calc.sum(1,1), 2);// calc.js
module.exports = {
sum: (n1, n2) => n1 + n2
}
Our first commit will be like this
❯ git add . && git commit -am "Sum feature"
If we execute `git describe` the result will be..
❯ git describe
fatal: No names found, cannot describe anything.
The reason is because there are nothing to describe, in this moment we don't have any tag just commits.
The documentation said that.
Describe a commit using the most recent tag reachable from it
So let's add an tag for our version
❯ git tag v1.0.0
As mention before, there are two kinds of tags, annotated and unannotated. The command above just create an unannotated tag.
There reason this is important is because git describe, by default, only shows annotated tags
❯ git describe
fatal: No annotated tags can describe ‘544a96f6fb66dcb858df2ec0172def47430297dc’.
However, there were unannotated tags: try — tags.
By default (without — all or — tags)
git describe
only shows annotated tags.
We can see our most recent tag using ` — tags` flag
❯ git describe — tags
v1.0.0
But this not helps us if our CI fail and we need to check the exact version that failed. Let’s try instead use unannotated tags, use more descriptive (annotated) tags.
Adding subtract feature
// calc.test.js
assert.equal(calc.sub(10,5), 5);// calc.js
sub: (n1, n2) => n1 - n2
And publish our app with version 1.1.0
❯ git add . && git commit -am "Add sub feature"
❯ git tag -a v1.1.0 -m "Subtract feature"
Now we have two tags `v1.0.0` with sum feature and `v1.1.0` with subtract feature.
❯ git tag
v1.0.0
v1.1.0
As we annotated our last tag, the `git describe` will show the most recent annotated tag.
❯ git describe
v1.1.0
The command finds the most recent tag that is reachable from a commit. If the tag points to the commit, then only the tag is shown.
Until now we have a publish 1.1.0
version of our app with sum and subtract feature.
But, what's happen if we keep changing our code and don't put any tag?
Adding multiply feature
// calc.test.js
assert.equal(calc.mult(5,5), 25);// calc.js
mult: (n1, n2) => n1 * n2
This time we will not publish a new tag(version), we simple commit the code
git add . && git commit -am "Add multiply feature"
The trick here is, we are no longer on version `1.1.0` , we are ahead of this version, if the test fails all information that we have is the git hash. Is when describe feature comes to handy.
❯ git describe
v1.1.0–1-g831f2d6
Let's split this ..
- v1.1.0 — Is the last tag
- 1 — Is how many commits we area ahead
- g — Stands for “git” and is used to allow describing the version of a software depending on the SCM the software is managed with.
- 831f2d6 — 7-char abbreviation for the tip commit of parent
Now describe can be useful, in our CI we know the exactly version and commit that fail.
We can keep adding features..
// calc.test.js
assert.equal(calc.div(10,2), 5);// calc.js
div: (n1, n2) => n1 / n2
The git describe will be..
❯ git add . && git commit -am "Add divider feature"
❯ git describe
v1.1.0-2-gdc8528b
2 because we are 2 commits ahead of the last tag, and dc8528b as 7-char abbreviation for the tip commit.
As you can see, is more descriptive way to display the exactly version of your code.
Use git-describe to manager our app version
git describe helps you to identify the exact version of your code, and we can use this to automatic display the app version.
Let’s do to understand
Let's build a web app that use our calc.js
module. To do this we will use webpack in order generate our bundle and HTML.
❯ yarn add webpack html-webpack-plugin -D
And configure
// webpack.config.jsconst path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js',
},
plugins: [new HtmlWebpackPlugin({
title: 'Calculator',
template: 'index.ejs',
})
]
};-----// app.jsconst calc = require('./calc');
const n1El = document.getElementById('n1');
const n2El = document.getElementById('n2');
const resultEl = document.getElementById('result');
const execOperation = (operation) => {
const n1 = parseInt(n1El.value);
const n2 = parseInt(n2El.value);
resultEl.textContent = operation(n1, n2);
}
const applyOperation = (elementId, operation) => {
document
.getElementById(elementId)
.addEventListener("click", function() {
execOperation(operation)
});
}
applyOperation("sumBtn", calc.sum);
applyOperation("subBtn", calc.sub);
applyOperation("multBtn", calc.mult);
applyOperation("divBtn", calc.div);-------// index.ejs<!DOCTYPE html>
<html>
<head>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<label for="n1">N1</label><input type="number" id="n1" />
<label for="n2">N2</label><input type="number" id="n2" />
<button id="sumBtn">+</button>
<button id="subBtn">-</button>
<button id="multBtn">*</button>
<button id="divBtn">/</button>
= <span id="result"></span>
<hr>
<footer>
<span id="version"></span>
</footer>
</body>
</html>
Run webpack
will generate in dist
folder our index.html
with script
tag point to app.js
.
And our `index.html` on browser will be like this
The question here is how to add git describe version in our html on tag #version.
To archive this we need to use the git-revision-webpack-plugin.
yarn add git-revision-webpack-plugin -D
This is a very simple and useful plugin that use git describe
to get our code version and allow us to use it our webpack configuration.
We can use this in conjunction with DefinePlugin to "export" our version to HTML.
Let's do it
First change the 'webpack.config.js' as follow
// Add ..const webpack = require('webpack');
const GitRevisionPlugin = require('git-revision-webpack-plugin');
const gitRevisionPlugin = new GitRevisionPlugin();
...// And in plugins
plugins: [
...
new webpack.DefinePlugin({
'VERSION': JSON.stringify(gitRevisionPlugin.version()),
'COMMITHASH': JSON.stringify(gitRevisionPlugin.commithash()),
'BRANCH': JSON.stringify(gitRevisionPlugin.branch()),
})
]
Now in our app.js
we have access to these variables, we can simple change the version.
const versionEl = document.getElementById('version');
versionEl.textContent = `VERSION: "${VERSION}" COMMITHASH: "${COMMITHASH}" BRANCH: "${BRANCH}"`;
And after publish a new version.
❯ git add . && git commit -am "Add web interface"
❯ git tag -a v1.2.0 -m "Add web interface to access the calculator features"
Our describe
will display the current version.
❯ git describe
v1.2.0
And our interface will display the same.
Conclusion
As demonstrated git-describe can be use to identify our code in CI or display version in our app.
Check my github repository with the full code.
Like this? Please click ❤️ bellow so other people can find it.