Version Bump for git using Fish Shell
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.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.
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
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 = '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
beta which will append a
-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) set vmajor (string split "." -- $v) set vminor (string split "." -- $v) set vpatch (string split "." -- $v) 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
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 follow me @ToddEidson on Twitter for the best way (for now) to be notified of future blog posts.
Date Published: 10 February, 2019