对不同 git 分支进行版本化的最佳方式

发布于 2024-08-18 06:11:35 字数 1093 浏览 6 评论 0原文

我们有以下场景:我们的游戏 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 阶段),然后标记为大多稳定或稳定。在某些罕见的情况下,即使在两个不同的测试版之间也可能会发生严重的变化(可能是网络协议)(当然,我们会尽力避免它们,但有时没有的话是不可能的)。

We have the following scenario: We have several base versions of our game OpenLieroX; right now 0.57, 0.58 and 0.59. For each base version, we have a seperate branch. Each such base version has several releases (like 0.57 beta1-beta8 and rc1, 0.58 beta1-beta9).

When we are working on new stuff, we are working in the highest base version branch (right now that is 0.59). When we are fixing some reported bugs, we do that in the earliest version (mostly 0.58) where that occured. From time to time, we always merge all changes in 0.58 into 0.59 (as long as we will still maintain and do changes on the old branch).

This all works really fine until it comes to some changes which we want to have only in 0.58 but not in 0.59. This happend only for one case so far: The version number. We have some Version.cpp file (and also some other files) which contains the version number. So, when we want to push a new release for 0.58, we change the versionstring in there to "0.58 beta10" (or whatever). Now, when we do the usual merging from 0.58 into 0.59, this change will also be applied. We fix such cases at the moment by just overwriting it again with the right version number (or in cases for other bad commits, probably a revert).

This detail about such unwanted changes seems to be a bit ugly to me. Is the way we manage this in general bad/uncommon? How would be the easiest way to do this to get the same result? Cherry-picking all commits of 0.58 in 0.59 would be much more work.


There is also one further detail which probably makes it more complicated: While working on the code, I have to set already the upcoming version number. This is because we have a network engine and we may have introduced some new functionality and there are checks in the code like 'if(client->version() >= Version(X,Y,Z)) ...'. Now, when we introduce something new, usually it means at some points also such checks. (But we are trying to avoid these changes in older branches.)

Another problem is that we don't just count the version up (like 0.58.1, 0.58.2, ...) but we count like this: 0.58 beta1, 0.58 beta2, ..., 0.58 betaX, 0.58 rc1, ..., 0.58, 0.58.1, 0.58.2, ... This is because we want to mark it as experimental for the beginning (beta stage) and then as mostly stable or stable. In some rare cases, there may be serious changes (maybe network protocol) even between two different beta releases (of course, we try to avoid them, but sometimes it's not possible without).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

晚雾 2024-08-25 06:11:35

使用额外分支

0.59 与 0.58 不同后,您可以使用单独的“release”分支来处理 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 等),那么你可以不用“release”分支。相反,您可以使用分离的 HEAD 或临时分支(在版本控制后删除)来进行外部版本更新提交并将其保存在标签中。

                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 中获得版本号。它通过编译器的参数传递到 C 文件 (-DGIT_VERSION=…),并使用 sed 将其替换为脚本。

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

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

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

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

如果您的“版本文件”包含版本控制 。信息,您可以通过使用 .gitattributes 将包含

的目录中的

/Version.cpp -merge

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

With Extra Branches

After 0.59 diverges from 0.58, you could use a separate “release” branch for the version number changes in 0.58. Each version (except the most recent) would have its own “release” branch that only contains merges from the base branch and changes that update the external version number. The branch structure might look something like this:

                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 labels the software “0.58 beta9”
  • B labels the software “0.58 rc1”
  • 0.58 has changes that have not yet been released
  • C labels the software “0.59 beta1”
  • 0.59 has changes that have not yet been released
  • 0.60 is not yet fully up to date with 0.59

Or, if you are very strict in only making changes at A, B, C, etc. that change the external version number (no significant code changes, those belong on the ‘base’ branches: 0.58, 0.59, etc.), then you could do without the “release” branches. Instead you could use a detached HEAD or temporary branch (deleted after the release is versioned) to make the external-version-update commit and save it in a tag.

                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 labels the software “0.58 beta9” and is tag 0.58-beta9
  • B labels the software “0.58 rc1” and is tag 0.58-rc1
  • C labels the software “0.59 beta1” and is tag 0.59-beta1

