简体   繁体   English

如何在git rebase期间展平合并提交

[英]How to flatten merge commit during git rebase

I have a topic branch which looks as following 我有一个主题分支,如下所示

* 77a706b
*   4cef576 Merge branch ...
|\
| * 7a13e09 
* | 2fd7265 
|/
* 736cd38 
* 2955a39 f

I'm going to interactive rebase this branch on another parent. 我将交互式地将此分支基于另一个父级。 How do I flatten the diverged history in the rebase process? 如何在变基过程中弄平分歧的历史记录? I want to get rid of that merge commit, and make the history linear instead (still containing those diverged commits, but not the merge commit itself, as it doesn't introduce any changes) 我想摆脱那个合并提交,而是使历史成为线性(仍然包含那些不同的提交,但不包含那些合并提交本身,因为它不会引起任何变化)

Well, I don't recommend this approach... in fact, 99% of the time I don't think the desire for a "simpler" history is justified... but if you want to do this, it's pretty much a default behavior of rebase . 好吧,我不推荐这种方法...实际上,在99%的时间中,我认为对“简单”历史的渴望是没有道理的...但是,如果您要这样做,那几乎是rebase默认行为。

If you just start the rebase, as in 如果您只是启动变基,如

git rebase --interactive --onto <new-parent> 2955a39^ 77a706b

you should find that all your non-merge commits are there in the TODO list, while the merge commit itself is gone. 您应该发现所有非合并提交都在TODO列表中,而合并提交本身已经消失了。 By default I believe the rebase will follow the merge's parents in order; 默认情况下,我认为rebase将按照合并的父级顺序进行; I'm not sure about that, but in any event you can reorder the TODO list if need be. 我不确定,但是在任何情况下都可以根据需要重新排序TODO列表。

Note that I've assumed here the need for an --onto , because you mentioned that you're moving the commits to a new parent. 请注意,我在这里假设需要--onto ,因为您提到要将提交移至新的父级。 Whether that's really necessary depends on how the new parent relates to the old one. 这是否真的必要取决于新父母与旧父母的关系。 Let's look at a bigger picture to see the difference: 让我们从更大的角度看一下,看看有什么不同:

  P
 /
o -- X -- o -- o -- O <--(master)
      \
       A -- B --- M -- D <--(branch)
             \   /
               C

If you're just moving branch from X to O , then you don't really need --onto ; 如果您只是将branchX移到O ,那么您就不需要--onto ; you can treat master as your upstream because the old branch point is an ancestor of the new parent. 您可以将master视为上游,因为旧的分支点是新父节点的祖先。

git rebase -i master branch

But if you're moving the branch to an arbitrary parent (which I inferred - perhaps incorrectly - from the phrasing of the question), then that doesn't work. 但是,如果您要将分支移动到任意父级(我从问题的措词推断出这一点-也许是错误地-),那么那是行不通的。 For example to move branch to P requires --onto syntax because if you just used P as the upstream then X would get caught up in the rebase. 例如,将branch移动到P需要使用--onto语法,因为如果您只是将P用作上游,则X会陷入重新配置中。 (This is a simple enough example that you could fix it in the todo list editor; but in general, it's important to remember the difference between an upstream and a newparent .) (这是一个非常简单的示例,您可以在待办事项列表编辑器中对其进行修复;但是通常,记住upstream和新newparent之间的区别很重要。)

Not only is this the default behavior, but overriding it (by supplying the --preserve-merges option) is specifically not recommended for interactive rebases. 这不仅是默认行为,而且特别建议将其覆盖(通过提供--preserve-merges选项)以用于交互式rebase。

So why don't I recommend it? 那为什么不推荐呢? A few reasons. 有几个原因。

The big one: if the merge applied any changes, they will be lost. 最大的问题:如果合并应用了任何更改,则它们将丢失。 Generally a merge shouldn't apply changes, but there are some gotchas. 通常,合并不应应用更改,但是有些陷阱。 Obviously if there were merge conflicts, their resolutions are in the merge commit. 显然,如果存在合并冲突,则其解决方案将在合并提交中。 (This ties into the 2nd reason I don't recommend this, but I'm getting ahead of myself...) If the merge were done with a strategy other than the default, this will read as a change in the merge that gets lost. (这是我不建议这样做的第二个原因,但我超越了我自己...)如果合并是通过默认策略以外的策略完成的,则将其理解为对合并的更改丢失。 And "ought to" aside, it's possible someone just created an evil merge for no particularly good reason. 并且“应该”放在一边,这可能是有人无缘无故地创建了一个邪恶的合并。 If you know none of those things apply, that's well and good... 如果您不知道所有这些方法都适用,那就太好了...

But then the next reason is that you may well have to do considerable conflict resolution as the "branch" commits are replayed one-by-one over the "mainline" commits. 但是,下一个原因是,您可能必须做相当大的冲突解决方案,因为“分支”提交要比“主线”提交逐一重播。 The more commits are on the branch, the bigger an issue this can be. 分支上的提交越多,这个问题就越大。

(In the extreme case: A complaint I hear quite often is, "during a rebase I have to fix the same conflict over and over". Honestly I don't know exactly how that happens, and I've never had an instance of it to fully examine myself (probably in part because I don't rebase for aesthetic purposes), but enough people have said it happens that I have to believe them.) (在极端情况下:我经常听到的一个抱怨是,“在调整基准期间,我必须一遍又一遍地解决相同的冲突。”老实说,我不知道到底是怎么发生的,而且我从未遇到过它可以对自己进行全面检查(可能部分是因为我不出于美学目的而变本加厉),但有足够多的人说我不得不相信他们。

Lastly, the new commits created by rebase are untested. 最后,未测试由rebase创建的新提交。 This may seem unimportant since they're "just intermediate commits", but it does break debugging workflows that depend on bisect. 这似乎并不重要,因为它们只是“中间提交”,但它确实破坏了依赖于bisect的调试工作流。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM