最近我需要使用git rebase master
进行一些变基以解决一些合并冲突。令我惊讶的是,Git忽略了合并提交,导致代码消失,给我们带来了很多麻烦。最终我发现使用选项-p
才能得到我想要的结果。但是为什么git rebase
的默认行为是忽略合并提交呢?
...--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
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
A---B
/ \
| M <-- feature/short
| /
...--o--o--o--o--o <-- master, origin/master
\
o--o--o <-- origin/feature/tall
Bob可以测试M
并确认它有效 - 现在安全地将A
和B
重新基于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
重新基础代码简单地说:这很困难,在大多数情况下我们并不想这样做,所以让我们不费力气。
(我认为这是错误的——如果你天真地重新基础涉及合并的链,你可能也想复制合并,但同时,我认为如果你天真地重新基础涉及合并的链,你还没有考虑清楚你在做什么。因此,默认行为有点合理。如果它检测到要跳过的合并,则警告或需要标志可能更有意义。)根据 man git-rebase
的说明:
交互式 rebase 命令最初是为处理单个补丁系列而设计的。因此,从待办事项列表中排除合并提交是有意义的,因为开发人员可能在分支上工作时合并了当前的主干,只是最终将所有提交 rebase 到主干上(跳过合并提交)。
我想补充说,如果您使用 git rebase --interactive
进行合并,则应该(也是根据 man git-rebase
)使用 --rebase-merges
而不是 --preserve-merges
。这将避免许多其他问题。