We use git to manage our project, we have a branch for each: dev staging production
I want to use git tags to manage versions of the software. As far as I can see if I am on a branch and add a few commits, I then have to run: git tag 1.0
Repacing 1.0 with whatever version number we are up to, then I can push the tag using: git push origin 1.0
And I can update the branch with: git push --tags
But how do I reuse a tag now? If I commit more code to my local repository and want it to be version 1.0 easily? Or do you just add a new tag like 1.1?
Also, what happens if my colleague uses the same tag name on his local repository and we both push the code for that same tag up?
Lastly, what happens if we accidentally push our code without running git tag to tag the commits.
I'm not really getting how tags work, I thought they would work like you would tag a blog post or something - you can tag lots of different commits with the same tag and reuse the tag etc. kind of like a branch I guess.
Tags are ref's that point to specific points in Git history. Tagging is generally used to capture a point in history that is used for a marked version release (i.e. v1. 0.1). A tag is like a branch that doesn't change.
git clone $ git clone -b <tagname> <repository> . If you only need the specific tag, you can pass the --single-branch flag, which prevents fetching all the branches in the cloned repository. With the --single-branch flag, only the branch/tag specified by the --branch option is cloned.
To create a Git tag with a message, use the “git tag” command with the “-a” option for “annotated” and the “-m” option for message. Note : if you don't provide the “-m” option, your default text editor will open in order for you to type the tag message.
Click History. Right-click the commit. If a commit has only one tag, click Delete Tag TAG NAME. If a commit has multiple tags, hover over Delete Tag... and then click the tag that you want to delete.
But how do I reuse a tag now? If I commit more code to my local repository and want it to be version 1.0 easily? Or do you just add a new tag like 1.1?
You can delete the tag with git tag -d 1.0
, then delete it on the server with git push origin :refs/tags/1.0
.
But the best practice is to only tag releases, and then create a maintenance branch for that release at the point where the tag is created. On that branch you push your fixes, and tag with 1.1, 1.2, ... as you make updated releases. It is bad practice to move a tag after you've given that code to a customer.
Also, what happens if my colleague uses the same tag name on his local repository and we both push the code for that same tag up?
I'm pretty sure the second one of you to push the tag will receive an error. Try it yourself to see what happens:
git checkout -b testbranch
git tag test1
git push origin tag test1
git tag -d test1
touch testfile
git add testfile
git commit -m "Added testfile"
git push origin testbranch
git tag test1
git push origin tag test1
Lastly, what happens if we accidentally push our code without running git tag to tag the commits.
You should push your tags after you've pushed the commits. You cannot do both at the same time (git push --tags
does not push commits, only tags). If you push tags first, the remote will have dangling references until you push the commits. So you should be doing
git push origin master
git push origin --tags
or similar, depending on your situation.
I'm not really getting how tags work, I thought they would work like you would tag a blog post or something - you can tag lots of different commits with the same tag and reuse the tag etc. kind of like a branch I guess.
Tags are like labels on commits, so you can mark some commits as being 'special'. Most commonly, this is used to tag releases, so you can always go back and see exactly what was in that release if a customer reports a bug.
Simply answering the title question, I've come up with a semi-professional solution (that may be of use to some people) that automatically tags my code with the git version tag I'm pointing to so I don't have to (remember to) manually update a version number each time I build. I currently work in a small group (< 5 developers), and our configuration management is still a work in progress. But until that matures, this is a solution that works for me.
High level view, these are the steps:
I wrote a script that queries git for my current version tag (using the beginning parts of this answer).
Auto-generate a header file that #define
s the extracted version and its parts.
#include
s this header file (which is not part of the repository), and voila, the version is automatically included without any manual input from me.In more detail:
I currently use a 3 number versioning scheme,, major.minor.build, where build can possibly be a string (for example, v1.8.3b). Note, that using echo -e
to print newlines works for me, but perhaps printf
is the better option
# queries git for the version tag I'm currently pointed at. Throughout SO there
# are different versions of this command, but this one works for me. And in fact
# all my tags are annotated, so I could just use "git describe"
VERSION=`git describe --tags`
# replace all the '.' with ' ', then split the array based on the spaces.
# Obviously this will have its limitations if there are spaces in your
# version tag, or maybe even wildcard characters, but that should never
# be the case for me
VER_ARRAY=(${VERSION//./ })
# pull out the major, minor, and build components. These can be used to
# pre-processor check different versions of my code for certain compatibility,
# should the need arise
V_MAJOR=${VER_ARRAY[0]}
V_MINOR=$(VER_ARRAY[1]}
V_BUILD=${VER_ARRAY[2]}
# all of my build tags are preceded by a 'v', so remove that simply by taking
# the substring starting at position 1
V_MAJOR=${V_MAJOR:1}
# define the path and header file
VERSION_HEADER=./path/to/codeVer.h
# write these to file. > creates the file and >> appends to the file
echo -e "// Auto-generated version header on " `date` "\n\n" > $VERSION_HEADER
echo -e "#define MY_CODE_VERSION \""$VERSION"\"\n\n" >> $VERSION_HEADER
echo -e "#define MY_CODE_MAJOR "$V_MAJOR >> $VERSION_HEADER
echo -e "#define MY_CODE_MINOR "$V_MINOR >> $VERSION_HEADER
echo -e "#define MY_CODE_BUILD \""$V_BUILD"\"\n\n" >> $VERSION_HEADER
At the top of my makefile, I have $(shell ./genVer.sh)
. This tells make to run a shell command, ./genVer.sh
is the path and name of the script. A better way to do this would be to make a .PHONY
target for the script, and then put that target as a prerequisite for the pertinent targets,, but I have a lot of targets and this was a one-liner catch all.
Now, in all relevant source/header files, I simply have
#include "codeVer.h"
....
#ifndef MY_CODE_VERSION
// although if codeVer.h cannot be found we will get a fatal error before
// this warning
#warning "Unable to find code version, defaulting to v0.0.0"
#define MY_CODE_VERSION "v0.0.0"
#endif
Now any time I make
, the current version is extracted, the header is generated, my code #include
s the file, and I get the correct version number without doing any manual work. Note, this doesn't just work for the latest version, if you checkout an older tag, this will work as well (provided of course the changes implementing this were in that version).
This does have its drawbacks. Most notably
codeVer.h
to the .gitignore list since I don't want it tracked in the repo. This means you could potentially hand your code off to someone with this file missing, and they won't know what version it is. But if they're using git (like they're supposed to be doing!) and they git pull/clone
your stuff, all the tags will come with it anyway.make clean
also generates this file (which seems counter-intuitive), but if you did it the right way and used a .PHONY
target as described above, that wouldn't be an issue.A great resource for tag info is on gitref.org
Don't try and reuse version numbers. Best is to just go to 1.1 or 1.0a. This is discussed at length in the man page.
For your question:
Lastly, what happens if we accidentally push our code without running git tag to tag the commits?
You can tag old commits by putting the commit ref in the command:
git tag 1.1 HEAD~3
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