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

Vic*_*sky 5 git merge github rebase

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

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

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

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


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

tor*_*rek 7

这是 rebase 和 merge 产生不同结果的情况的构造证明。我认为这就是他们正在谈论的情况。 编辑:还有另一种可能发生的情况,当合并分支时,要重新定位的侧分支已或合并包含一个在变基期间将被跳过的提交(由于补丁 ID 匹配),然后是该提交的还原提交(不会被跳过)。请参阅合并不保留对文件的更改,为什么? 如果以后有时间,我也会尝试为该示例添加构造证明。

诀窍是,由于 rebase 副本提交但省略了合并,我们需要删除其解析不是其前辈的简单组合的合并。为了这次合并没有冲突,我认为它必须是一个“邪恶的合并”,所以这就是我放入脚本的内容。

我们构建的图形如下所示:

  B   <-- master
 /
A--C--E   <-- branch
 \   /
  \ /
   D   <-- br2
Run Code Online (Sandbox Code Playgroud)

如果你是master(你的小费提交的B),你git merge branch,这个结合了从版本比较变更A航班吗B与那些从版本比较A航班吗E。结果是:

  B-----F   <-- master
 /     /
A--C--E   <-- branch
 \   /
  \ /
   D   <-- br2
Run Code Online (Sandbox Code Playgroud)

和提交的内容F是由那些的确定ABE

If you are on branch (your tip commit is E) and you git rebase master, this copies commits C and D, in some order (it's not clear which). It completely omits commit E. The resulting graph is:

  B   <-- master
 / \
A   C'-D'   <-- branch
 \
  D   <-- br2
Run Code Online (Sandbox Code Playgroud)

(the original C and E are only available through reflogs and ORIG_HEAD). Moving master in a fast-forward fashion, the tip of master becomes commit D'. The contents of commit D' are determined by adding the changes extracted from C and D to B.

Since we used an "evil merge" to make changes in E that appear in neither C nor D, those changes vanish.

Here is the script that creates the problem (note, it makes a temporary directory tt that it leaves in the current directory).

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