gpt4 book ai didi

git - git merge vs git rebase用于 merge 冲突场景

转载 作者:行者123 更新时间:2023-12-04 21:56:25 25 4
gpt4 key购买 nike

我想确保我正在正确地看这件事。

当我进行git merge导致冲突时,我看到存在冲突的文件为:

<<<<<<<<<HEAD
my local changes first
=============
The remote github changes here.
>>>>>>>>>>


而由于git rebase而导致冲突时,我看到相反的结果:

<<<<<<<<<
The remote github changes here.
=============
my local changes first
>>>>>>>>>>


我在这里想念什么吗?

最佳答案

Tim Biegeleisen's answer是正确的,但我会以不同的方式绘制图表。开始时,在您自己的(本地)Git存储库中,您将执行以下一系列提交:

...--G--H   <-- origin/somebranch
\
I--J <-- somebranch (HEAD)


也就是说,您已经进行了一个或多个自己的提交-在这里,我将它们标记为 IJ;它们的真实名称是一些丑陋的哈希ID,而您的分支名称 somebranch指向您所做的这些新提交中的最后一个(包含哈希ID)。

然后,您运行 git pull --rebase somebranch,或者(我的首选方法)运行两个单独的命令 git fetch,后跟 git rebase origin/somebranchgit pull为您执行的步骤分为两步:它运行两个Git命令,第一个始终是 git fetch,第二个是您在了解 git fetch之前先选择的命令。 (我想看看 git fetch做了什么,然后决定:我是要变基,合并,等待还是完全执行其他操作?)

git fetch步骤获取其他人所做的新提交,为您提供以下内容:

...--G--H------K--L   <-- origin/somebranch
\
I--J <-- somebranch (HEAD)


同样,大写字母代表某个实际的实际哈希ID,无论它是什么。

使用 git merge时,Git会合并。可以稍微不同地绘制图形以使其更清晰:

          I--J   <-- somebranch (HEAD)
/
...--G--H
\
K--L <-- origin/somebranch


合并的共同起点是commit H;您的提交 HEAD是提交 J;他们的提交当然是 L。因此,如果发生冲突,则在正在进行的合并中以 HEAD看到的是来自 J的代码,而从他们那里看到的是 L中的代码。如果将 merge.conflictStyle设置为 diff3,则作为基准的内容将是 H .1中的内容。

注意,合并有三个输入。提交 H是合并的基础,而提交 JLHEAD及其它们)是涉及的两个分支技巧。此处执行完全合并操作的最终结果将是新的合并提交 M,它将指向其两个直接输入:

          I--J
/ \
...--G--H M <-- somebranch (HEAD)
\ /
K--L <-- origin/somebranch


合并 M中的快照是将合并的更改应用于提交 H中的快照的结果。也就是说,Git发现:


HJ的区别:您所做的更改;
HL的区别:它们的变化;


并尝试将它们自己结合起来。 Git在合并它们时遇到了问题(合并冲突),因此放弃并强迫您将它们合并。完成后,使用 git merge --continue完成该过程,Git从合并的结果中得出 M

(Commit M不会直接记住commit H。Git可以稍后使用与本次查找相同的过程重新发现合并基础 H。)2



1我喜欢设置此选项。这样,您不仅可以看到您输入的内容以及他们输入的内容,还可以看到合并基础提交中最初存在的内容。当您或他们删除了相关代码时,此功能特别有用。

2这实际上是一个错误,因为您可以使用 git merge运行带有修改内容的选项,包括(在某些相对罕见的情况下)所使用的合并库。 merge命令应记录您使用的选项,以使合并真正可重复。



但是,当您使用 git rebase时,Git会复制每个现有的提交(在这种情况下为两次),一次一次。此复制过程使用“分离的HEAD”,其中 HEAD直接指向提交。 Git首先将他们的提交 L作为独立的HEAD签出,如下所示:

...--G--H------K--L   <-- HEAD, origin/somebranch
\
I--J <-- somebranch


现在,从技术上讲,cherry-pick是合并的一种形式,或者,正如我喜欢说的那样,将其作为动词进行合并:合并的过程,而无需实际进行合并提交。也就是说,您仍在执行与 git merge相同的所有工作。区别在于对合并的输入提交,完成后,最终的提交不是合并提交:它只是一个父母的日常常规提交。