Like Git Does It

You also might look into the way Git does its own versioning.

For builds done out of a Git working tree, the version number is generated from the output of git describe HEAD. The Makefile knows which files need to be recompiled/rebuilt if the version number changes and it always runs the GIT-VERSION-GEN script to make sure it has the most recent version number. The version number is available in the Makefile by inclusion of the generated version file. It is passed to C files by a argument to the compiler (-DGIT_VERSION=…) and it is substituted into scripts by using sed.

There are some provisions for overriding the version number “burned into” a build, but they are generally there only for builds done outside a working tree (e.g. a build done from a tree extracted from a tar file).

Mixing Version-String Changes With Other Changes

In your addendum to your question, you state that you need to adjust the version number while doing development. First, I think that the “0.58-release” branch scheme that seh and I have described can still work for you. It will just take more discipline to separate your changes. If you think about the *-release branches as “released for internal testing” and not just “released to customers (or for external testing)”, then it still makes sense. Always do your development on the base branch (e.g. “0.58”), and always merge the base branch into the release branch (e.g. “0.58-release”) before doing a build that will require a specific version number (always build from such a merged release branch).

If you insist on putting version-number changes and (non-merge) code changes in the same line of history, then is seems to me that you will have little choice but to deal with the conflict when merging (unless you go with git cherry-pick (per Damien Wilson, or an automated edit script aimed at git rebase -i).

If your “version files” only contain versioning information, you might be able to ease the conflict resolution by using .gitattributes to mark your Version.cpp file as unmergable.

.gitattributes in the dir that contains Version.cpp

/Version.cpp -merge

Marking it like this (same as merge=binary) will always cause a conflict if the file is different between merged branches. The post-merge working-tree version will default to the version from the branch you have checked out (not the one from the branch(es) you are merging), so you can just git add Version.cpp && git commit to finish the merge (assuming all other conflicts are also resolved).

月棠 2024-08-25 06:11:35

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

您可以添加构建版本,0.58.1、0.58.2 等。这样您就可以添加任意数量的内容,并且您仍然可以将其统称为“0.58”,即使它有一个内部版本号。

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

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

It looks like what you're doing is the right way (for this result). But maybe you should reconsider your version system.

You could add a build version, 0.58.1, 0.58.2, etc. that way you can add as much stuff as you want, and you'll still collectively call it "0.58", even though it has a build number to it.

Upon release you could add beta, RC, whatever to it, but that isn't something the versioning system should care about.

The release "0.58.3 (beta1)" just means version 0.58.3. The beta1 part is human information and not a versioning system concern.

何必那么矫情 2024-08-25 06:11:35

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

有关该命令的更多信息,请参见 git 文档< /a> 和 Git Ready

If I understand the problem, it sounds like you want to include a certain subset of commits from different branches. If that's the case, you may just need to run git cherry-pick and only apply the commits you want.

More information on the command in the git docs and on Git Ready.

硪扪都還晓 2024-08-25 06:11:35

棘手的部分是将版本指定与底层代码隔离。

您可以将版本指定分支浮动在已发布代码分支的顶部,这样您就可以随时安全地将所有代码从已发布分支 (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”。

The tricky part is isolating the version designation from the underlying code.

You can float a version-designating branch on top of the released code branch, such that you can safely merge all of that code from your released branch (0.58) to your main branch (0.59) at any point, without mingling the conflicting version designations. That version-designating branch would never be merged back down to the released branch; you will merely rebase it on top of the released branch when you want to include new code in a versioned release.

You can arrange this easily with the following entry in your .git/config file:

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

With that, your release branch is called "0.58", and you'd make your versioned builds using the "0.58-release" branch. When it's time to make a release build, you'd issue the following commands:

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

All the changes to the version-designating files live only on the "58-release" branch, and can be moved forward safely with git rebase. Alternately, if you want each change to the version-designating file to stick with a state of the code from the "0.58" branch, you could merge the "0.58" branch into the "0.58-release" branch rather than rebasing "0.58-release" on top of "0.58".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文