Git rebase 工作流程 - 将 bug 修复添加到“稳定”分支

3

我正在参与的这个项目中,我们使用的是相当标准的git rebase工作流程。也就是说,我们会在一个feature分支中完成所有的工作。当一个功能准备好进行测试时,其他人会执行以下操作:

git checkout master
git merge feature

我们还有一个stable分支,基本上是master的一个不那么前沿的副本。在master中的更改经过他人彻底测试后,某人将会:

git checkout stable
git merge master

我遇到的问题如下:
1.由于新功能刚推出进行测试,因此“master”比“stable”有许多新提交。
2.“master”中的提交还没有准备好合并到“stable”。
3.在“stable”中发现了一个错误,需要立即修复。
我不能简单地将bugfix添加到“stable”,然后在其上重新设置“master”,因为其他人已经检出了“master”。我也不能将bugfix添加到“master”,然后将其合并到“stable”,因为“master”包含尚未准备好使用的提交。最后,我不想只将bugfix添加到“stable”和“master”的末尾,因为这会导致下一个“git checkout stable && git merge master”失败。
如何调整我的工作流以适应这种情况?我想避免重复提交(即,“stable”以两个具有不同提交哈希值的相同提交结束)或合并提交。目前,由于这种情况很少发生,我只是将“master”重新设置为“stable”,并确保每个检出它的人都知道。但是我想知道是否有更清洁的方法来实现这一点。

你说这个 bug 是在“stable”版本中被发现的,但只提到通过从“master”合并到“stable”才能达到稳定状态的代码。据我理解,这意味着该 bug 是在最后一次合并到“stable”之前的某个提交中引入的。“这样理解正确吗? - jthill
没错。理论上,在将代码合并到稳定版本之前,所有的漏洞都应该在主分支中得到修复。然而,实际上总会有“无法避免”的漏洞,所以有时候它们会被合并进来,然后我们会在主分支上继续开发,直到它们被检测出来。 - CmdrMoozy
从评论中可以看出,您不希望在主分支中合并提交记录。您是想避免除“feature”以外的任何合并提交记录,还是只想避免来自“stable”的合并提交记录?啊,好的,“变基工作流”,所有从“feature”到“master”的合并都是快进式的吗? - jthill
如果可能的话,我更喜欢避免所有合并提交。然而,来自“stable”的合并提交比来自“feature”的合并提交要少一些丑陋(在我看来)。在正常情况下(这是一个不太常见的奇怪情况),我在任何两个分支之间进行的每个合并都是快进合并。 - CmdrMoozy
2个回答

5
将错误修复从“stable”分支中移除,然后将其合并到“stable”和“master”两个分支中。
git checkout -b bugfix stable
# Make and commit changes
git checkout stable
git merge bugfix
git checkout master
git merge bugfix

这样做的好处是,只有一个提交(或一组提交)包含了错误修复,因此在将master合并到stable时不应该出现冲突。


1
@CmdrMoozy 我不这么认为。你并没有用相同的内容创建单独的提交,而是将相同的提交合并到两个不同的分支中。 - Ajedi32
它似乎有些工作,但它会在master中创建合并提交,而我不想要这个。 - CmdrMoozy
2
@CmdrMoozy,恐怕没有什么好方法可以避免重复提交。 - Ajedi32
1
@Ajedi32 第一次 merge bugfix 会进行快进,对吗?它将从 master 的祖先中移除 stable 分支,但是第二次 merge bugfix 当然会将其链接回来,所以一切都很好。 - jthill
1
@jthill 正确。除非您明确提供 --no-ff 选项,否则将 bugfix 合并到 stable 中只会是一个快进。 - Ajedi32
显示剩余4条评论

2

这里有一种简单的方法,希望经过一些学习后会变得容易,它可以避免合并提交。

从文本和评论中我看到你正在使用masterstable进行虚线框技巧,其中唯一允许执行的操作(至少通常是这样)是快进式合并:

...--X--...S                        stable
            \
             m--...--M              master
                      \
                       f--...--F    feature

我建议如下,当你看到这个第一部分的丑陋结果时,请耐心等待:

我建议如下,当你看到这个第一部分的丑陋结果时,请耐心等待:

git checkout master  -B m-temp   # let's do this with nonce names at first
git revert X
# (maybe **amend** the commit to what X should have been here)

git checkout stable  -B s-temp 
git cherry-pick m-temp

git checkout feature -B f-temp
git cherry-pick m-temp

生产:

...--X--...S---X''                         s-temp
            \
             m--...--M---X'                m-temp
                      \
                       f--...--F---X'''    f-temp

假设你所有的分支上都只有一个X的修复。这看起来很混乱,但是请注意快进合并实际上是什么。当需要将稳定版本与主版本同步时,你可以使用以下任何一种方法正确地完成。

git checkout s-temp            # the slow way
git reset --hard @{1}          # . (reset one commit from s-temp, i.e. to S)
git merge m-temp               # .

或者使用以下代码,可以获得完全相同的效果:

git checkout -B s-temp m-temp  # exactly the same, without the rube goldberg

每个人都在生产:
             X''  <-- discarded cherry-pick of X'
            /        
...--X--...S---m--...--M---X'               m-temp s-temp
                        \
                         f--...--F---X'''   f-temp

...并且你的分支仍然都只有一个修复X的提交。当是合并到主分支时,也要这样做,将X'丢弃,让X'''成为你历史记录中唯一的X修复,或者你可以让你的特性分支开发者在X'上进行变基,并放弃他们自己的X'''。


Git对于分支有一个“描述”配置项,在post-checkout钩子中加入以下内容会很有用:

cat >>.git/hooks/post-checkout <<\EOF
#!/bin/sh
#
#    if there's a stored note about this checkout, show it:

# $3 = 1 for a full branch checkout
if branch=`git symbolic-ref --short -q HEAD` && test $3 = 1; then
        git config --get-all branch.$branch.description
fi
EOF
chmod +x .git/hooks/post-checkout

当你想要提醒自己某件事情时,

git config --add branch.stable.description \
     "reset to commit c0ffee before merging master"

这使得挑选你想要的主修复程序变得非常容易。当你想要删除该注释时,
git config --unset branch.stable.description c0ffee

使所有与正则表达式匹配的注释消失。

这看起来是一个很好的解决方案!我的一个问题是,最终结果(在我最终将SM同步之后),似乎最终结果将是提交以不同的顺序出现 - 也就是说,来自M的新提交将被插入到S中的X提交之前。这对我来说似乎是“安全”的,但只是为了确认:如果经过这个过程后,在客户端上执行git checkout stable && git pull,它会想要合并吗?如果我理解正确,它似乎仍然能够快进。 - CmdrMoozy
对于你的问题:不,X''是完全被丢弃了的,(假设你已经像往常一样让你的特性分支开发人员在主分支上进行变基),没有主分支历史记录会改变——上面的图片包含了所有相关信息,Git中的提交图不仅仅是概念性的。 - jthill
关于客户端拉取“stable”分支的问题,如果你重置了“stable”,那么之前已经拉取过“X”的客户端在下一次拉取时会收到重置警告,除非他们已经配置了“branch.stable.rebase”。很好的发现。对我来说这似乎不是什么大问题,毕竟没有人应该以此为基础进行工作,对吧?即使不是那个确切的提交,修复本身也将出现在他们的下一次拉取中。 - jthill
没错,没有人应该在其基础上工作。它被拉取的唯一时间是在我们的服务器之一上,当我们准备进行代码移动时。由于管理此操作的人不会是任意一个人,因此重置或更改服务器配置不会成为问题。谢谢! - CmdrMoozy

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