假设我有这样的提交历史
master
|
|A| -> |B| -> |E|
|
|C| -> |D|
|
hotfix
假设提交E和D有冲突。现在,根据docs,在 rebase
之后$> git checkout hotfix
$> git rebase master
# fix conflicts
$> git add -A
$> git rebase --continue
$> git push --force # rewrite history of branch hotfix on remote
我将以
结束 master
|
|A| -> |B| -> |E|
|
|C| -> |D|
|
hotfix
但是,我看不到我的合并/冲突结果在哪里? 如果我再次 rebase
$> git rebase master
我不希望再次发生同样的冲突,对吧?
最后一个问题,如果提交D在提交E之前,我上面显示的图表(在rebase之后的结果)是否仍然相同?
答案 0 :(得分:5)
但是,我没有看到我的合并/冲突结果在哪里?
当你将git存储在.git
目录下的临时区域中时,将临时对象存储起来。 (例如,.git/rebase-merge
。)如果存在冲突,将要求您在执行rebase的过程中解决它们。
如果我再次做出反抗......我不希望再次发生同样的冲突,对吗?
不,你不会再次得到同样的冲突,因为你已经在之前的(第一次)rebase中解决了这些冲突。
最后一个问题,如果提交D在提交E之前,我上面显示的图表(在rebase之后的结果)是否仍然相同?
是C
和D
的结果,它仍然是相同的,因为它们将应用于E
的顶部 - 主人的提示,但是在这两种情况下,它都不完全是您绘制的图表。主要区别在于提交将是D'
和C'
,即使它们与D
和C
完全相同,它们也是新的提交,如果没有反叛冲突。
答案 1 :(得分:3)
当你做一个底板时,你所做的git“幕后操作”实际上是一系列的挑选。如果你以不同的方式标记提交,那就更明显了:让我们调用C
和D
,C'
和D'
的“新”版本。而且,让我们把旧的留在那里,但“放弃”(失去和孤独,就像它)。所以我们从这开始(我已经颠倒了箭头,因为提交指向他们的父提交,而不是他们的孩子:E
有B
作为父,D
有C
,C
有B
,B
有A
):
A <-- B <-- E <-- master
^
\
C <-- D <-- hotfix
要执行rebase,git cherry-picks提交C
,使C'
为E
作为其父级;然后挑选D
,打算用D'
作为其父级C'
。此时存在冲突(正如您所说),因此整个过程停止并使您解决冲突并继续。这最终生成D'
,然后git重写hotfix
标签以指向D'
:
A <-- B <-- E <-- master
^ ^
| \
C - D \
\
C' <-- D' <-- hotfix
旧的提交C
和D
实际上仍在那里(但没有分支标签 - 尽管在{{1}中仍然有对它们的引用分支reflog,暂时,rebase留下一个拼写为hotfix
的特殊标签,指向ORIG_HEAD
)。只是当你想看到什么是“在分支D
上”时,你现在看到了复制的提交。
您应用的冲突解决方案位于附加到提交hotfix
的树中(因为那是发生冲突的地方并且您手动修复了它)。如果你挖掘D'
的提交ID,或者使用reflog或D
,你可以对ORIG_HEAD
和D
的树进行区分,看看你做了什么: / p>
D'
例如。 (但这也包括$ git diff ORIG_HEAD hotfix
的变化,所以这可能也会产生误导。)
(松散地说,每个樱桃挑选都是通过将其被提取的提交树与其父树一起分离,然后将该差异作为补丁应用于提交“樱桃”被添加到其上来完成。所以挑选E
并将其添加到C
以获取E
,git diffs C'
和B
。然后,挑选C
},git diffs D
和C
,这次将差异应用到D
。因此C'
的树不会包含来自D
的任何行,但E
的树可能会。)