Git将修补程序合并到多个分支

Posted

技术标签:

【中文标题】Git将修补程序合并到多个分支【英文标题】:Git merging hotfix to multiple branches 【发布时间】:2012-06-01 10:41:23 【问题描述】:

我一直在尝试围绕 git 分支模型。我一直在查看http://nvie.com/posts/a-successful-git-branching-model/ 的一些想法,并且来自 Subversion 我真正期待的一件事是在一个地方进行更改并将其合并到所有需要它的分支。在 Subversion 中,我们最终做了很多代码副本。

但是我仍然没有完全理解这一点。这是我拥有的标准工作流类型,它总是会出现冲突。

# create new version branch
git checkout master
git checkout -b v3
vim pom.xml  # change branch version to "3.1-SNAPSHOT"
git commit -a
git checkout master
vim pom.xml  # change master version to "4.0-SNAPSHOT"
git commit -a

所以master在4.0-SNAPSHOT,分支在3.1-SNAPSHOT。

我不想在分支上创建修补程序并将其移动到主干。

git checkout v3
git checkout -b hotfix
vim file.txt  # make a bugfix change
git commit -a
git checkout v3
git merge hotfix  # this works fine
git checkout master
git merge hotfix  # this has a conflict since both branches have changed the version

我明白它为什么会发生,而且它是有道理的。有更好的方法吗?

我读到了cherry-pick,我对其进行了测试并且确实有效:

git checkout v3
git cherry-pick a518b0b75eaf28868
git checkout master
git cherry-pick a518b0b75eaf28868

但是,这似乎不是处理此问题的“正确”方式。有什么建议吗?

【问题讨论】:

【参考方案1】:

在这种情况下,您正在处理分支“4.0”并且必须修复“3.1”,您可以在提交“3.1”后重新设置“4.0”:

确保您在功能分支 4.0:

git checkout 4.0

保存当前工作,以便查看其他分支:

git stash  
git checkout 3.1  

编辑和提交:

git commit -a -m "bug fix"  
git checkout 4.0  

取回您的更改:

git stash apply  

更改 4.0,使其分支“3.1”的当前头部:

git rebase "3.1"

【讨论】:

我想评论一下,虽然这是可能的,但它消除了依赖标签、推送或有效共享 4.0 代码的能力。就个人而言,Rebase 很棒,但当你已经推送时,它就不那么好了。【参考方案2】:

真的,您的答案取决于您是否希望您的树基于相同的历史...例如,4.0 是基于最新的 3.X + 4.0 中的所有更改...

就个人而言,一旦您决定为新版本启动新分支,我不建议您这样做。在给定的时间点,软件正在朝着不同的方向发展,因此您的分支机构也应该如此。

这使得git cherry-pick 成为您的理想解决方案。在最有意义的任何分支中进行更改,然后将其挑选到旧版本。这就像您检查了旧分支并手动应用了相同的更改并进行了新的提交。它保持清洁和重点。

Git merge 或 rebase 将尝试以各自的方式将分支历史整合在一起,我怀疑您在向后移植错误修复等时不希望这样做......

【讨论】:

我同意(尽管我认为@ellotheth 的回答可能会根据具体情况更优雅)。根据 git 自己的 branching philosophy 你真的 arethis commit 是唯一属于所有分支的东西。所以挑选樱桃就是“说”的。 谢谢,我认为这是有道理的。来自 Subversion,有时我们将修复推送到主干和分支(基本上是两次修复)对我们来说是多么痛苦,我认为我可以在任何我想要的地方合并功能分支。当这没有像我预期的那样奏效时,我有点沮丧。不过,“cherry-pick”很有意义。我只需要提出一个所有开发人员都容易理解的流程,我认为这可以说得很清楚。【参考方案3】:

如果您想获得关于它的超级技术,您可以从一个共同的祖先创建修补程序:

git merge-base v3 master
git checkout -b hotfix <whatever you got from merge-base>
# make your fix
git checkout v3 && git merge --no-ff hotfix
git checkout master && git merge --no-ff hotfix

        v3--------v3 (hotfixed)
       /         /
ancestor----hotfix
       \         \
        master----master (hotfixed)

--no-ff 标志用于突出显示 Git 将创建合并提交,将 hotfix 分支标签保留在修补程序提示处,而不是将标签拉到 v3master。 (您可以省略该标志并获得相同的行为,因为hotfix 分支有一个不在masterv3 中的提交。更多信息in the docs。)

就个人而言,我认为这太过分了。我会选择 gahooa:在分支上制作有意义的修补程序,然后根据您希望分支如何相互关联来合并或挑选。

【讨论】:

+1 merge-base--no-ff 和所有好的建议。 cherry-pick 创建新的提交:相同的差异、日志消息、时间戳,但不同的哈希。如果清楚的历史很重要,我认为合并基础一点也不夸张。樱桃采摘适用于简单的情况,但要注意这样的事情:news.ycombinator.com/item?id=3947950 --no-ff 不应该对hotfix 产生任何影响。它告诉git merge 始终创建一个合并提交,而不是仅仅移动当前签出的引用(v3master)指向与hotfix 相同的提交。在图示的场景中,无论如何都不应该发生这种情况 - 如果您要合并的提交是您当前已签出的提交的直接后代,它只能快进。如果ancestor 实际上分别是v3master,它只会移动v3master【参考方案4】:

我也一直在为这个问题苦苦挣扎,我认为如果你愿意稍微改变你的版本控制策略(即,脱离 Maven 鼓励的 -SNAPSHOT 版本),这可以通过使用master(或任何您的开发分支)上的固定版本(如 SNAPSHOT 或 0.0.0-SNAPSHOT)。 (如果您使用 Maven,SNAPSHOT 后缀很重要,因为 Maven 对待 SNAPSHOT 版本的工件与其他工件不同。)

事实上,我认为您希望制定一项政策,即只在您的生产分支(用于构建发布的分支)或仅用于发布目的的分支(例如,更改版本)上更改版本号numbers) 并且您从不打算将其合并回开发分支。

我还没有真正使用过这个策略,只是在想它,我想我会开始尝试它。

【讨论】:

以上是关于Git将修补程序合并到多个分支的主要内容,如果未能解决你的问题,请参考以下文章

Git:将提交合并到不同的分支

3.2 Git 分支 - 分支的新建与合并

Git章鱼多个分支的合并顺序

git标签合并了吗?

idea中git分支合并与使用

Git将多个分支合并到一个新分支中[重复]