所以树目前看起来像这样:
B--F <-- feature/a: colleague's feature branch (on review, squashed when merged)
/
...--A--C--E <-- master
\
D--G <-- feature/b: my feature branch (wip)
我需要的是在 feature/a
合并为壁球提交后将更改从 feature/a
复制到 feature/b
而不会发生冲突。
期望的结果应该是这样的:
B--F <-- feature/a (squash merged as commit H)
/
...--A--C--E--H (--J) <-- master (J is not present yet, master is at H)
\
D--G--B'--F' <-- feature/b (will be merged later as squash commit J)
我需要一种复制 feature/a
的方法,而不需要 git 认为 B
和 F
在我的分支将被 sqash 合并时是重复的更改。
上次我做了类似的事情时,我被冲突淹没了,因为 squash commit J
没有与 F
的直接历史记录(没有从 H
到 F
的指针),所以 F'
被认为是重复的。
回答1
我需要的是在将 feature/a 合并为 squash 提交后将更改从 feature/a 复制到 feature/b 而不会发生冲突。
一般来说,你不能。但你也许能够得到你需要的东西。
在两种不同的条件下,两次提交实际上是相同的提交:
它们具有相同的提交哈希 ID。然后它们实际上是相同的提交:实际上只有一个提交。这就是 Git 知道其他存储库中的某些提交与此存储库中的提交相同的方式。
它们具有相同的补丁 ID(参见 https://git-scm.com/docs/git-patch-id)。
当有人使用 git merge --squash
时,他们会得到一个新的提交——即具有不同哈希 ID 的提交——其补丁 ID 几乎可以肯定与单个提交的补丁 ID 不同。这是因为补丁 ID 是精简 diff 的加密校验和(有关详细信息,请参阅文档):如果 squash 提交的 diff 匹配,则补丁 ID 匹配,但如果不匹配,则不匹配。如果 squash 提交是 squash 两个或多个提交的结果,它将有一个补丁 ID,不会匹配任何单个提交的任何单个补丁 ID,它们都不会产生特定的差异:你只会得到通过将各个提交加在一起来确定特定的差异。
你可以做的很简单。与其在所有 feature/a
提交中挑选樱桃,不如 *做你自己的 git merge --squash
。这将为您提供一个单一的提交,我们可以称之为 H'
,它将与未来的 H
具有相同的补丁 ID,前提是 H
是通过合并压缩构建的 B
和 F
到 E
并且差异不会受到这种合并压缩效果的干扰。
也就是说,H'
将对 G
进行与 B
+F
将对 E
进行相同的更改。行号可能不同,以及 git patch-id
丢弃的一些其他信息,但只要不同的东西被剥离,补丁 ID 就会匹配。
未来的 git rebase
将删除与补丁 ID 等效的 H'
。因此,一旦 H
存在,您可以简单地将 feature/b
重新定位到 master
,然后从使用您的 H'
切换到使用他们的 H
。当然,这具有任何 rebase 的所有常见缺点,但它是自动的,并且删除了可能导致合并冲突的重复。
(完全重复的重复被 git merge
省略。这包括 git merge --squash
在进行非合并提交之前使用的合并作为动词的过程,其中“合并”是一个形容词。但是,根据每个不同提交中的内容,您避免冲突的机会通常会通过这种 H
-vs-H'
诡计来提高。)
当然,您最好的选择是在提交 H
存在之前完全避免将 feature/a
复制到 feature/b
中,然后再进行变基,但是如果您发现需要 feature/a
,这可能会让您不那么痛苦地到达那里.