我怎样才能以易于回滚的方式进行 git 合并?
有很多关于在 git 中“撤消”合并并不容易的讨论。简短版本:如果您撤消合并提交,它还会告诉 git 将来永远不要合并这些更改。
在进行合并时我可以做些什么来减轻这个问题吗?在很多情况下,撤消合并确实非常有用,只是在软件开发的正常过程中,更重要的是,在需要回滚更改时控制发布分支的状态。
编辑
我在这篇文章 并且不要真正将其视为解决方案,更多的是对问题的解释。 它需要
- 始终使用 --no-ff
- 当您想要带回依赖于它们的代码时,
记住所有未完成的合并(这可能是未来的几个小时,几天,一周或几个月......) 什么我想要
这是它在 Subversion 中的工作原理。假设我有一个名为“release-candidate”的分支,这是我们在临时服务器上运行的分支,也是我们尝试功能的地方。假设我合并到功能 A 分支中。在 Subversion 中,一切都是一个变更集,并且所有文件的所有历史记录都会合并。假设我们不喜欢它,所以我们想把它删除。我们只需撤消该单个变更集,无需考虑其他任何事情。我们可以在将来的任何时候将功能分支 A 合并回来,而不必记住我们曾经将其合并并取出。
我希望能够尽可能接近这种流程。我想优化“将来不必记住一些东西”,即使这会让事情在某种程度上采取更多步骤。 (这可能是不可能的……)
There is lots of talk about how it's not easy to "undo" a merge in git. Short version: if you undo a merge commit, it also tells git to never merge those changes back in in the future.
Is there something I can do when doing the merge in order to abate this problem? There are plenty of situations where undoing a merge would be really, really useful, just in the normal course of software dev, and more crucially, in controlling the state of a release branch, when changes need to be rolled back.
edit
I have seen the solution in this article and don't really consider it a solution, more of an explanation of the problem. It requires
- always use --no-ff
- remember all your undone-merges when you want to bring back in code that depends on them (this could be a few hours, days, week, or months in the future…)
what I want
Here is how it works in Subversion. Let's say I have a branch called "release-candidate", which is what we run on the staging server and where we try out features. Let's say I merge in feature A branch. In Subversion, it's all one changeset, and all history for all files is merged. Let's say we don't like it, so we want to take it out. We just undo that single changeset, and don't have to think about anything else. We can merge feature branch A back in at any time in the future without having to remember that we at one point merged it in and took it out.
I'd like to be able to get as close to that flow as possible. I'd like to optimize for "not having to remember stuff in the future", even if it makes things take more steps along the way somehow. (this might be impossible...)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
更新:
可以更轻松地使用按功能分支的工作流程如下:http://dymitruk.com/blog/2012/02/05/branch-per-feature/
(问题的SVN部分已经在最后回答了)
是的,这里是你重新引入的方法您取消合并的功能。考虑以下历史记录(假设您已经“取消”合并):
F 是功能分支,M 是合并,U 是取消合并该功能时的相反情况,L 是最新提交。
以下是您的选择:
恢复 U(无需推送
--force
):<前><代码>x---x----x--x---x--M--U--L--^U
\ /
x--x--x--xF
将 F 重新设置为 L(然后合并
--ff-only F') (无需推送
--force
):<前><代码>x---x----x--x---x--M--U--L
\ / \
x--x--x--xx x'--x'--x'--x'--F'
将 F 重新设置为 L(然后合并
--no-ff F'
- 保留新的分支点)(无需 --force 推送):<前><代码>x---x----x--x---x--M--U--L-------------------- -M2
\/\/
x--x--x--xx x'--x'--x'--x'--F'
rebase -i head^^
并从列表中删除 U(--force
是推送所必需的):<前><代码>x---x----x--x---x--M--L
\ /
x--x--x--xF
rebase --onto M^1 L^ L
摆脱合并和取消合并。现在您可以稍后重新合并 F。<前><代码> L'
/
x---x----x--x---x--M--U--L
\ /
x--x--x--xF
要压缩所有功能提交,请在初始合并时使用
--squash
修饰符。我会让你发挥想象力,想象一下历史上会是什么样子。我不建议这样做是有原因的。了解如何让某个功能发挥作用以及采取了哪些步骤是很有价值的。后续合并会更容易,因为 Git 可以检查某个文件的历史记录,了解其外观的原因。将提交压缩在一起会丢失该信息。还有一些其他缺点可能会或可能不会影响您利用 rerere 历史记录的能力。
我建议始终在 master 中用空白合并标记发布的内容。这是通过与
--no-ff
选项合并来完成的。你永远不会在 master 上工作,唯一完成的提交就是这些合并 - 没有代码更改提交。在 QA 分支中,您可以标记标记发布点的提交。因此,当您执行 git merge --no-ff rc-12.2 时,您将自动生成提交注释“merged rc-12.2”。查看 git-flow。
希望能为您提供更多详细信息。
UPDATE:
A workflow that makes it easier to work with branch-per-feature is here: http://dymitruk.com/blog/2012/02/05/branch-per-feature/
(the SVN part of the question has been answered at the end)
Yes, here is how you reintroduce a feature that you unmerged. Consider the following history (assumes you "undid" a merge already):
F is the feature branch, M is the merge, U is the opposite when you unmerge that feature, L is the latest commit.
Here are your choices:
revert U (no
--force
necessary to push):rebase F onto L (and then merge
--ff-only F'
) (no--force
necessary to push):rebase F onto L (and then merge
--no-ff F'
- preserves your new branch point) (no --force necessary to push):rebase -i head^^
and eliminate U from the list (--force
is necessary to push):rebase --onto M^1 L^ L
to get rid of the merge and unmerge. Now you can remerge F later.To squash all the feature commits, use the
--squash
modifier on the initial merge. I'll let your imagination do the work on how that would look in history. There is a reason I don't recommend doing this. There is value in knowing how you got a feature working and what steps it took. Subsequent merges will be easier since Git can examine the history of why a certain file looks like it does. Squashing the commits together loses that information.There are additional drawbacks that may or may not affect your ability to take advantage of rerere history.
What I recommend is always marking what is released with a blank merge in master. This is done via a merge with the
--no-ff
option. You never work on master and the only commits that are done there are those merges - no code change commits. In the QA branch, you tag the commit that marks the point at which you released. So when you dogit merge --no-ff rc-12.2
, you will autogenerate a commit comment "merged rc-12.2".Check out git-flow.
Hope that provides you more detail.