I've just finished the first working version of a more complex bash script, and I'm wrapping my head around on how to maintain the scripts version.
Why do I need this? Following GNU Coding Standards For Commandline Interfaces I've added a version option which among a license and copyright header shows the current version.
Still, I don't know how to keep the version 'up-to-date'.
My idea so far is to use git tags for major | minor | patch releases, and somehow replace a variable contained in the script.
So, if I have a tag named 1.1.0
, then
$ myscript --version
Should output something like:
myscript 1.1.0
The script contains a shell variable for this:
version=1.1.0
Still, I don't now how to keep the version in sync with the latest tag?
Another solution can be to use the Git tags to automatically generate the version number. A script can find the closest tag starting with v such as v0. 1.2 and use the tag name as the version number plus the first n digits of the current commit ( v0. 1.2 (build 4acd21) ).
Git can be enabled on a specific folder/directory on your file system to version files within that directory (including sub-directories). In git (and other version control systems) terms, this “tracked folder” is called a repository (which formally is a specific data structure storing versioning information).
The source Command The built-in bash source command reads and executes the content of a file. If the sourced file is a bash script, the overall effect comes down to running it. We may use this command either in a terminal or inside a bash script.
As far as I can tell, what you want is impossible. In order to have the version number be committed into the version control software, you'd have to edit the version number, commit, then tag; not the other way around. You can however have the process a little more streamlined.
We can do this by writing a post-commit hook that'll read your script's version number and if it has changed from last time, write out a new tag. In order to do this, cd into .git/hooks
from your project directory, create a file called post-commit
(or move post-commit.sample
) and make it executable. Then edit it so it looks something like this:
#!/bin/bash
NEWEST_TAG=$(git describe --abbrev=0 --tags)
SCRIPT_VERSION=$(grep "^version=" myscript | awk -F= '{print $2}')
if [ x$NEWEST_TAG != x$SCRIPT_VERSION ]; then
git tag -a $SCRIPT_VERSION -m "version $SCRIPT_VERSION"
fi
Next time you bump your script's version number and commit your changes, you'll see a new tag added to your latest commit.
The hook-based answers previously given tightly couple the synchronization of the version string with a git commit
; however it sounds like you want it to work the other way around, i.e. the version is extracted from manually created git tag
metadata. It turns out that in fact this is pretty much the approach the git
source code itself uses, so let's learn how you could adopt something similar by examining its approach:
git describe
, but falls back to a hardcoded default if that doesn't work. The version is written to GIT-VERSION-FILE
at the top of the source tree.The Makefile
invokes this script and include
s the generated file:
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
-include GIT-VERSION-FILE
Now the version is accessible to the rest of the Makefile
via $(GIT_VERSION)
.
Various Make rules then use this to perform substitutions on any files which need the version string hardcoded, such as various Perl scripts:
$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
$(QUIET_GEN)$(RM) $@ $@+ && \
INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
sed -e '1{' \
[... snipped other substitutions ...]
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
[email protected] >$@+ && \
chmod +x $@+ && \
mv $@+ $@
For example if you look near the beginning of git-svn.perl
, you'll see:
$VERSION = '@@GIT_VERSION@@';
In my source tree, this rule has compiled to a file git-svn
which contains the line:
$VERSION = '1.7.11.rc0.55.gb2478aa';
so if I check the version of my locally compiled git-svn
, I see:
$ git svn --version
git-svn version 1.7.11.rc0.55.gb2478aa (svn 1.6.17)
whereas if I run the rpm-based installation, I see:
$ /usr/bin/git svn --version
git-svn version 1.7.6.5 (svn 1.6.17)
This last output demonstrates that the approach works even when the source code is compiled from a released tarball which does not contain any version control metadata in the .git/
subdirectory. This means that the version string nicely distinguishes between stable releases and development snapshots.
Although git-svn
is a Perl script, clearly the same substitution approach would work fine for your shell-script.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With