基准结果可能与合并结果有何不同? [英] How rebase result may differ from result of a merge?

查看:85
本文介绍了基准结果可能与合并结果有何不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


您无法在GitHub上自动重新绑定和合并:提交被认为是不安全的,例如,如果没有合并冲突,但可能产生与合并不同的结果,则可能发生变更。



<对我而言,并不清楚底线如何产生与合并不同的结果。


任何人都可以解释它怎么可能?




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

解决方案

下面是一个基础结构证明,其中重定位和合并产生不同的结果。我想这是他们正在谈论的情况。 编辑:在合并分支的情况下,可能会发生另一种情况,在分支中,要重新绑定的分支包含一个提交(由于补丁ID匹配,将在跳转期间跳过) ,然后是该提交的回复(不会被跳过)。请参阅对文件所做的更改未通过合并保留,为什么?如果我有时间后,我会尝试添加工程证明也就是说。

诀窍在于,由于rebase副本提交但省略了合并,我们需要删除一个合并,其分辨率不是其前辈的简单合成。对于这种合并没有冲突,我认为它必须是邪恶的合并 ,所以这就是我写入脚本的内容。



我们构建的图如下所示:



<$ p $ b < - c $ c> B < - master
/
A - C - E < - 分支
\ /
\ /
D < - br2

如果您位于 master (你的提示提交是 B )和你 git合并分支差异 A -vs - B 与差异 A -vs - 电子。结果为:

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

以及 F 的内容由 A B E



如果您位于分支(您的提示提交为 E )且您 git rebase master ,这个副本提交了 C D ,在一些顺序(目前还不清楚)。它完全省略了提交 E 。结果为:

  B < -  master 
/ \
A C'-D'< - 分支
\
D < - br2



<原始 C E 只能通过reflogs和 ORIG_HEAD )。以快进的方式移动 master master 的提示变为提交 D'。通过添加从 C D <>中提取的更改来确定提交内容 D' / code>到 B



由于我们使用了合并合并 E 中的 C 也不是 D ,这些变化消失。



这是创建问题的脚本,它会创建一个临时目录 tt ,它将保留在当前目录中)。

 #! / bin / sh 

fatal(){
echo fatal:$ @1>& 2;出口1
}

[-e tt]&&致命tt已经存在

mkdir tt&& cd tt&& git init -q ||致命未能创建tt回购

echo README> README&& git add README&& git commit -q -m A ||致命的A
git分支分支||致命的无法使分支
回应master> bfile&& git add bfile&& git commit -q -m B ||致命B

git checkout -q -b br2分支||致命结帐-b br2分支
用于C>的回显文件cfile&& git add cfile&& git commit -q -m C ||致命的C
git checkout -q branch ||致命结账分支
用于D>的回显文件dfile&& git add dfile&& git commit -q -m D ||致命D
git merge -q --no-commit br2&& git rm -q -f cfile&& git commit -q -m E ||
致命E
git分支-D br2
git checkout -q主机||致命结账大师

回声合并分支
git合并 - 无编辑分支||致命的合并失败
的回声结果是:*

回声消除合并,替换为分支到基础
重新分配git reset -q --hard HEAD ^ ||致命重置失败
git checkout -q branch ||致命的切换回主失败
git rebase master ||致命rebase失败
回声结果是:*

回声消除rebase以及你可以戳到
附近git reset --hard ORIG_HEAD


In one of GitHub's articles I read the following:

You aren't able to automatically rebase and merge on GitHub when: Rebasing the commits is considered "unsafe", such as when a rebase is possible without merge conflicts but would produce a different result than a merge would.

It isn't clear for me how a rebase may produce a different result than a merge.

Can anyone explain how is it possible?


Link to the original article: https://help.github.com/articles/about-pull-request-merges/

解决方案

Here's a construction proof of a case where rebase and merge produce different results. I assume this is the case they are talking about. Edit: There is another case that can occur, when merging branches where the side branch to be rebased has-or-merged contains one commit that will be skipped (due to patch-ID matching) during a rebase, followed by a reversion of that commit (that will not be skipped). See Changes to a file are not retained by merge, why? If I have time later I will try to add a construction proof for that example as well.

The trick is that since rebase copies commits but omits merges, we need to drop a merge whose resolution is not simple composition of its predecessors. For this merge to have had no conflicts, I think it must be an "evil merge", so this is what I put into the script.

The graph we build looks like this:

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

If you are on master (your tip commit is B) and you git merge branch, this combines the changes from diffing A-vs-B with those from diffing A-vs-E. The resulting graph is:

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

and the contents of commit F are determined by those of A, B, and E.

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

(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

这篇关于基准结果可能与合并结果有何不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