因此,既然Git已经完成了 git checkout --detach origin/somebranch,因此他们的提交 L是您当前的提交,它就会执行 git cherry-pick <hash-of-I>复制提交 I。此选择开始了合并过程。此特定合并的三个输入是:


合并基数,它是Git提交的父对象,被告知进行选择:这是 H;
--ours提交,始终为 HEAD,在这种情况下为提交 L:他们的提交;和
--theirs提交,这是Git被告知进行选择的提交:这是 I,这是您的提交。


因此,用于合并操作的 --theirs提交就是您的提交,而用于合并操作的 HEAD--ours提交就是他们的提交 L!这就是这种明显逆转的来源。 Git正在做一个樱桃选择,这是合并的一种形式。 --ours输入是他们的提交,而 --theirs输入是您的提交。

解决任何合并冲突后,将运行 git rebase --continue。 (如果您自己运行了 git cherry-pick,则将运行 git cherry-pick --continuegit rebase会为您执行此操作。)这将完成樱桃的选择,这是通过普通的提交来完成的:

                    I'  <-- HEAD
/
...--G--H------K--L <-- origin/somebranch
\
I--J <-- somebranch


现在,分离的HEAD直接指向此新的普通提交,即原始提交 I'的副本 I。请注意,提交 I'与“提交 I就像”一样,除了:


它有一个不同的父提交, L;和
它有一个不同的快照。 I'中的快照是将 HI之间的差异(即,您所做的更改)并将该差异与 HL之间的差异合并而成的结果。


las,因为这是 git rebase而不是 git merge,所以我们尚未完成。现在我们也必须复制提交 J,就像通过 git cherry-pick <hash-of-J>复制一样。我们的情况仍然是,分离的 HEAD指向新的提交 I'。此合并的三个输入是:


合并基础: J的父级,即 I
HEAD提交为 --ours:commit I',我们刚创建的那个;和
要复制的提交为 --theirs:提交 J,即您的第二次提交。


与合并一样,Git会比较合并基础中的快照与两个提示提交中的每一个。所以Git:


将快照从您的 I与您自己的 I'进行比较,以查看您所做的更改:这就是您通过提交 L引入的代码。如果发生冲突,这将显示在 <<<<<<< HEAD中。
将快照从您的 I与自己的 J进行比较,以查看“它们”发生了什么变化:这就是您制作 J时所做的更改。如果发生冲突,这将显示在 >>>>>>> theirs中。


这次,在冲突的 HEAD方面,它不再只是 --ours的代码,而是它们的代码和您的代码的混合。同时,任何冲突的 --theirs端仍然是其代码。一旦解决了冲突并使用 git rebase --continue,Git就会像下面这样进行新的普通提交 J'

                    I'-J'  <-- HEAD
/
...--G--H------K--L <-- origin/somebranch
\
I--J <-- somebranch


这里的 J'J的精选副本。

由于这些都是必须复制的提交,因此Git现在通过将名称 somebranch移出提交 J并将其附加到新的提交 J'上,然后将 HEAD重新附加到该结名称 somebranch

                    I'-J'  <-- somebranch (HEAD)
/
...--G--H------K--L <-- origin/somebranch
\
I--J [abandoned]


并完成了基准。运行 git log将显示您的新副本,而不再显示原始的 IJ提交。原始提交最终将被回收并销毁(通常在30天后的某个时间)。

这就是从根本上说,合并比合并要难。重新设置涉及重复的樱桃小贴士,每个樱桃小贴士都是合并。如果必须复制十个提交,则表示要进行十次合并。 Git通常可以自动执行它们,而Git通常可以正确处理它们,但是每次合并只是Git愚蠢地应用了一些简单的文本差异合并规则,因此每次合并都是出错的机会。您必须仔细检查和/或测试结果。理想情况下,您应该检查和/或测试所有十个副本,但是如果最后一个很好,则其他所有副本也可能都不错。

关于git - git merge vs git rebase用于 merge 冲突场景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59622140/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com