Version Bump for git using Fish Shell
Intro
One feature that I really like from npm is the version
command which handles bumping either patch, minor, or major version number following the Semantic Versioning standards. This sets the version attribute in your package.json
file and creates a git tag using the new version number.
For example you can run the npm version minor
command from the root of an npm project and it will change the version from 1.2.12
to 1.3.0
write this out to your package.json
file and create a git tag for the new version.
Since the vast majority of my projects are php projects and not npm, I don't get a chance to use this feature nearly as much as I would like, so I found myself wishing there was a way to do this directly from git.
Details
I have been a big fan of the fish shell since first learning about it on syntax fm's "The Command Line for Web Developers" episode, mostly for the autosuggest and autocomplete features, but more recently I've discovered the powerful scripting features. So I decided to see if I could implement this functionality through the command line via a fish
script.
So basically what I wanted to do was to write a script that would read the current git tag, break it down into major, minor, and patch variables, increment the correct element, reassamble it into major.minor.patch format and create a new git tag. Once this was working I realized that if the major or minor version was incremented I needed to reset the following elements to zero. After that was worked out, I thought that I could save myself another step if it went ahead and pushed the new tag to my remote repo.
At first I had it working with a custom function name, so from the root of my repo I could type git_version minor
and the new tag was calculated, created, and pushed. However, I don't personally like typing underscores, if I don't have to. So I wondered if I could "override" the git command and look for my custom command and then call git with the command line arguments, if it didn't see my custom version
command. That way it would feel like a more natural extension to git. That is when I came up with this solution:
# ~/.config/fish/functions/git.fish
function git
if count $argv > /dev/null
if [ $argv[1] = 'version' ]
git_version $argv
else
command git $argv
return $status
end
else
command git
return $status
end
end
This worked beautifuly. If git version minor
is ran from the terminal, it calls my custom git_version
function and passes the arguments to it, if anything other than version
is passed as the first argument, it hands it off to git to handle. Of course, this can be altered to add many more custom commands to git, I'm looking forward to adding more functionality in the future.
And here is the custom function that is called if the version
argument is passed to git
. I'm sure there is room for improvements, but the few dozen times I've used it so far it behaved as expected. It expects an argument of either 'major', 'minor', or 'patch' to determine which element to bump, with an optional build
argument of alpha
or beta
which will append a -alpha
or -beta
to the tag. There is also a --force
flag which will create and push the tag even if there are uncomitted changes on the branch. The other flag is a --dry
flag, if you just want to see the outcome of the command without creating a tag. Lastly, just running git version
will display the current version.
# ~/.config/fish/functions/git_version.fish
function git_version
set dry false
set build ''
set type ''
set force false
getopts $argv | while read -l key value
switch $key
case _
switch $value
case major minor patch
set type $value
case alpha beta
set build $value
end
case d dry
set dry true
case f force
set force true
case v version
_git_print_version
return 0
case \*
# Handle unknown flags here
echo unknown flag $key
end
end
set v (git describe --abbrev=0 --tags 2>/dev/null)
if [ $status != 0 ]
set v '0.0.0'
end
# strip any thing from the hyphen after to remove -alpha or -beta
set v (string split "-" -- $v)[1]
set vmajor (string split "." -- $v)[1]
set vminor (string split "." -- $v)[2]
set vpatch (string split "." -- $v)[3]
if [ $type = 'patch' ]
set vpatch (math $vpatch + 1)
else if [ $type = 'minor' ]
set vminor (math $vminor + 1)
set vpatch 0
else if [ $type = 'major' ]
set vmajor (math $vmajor + 1)
set vpatch 0
set vminor 0
else
echo $v
return 0
end
if [ $build ]
if [ $build = 'alpha' ]
set build alpha
else if [ $build = 'beta' ]
set build beta
else
echo "The 'build' can only be blank, alpha, or beta"
return 1
end
set tag $vmajor.$vminor.$vpatch-$build
else
set tag $vmajor.$vminor.$vpatch
end
if $dry
echo $tag
else
if git_is_dirty
if $force
echo 'Forcing new version'
else
echo 'git is dirty - must use --force'
return 1
end
end
git tag $tag
git push origin master --tags
end
end
function _git_print_version
echo git verison bump 1.2.0
end
Conclusion
Granted, this only works for a specific work flow, and the keystrokes it saves are negligible, but it was a neat learning experience and now I am ready to tackle some more fish scripting to make my life easier.
If you are interested in using this, it can be installed via fisher:
fisher add eidsonator/fish-git-version
The source code is available on github at fish-git-version and pull requests are welcome, if you see any room for improvement.
Please leave a comment if you can see any cons to me overriding git like this, or if you have any custom fish scripts you'd like to share.
If you liked this post, you can subscribe to the rss feed or follow me @ToddEidson on Twitter to be notified of future blog posts.Date Published: 10 February, 2019