rebase结果如何与合并结果不同?

时间:2017-06-14 13:59:45

标签: git github merge rebase

在GitHub的一篇文章中,我阅读了以下内容:

  

在以下情况下,您无法在GitHub上自动重新绑定和合并:重新提交提交被认为是“不安全的”,例如在没有合并冲突的情况下可以使用rebase但是会产生与合并不同的结果。

我不清楚rebase如何产生与合并不同的结果。

任何人都可以解释它是如何可能的?

链接到原始文章: https://help.github.com/articles/about-pull-request-merges/

1 个答案:

答案 0 :(得分:4)

这是一个结构证明,其中rebase和merge产生不同的结果。我认为这是他们正在讨论的情况。 编辑:还有另一种情况可能发生,当合并分支时,要进行重新分配的侧分支已经或者合并包含一个在rebase期间将被跳过的提交(由于补丁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 - 与 - B之间的变化与那些来自A - vs - E。生成的是:

  B-----F   <-- master
 /     /
A--C--E   <-- branch
 \   /
  \ /
   D   <-- br2

并且提交F的内容由ABE的内容确定。

如果您在branch(提示提交为E)且您为git rebase master,则此副本会按某种顺序提交CD它不清楚哪个)。它完全省略了提交E。生成的是:

  B   <-- master
 / \
A   C'-D'   <-- branch
 \
  D   <-- br2

(原始CE仅可通过reflog和ORIG_HEAD获得。以快进方式移动mastermaster的提示变为提交D'。提交D'的内容是通过将从CD提取的更改添加到B来确定的。

由于我们使用"evil merge"E进行了更改,而CD都没有,因此这些更改会消失。

以下是创建问题的脚本(注意,它创建了一个临时目录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