鉴于这些步骤:
- 一个分支 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 的版本。