使用分布式版本控制时如何构建代码提交顺序

30

现在,我们使用Perforce进行版本控制。它有一个很方便的特性——严格递增的变更号码,我们可以用它来引用构建,例如:“如果您的构建至少为44902,则会获得错误修复”。

我想切换到使用分布式系统(可能是Git)以使分支和在家工作更容易(这两者在Perforce中完全可行,但Git工作流具有某些优点)。因此,尽管“支流开发”将是分布式的,并且不涉及常见的版本序列,我们仍将维护一个主Git仓库,在创建构建之前,所有更改都需要进入该仓库。

如何保留严格递增的构建ID?我能想到的最直接的方法是,每当主仓库更新时触发某种后提交挂钩,并将新树对象(或提交对象?我对Git还不熟悉)的哈希值注册到一个集中式数据库中,该数据库分配ID(我说“数据库”,但我可能会使用Git标签来执行此操作,并查找下一个可用的标签号码或类似物。因此,“数据库”实际上将是.git/refs/tags/build-id/)。

这是可行的,但我想知道是否有更简单、已实现或标准/“最佳实践”的方法来实现这一点。

8个回答

30

可以使用以下方式生成与当前提交对应的单调递增数字:

git log --pretty=oneline | wc -l

这个函数会返回一个单独的数字。你也可以将当前的sha1附加到该数字上,以增加唯一性。

这种方法比git describe更好,因为它不需要您添加任何标签,并且自动处理合并。

它可能在变基时存在问题,但变基本身就是一个“危险”的操作。


这种方法的问题在于你无法区分分支。不过你也可以将分支名称添加到构建ID中。 - timurb
你可以从特定的分支构建某些二进制文件(例如-beta,-stable,-nightly)。因此,分支名称对于构建编号来说是“外部的”。 - squadette

28

我赞同使用git describe的建议。假设你有一个合理的版本控制策略,并且不会对存储库进行任何疯狂的操作,git describe将始终是单调的(至少在您的修订历史是一个DAG而不是一棵树时,它可以尽可能地单调)并且是唯一的。

以下是一个小演示:

git init
git commit --allow-empty -m'Commit One.'
git tag -a -m'Tag One.' 1.2.3
git describe    # => 1.2.3
git commit --allow-empty -m'Commit Two.'
git describe    # => 1.2.3-1-gaac161d
git commit --allow-empty -m'Commit Three.'
git describe    # => 1.2.3-2-g462715d
git tag -a -m'Tag Two.' 2.0.0
git describe    # => 2.0.0
git describe 命令的输出包括以下组成部分:
  1. 从你要描述的提交可达的最新标签
  2. 提交和标签之间的提交数(如果非零)
  3. 提交的(缩写)ID(如果#2非零)
当提交是标签时,#2被省略,这使得输出单调;而#3被省略,则输出具有唯一性。因此,git describe 也适用于生产发布。

1
标签不能处理分支和合并。正确的自动添加适当顺序的方法是计算当前提交之前的提交数量。详见下面我的回答。 - squadette

8
    git rev-list BRANCHNAME --count

这比其他方法使用更少的资源。

    git log --pretty=oneline | wc -l

4

git tag 可能已经足够满足你的需求了。选择一个所有人都同意不使用的标签格式。

注意:当你在本地打标签时,git push 不会更新服务器上的标签。请使用 git push --tags 来完成这个操作。


2

你应该去研究一下 git describe 命令,它会返回一个唯一的字符串,用最新的注解标签、距离标签的提交次数和当前分支头部的简短提交 id 来描述当前分支(或任何传入的提交 id)。

假设你有一个单一的分支,你要在其上进行可控制的构建发布。在这种情况下,我建议你对早期提交进行已知标记格式的标记,然后使用 git describe 带上 --match 选项来描述相对于已知标记的当前 HEAD。然后你可以直接使用 git describe 的结果,或者如果你真的只想要一个单独的数字,你可以使用正则表达式从标记中提取出这个数字。

假设你从不回滚该分支,那么以下提交次数将始终标识分支历史记录中的一个唯一点。

例如(使用 bash 或类似命令):

# make an annotated tag to an early build in the repository:
git tag -a build-origin "$some_old_commitid"

# describe the current HEAD against this tag and pull out a build number
expr "$(git describe --match build-origin)" : 'build-origin-\([0-9]*\)-g'

1

我会使用“标签”。每当你有一个成功的(甚至不成功的)构建时,创建一个标签,这样你就能永远识别该构建。虽然不完全相同,但它确实提供了这些构建编号,同时仍然提供分布式开发的好处。


0

正如你所知,Git计算一个哈希值(一个数字),用于唯一标识历史记录中的节点。虽然这些哈希值不是严格递增的,但使用它们似乎已经足够了。(更好的是,它们总是对应着源代码,因此如果你有哈希值,你就拥有相同的代码。)它们是很大的数字,但通常你只需要前面6位左右。

例如:

那个错误在064f2ea修复了...


6
好的,但我有1a92b6这个版本。我是否已经拥有了错误修复? - sfink
git rev-list 1a92b6 | grep 064f2ea --> 如果有输出结果,那么你就找到了;否则就没有。 - EfForEffort
git branch --contains=<commit> 会给你所有包含 <commit> 的分支(通常更有用)。 - Stein G. Strindhaug
1
您不能假设最终用户可以访问GIT存储库,甚至知道它是什么——他们只有产品和版本号,这就是@sfink所说的。发布给最终用户的版本号需要排序。 - simon.watts

0

使用Mercurial,您可以使用以下命令:

# get the parents id, the local revision number and the tags
[yjost@myhost:~/my-repo]$ hg id -nibt
03b6399bc32b+ 23716+ default tip

查看hg identify


这不是严格递增的。 - OrangeDog

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