如何在Git中使用标签来管理软件版本

How do you use tags in git to manage software versions

我们使用Git来管理我们的项目,每个项目都有一个分支:DEV分期生产

我想使用git标签来管理软件的版本。据我所知,如果我是在一个分支上并且添加了一些提交,那么我必须运行:Git标签1

用我们能达到的任何版本号重新配置1.0,然后我可以使用以下方法推送标签:Git Push原点1.0

我可以将分支更新为:git推-标签

但现在如何重用标签?如果我向本地存储库提交更多的代码,并希望它轻松地成为1.0版?或者你只是添加一个像1.1这样的新标签?

另外,如果我的同事在他的本地存储库中使用相同的标记名,并且我们都为相同的标记推送代码,会发生什么?

最后,如果我们不运行git标记来标记提交而意外地推送代码,会发生什么情况。

我真的不知道标签是如何工作的,我以为它们会像你标记博客文章或其他东西一样工作——你可以用相同的标签标记很多不同的提交,并重用标签等。我想这有点像一个分支。


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?

您可以删除带有git tag -d 1.0的标签,然后在带有git push origin :refs/tags/1.0的服务器上删除它。

但是,最佳实践是只标记发布,然后在创建标记时为该发布创建维护分支。在这个分支上,您推送修复程序,并用1.1、1.2……标记。当您发布更新的版本时。把代码交给客户后再移动标签是一种糟糕的做法。

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?

我敢肯定你们中第二个推标签的人会收到一个错误。自己试试看会发生什么:

1
2
3
4
5
6
7
8
9
10
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.

您应该在推送提交之后推送标签。不能同时执行这两项操作(git push --tags不推提交,只推标记)。如果首先推送标记,则在推送提交之前,远程程序将具有悬空引用。所以你应该这么做

1
2
git push origin master
git push origin --tags

或者类似的,视情况而定。

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.

标记类似于提交上的标记,因此可以将某些提交标记为"特殊"。最常见的是,它用于标记发布,因此如果客户报告了一个bug,您可以返回查看该发布中的确切内容。


我以前也有过类似的问题。以下是我发现的有用之处:

  • VONC对我类似问题的回答


只需回答标题问题,我就想出了一个半专业的解决方案(可能对某些人有用),它会自动用我指向的Git版本标记标记我的代码,这样我就不必每次构建时(记住)手动更新版本号。我目前在一个小组(<5个开发人员)工作,我们的配置管理仍在进行中。但在这一切成熟之前,这是一个对我有效的解决方案。

高级视图,步骤如下:

  • 我编写了一个脚本来查询Git的当前版本标记(使用这个答案的开头部分)。

  • 自动生成一个头文件,其中#define是提取的版本及其部分。

  • 在运行这个脚本的顶级makefile中尽早使用shell命令(所以每次构建东西时都会生成头文件)。
  • 相关代码#include的这个头文件(它不是存储库的一部分)和voila,版本自动包含,不需要我手工输入。

更详细地说:

剧本

我目前使用3号版本控制方案major.minor.build,其中build可能是字符串(例如v1.8.3b)。注意,使用echo -e打印换行对我来说很有用,但也许printf是更好的选择。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 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`"

"> $VERSION_HEADER
echo -e"#define MY_CODE_VERSION ""$VERSION""

">> $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""

">> $VERSION_HEADER

生成文件

在我制作的文件的顶部,我有一个$(shell ./genVer.sh)。这告诉make运行shell命令,./genVer.sh是脚本的路径和名称。一个更好的方法是为脚本生成一个.PHONY目标,然后将该目标作为相关目标的先决条件,但我有很多目标,这是一条单行线。

代码

现在,在所有相关的源/头文件中,我只是

1
2
3
4
5
6
7
8
#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

现在,每当我执行make操作时,都会提取当前版本,生成头文件,我的代码#include是文件,并且在不进行任何手动操作的情况下获得正确的版本号。注意,这不仅适用于最新版本,如果签出一个较旧的标记,也可以(当然前提是实现此版本的更改在该版本中)。

这确实有其缺点。最值得注意的

  • 为了得到版本,您必须构建一些东西。我实际上把codeVer.h添加到了.gitignore列表中,因为我不希望在repo中跟踪它。这意味着您可能会将代码交给缺少此文件的人,而他们不知道它是什么版本。但如果他们使用Git(就像他们应该做的那样!)而且他们用你的东西,所有的标签都会带上。
  • make clean也会生成这个文件(这看起来有点违反直觉),但是如果您按正确的方式执行并使用了上面描述的.PHONY目标,这就不是问题了。
  • 可能还有其他我现在没想到的。

  • 标签信息的一个好资源在gitref.org上。

    不要尝试重新使用版本号。最好的方法是只转到1.1或1.0a。这将在手册页中详细讨论。

    对于您的问题:

    Lastly, what happens if we
    accidentally push our code without
    running git tag to tag the commits?

    您可以通过将commit-ref放入命令来标记旧提交:

    1
    git tag 1.1 HEAD~3