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

Mit*_*lin 3 git rebase

最近我不得不使用git rebase master. Git,令我惊讶的是忽略了合并提交,这导致了很多令人头疼的问题,代码会消失。最终我发现这-p就是我想要的,但为什么git rebase忽略合并提交的默认行为是?

tor*_*rek 5

任何时候你问一个为什么的问题,你都会进入哲学领域,这可能非常棘手。但无论如何我都可以提出两个答案(其中一个得到了文档的支持,如padawin 的答案.

第一个是 rebase 背后的原始想法是,它是个人在合并到某种更权威的存储库之前或期间会做的事情。

让我们发明两个玩家,Alice 和 Bob。Alice 拥有权威版本:任何想要软件的最新和最好版本的人都可以找 Alice。

在 Alice 的存储库中,有多种开发路线:

...--o--o--o--o--o   <-- master
            \
             o--o--o   <-- feature/tall
Run Code Online (Sandbox Code Playgroud)

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

...--o--o--o   <-- master, origin/master
            \
             o--o--o   <-- origin/feature/tall
Run Code Online (Sandbox Code Playgroud)

在 Alice 添加到她的权威的最后两个提交之前master

Bob 然后feature/short他的 开发了他的特征master,所以他有:

             A--B   <-- feature/short
            /
...--o--o--o   <-- master, origin/master
            \
             o--o--o   <-- origin/feature/tall
Run Code Online (Sandbox Code Playgroud)

他认为他已经准备好向爱丽丝提交他的结果。所以他跑去git fetch origin获取她的任何更新,现在他有了这个:

             A--B   <-- feature/short
            /
...--o--o--o   <-- master
           |\
           | o--o   <-- origin/master
            \
             o--o--o   <-- origin/feature/tall
Run Code Online (Sandbox Code Playgroud)

他现在可能会更新自己master的提交,使其指向与他的提交相同的提交origin/master(爱丽丝的当前提示master):

             A--B   <-- feature/short
            /
...--o--o--o--o--o   <-- master, origin/master
            \
             o--o--o   <-- origin/feature/tall
Run Code Online (Sandbox Code Playgroud)

在向A--BAlice 提交他的一系列提交之前,他应该确保它们有效。所以他可以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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

请注意,commitM已从 rebase 中消失feature/short:Bob 现在应该将新的和改进A'-B'的提交链交付给 Alice,Alice 可以选择是合并它们,还是快进到B',或者她喜欢的任何东西。

这里的第二个想法是实际上不可能复制合并提交。将提交复制AA'只是A进行与其父项相比所做的相同更改。复制BB'只是BA. 但是你不能复制一个合并;你必须做一个全新的合并。那当然是可能的;这就是旧的-p或新的幻想--rebase-merges实际上所做的:他们只是确定以前合并发生的位置,然后进行新的合并——如果新的合并基础不同,结果可能会有很大不同——只要有意义。

新合并的两个父项之一是显而易见的:它是来自原始合并的父项的某个原始提交的重新基址副本提交。在其他家长假设双亲合并,反正,是不是真的那么明显:有时它是一个不变的原始提交,有时候这是一个重建基础提交。所以这项工作比起初看起来更难。旧的非-prebase 代码只是说:这很难,而且在大多数情况下我们根本不想这样做,所以我们不要费心去尝试。

(我认为这是错误的——如果你天真地对一个涉及合并的链进行变基,你可能也想复制合并——但与此同时,我认为如果你天真地对一个链进行变基涉及到合并,你还没有充分考虑你在做什么。所以默认行为有点有意义。如果它检测到合并它会跳过,并警告或需要一个标志,它可能更有意义。)