如何维护由 git 源代码控制的 bash 脚本的版本号?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11935480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I maintain the version number of my bash script which is git source controlled?
提问by helpermethod
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.
我刚刚完成了一个更复杂的 bash 脚本的第一个工作版本,我正在思考如何维护脚本版本。
Why do I need this? Following GNU Coding Standards For Commandline InterfacesI've added a version option which among a license and copyright header shows the current version.
为什么我需要这个?遵循命令行界面的 GNU 编码标准,我添加了一个版本选项,在许可证和版权标题中显示当前版本。
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.
到目前为止,我的想法是使用 git 标签作为主要 | 未成年 | 补丁发布,并以某种方式替换脚本中包含的变量。
So, if I have a tag named 1.1.0, then
所以,如果我有一个名为 的标签1.1.0,那么
$ myscript --version
Should output something like:
应该输出类似:
myscript 1.1.0
The script contains a shell variable for this:
该脚本为此包含一个 shell 变量:
version=1.1.0
Still, I don't now how to keep the version in sync with the latest tag?
不过,我现在不知道如何使版本与最新标签保持同步?
采纳答案by akciom
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/hooksfrom 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:
我们可以通过编写一个 post-commit 钩子来实现这一点,该钩子将读取您的脚本的版本号,如果它与上次相比发生了变化,则写出一个新标签。为此,请.git/hooks从项目目录cd 进入,创建一个名为post-commit(或 move post-commit.sample)的文件并使其可执行。然后编辑它,使它看起来像这样:
#!/bin/bash
NEWEST_TAG=$(git describe --abbrev=0 --tags)
SCRIPT_VERSION=$(grep "^version=" myscript | awk -F= '{print }')
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.
下次您修改脚本的版本号并提交更改时,您会看到一个新标签添加到您的最新提交中。
回答by Adam Spiers
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 tagmetadata. It turns out that in fact this is pretty much the approach the gitsource codeitself uses, so let's learn how you could adopt something similar by examining its approach:
先前给出的基于钩子的答案将版本字符串的同步与git commit; 但是听起来您希望它以相反的方式工作,即版本是从手动创建的git tag元数据中提取的。事实证明,实际上这几乎是git源代码本身使用的方法,所以让我们通过检查其方法来了解如何采用类似的方法:
- It has a GIT-VERSION-GENshell script which attempts to intelligently determine the current version. Essentially it tries to extract the version string via
git describe, but falls back to a hardcoded default if that doesn't work. The version is written toGIT-VERSION-FILEat the top of the source tree. The
Makefileinvokes this script andincludes the generated file:GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN -include GIT-VERSION-FILENow the version is accessible to the rest of the
Makefilevia$(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@@';
- 它有一个GIT-VERSION-GENshell 脚本,它试图智能地确定当前版本。本质上,它尝试通过 提取版本字符串
git describe,但如果不起作用,则回退到硬编码的默认值。版本被写入到GIT-VERSION-FILE源代码树的顶部。 在
Makefile调用此脚本和includeS中生成的文件:GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN -include GIT-VERSION-FILE现在该版本可供其余的
Makefilevia 访问$(GIT_VERSION)。各种 Make 规则然后使用它对需要硬编码版本字符串的任何文件执行替换,例如各种 Perl 脚本:
$(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 $@+ $@例如,如果您查看 的开头附近
git-svn.perl,您会看到:$VERSION = '@@GIT_VERSION@@';
In my source tree, this rule has compiled to a file git-svnwhich contains the line:
在我的源代码树中,此规则已编译为git-svn包含以下行的文件:
$VERSION = '1.7.11.rc0.55.gb2478aa';
so if I check the version of my locally compiled git-svn, I see:
所以如果我检查我本地编译的版本git-svn,我会看到:
$ 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:
而如果我运行基于 rpm 的安装,我会看到:
$ /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.
最后一个输出表明,即使源代码是从已发布的 tarball 编译的,该 tarball 在.git/子目录中不包含任何版本控制元数据,该方法仍然有效。这意味着版本字符串可以很好地区分稳定版本和开发快照。
Although git-svnis a Perl script, clearly the same substitution approach would work fine for your shell-script.
虽然git-svn是 Perl 脚本,但显然相同的替换方法适用于您的 shell 脚本。
回答by chepner
Instead of creating the tag yourself, use a post-commit hook. The idea is to check if HEAD contains a line modifying the version assignment, and if so, create a new tag. This is just a rough example; it may be buggy, and it is definitely not as efficient as it could be.
不要自己创建标签,而是使用 post-commit 钩子。这个想法是检查 HEAD 是否包含修改版本分配的行,如果是,则创建一个新标签。这只是一个粗略的例子;它可能有问题,而且绝对没有它应有的效率。
#!/bin/bash
before=$( git log HEAD | awk -F= '/-version=/ {print }' )
after=$( git log HEAD | awk -F= '/+version=/ {print }' )
if [[ $before != $after ]]; then
git tag myscript-$after
fi
回答by Jason Huntley
Still, I don't know how to keep the version 'up-to-date'.
不过,我不知道如何使版本保持“最新”。
I do like the post-hook recommendations. However, an alternative approach, you could also use a build system if you already have one available. Do you have an automatic build system? Jenkins or Bamboo? Our build system creates a new tag for each successful build passing all unit tests. Granted this is a script, so you may only have to run unit tests, if you have them. You can add task in your build job to increment or match the version with the tag of the successful build or latest commit which runs and passes any tests.
我确实喜欢挂钩后的建议。但是,另一种方法是,如果您已经有可用的构建系统,您也可以使用构建系统。你有自动构建系统吗?詹金斯还是竹子?我们的构建系统为通过所有单元测试的每个成功构建创建一个新标签。当然,这是一个脚本,因此您可能只需要运行单元测试(如果有的话)。您可以在构建作业中添加任务,以增加或匹配版本与成功构建或最新提交的标签,该标签运行并通过任何测试。

