使用git跟踪修订版本号

3
Subversion有一个修订号,每次提交后都会递增。我们用它来包含在每个版本号中,格式为X.Y.Z,其中X是主要版本,Y是次要版本,Z是修订号。
在我们的问题跟踪器中,我们只需引用Subversion修订号(或在提交消息中引用问题编号),就可以轻松确定特定版本是否已包含修复程序。
现在,由于git提交由哈希值标识。由于这不能用作修订号,因此我们使用提交计数代替,以便在构建过程中生成版本号。
现在的问题是,当用户报告错误时,错误报告通常包括版本号,很难查找是否在更近期的版本中已经修复了该问题,还是仍未解决,因为git中我们只看到提交哈希。
一种解决方案是维护一个翻译表,列出每个提交哈希并将其映射到修订号,但这会使生活变得更加困难。
您能否推荐解决此问题的最佳实践?
4个回答

1
我会用git describe的方法来处理这个问题,它可以方便地打包三个重要信息:
  1. 哈希值
  2. 最新标签
  3. 自最新标签以来的提交次数,以防我们在未标记的提交上。
此外,在大多数项目中,我有一个标准的发布版本标记方式:vXXX.YYY.ZZZ。我在需要精确引用提交时使用git describe的输出。例如,我的一个项目位于:
v1.1.9-19-g3024adf

我通常运行一个预编译脚本,将这个注入一些编译器符号中以包含在二进制文件中。有一个标准的命名方式可以确保我得到一个上限长度的输出 git describe ,这对我很重要,因为我需要将其压缩在我嵌入式系统中包含的任何协议中。

0

不要使用提交计数。只需包含哈希的前几个字符代替旧版本号即可。您无需包含整个字符串,前五或六个字符就足够了。

在分布式环境中,版本号没有意义,因为历史记录绝非线性。对于您来说,第10次提交可能是其他人克隆的完全不同的提交。


发布是线性的。我们从1.0.42到1.0.43。我们需要能够轻松地确定开发人员在其远程分支中进行的修复是否已合并并发布在1.0.43中。 - b0ti
@b0ti,那么如何确定开发人员所做的“修复”呢?你有哈希值吗?这不是很清楚。如果你正在寻找一种检查给定提交是否已经合并到发布分支的方法,可以像这样去做。 - s.m.
开发人员在问题跟踪器中的工单上添加注释“已修复于<deadbeefgithash>”(或者这个注释会自动从提交消息中引用该工单而被添加)。 - b0ti

0

所以,有一个概念上的问题(虽然 SVN 可以做到,但需要更多手工操作),git 强调不同分支的合并。

所以让我们假设

     /--> B1 --> B2 --> … --> B18-\
A -->                              +--> D
     \--> C1 --> C2 --------------/

D 应该有什么版本号?是 version(A) + 19(上面的路径)还是 version(A) + 3(下面的路径)?或者你把合并算作修订(+1 计数)?

因此,即使在 SVN 时代,你单调的修订基本上只是一种约定,并且如果从那个数字中可以看到是否存在修复,你可能真的没有在分支上工作过。

在一个允许你在不必为修复Bug而在另一个分支上操作的系统或团队现代开发中,单一分支方案是没有意义的。因此,把一个分支声明为“版本化”分支只是一个惯例,通常只有一个“主分支”(在git中是默认分支),所有特性分支都会合并到其中,只要它们能正常工作,并从这个分支中派生新的特性分支,每当有人想开发新功能时。然后,你只需在主分支上使用git tag标记提交,每当有重要事件发生 - 例如新发布。典型的标记名称是 release_001_002_001 。是的,与SVN上的自动修订计数相比,它是手动的,但实际上对于您的代码管理非常有用 - 查找某个Bug修复提交哈希是否发生在另一个提交哈希之前或之后只是一个 git log 的问题。

您实际上可以计算AD之间的提交数量。然后,version(D)将是version(A) + 18 + 2 + 1。这相对容易做到;你应该尝试一下。

git log A..D --pretty=oneline | wc -l

再说,我怀疑那的有用性。


