高阶-修改历史
前置知识:
修改历史是git中最强大但是也最危险的操作之一。在修改历史前,强烈建议进行数据备份并思考你是否真的需要修改历史。以下一般不构成修改历史的理由:
- 之前的commit里面有误:请创建一个新的commit来修正它
- 删掉某个commit:请创建一个revert commit来去掉这个commit的修改
- 回滚到某个版本:从那个版本开始新建一个分支;
需要修改历史的常见原因有:
- 提交了带密码的文件
- 提交了过大的文件
- 项目要求线性历史(linear history)或one commit per PR
下面的指令如果完成之后你感觉有些晕乎乎的,不知道仓库发生了什么,请永远记得git status
和git log
。
修改历史后如何与远程同步
远程一般只允许fast forward一个分支,即branch的新位置需要包含之前的所有commit。修改历史后,我们得到的是完全不同的一个分支(原因请参考Git原理),remote会拒绝我们push过去。这时候需要用--force
指令:
由于这是一个危险的指令,很多仓库的主分支main
不允许force-push,请留意。
回滚到上一个版本
这是在有问题的commit刚刚发生时的急救措施。比如我们突然想起来刚刚的commit中不小心加入了一个编译的二进制文件,而我们还没有把结果push到远程,那么我们可以立刻进行一个回滚:
HEAD^
的意思是当前HEAD
的上一个commit,改成HEAD^^
可以回滚到再上一个。这个指令并不会更改你工作区中的文件,只修改了branch指向的commit,所以你可以进行一些修改之后再次commit。
Squash
“Squash”的意思是把多个commit合并为一个commit。GitHub的PR页面上有一键squash的功能,我们在这里也介绍一个比较简单直接的操作方法。
假设你需要把当前分支的最后3个commit squash到一起:
这两行代码相当于是把最后的几个commit先撤销,然后我们再一次性全部commit回去。类似地,如果你决定要把某个commit 123abc
之后的squash在一起(不包含123abc
),则命令是:
下一项工作是?
后面是比较复杂的概念,实际用的机会不多,而且有许多可能发生的特殊情况,放在这里稍显冗长,我们直接给出参考资料。
- Rebase: 在合并入主分支的时候,让自己的分支“看起来”像基于最新的commit开始的。
- 从存储库中删除敏感数据