Git: 压缩合并后反向合并

Git: Merging in reverse direction after squashed merge

我的团队正在使用类似 Gitflow 的工作流程,但最近从 developmaster 的发布合并是无意中作为挤压合并完成的。当时,我们没有发出任何警报,并认为下次我们会做对的,但后来我们不得不对该版本进行修补程序。现在,我们需要将该修补程序合并回 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;由于 EFG 之间的 legitimate 重叠,我预计会有一些冲突(因此我不能简单地全局说 "use ours" 或 "use theirs").但是我在 BCD 中基本上遇到了冲突,大概是因为 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。如果不是因为 CD 具有相同的内容,这个 将无法工作

在克隆中你可以说

git replace --graft <E> <D>

(其中 <E><D> 是解析为相应提交的表达式;在上面的示例中,这可能是 git replace --graft develop^ master^)。这将创建一个新提交 E' "looks like" E,但它的 parent 是 D。然后它使用 E' 作为 E 的替代 - 所以当一个操作导致 git 到 E 时,它仍然看到 Es 提交 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 作为合并基础。因为CD的内容是一样的,所以计算出的合并结果才是应该的。结果"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" 解决方案)它并不可怕。

一旦完成,您就不再需要更换了。 masterdevelop 之间的未来合并无论如何都会将 G 视为合并基础,因此之前的混乱并不重要。