我们已经在使用提交计数wc -l。标签并没有帮助,因为它们是在发布时应用的,而不是开发人员修复问题时应用的。我确实理解Git分布式分支背后的概念,但问题是关于另一件事。 - b0ti
那么,你可能没有完全理解答案,或者没有仔细思考:使用git进行版本控制的方式是无法有线性数字的,因为它没有线性历史记录。因此,你正在追逐不可能实现的东西。 - Marcus Müller
我完全不同意你的观点:“客户打来电话,很难查看问题是否已经解决”。实际上并不是这样。在这两种情况下,都需要查看修订历史记录。 - Marcus Müller
你需要知道修订号(SVN)或提交哈希值(git)来查找bug修复版本的历史记录。因此,只需查找这些信息是否在历史记录中即可。 - Marcus Müller
另外:你必须要停止直接从源代码控制中心提供非发布版本给客户,或者你需要接受他们将会拥有奇怪软件版本的事实。你不能既想吃蛋糕又想保留蛋糕。 - Marcus Müller
1
@MarcusMüller是正确的,您不能使用线性计数来描述非线性过程。 SVN能够做到这一点,因为它专门线性化了该过程,通过为每个新提交分配唯一的顺序号来实现。这是可能的,因为提交仅存储在中央服务器上。有一个真正的信息来源。现在,*确实有一种方法可以使用Git进行类似的操作,但是评论中没有空间,所以我必须提供单独的答案。 :-) - torek

0

正如我在评论中所说,这里的问题归结为线性化。如果您想要一个简单的递增计数来指定某个特定的提交,那么您必须有一个单一的源点来生成这个简单的递增计数。

在SVN中,有一个明显的地方可以做到这一点:所有提交都存储在主中央服务器上。为了进行新的提交,您需要调用中央服务器并说:进行新的提交。这要么成功并获得一个简单的递增数字,要么失败并且没有提交。

在Git中,没有指定的中央服务器。每个开发人员都会进行自己的提交。提交是在同行之间交换的。任何给定提交的全局唯一标识符都是其哈希值:Git保证没有两个提交具有相同的哈希值。1

缺乏单一的中央计数点会破坏自己制作简单修订计数的有用性,因为不同的存储库可以并且将具有相同数量的提交,而不包含相同的提交集。我可能有17个提交,其中2个与您的17个提交不同,因此如果我们合并我们的两个存储库,我们都会得到19个提交。(如果我将您的存储库与我的存储库合并,我将获得19个提交-从您那里获得的两个新提交以及我们已经共享的15个提交-而您仍然有17个提交:您必须仍然获取我拥有但您缺少的两个提交。)
但是,您可以使用您的想法:只需指定一个中央计数点:
“一种解决方案是维护一个翻译表,列出每个提交哈希并将其映射到修订号,但这使生活变得更加困难。”
如果您已经拥有一个中央服务器,那么这并不是那么困难。例如,如果任何发布构建都在“发布构建”系统上完成,并且发布构建系统具有Git存储库,则只需指定其存储库为中央计数点即可。

它维护着这个表格。计数可以存储库中提交的数量。2但这已经超出了我们的需求:计数可以简单地是表格中条目的数量;没有必要计算非构建版本。无论如何,从“计数”到“哈希”,或者反之亦然,都是通过查找或添加适当的条目到表格中来完成的。

这种简化计数的价值最多是可疑的。看看真正的软件发布,通常会标记一个“点版本”:Git版本2.8.4、Git版本2.9.0、Git版本2.10.1;Python 2.7.12、Python 3.4.5等等。7.3.12与7.4.0相比如何?它严格地“小于”,还是不是?使用Git构建发布时,可以使用这样的点版本进行标记。标签可以使用Git内置机制进行分发,每个人都可以在本地查找v7.3.12并找到提交。如果您没有标签,则可能没有该版本:您必须从拥有标签的人那里使用git fetch,可能还要使用--tags

标签实际上是这个中央映射表的分布式版本。但我们不是计算标签,而是直接使用它们的名称,这些名称的形式为vXvX.Y或其他形式。

这些标签可以通过git describe进行扩展,它允许您说“距离此固定标记有这么多次提交,加上一个唯一的验证器/定位器,以防分布式构建使相对计数失效。”请参见Sébastien Dawans的答案

1这个"保证"是通过一个简单的机制来保持的:如果两个提交具有相同的哈希值,Git就简单地拒绝相信第二个提交存在。它不会接受它,不会将其存储到存储库中,并且现有的哈希值“获胜”。对于任何给定的一对对象,这种情况发生的概率都非常小:2-N,其中N是哈希中的位数。由于Git使用SHA-1,它是160位,因此为2-160

由于所谓的生日悖论或生日问题,随着对象数量的增加,概率迅速上升。然而,我们从一个如此小的基础开始,以至于在机会甚至达到未被检测到的存储介质损坏的机会水平之前,我们可以拥有数万亿个对象,也许多达1.7千万亿个左右。(这里使用“短刻度”名称;请参见https://en.wikipedia.org/wiki/Quadrillion)。

2如果您使用此方法(计算其存储库中提交的数量),则必须确保您从不删除任何提交,否则计数将下降,因此不会像升序函数一样运行。这是表条目计数可能更好的原因之一;或者您可以使用一个永远不会重置的单独计数器,在选择下一个数字时进行原子获取和递增。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接