关于工作流:版本化不同git分支的最佳方法

best way to versionize different git branches

我们有以下场景:我们的游戏openlierox有几个基本版本;现在是0.57、0.58和0.59。对于每个基本版本,我们都有一个单独的分支。每个这样的基本版本都有几个版本(比如0.57 beta1-beta8和rc1,0.58 beta1-beta9)。

当我们处理新事物时,我们在最高基础版本分支(现在是0.59)中工作。当我们修复一些报告的错误时,我们会在发生错误的最早版本(主要是0.58)中进行修复。有时,我们总是将0.58中的所有更改合并为0.59(只要我们仍然保持并对旧分支进行更改)。

这一切都很好,直到出现一些变化,我们希望只有0.58而不是0.59。到目前为止,这种情况只适用于一种情况:版本号。我们有一些version.cpp文件(以及其他一些文件),其中包含版本号。所以,当我们想为0.58推出新版本时,我们将其中的versionString更改为"0.58 beta10"(或其他版本)。现在,当我们进行从0.58到0.59的常规合并时,这个更改也将被应用。我们现在通过用正确的版本号再次覆盖它来修复这种情况(或者在其他错误提交的情况下,可能是还原)。

这种不必要的变化的细节对我来说似乎有点难看。我们处理这件事的方式一般不好/不常见吗?要得到相同的结果,最简单的方法是什么?挑选0.59中0.58的所有承诺将是更多的工作。

还有一个更详细的细节,可能会使它更复杂:在处理代码时,我必须设置即将到来的版本号。这是因为我们有一个网络引擎,我们可能引入了一些新功能,并且在代码中有一些检查,比如"if(client->version()>=version(x,y,z))…"。现在,当我们介绍一些新的东西时,通常意味着在某些地方也会进行这样的检查。(但我们正在努力避免在较老的分支中发生这些变化。)

另一个问题是我们不只是计算版本(比如0.58.1,0.58.2,…),而是这样计算:0.58 beta1,0.58 beta2,…,0.58 betax,0.58 rc1,…,0.58,0.58.1,0.58.2,…。这是因为我们想把它标记为开始的实验阶段(beta阶段),然后标记为基本稳定或稳定。在一些罕见的情况下,甚至在两个不同的beta版本之间可能会有严重的变化(可能是网络协议)(当然,我们试图避免它们,但有时没有它们是不可能的)。


有额外的分支

在0.59偏离0.58之后,您可以使用单独的"发布"分支来更改0.58中的版本号。每个版本(除了最新版本)都有自己的"发布"分支,它只包含来自基本分支的合并和更新外部版本号的更改。分支结构可能如下所示:

1
2
3
4
5
6
7
8
9
                A--------o--B                  0.58-release
               /        /
...--o--o--o--o--o--o--o--o                    0.58
      \        \        \  \
       \        \        \  \            C     0.59-release
        \        \        \  \          /
         o--o--o--o--o--o--o--o--o--o--o--o    0.59
                                  \     \
                                   o--o--o     0.60
  • A标记软件"0.58 beta9"
  • B标记软件"0.58 RC1"
  • 0.58有尚未发布的更改
  • C标记软件"0.59 beta1"
  • 0.59有尚未发布的更改
  • 0.60尚未完全更新,0.59

或者,如果您非常严格地只对更改外部版本号的A、B、C等进行更改(没有重大代码更改,这些更改属于"基本"分支:0.58、0.59等),那么您可以不使用"发布"分支。相反,您可以使用分离的头部或临时分支(在版本化后删除)来提交外部版本更新并将其保存在标记中。

1
2
3
4
5
6
7
8
9
                A        B
               /        /
...--o--o--o--o--o--o--o--o                    0.58
      \        \        \  \
       \        \        \  \            C
        \        \        \  \          /
         o--o--o--o--o--o--o--o--o--o--o--o    0.59
                                  \     \
                                   o--o--o     0.60

  • a将软件标记为"0.58 beta9",并标记为0.58-beta9。
  • b标记软件"0.58 RC1",并标记为0.58-RC1。
  • C标记软件"0.59 beta1"并标记为0.59-beta1

