Git: 压缩合并后反向合并
Git: Merging in reverse direction after squashed merge
我的团队正在使用类似 Gitflow 的工作流程,但最近从 develop
到 master
的发布合并是无意中作为挤压合并完成的。当时,我们没有发出任何警报,并认为下次我们会做对的,但后来我们不得不对该版本进行修补程序。现在,我们需要将该修补程序合并回 develop
,后者已从 master
中分离出来。我们遇到了冲突,一些 legitimate,但大多数冲突是由于 git 认为 master
上的 squash-merge 提交代表了它自己单独的更改提交,而不是比来自 develop
.
的合并
图表可能有助于说明问题:
A ---------- D -- G (master)
\
\- B -- C -- E -- F (develop)
在这种情况下,D
是 B 和 C 的挤压合并的结果(而不是像我们通常那样进行的常规合并)。请注意 git diff C D
returns 为空 - 即它们的内容相同。
现在,我想将 master
合并到 develop
;由于 E
、F
和 G
之间的 legitimate 重叠,我预计会有一些冲突(因此我不能简单地全局说 "use ours" 或 "use theirs").但是我在 B
、C
和 D
中基本上遇到了冲突,大概是因为 git 将 D
(可以理解)视为它自己的提交master
上的单独提交链,从 A.
开始
长话短说,我希望的是 "merge relative to these two identical commits (C
and D
)" 而不是 "merge relative to A
"。有点像 rebase --onto
,但我想是为了合并。
FWIW,我知道我可以手动解决冲突;我只是好奇是否有一种方法可以跳过在创建 D
时进行压缩合并而不是常规合并而引入的所有垃圾冲突。
更新 - 我忘记了有关其具体工作原理的重要信息;已修复。
现在我假设重写历史记录(以及随后的 clean-up)并不是真正可行的解决方案...
在这种特定情况下,最简单的破解方法是在合并期间使用 git replace
。如果不是因为 C
和 D
具有相同的内容,这个 将无法工作 。
在克隆中你可以说
git replace --graft <E> <D>
(其中 <E>
和 <D>
是解析为相应提交的表达式;在上面的示例中,这可能是 git replace --graft develop^ master^
)。这将创建一个新提交 E'
"looks like" E
,但它的 parent 是 D
。然后它使用 E'
作为 E
的替代 - 所以当一个操作导致 git 到 E
时,它仍然看到 E
s 提交 ID,但它得到来自 E'
的有关该提交的其余信息。身体上你有
E'
/
A ---------- D -- G (master)
\
\- B -- C -- E (REPLACE:E')
\
F (develop)
那么你
git chekcout develop
git merge master
(或者 git merge hotfix-branch
但你没有在图表中显示,所以我们将使用简化的示例)...现在 merge
命令 "sees"
A ---------- D -- G (master)
\
(E|E') -- F (develop)
所以它使用 D
作为合并基础。因为C
和D
的内容是一样的,所以计算出的合并结果才是应该的。结果"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
"looks funny" 附近的历史记录,这是这样做的缺点(而不是用历史修正替换 D
真正的合并)。 M
是一个边界线 "evil merge",但由于默认合并无论如何都会发生冲突(并且由于计算结果是冲突的 "natural" 解决方案)它并不可怕。
一旦完成,您就不再需要更换了。 master
和 develop
之间的未来合并无论如何都会将 G
视为合并基础,因此之前的混乱并不重要。
我的团队正在使用类似 Gitflow 的工作流程,但最近从 develop
到 master
的发布合并是无意中作为挤压合并完成的。当时,我们没有发出任何警报,并认为下次我们会做对的,但后来我们不得不对该版本进行修补程序。现在,我们需要将该修补程序合并回 develop
,后者已从 master
中分离出来。我们遇到了冲突,一些 legitimate,但大多数冲突是由于 git 认为 master
上的 squash-merge 提交代表了它自己单独的更改提交,而不是比来自 develop
.
图表可能有助于说明问题:
A ---------- D -- G (master)
\
\- B -- C -- E -- F (develop)
在这种情况下,D
是 B 和 C 的挤压合并的结果(而不是像我们通常那样进行的常规合并)。请注意 git diff C D
returns 为空 - 即它们的内容相同。
现在,我想将 master
合并到 develop
;由于 E
、F
和 G
之间的 legitimate 重叠,我预计会有一些冲突(因此我不能简单地全局说 "use ours" 或 "use theirs").但是我在 B
、C
和 D
中基本上遇到了冲突,大概是因为 git 将 D
(可以理解)视为它自己的提交master
上的单独提交链,从 A.
长话短说,我希望的是 "merge relative to these two identical commits (C
and D
)" 而不是 "merge relative to A
"。有点像 rebase --onto
,但我想是为了合并。
FWIW,我知道我可以手动解决冲突;我只是好奇是否有一种方法可以跳过在创建 D
时进行压缩合并而不是常规合并而引入的所有垃圾冲突。
更新 - 我忘记了有关其具体工作原理的重要信息;已修复。
现在我假设重写历史记录(以及随后的 clean-up)并不是真正可行的解决方案...
在这种特定情况下,最简单的破解方法是在合并期间使用 git replace
。如果不是因为 C
和 D
具有相同的内容,这个 将无法工作 。
在克隆中你可以说
git replace --graft <E> <D>
(其中 <E>
和 <D>
是解析为相应提交的表达式;在上面的示例中,这可能是 git replace --graft develop^ master^
)。这将创建一个新提交 E'
"looks like" E
,但它的 parent 是 D
。然后它使用 E'
作为 E
的替代 - 所以当一个操作导致 git 到 E
时,它仍然看到 E
s 提交 ID,但它得到来自 E'
的有关该提交的其余信息。身体上你有
E'
/
A ---------- D -- G (master)
\
\- B -- C -- E (REPLACE:E')
\
F (develop)
那么你
git chekcout develop
git merge master
(或者 git merge hotfix-branch
但你没有在图表中显示,所以我们将使用简化的示例)...现在 merge
命令 "sees"
A ---------- D -- G (master)
\
(E|E') -- F (develop)
所以它使用 D
作为合并基础。因为C
和D
的内容是一样的,所以计算出的合并结果才是应该的。结果"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
"looks funny" 附近的历史记录,这是这样做的缺点(而不是用历史修正替换 D
真正的合并)。 M
是一个边界线 "evil merge",但由于默认合并无论如何都会发生冲突(并且由于计算结果是冲突的 "natural" 解决方案)它并不可怕。
一旦完成,您就不再需要更换了。 master
和 develop
之间的未来合并无论如何都会将 G
视为合并基础,因此之前的混乱并不重要。