logo

鱼肚的博客

Don't Repeat Yourself

Git的顺序号及其应用

引言

Git中每条Commit都会有一个 commit id,它是一个 sha1 hashsha1 hash 是commit的唯一标识。

SVN中的每条Commit则一般会带有一个顺序号。可以比较直观地看到commit序号的顺序增长。

那么Git中是否有类似SVN中顺序号的概念呢?答案是有的。而且在有些场合中,它还会发挥作用。

Git的顺序号

顺序号的定义

要获取顺序号,首先要明确顺序号的含义。

一般来说,有如下两种常用的定义:

  • 从给定的 git revision 开始,递归寻找 parent revision。所有能找到的 revision数量+1即为当前revision的顺序号。
  • 从给定的git revision开始,递归寻找parent revision,但是在有多个parent时(Merge)只取第一个parent。所有能找到的revision数量+1即为当前revision的顺序号。

两种方式的主要区别是在遇到Merge时,是否处理所有链路。

顺序号的获取

新版的 git 中,提供了 rev-list命令,可以列出所有的parent revision。通过参数,还可以控制对Merge的处理方式。

因此要获取顺序号,只需要 git rev-list --count HEADgit rev-list HEAD|wc -l即可。

在遇到Merge请求时,默认采用方式一,即递归查找所有的parent revision。rev-list中也提供了--first-parent选项,可以使用方式二,即只取第一个parent的方式。

顺序号的应用

知道了顺序号之后,能用来做什么呢?

一个典型的应用场景,是在持续集成环境中,使用顺序号发布决定版本号,提供一种易读的版本自增方案。

举例来说,对npm仓库中的软件包,如果希望每次 git push时都自动发布版本,则有如下选择:

  1. 每次版本发布时,自动修改package.json中的版本号。如将 2.1.0 自动改成 2.1.1。
  2. 每次版本发布时,不修改package.json中的版本号,通过给它加后缀来使其唯一。如2.1.0-234,或 2.1.0-sha1。这里的234是指顺序码。

第一种方式不太可取,因为它会自动添加很多个Commit,对持续集成是比较大的干扰。

第二种方式中,添加后缀的时候,可选择顺序号或sha1,或者同时添加。顺序号相对会比较容易理解,且能够方便地通过版本号看出版本间的时间先后关系,所以优先使用顺序号。

这种方式在多分支环境中不能保证唯一性,所以一般会通过加 preid (一般是分支名)来保证唯一性。另外在发布到 npm 仓库时,也可以使用 --dist-tag 的方式,使每个分支的 dist-tag相互独立,不互相干扰。

顺序号和sha1之间的关联

顺序号和sha1之间的关联是 1:N。

  • 通过给定的sha1,可以得到固定的顺序号
  • 通过给定的顺序号,无法得到确切的sha1

这也是为什么上方中提到,涉及到多分支时,通过顺序号无法保证版本号的唯一性。

示意图如下:

1git init
2Initialized empty Git repository in /private/tmp/git/.git/
3touch README.md && git add . && git commit -m 'init' 
4[master (root-commit) 220ec4b] init
5 1 file changed, 0 insertions(+), 0 deletions(-)
6 create mode 100644 README.md
7git rev-list --count HEAD   
81
9git checkout -b develop && touch 1.txt && git add . && git commit -m '1.txt'
10Switched to a new branch 'develop'
11[develop 014af28] 1.txt
12 1 file changed, 0 insertions(+), 0 deletions(-)
13 create mode 100644 1.txt
14git rev-list --count HEAD   
152
16git checkout master && touch 2.txt && git add . && git commit -m '2.txt'
17git rev-list --count HEAD   
182
19git merge develop
20git rev-list --count HEAD   
214

最初的 init 顺序号是1,切出新分支或在原分支中做修改,之后顺序号都是2。而在两个分支合并后,顺序号就变成了4。

因此,顺序号是不唯一的,在上面的示例中,出现了两个顺序号为2的revision。

以上就是对Git顺序号的简单介绍,希望对您有所帮助。