18

我刚刚完成了一个更复杂的 bash 脚本的第一个工作版本,我正在思考如何维护脚本版本。

为什么我需要这个?遵循命令行接口的 GNU 编码标准,我添加了一个版本选项,它在许可证和版权标题中显示当前版本。

不过,我不知道如何保持版本“最新”。

到目前为止,我的想法是使用 git 标签作为专业 | 未成年人 | 补丁发布,并以某种方式替换脚本中包含的变量。

所以,如果我有一个名为 的标签1.1.0,那么

$ myscript --version

应该输出如下内容:

myscript 1.1.0

该脚本为此包含一个 shell 变量:

version=1.1.0

不过,我现在不知道如何使版本与最新标签保持同步?

4

4 回答 4

14

据我所知,你想要的是不可能的。为了将版本号提交到版本控制软件中,您必须编辑版本号,提交,然后标记;不是相反。但是,您可以简化流程。

我们可以通过编写一个 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 $2}')

if [ x$NEWEST_TAG != x$SCRIPT_VERSION ]; then
    git tag -a $SCRIPT_VERSION -m "version $SCRIPT_VERSION"
fi

下次您修改脚本的版本号并提交更改时,您会看到一个新标签添加到您的最新提交中。

于 2012-08-13T14:41:49.723 回答
8

先前给出的基于钩子的答案将版本字符串的同步与git commit;紧密结合在一起。但是听起来您希望它以相反的方式工作,即版本是从手动创建的git tag元数据中提取的。事实证明,实际上这几乎就是git源代码本身使用的方法,所以让我们通过检查它的方法来了解如何采用类似的方法:

  • 它有一个GIT-VERSION-GEN shell 脚本,它试图智能地确定当前版本。本质上,它尝试通过 提取版本字符串git describe,但如果这不起作用,则回退到硬编码的默认值。版本被写入GIT-VERSION-FILE源代码树的顶部。
  • Makefile调用此脚本并生成生成的include文件:

    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' \
                $@.perl >$@+ && \
            chmod +x $@+ && \
            mv $@+ $@
    

    例如,如果您查看 的开头附近git-svn.perl,您会看到:

    $VERSION = '@@GIT_VERSION@@';
    

在我的源代码树中,此规则已编译为git-svn包含以下行的文件:

    $VERSION = '1.7.11.rc0.55.gb2478aa';

所以如果我检查本地编译的版本git-svn,我会看到:

    $ git svn --version
    git-svn version 1.7.11.rc0.55.gb2478aa (svn 1.6.17)

而如果我运行基于 rpm 的安装,我会看到:

    $ /usr/bin/git svn --version
    git-svn version 1.7.6.5 (svn 1.6.17)

最后的输出表明,即使源代码是从已发布的 tarball 编译的,该压缩包在.git/子目录中不包含任何版本控制元数据,该方法仍然有效。这意味着版本字符串可以很好地区分稳定版本和开发快照。

虽然git-svn是 Perl 脚本,但显然相同的替换方法适用于您的 shell 脚本。

于 2012-08-15T17:13:45.467 回答
3

与其自己创建标签,不如使用提交后挂钩。这个想法是检查 HEAD 是否包含修改版本分配的行,如果是,则创建一个新标签。这只是一个粗略的例子;它可能有问题,而且绝对没有它应该的效率。

#!/bin/bash

before=$( git log HEAD | awk -F= '/-version=/ {print $1}' )
after=$( git log HEAD | awk -F= '/+version=/ {print $1}' )

if [[ $before != $after ]]; then
    git tag myscript-$after
fi
于 2012-08-13T14:24:49.340 回答
2

不过,我不知道如何保持版本“最新”。

我确实喜欢挂钩后的建议。但是,另一种方法是,如果您已经有一个可用的构建系统,您也可以使用它。你有自动构建系统吗?詹金斯还是竹子?我们的构建系统为通过所有单元测试的每个成功构建创建一个新标签。当然这是一个脚本,所以你可能只需要运行单元测试,如果你有的话。您可以在构建作业中添加任务,以增加或匹配版本与成功构建或最新提交的标签,该标签运行并通过任何测试。

于 2012-08-15T15:36:31.593 回答