Git:压缩合并后,反向合并 [英] Git: Merging in reverse direction after squashed merge
问题描述
我的团队正在使用类似Gitflow的工作流程,但是最近一次从develop
到master
的发行版合并是作为壁球合并无意进行的.当时,我们没有发出任何警报,并认为下次可以正确使用它,但是随后我们不得不对该版本进行修补.现在,我们需要使该修补程序重新合并到develop
中,此后又与master
分叉了.我们遇到了一些冲突,这是合法的,但是其中大多数是由于git认为master
上的squash-merge提交代表其自己的更改提交而不是与develop
合并而引起的.
My team is using a Gitflow-like workflow, but a recent merge from develop
to master
for a release was unintentionally done as a squash merge. At the time, we didn't raise any alarms and figured we'd get it right next time, but then we had to do a hotfix off of that release. Now, we need to get that hotfix merged back into develop
, which has since diverged from master
. We're getting conflicts, some legitimate, but most of them noise due to git thinking that the squash-merge commit on master
represents its own separate commit of the changes, rather than a merge from develop
.
图表可能有助于说明问题:
A graph may help illustrate the issue:
A ---------- D -- G (master)
\
\- B -- C -- E -- F (develop)
在这种情况下,D
是B和C的壁球合并的结果(而不是常规合并的常规合并).请注意,git diff C D
返回空-即它们的内容相同.
In this case, D
is the result of a squash-merge of B and C (instead of a regular merge, as we would have normally done). Note that git diff C D
returns empty - i.e. they are identical in content.
现在,我想将master
合并到develop
中;由于E
,F
和G
之间的合法重叠,我预计会有一些冲突(因此,我不能简单地全局地说使用我们的"或使用他们的").但是我基本上在B
,C
和D
中的所有内容上都有冲突,大概是因为git将D
(可以理解)视为其自己的提交,而在master
的单独提交链中,从A开始
Now, I want to merge master
into develop
; I expect some conflicts due to legitimate overlap between E
, F
, and G
(hence I can't simply globally say "use ours" or "use theirs"). But I'm getting conflicts for basically everything in B
, C
, and D
, presumably because git views D
(understandably) as its own commit in a separate chain of commits on master
starting from A.
长话短说,我希望获得的是类似于相对于这两个相同提交(C
和D
)的合并"而不是相对于A
的合并".有点像rebase --onto
,但我想是为了合并.
Long story short, what I'm hoping for is something like "merge relative to these two identical commits (C
and D
)" rather than "merge relative to A
". Sort of like rebase --onto
, but for merging, I guess.
FWIW,我知道我可以手工解决冲突.我只是很好奇,是否有一种方法可以跳过通过创建D
时执行的壁合并而不是常规合并而引入的所有垃圾冲突.
FWIW, I know that I can just resolve the conflicts by hand; I'm just curious if there's a way to skip all the garbage conflicts introduced by having done a squash-merge instead of a regular merge when D
was created.
推荐答案
更新-我忘记了有关其工作原理的重要信息;固定.
UPDATE - I had forgotten important information about exactly how this works; fixed.
现在,我假设进行历史记录重写(以及随后的清理)并不是一个切实可行的解决方案...
For now I'll assume that doing a history rewrite (and the subsequent clean-up) isn't really a practical solution...
在这种情况下,最简单的方法是在合并过程中使用git replace
.如果C
和D
具有相同的内容,这将不起作用.
In this specific case, the simplest hack would be to use git replace
during the merge. This would not work if not for the fact that C
and D
have the same content.
在克隆中你可以说
git replace --graft <E> <D>
(其中<E>
和<D>
是解析为相应提交的表达式;在上面的示例中,它可能是git replace --graft develop^ master^
).这将创建一个新的提交E'
,其外观类似于E
,但其父级为D
.然后,它使用E'
代替E
-因此,当操作将git引导至E
时,它仍然会看到E
的提交ID,但会从E'
获取有关该提交的其余信息. .身体上你有
(where <E>
and <D>
are expressions that resolve to the corresponding commits; in the above example, this might be git replace --graft develop^ master^
). This creates a new commit E'
that "looks like" E
, but its parent is D
. It then uses E'
as a replacement for E
- so when an operation leads git to E
, it still sees E
s commit ID, but it gets the rest of its info about that commit from E'
. Physically you have
E'
/
A ---------- D -- G (master)
\
\- B -- C -- E (REPLACE:E')
\
F (develop)
那你呢
git chekcout develop
git merge master
(或者也许是git merge hotfix-branch
,但是您没有在图形中显示它,因此我们将使用简化的示例)...现在,merge
命令可以看到"
(or maybe git merge hotfix-branch
but you didn't show that in your graph, so we'll go with the simplified example)... Now the merge
command "sees"
A ---------- D -- G (master)
\
(E|E') -- F (develop)
,因此它使用D
作为合并基础.因为C
和D
具有相同的内容,所以计算出的合并结果应为应有的结果.结果看起来像"
so it uses D
as the merge base. Because C
and D
have the same content, the calculated merge result is what it should be. The result "looks like"
A ---------- D ------------ G (master)
\ \
(E|E') -- F -- M (develop)
这是真的
E'
/
A ---------- D ------ G (master)
\ \
\ F -- M (develop)
\ /
\- B -- C -- E (REPLACE:E')
现在,D
.. M
周围的历史记录看起来很有趣",这就是这样做的缺点(而不是用真实的合并替换D
的历史记录校正). M
是边界邪恶合并",但是由于默认合并仍然会发生冲突(并且由于计算结果是冲突的自然"解决方案),因此并不可怕.
Now the history around D
..M
"looks funny", and that's the down side of doing this (rather than a history correction to replace D
with a true merge). M
is a borderline "evil merge", but since the default merge would conflict anyway (and since the calculated result is the "natural" resolution of the conflict) it's not terrible.
完成此操作后,您将不再需要更换.将来master
和develop
之间的合并将仍然将G
作为合并基础,因此之前的混乱并不重要.
Once this is done you no longer need the replacement. Future merges between master
and develop
will see G
as the merge base anyway, so the messiness that precedes it doesn't matter.
这篇关于Git:压缩合并后,反向合并的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!