I use tags in git to version my code and push changes to production. Tagging is fairly simple using the git cli, but I’ve made it even easier using a simple Grunt task.

Git tags are what we use to push code to production. Whenever a new tag is pushed to origin master, our CI server (Jenkins) does a build and then pushes that new code to production. The act of tagging is fairly trivial, but it is a few different commands. Typically one would do the following:


$ git describe —tags —abbrev=0


$ git tag 1.200.70

$ git push origin —tags


Unfortunately, thats a tiny bit of a pain and still a manual process prone to error. Someone recently pushed 3 different tags to our master branch of “list”, “describe”, and “show”. Obviously a mistake when using git commands but still, these random tags have actually proved to be a much bigger pain in the rear than they should!

We already had Grunt setup for this particular project because we were using a simple build command to compile our SASS files. Including a new task specifically for git tagging seemed a no-brainer. Now to push a tag we simply execute:


$ grunt tag


By default it will do a :patch, but additional options can be included for minor and major i.e.:


$ grunt tag:minor


The code is fairly straightforward:

[sourcecode lang=”javascript”]

// jshint node:true

‘use strict’;

var semver = require(‘semver’),

exec = require(‘exec’);

module.exports = function(grunt) {

‘use strict’;


var gitVersion;


pkg: grunt.file.readJSON(‘package.json’),

shell: {

options: {

stdout: true,

stderr: true


tag: {

command: [

‘git tag <%= grunt.option(“tag”) %>’,

‘git push origin –tags’

].join(‘ && ‘)




// Auto increment GIT TAG and PUSH to ORIGIN

grunt.registerTask(‘tag:patch’, [‘tag’]);

grunt.registerTask(‘tag:minor’, function() {

grunt.option(‘tagType’, ‘minor’);



grunt.registerTask(‘tag:major’, function() {

grunt.option(‘tagType’, ‘major’);



grunt.registerTask(‘tag’, function() {

if (grunt.option(‘tagType’) !== ‘major’ &&

grunt.option(‘tagType’) !== ‘minor’) {

grunt.option(‘tagType’, ‘patch’);


var done = this.async();

exec(‘git describe –tags –abbrev=0’,

function(err, stdout, stderr) {

if (stderr) {


} else {

gitVersion = semver.inc(




grunt.log.ok(‘Tagging: ‘ + gitVersion +

‘ (‘ + grunt.option(‘tagType’) + ‘)’);

grunt.option(‘tag’, gitVersion);









And the devDependencies in the package.json:

[sourcecode lang=”javascript”]

“devDependencies”: {

“grunt”: “^0.4.4”,

“load-grunt-tasks”: “^0.4.0”,

“semver”: “^2.2.1”,

“exec”: “^0.1.0”,

“grunt-shell”: “^0.6.4”



You can download the complete Gruntfile.js from this gist:


Important Note: Some asked why I didn’t just use grunt-bump for this type of solution. The main problem I had was that grunt-bump wants to require the version number stored in the package.json file. If the version (or tag) changes outside of the package.json file then grunt-bump stops working properly. With a shared project repo like this particular one, with many old-school people not using (or refusing to use) Grunt, manual git tags are still pushed daily. The risk of the package.json file being out of sync (version # wise) was too high. This method forcefully uses the actual last git tag to increment.