防止 Git 快进自动合并
Posted
技术标签:
【中文标题】防止 Git 快进自动合并【英文标题】:Prevent Git Fast Forward Automatic Merge 【发布时间】:2021-12-05 15:03:31 【问题描述】:问题上下文示例:
-
一个分支 B 是从 A 分支创建的
在分支 B 中创建了一个名为
XPTO.txt
的文件并对其进行了多次编辑(多次提交)
之后又从分支B创建了另一个分支C
在 B 和 C 分支中,XPTO.txt
被同时编辑了多次(多次提交)
分支 C 必须合并回 A
从分支 C 到分支 A 的拉取请求 (PR) 不得有之前在分支 B 的 XPTO.txt
中所做的更改C 分支已创建
假设删除 B 分支代码的这些更改(提交)已正确完成并且不会影响项目构建等。
我应该如何正确管理存储库以便:
合并分支 B 代码删除提交到分支 A 在分支 B 打开 PR 以合并到分支 A 时(尽可能)避免合并冲突 最重要的一点:隐式避免,如果可能,Git 快进可能发生的情况将示例扩展到多个文件和多个更改(提交)。
到目前为止,我认为唯一的答案是强制从分支 B 到分支 A 的非 FF 合并,但有时仍会得到 Already up to date!
。
谢谢。
【问题讨论】:
无论您描述的具体工作流程如何,即使可以进行快进,也可以使用--no-ff
强制合并提交。
感谢@RomainValeri 我编辑了这些问题,为您提供更多背景信息:)
【参考方案1】:
鉴于这些步骤:
-
一个分支 B 是从 A 分支创建的
在分支 B 中创建了一个名为
XPTO.txt
的文件并对其进行了多次编辑(多次提交)
之后又从分支B创建了另一个分支C
在 B 和 C 分支中,XPTO.txt
被同时编辑了多次(多次提交)
您的存储库如下所示:
(B)
|
v
<--b3 <--b4
/
a1 <--a2 <--b1 <--b2
^ \
| <--c1 <--c2
(A) ^
|
(C)
小写标签是单独的提交,通过它们的“父”引用(向后的箭头)链接在一起。大写标签是分支,在 git 模型中只是指向特定提交的指针,可用于引用该提交及其所有祖先。
请注意,提交 b1 和 b2 是最初在分支 B 上创建的,但就 git 而言,它们只是分支 C 历史的一部分。
那么现在:
从分支 C 到分支 A 的拉取请求 (PR) 不得在创建分支 C 之前对分支 B 的 XPTO.txt 进行更改没有直接的方法告诉 git - 它不知道哪些提交“属于”分支 B 或“之前”分支 C。如果您要求将分支 C 合并到 A,它会回顾直到它找到一个共同的祖先,即 a2,因此要合并的提交是 b1、b2、c1 和 c2。
为了“删除”这些提交,您需要创建在历史记录中没有它们的新提交。这就是“git rebase”命令的用途。
在这种情况下,您需要将“b2”之后的提交重新设置为“A”,因此命令将是git rebase b2 C --onto A
。结果将如下所示:
(B)
|
v
<--b3 <--b4
/
a1 <--a2 <--b1 <--b2
^ \ \
| \ <--c1 <--c2
(A) \
<--c3 <--c4
^
|
(C)
现在提交 b1 和 b2 不再是 C 历史的一部分。
提交 c3 和 c4 将分别由基于 c1 和 c2 的 rebase 命令创建,但不要以任何方式链接到它们。如果没有其他分支或标签指向提交 c1 和 c2,它们最终将作为孤立数据被“垃圾收集”。
如果您想要部分从提交 b1 和 b2 中获得更改,则需要手动将它们添加回来作为新提交。这可能会或可能不会导致以后发生冲突,这取决于合并算法是否可以弄清楚您要做什么。但这只是生活中的事实:对同一个文件的两个并行更改存在冲突的风险。
请注意,这与恢复更改(使用“git revert”或手动撤消它们)非常不同,后者会在历史记录中创建附加提交:
(B)
|
v
<--b3 <--b4
/
a1 <--a2 <--b1 <--b2
^ \
| <--c1 <--c2 <--rb1 <--rb2
(A) ^
|
(C)
这里,“rb1”撤消了“b1”的更改,“rb2”撤消了“b2”的更改,但是所有四个提交都是 C 历史的一部分。一旦你合并到 A,它们也都将成为 A 历史的一部分,所以当你合并到分支 B 时,只有 b3 和 b4 将是“新的”。
解决此问题的唯一其他方法是重新设置分支 B 以创建提交的新副本以在还原后合并 。这会导致混乱的历史,但有时是摆脱混乱的方法。
(B)
|
V
<--b5 <--b6 <--b7 <--b8
/
|
| <--b3 <--b4
| /
a1 <--a2 <--b1 <--b2
^ \
| <--c1 <--c2 <--rb1 <--rb2
(A) ^
|
(C)
这里的 b5、b6、b7 和 b8 是 rebase 命令重新创建的 b1、b2、b3 和 b4 的版本。
【讨论】:
到目前为止,我只阅读了第二张图表。但我建议将git rebase b2 C --onto A
更改为git rebase --onto A b2 C
,因为我认为这是 far 更常见的语法用法? (我不知道我是否曾经在结尾看到过 --onto,很多人用“第一”、“第二”参数等来指代 --onto。)另外,也许在第二个图c3和c4是c1和c2的replay?
顺便说一句,关注 cmets 的人有一篇关于它的精彩文章:tanzu.vmware.com/content/blog/git-rebase-onto
@TTT 你说得对!
@TTT 我倾向于这样写,因为这就是您用英语所说的顺序:“将提交从 b2 重新定位到 C 到 A”。最后,它没有任何区别,因为实际上只有 A 附加到“--onto”。以上是关于防止 Git 快进自动合并的主要内容,如果未能解决你的问题,请参考以下文章
Git hook prepare-commit-msg 以防止合并禁止的分支 - 将 Ruby 转换为 Bash