在推送修复程序后,仍然显示合并冲突

时间:2018-03-07 20:09:43

标签: git

我使用master命令将我的uat分支合并到我的git merge --squash master分支中,我解决了所有冲突并将我的更改推送到了repo中。现在,自从我合并后没有人触及uat分支,但是当我在git merge --squash master分支中运行uat时,即使我修复了这些冲突并推送它们,我仍然会看到相同的冲突。

1 个答案:

答案 0 :(得分:2)

这很正常。

问题是git merge --squash是人们在分支上可能称之为终端操作:在执行git merge --squash branch之后,你应该 1 < em>删除分支git branch -D branch,或者至少将其重命名为“不再对此进行处理”#34;例如:git branch -m branch dead-branches/branch

1 &#34;宜&#34;这是一个价值判断。没有技术要求,你可能会忽略保留分支的原因:你只需要知道Git正在做什么以及保留分支的意义。

真正的合并

在考虑壁球&#34;合并&#34;之前,值得看看正常(非压缩)合并的作用,看看为什么我将单词merge合并为{{1的引号}} 案件。 Git的--squash是关于结合工作,它使用的机制是找到一个共同的起点。这是一个提交 - 理想情况下是一次提交, 提交 - 位于两个分支上,最靠近每个分支的尖端。如果我们按照我喜欢的方式绘制它们,分支名称和提交看起来像这样:

git merge

您已检出的主线分支 - 由分支名称 C--D--E <-- mainline (HEAD) / A--B [common starting point] \ F--G--H <-- branch 附加的单词HEAD表示 - 表示实际上是&#34;提交mainline& #34 ;.提交EA的提交都在该分支上,因为Git从E开始向后工作:E的父级是E; D的父母是D; C的父母是C; B&#39; s是B。 (A是有史以来第一次提交,因此它没有父级:它是 root commit 。这在这里并不重要,但值得一提,因为你做的第一次提交在新的存储库中是这些根提交之一,通常只有 一个。)

同时,另一个分支A实际上意味着&#34;提交branch&#34;。提交HABF的所有内容都在分支H上。

请注意,提交branch在两个分支上!它的提交是最近的&#34;提交两个提示,BE,因此它是合并基础

在给出提示提交的情况下,通过查找合并基础开始真正的合并。实际上,Git会将保存为合并基础快照的内容与您H之后的内容进行比较。当前提交git checkout <hash-of-B>

E

它用基数和你的其他分支提示重复这个:

git diff --find-renames <hash-of-B> <hash-of-E>   # what we did

这是Git应该结合起来的工作。如果您更改了三个根本没有更改的文件,Git应该将更改应用到基础。如果他们更改了一些你根本没有改变的文件,Git应该将他们的更改应用到基础。如果你和他们都触及了相同的文件,Git应该将这些更改结合起来,如果可以的话,确保如果你们两个都做了完全相同的更改,Git只接受< em>该变更的一个副本。

将组合的更改应用于基础会产生新的快照(或者有合并冲突;然后Git通常会停止并让您清理混乱)。假设一切顺利,Git提交新快照,将第一个父级设置为当前提交,将其第二个父级设置为另一个提交:

git diff --find-renames <hash-of-B> <hash-of-H>   # what they did

让我们以一种不那么弯曲的方式重新绘制它:

     C--D--E
    /       \
A--B         I   <-- mainline (HEAD)
    \       /
     F--G--H   <-- branch

合并提交 A--B--C--D--E--I <-- mainline (HEAD) \ / F---G---H <-- branch 仅在一个分支上,在本例中为主线分支。让我们查看旁边分支I并立即开展更多工作:

branch

如果我们A--B--C--D--E--I <-- mainline \ / F---G---H--J--K <-- branch (HEAD) (将我们的HEAD附加到那里)并运行git checkout mainline,Git现在必须再次找到上的最佳提交分支机构。我们从侧面分支的git merge branch开始,然后查看K,然后查看J。同时,我们从主线H开始,然后同时查看IE。提交H在我们的分支提交列表中,因此它是最接近两个分支的那个:它是新的合并基础。

Git现在将我们的更改与他们的更改结合起来。这些变化是:

H

请注意,这次从git diff --find-renames H I # what we did git diff --find-renames H K # what they did 开始,Git 不是:由于合并提交B,合并基础现为H。< / p>

假设一切顺利,Git进行了一次新的提交,其中组合的更改应用于I中的任何内容:

H

我们都完成了。

壁球&#34;合并&#34;

现在让我们看看A--B--C--D--E--I-----L <-- mainline (HEAD) \ / / F---G---H--J--K <-- branch 做了什么,从我们原来的同样开始:

git merge --squash

Git执行相同的合并基础查找,并进行相同的组合。我喜欢将其称为合并为动词:它是找到合并库,获得两个A--B--C--D--E <-- mainline (HEAD) \ F---G---H <-- branch 并组合结果的动作。

但下一步,当一切顺利时,情况会有所不同。而不是将合并提交 - 合并作为形容词,修改 commit ,意味着提交 two (或更多)parents-Git使用一个父进行提交。好吧,事实上,它完全停止,好像你运行了git diff,但是当你通过运行git merge --no-commit完成了这个过程时, 进行了一次普通的非合并提交{ {1}}:

git commit

新提交I与将三个提交A--B--C--D--E--I <-- mainline (HEAD) \ F---G---H <-- branch 合并并将其应用于I的内容具有相同的效果:内容方面,它是您将得到的内容如果您在F-G-H上执行E并将最后两个git rebase -i master命令更改为branch。但它不是合并提交!它不是一个合并为形容词,即使它做了合并动词动作。

所以,如果您现在pick并进行更多提交然后切换回主线,那么您现在拥有的内容如下:

squash

如果你现在要求Git合并两个分支,Git首先找到合并基础。合并基础是两个分支上的第一个提交,由于git checkout branch不是合并提交,因此再次提交A--B--C--D--E--I <-- mainline (HEAD) \ F---G---H--J--K <-- branch

请注意I在其内容中包含B的所有更改(因为我们是通过merge-as-a-verb-ing制作的),但是Git不知道,所以下次合并必须查看I vs F-G-H,这意味着再次放入B的所有内容。

如果Git能够自己上次解决所有冲突,那么它也可以自己解决所有冲突。这个新的合并动词,无论我们是否使用H,都可以自动完成所有操作。如果Git上次不得不停下来得到帮助,那么这次也有可能不得不停下来寻求帮助:许多相同的冲突都会发生。它们甚至可能更糟糕,取决于我们解决它们做出提交F-G-H时所做的事情。

正常的解决方案是当我们执行--squash并生成提交I时,我们完全抛弃侧支:

git merge --squash

如果我们想进行更多更改,我们会建立一个新的分支:

I

然后对其进行新的提交:

A--B--C--D--E--I   <-- mainline (HEAD)

通过A--B--C--D--E--I <-- mainline, branch2 (HEAD) 提交A--B--C--D--E--I <-- mainline \ J--K <-- branch2 (HEAD) 已被放弃(很快就会消失,特别是如果我们删除名称F,因为这也会删除H的reflog这会将剩余的提交保护减少到branch reflog中的#34;无法访问&#34;提交的30天。但是,我们不再需要或不再需要它们:这三个旧的无聊快照现在表示为提交branch的单个快照。