一种方法是使用 rebase。
无论选择哪种方法,你都必须重写你的仓库历史记录。你必须接受这个事实,否则就得接受当前的历史记录。
让我们总结一下你的历史记录的不同部分:
- 提交4、5和8,在主分支上
- 提交3、6、7和9现在也在主分支上,但最初位于不同的分支上
- 提交10和11在主分支上,上面合并了两个并行的历史记录
为了解决这个问题,我会执行以下步骤:
- 检出“原始分支”,也就是第 9 个提交
- 在此处创建一个新的分支,只是为了确保我们可以玩耍一下
- 将这个由提交3、6、7和9组成的新分支(当你最初合并时)重新定位到主分支的顶部,因此定位到提交8的顶部
- 解决任何合并冲突(当你最初合并时,你也会遇到这些问题,但由于 rebase 操作与合并操作的不同,可能需要以不同的方式处理它们)
- 完成以上步骤后,请检出主分支上的上一个提交,即 11 号提交,并将提交 10 和 11 重新定位到你的新分支上
- 如果一切现在看起来都很好,你可以硬重置主分支到这个新分支,并强制推送到你的远程仓库以使它成为新的历史记录
以下是该过程的逐步图示(命令如下):
现在的状态:
master
v
1---2---4---5---8---M--10--11
\ /
3---6---7---9
为9创建新分支:
master
v
1---2---4---5---8---M--10--11
\ /
3---6---7---9
^
TEMP1
将基于8进行变基,这将创建3'、6'、7'、9'(其中'
表示“提交的副本,内容相同,新的哈希值”)
TEMP1
v
3'--6'--7'--9'
/
1---2---4---5---8---M--10--11
\ / ^
3---6---7---9 master
创建一个新分支用于11(我不喜欢动主分支)。
TEMP1
v
3'--6'--7'--9'
/
1---2---4---5---8---M--10--11
\ / ^
3---6---7---9 master
^
TEMP2
将这个分支(10和11)在TEMP1的顶部进行变基:
TEMP1 TEMP2
v v
3'--6'--7'--9'-10'-11'
/
1---2---4---5---8---M--10--11
\ / ^
3---6---7---9 master
确认TEMP2与当前主分支完全相同,没有丢失也没有添加任何内容。
然后将主分支硬重置为TEMP2:
master
v
TEMP1 TEMP2
v v
3'--6'--7'--9'-10'-11'
/
1---2---4---5---8---M--10--11
\ /
3---6---7---9
我将删除TEMP1和TEMP2这两个分支。
请注意,提交3、6、7、9、M、10和11仍然存在于存储库中,但它们不直接可用,因为没有任何东西引用它们。因此,它们有资格进行垃圾回收,实际上您的存储库的实际历史现在是这样的:
1---2---4---5---8---3'--6'--7'--9'-10'-11'
^
master
执行这些操作的命令是:
(第0步:完全复制您的本地文件夹,包括工作文件夹和.git存储库。如果可以,请在该副本中执行以下命令。如果出错,请删除副本并重新开始,不要没有安全网就跳)
git checkout <HASH-OF-9>
git checkout -b TEMP1
(是的,您可以使用 git checkout -b TEMP1 <HASH-OF-9>
一条命令同时执行前面两个命令)
git rebase -i --onto <HASH-OF-8> <HASH-OF-2> TEMP1
- 解决合并冲突并提交更改(如果有的话)
git checkout -b TEMP2 <HASH-OF-11>
git rebase --onto TEMP1 <HASH-OF-MERGE> TEMP2
- 检查是否一切正常
git checkout master
git reset --hard TEMP2
最后,清理:
git branch -d TEMP1 TEMP2
git push -f
只有在你确定一切都没问题的情况下才能使用 force-push