这里是 rebase 和 merge 产生不同结果的情况的构造证明。我想这就是他们正在谈论的情况。 编辑:还有另一种情况可能发生,当合并分支时,要变基的侧分支包含一个在变基期间将被跳过的提交(由于补丁 ID 匹配) ,然后是该提交的恢复(不会被跳过)。请参阅Changes to a file are not retained by merge, why? 如果以后有时间,我也会尝试为该示例添加构造证明。
诀窍在于,由于 rebase 复制提交但忽略了合并,我们需要删除一个合并,其解决方案不是其前任的简单组合。为了让这个合并没有冲突,我认为它必须是"evil merge",所以这就是我在脚本中输入的内容。
我们构建的图表如下所示:
B <-- master
/
A--C--E <-- branch
\ /
\ /
D <-- br2
如果你在master(你的提示提交是B)并且你git merge branch,这结合了来自差异A-vs-B的变化与来自差异A-vs-的变化E。结果图表是:
B-----F <-- master
/ /
A--C--E <-- branch
\ /
\ /
D <-- br2
而提交F的内容由A、B和E的内容决定。
如果你在branch(你的提示提交是E)并且你git rebase master,这个副本提交C和D,以某种顺序(不清楚哪个)。它完全省略了提交E。结果图表是:
B <-- master
/ \
A C'-D' <-- branch
\
D <-- br2
(原来的 C 和 E 只能通过 reflogs 和 ORIG_HEAD 获得)。以快进方式移动master,master 的尖端变为提交D'。提交D' 的内容是通过将提取自C 和D 的更改添加到B 来确定的。
由于我们使用"evil merge" 对E 进行更改,而这些更改既未出现在C 中,也未出现在D 中,因此这些更改将消失。
这是产生问题的脚本(注意,它会在当前目录中创建一个临时目录tt)。
#! /bin/sh
fatal() {
echo fatal: "$@" 1>&2; exit 1
}
[ -e tt ] && fatal tt already exists
mkdir tt && cd tt && git init -q || fatal failed to create tt repo
echo README > README && git add README && git commit -q -m A || fatal A
git branch branch || fatal unable to make branch
echo for master > bfile && git add bfile && git commit -q -m B || fatal B
git checkout -q -b br2 branch || fatal checkout -b br2 branch
echo file for C > cfile && git add cfile && git commit -q -m C || fatal C
git checkout -q branch || fatal checkout branch
echo file for D > dfile && git add dfile && git commit -q -m D || fatal D
git merge -q --no-commit br2 && git rm -q -f cfile && git commit -q -m E ||
fatal E
git branch -D br2
git checkout -q master || fatal checkout master
echo merging branch
git merge --no-edit branch || fatal merge failed
echo result is: *
echo removing merge, replacing with rebase of branch onto master
git reset -q --hard HEAD^ || fatal reset failed
git checkout -q branch || fatal switch back to master failed
git rebase master || fatal rebase failed
echo result is: *
echo removing rebase as well so you can poke around
git reset --hard ORIG_HEAD