【问题标题】:best way to versionize different git branches版本化不同 git 分支的最佳方法
【发布时间】:2011-01-05 20:44:50
【问题描述】:

我们有以下场景:我们的游戏 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 的新版本时,我们将其中的版本字符串更改为“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 版本之间也可能会发生严重的变化(可能是网络协议)(当然,我们会尽量避免它们,但有时如果没有这些变化是不可能的)。

【问题讨论】:

    标签: git workflow branch


    【解决方案1】:

    看起来你正在做的是正确的方法(对于这个结果)。但也许你应该重新考虑你的版本系统。

    您可以添加构建版本、0.58.1、0.58.2 等给它编号。

    发布后,您可以添加 beta、RC 等任何内容,但这不是版本控制系统应该关心的事情。

    “0.58.3 (beta1)”版本仅表示版本 0.58.3。 beta1 部分是人工信息,与版本控制系统无关。

    【讨论】:

    • 嗯,在“0.58 beta X”中,X 是内部版本号。我们也可以将其称为“0.58.X”。问题如下:在 Version.cpp 中,我们有一些静态 const std::string VERSION = "0.58.8"。现在,我们做了一些工作,然后我们想要发布一个新版本,我们将 std::string 更改为“0.58.9”。此版本更改的此提交是有问题的提交,因为此单个提交在 0.59 分支中没有意义(因此我们只希望所有其他 0.58 提交到 0.59,除了这个)。
    • 也许从 repo 中排除 version.cpp,只在构建中包含它?难道你不能也有版本是某种构建变量吗?我不是 c/pp 程序员,所以对构建的工作方式不太熟悉。
    • 那只会让整个事情变得更复杂。我应该把它存放在哪里?我希望能够切换一个分支并进行一些重新编译。不得不关心通过从某个地方复制一些 Version.cpp 来手动设置正确的版本似乎不太好。
    • 我意识到这很困难。但是构建变量选项呢?
    【解决方案2】:

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

    有关git docs 和Git Ready 中的命令的更多信息。

    【讨论】:

    • 是的,但这不是一个好的解决方案,因为它需要更多的工作,我在这里寻找最简单/最好的解决方案。在 0.58 中可能有 100 次左右的提交,我们希望在 0.59 中和一个我们不想要的(版本字符串更改)。
    • 您是否尝试过更改合并策略?也许是子树合并?关于 git 合并策略以及给定策略何时有意义的 SO 上有另一个线程。 kernel.org/pub/software/scm/git/docs/howto/…stackoverflow.com/questions/366860/…
    【解决方案3】:

    有额外的分支

    在 0.59 与 0.58 不同后,您可以使用单独的“发布”分支来更改 0.58 中的版本号。每个版本(最新版本除外)都有自己的“发布”分支,其中仅包含来自基本分支的合并和更新外部版本号的更改。分支结构可能如下所示:

                    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 等。 ),那么你可以不用“发布”分支。相反,您可以使用分离的 HEAD 或临时分支(在版本化后删除)进行 external-version-update 提交并将其保存在标签中。

                    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 工作树完成的构建,版本号是从 git describe HEAD 的输出生成的。 Makefile 知道如果版本号发生更改需要重新编译/重建哪些文件,并且它始终运行 GIT-VERSION-GEN 脚本以确保它具有最新的版本号。通过包含生成的版本文件,可以在 Makefile 中获得版本号。它通过编译器的参数 (-DGIT_VERSION=…) 传递给 C 文件,并使用 sed 替换到脚本中。

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

    将版本字符串更改与其他更改混合

    在您的问题附录中,您声明在进行开发时需要调整版本号。首先,我认为我和 seh 描述的“0.58-release”分支方案仍然可以为你工作。将您的更改分开需要更多的纪律。如果您将 *-release 分支视为“为内部测试发布”而不仅仅是“发布给客户(或用于外部测试)”,那么它仍然有意义。始终在基础分支(例如“0.58”)上进行开发,并始终将基础分支合并到发布分支(例如“0.58-release”),然后再进行需要特定版本号的构建(始终从这样的合并发布分支)。

    如果您坚持将版本号更改和(非合并)代码更改放在同一条历史记录中,那么在我看来,您别无选择,只能在合并时处理冲突(除非您去使用 git cherry-pick(根据 Damien Wilson,或针对 git rebase -i 的自动编辑脚本)。

    如果您的“版本文件”仅包含版本信息,您可以通过使用.gitattributes 将您的Version.cpp 文件标记为不可合并来缓解冲突。

    .gitattributes 在包含 Version.cpp 的目录中

    /Version.cpp -merge
    

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

    【讨论】:

    • 我有点想已经这样做了,但还有一个问题:在处理代码时,我必须设置即将发布的版本号。这是因为我们有一个网络引擎,我们可能已经引入了一些新功能,并且在代码中进行了检查,例如 'if(client->version() >= Version(X,Y,Z)) ...'。现在,当我们引入新的东西时,通常在某些时候也意味着这样的检查。另一个问题是我们不只是计算版本(如 0.58.1、0.58.2、...),但在某一时刻,我们不再称它为 beta 而是 rc(如 0.58 betaX
    • 我添加了一个新的部分“将版本字符串更改与其他更改混合”,以另一种方式思考 *-release 分支的含义,以及一个额外的建议(将版本文件标记为不可合并)。至于从编号 beta 到编号 rc 再到编号的变化,我看不出这与 Git 有什么关系。只要您的代码能够理解它们,您想要的任何版本字符串都应该没问题。
    • 感谢您提供更多信息。但我认为总是不得不切换分支来做一个简单的“制作”会很烦人。总是产生冲突也不是真正的解决方案 - 不要意外忽略这样的变化可能很有用,但似乎也很烦人。但也许我可以为一个简单的文件设置一个合并策略?在这种情况下,我可以将“我们的”策略设置为此文件。这实际上可以解决所有问题。
    【解决方案4】:

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

    您可以在已发布的代码分支上浮动一个版本指定分支,这样您就可以安全地将已发布分支 (0.58) 中的所有代码合并到您的主分支 (0.59)在任何时候,都不会混淆相互冲突的版本名称。该版本指定分支永远不会合并回已发布的分支;当您想在版本化版本中包含新代码时,您只需将其重新定位在已发布的分支之上。

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

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

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

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

    对版本指定文件的所有更改仅存在于“58-release”分支上,并且可以使用git rebase 安全地向前推进。或者,如果您希望版本指定文件的每次更改都保持“0.58”分支中的代码状态,您可以将“0.58”分支合并到“0.58-release”分支而不是在“0.58”之上重新定位“0.58-release”。

    【讨论】:

    • 我不确定这样使用 rebase 是否有意义。如果您刚刚发布了 0.58-rc2,然后回顾 0.58-release 分支的历史记录,我们会看到 0.58-rc2、0.58-rc1、 0.58-beta9, ..., 0.58-beta1,最后是 0.58-rc2 本身的提示“内容提交”。如果“标记提交”仅包含将特定版本号标记到代码中的提交,为什么还要继续拖所有旧的?使用合并会在我的答案中生成第一个图表。
    • 是的,克里斯,我同意。我将这个想法分享为一种重新利用的技术,我将其用于更合适的用途——保留项目 Makefile 的本地定制版本,它应该始终基于最新的上游更改,并且永远不会合并回来。我的回答接近最后,建议合并而不是变基以保持时间一致性。这与您在我完成编辑之前不久发布的答案相匹配。我给你的答案我的投票。
    • 这也是一个问题,因为我必须在处理即将发布的版本时设置版本号(请参阅问题描述,我最后扩展了该部分)。跨度>
    猜你喜欢
    • 2019-11-12
    • 1970-01-01
    • 1970-01-01
    • 2015-04-17
    • 2021-10-16
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多