就像吉特那样

您还可以研究Git自己进行版本控制的方式。

对于由Git工作树完成的构建,版本号是从git describe HEAD的输出生成的。makefile知道如果版本号改变,哪些文件需要重新编译/重建,它总是运行git-version-gen脚本来确保它有最新的版本号。通过包含生成的版本文件,版本号在makefile中可用。它通过一个参数传递给编译器(-DGIT_VERSION=…)到C文件,并通过使用sed将其替换为脚本。

有一些覆盖版本号"烧录到"构建的规定,但它们通常只适用于在工作树之外完成的构建(例如,从tar文件中提取的树中完成的构建)。

混合版本字符串随其他更改而更改

在问题的附录中,您声明在进行开发时需要调整版本号。首先,我认为SEH和我描述的"0.58版本"分支方案仍然可以为您工作。只是需要更多的纪律来区分你的变化。如果您认为*-发布分支是"为内部测试而发布",而不仅仅是"为客户(或外部测试)而发布",那么它仍然是有意义的。始终在基本分支(例如"0.58")上进行开发,并始终在进行需要特定版本号的构建之前将基本分支合并到发布分支(例如"0.58-release")。

如果您坚持将版本号更改和(非合并)代码更改放在同一历史行中,那么在我看来,您除了在合并时处理冲突之外别无选择(除非您使用git cherry-pick(根据damien wilson,或针对EDOCX1的自动编辑脚本)〔3〕。

如果您的"版本文件"只包含版本信息,则可以使用.gitattributes将您的Version.cpp文件标记为不可读取,从而减轻冲突解决。

目录中包含version.cpp的.gitattributes

1
/Version.cpp -merge

如果合并分支之间的文件不同,那么这样标记(与merge=binary相同)将始终导致冲突。合并后工作树版本将默认为您已签出的分支的版本(而不是您正在合并的分支的版本),因此您只需git add Version.cpp && git commit即可完成合并(假设所有其他冲突也已解决)。


棘手的部分是将版本名称与底层代码隔离开来。

您可以在已发布代码分支的顶部浮动一个指定分支的版本,这样您就可以在任何时候安全地将所有代码从已发布分支(0.58)合并到主分支(0.59),而不会混淆冲突的版本指定。指定分支的版本永远不会合并回已发布的分支;当您希望在版本化的版本中包含新代码时,您只需在已发布分支的顶部重新设置分支。

您可以使用.git/config文件中的以下条目轻松地安排此操作:

1
2
3
4
[branch"0.58-release"]
        remote = .
        merge = refs/heads/0.58
        rebase = true

这样,您的发布分支就被称为"0.58",您将使用"0.58发布"分支进行版本化构建。当需要进行发布构建时,您将发出以下命令:

1
2
3
4
git checkout 0.58-release
git pull
# Edit the version-designating file.
git commit -a -m'Updated version.'

对指定文件的版本的所有更改只存在于"58发行版"分支上,并且可以使用git rebase安全地向前移动。或者,如果您希望对指定文件的版本所做的每个更改都保持"0.58"分支的代码状态,则可以将"0.58"分支合并到"0.58-release"分支中,而不是在"0.58"之上重新设置"0.58-release"。


如果我理解这个问题,听起来您希望包含来自不同分支的某个提交子集。如果是这样,您可能只需要运行git cherry-pick,并且只应用您想要的提交。

关于git docs中的命令和git ready的更多信息。


看起来你所做的是正确的方式(为了这个结果)。但也许你应该重新考虑你的版本系统。

你可以添加一个构建版本,0.58.1,0.58.2,等等,这样你可以添加任意多的东西,你仍然可以统称它为"0.58",即使它有一个构建号。

在发布之后,您可以添加beta、rc,无论它是什么,但这不是版本控制系统应该关心的。

版本"0.58.3(beta1)"仅表示版本0.58.3。beta1部分是人类信息,而不是版本控制系统。