开发者

How do you use tags in git to manage software versions [duplicate]

This question already has answers here: Automatic tagging of releases (10 answers) Closed 3 years ago.

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 o开发者_Python百科f like a branch I guess.


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 #defines the extracted version and its parts.

  • Put a shell command early on in my top-level makefile that runs this script (so the header file is generated every time I build something).
  • Relevant code #includes 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:

The Script

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

The makefile

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.

The code

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 #includes 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

  1. You have to build something in order to get the version. I actually added 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.
  2. 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.
  3. Probably others I'm not thinking about at the moment.


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