为什么git rebase会忽略合并提交?

3

最近我需要使用git rebase master进行一些变基以解决一些合并冲突。令我惊讶的是,Git忽略了合并提交,导致代码消失,给我们带来了很多麻烦。最终我发现使用选项-p才能得到我想要的结果。但是为什么git rebase的默认行为是忽略合并提交呢?

2个回答

8
任何时候你问一个“为什么”的问题,就会涉及到哲学领域,这可能会很棘手。但是我可以提出两个答案(其中一个得到了文档的支持,如padawin's answer所述)。
第一个答案是,rebase的最初想法是在将代码合并到某种更权威的代码库之前或之后,由个人执行的操作。
我们来假设两个玩家,Alice和Bob。Alice拥有权威版本:任何想要获得软件的最新版本的人都会去找Alice。
在Alice的代码库中,有各种各样的开发线路:
...--o--o--o--o--o   <-- master
            \
             o--o--o   <-- feature/tall

等等。Bob 在某个时候克隆了 Alice 的存储库,可能是在 这个 时刻:

...--o--o--o   <-- master, origin/master
            \
             o--o--o   <-- origin/feature/tall

这是在 Alice 把最后两个提交添加到她的主分支 master 之前。

然后 Bob 从 他自己的 master 分支开发了他的功能 feature/short,所以他有:

             A--B   <-- feature/short
            /
...--o--o--o   <-- master, origin/master
            \
             o--o--o   <-- origin/feature/tall

他认为自己已经准备好向Alice提交结果了。因此,他运行了git fetch origin以获取她的任何更新,现在他有了这个:
             A--B   <-- feature/short
            /
...--o--o--o   <-- master
           |\
           | o--o   <-- origin/master
            \
             o--o--o   <-- origin/feature/tall

他现在可以更新他自己的master,使其指向与他的origin/master(Alice当前的master末尾)相同的提交:
             A--B   <-- feature/short
            /
...--o--o--o--o--o   <-- master, origin/master
            \
             o--o--o   <-- origin/feature/tall

在向Alice提交他的A--B系列提交之前,他应该确保它们能够正常工作。因此,他可以执行"git checkout master && git merge feature/short"命令,该命令会产生:
             A---B
            /     \
           |       M   <-- feature/short
           |      /
...--o--o--o--o--o   <-- master, origin/master
            \
             o--o--o   <-- origin/feature/tall

Bob可以测试M并确认它有效 - 现在安全地将AB重新基于master分支的顶端,得到:

           [old commits, no longer in use]
           |
           |       A'-B'  <-- feature/short
           |      /
...--o--o--o--o--o   <-- master, origin/master
            \
             o--o--o   <-- origin/feature/tall

请注意,提交记录M已从变基的feature/short中删除:Bob现在应该向Alice提供新的改进版A'-B'提交记录链,而Alice可以选择是否将它们合并,或者快进到B',或者做任何她喜欢的事情。
这里的第二个想法是,实际上无法复制合并提交。将提交记录A复制到A'只是一种对与其父提交的比较所做的相同更改。将B复制到B'只是一种对A所做的相同更改。但你无法复制合并;你必须进行全新的合并。当然,这是可能的;这就是旧的-p或新的高级--rebase-merges所做的事情:它们只是识别以前发生过合并的位置,并在需要的任何地方进行全新的合并——如果新的合并基不同,结果可能会非常不同。
新合并的两个父提交中,一个是显而易见的:它是从某个原始提交派生的重新基础的副本提交,该原始提交是原始合并的一个父提交。另一个父提交(假设是双亲合并)不太明显:有时它是未更改的原始提交,有时它是重新基础的提交。因此,这项工作比起初看起来要困难得多。旧的、非-p重新基础代码简单地说:这很困难,在大多数情况下我们并不想这样做,所以让我们不费力气。 (我认为这是错误的——如果你天真地重新基础涉及合并的链,你可能也想复制合并,但同时,我认为如果你天真地重新基础涉及合并的链,你还没有考虑清楚你在做什么。因此,默认行为有点合理。如果它检测到要跳过的合并,则警告或需要标志可能更有意义。)

4

根据 man git-rebase 的说明:

交互式 rebase 命令最初是为处理单个补丁系列而设计的。因此,从待办事项列表中排除合并提交是有意义的,因为开发人员可能在分支上工作时合并了当前的主干,只是最终将所有提交 rebase 到主干上(跳过合并提交)。

我想补充说,如果您使用 git rebase --interactive 进行合并,则应该(也是根据 man git-rebase)使用 --rebase-merges 而不是 --preserve-merges。这将避免许多其他问题。


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