问题
李四在develop分支提交了错误的代码(涉及到2次commit,commit-a和commit-b)并且已经push,这时发现提交代码有问题,想要回滚,于是执行了以下操作:
git commit * 2:分别提交了commit-a和commit-bgit push:将commit-a和commit-b提交推送到服务器端- 发现
commit-a和commit-b提交是错误的,后悔了,于是继续下面的操作进行代码“回滚” git reset --hard HEAD^^:清理掉本地commit-a和commit-bgit push --force:强制远程服务器端清理掉commit-a和commit-b
那么问题是,上述操作是否安全?
场景分析
上述操作的危险性在于git本身是分布式的,如果在第2步和第4步之间,有人已经将commit-a和commit-b提交fetch或pull到了本地,那么此人本地已经有了commit-a和commit-b,之后他重新在feature分支做提交时可能会带上commit-a和commit-b,导致远程的服务器端重新出现了不想要的代码。
下面我们将分几种情况分别进行实验和分析,探究在git工具中进行上述操作的影响
develop分支fetch
假设张三在第2、4步之间于develop分支上执行了fetch操作,那么其过程和结果如下:
-
张三在
develop分支上执行了fetch操作,命令行界面显示dc1e846..3f821e9 develop -> origin/develop,本地的origin/develop上会有commit-a和commit-b提交 -
李四执行
第4、5步,进行代码回滚 -
张三继续在
develop分支上执行fetch操作,命令行界面显示+ 3f821e9...a113d93 develop -> origin/develop (forced update),此时本地的origin/develop上commit-a和commit-b提交消失
可见这种情况下达到了想要的回滚效果
feature分支fetch/pull
假设张三在第2、4步之间在另一个分支,feature分支上执行了fetch或pull操作,其结果如上,回滚效果生效
develop分支pull
假设张三在第2、4步之间于develop分支上执行了pull操作,那么其过程和结果如下:
- 张三在
develop分支上执行了pull操作,则本地会有commit-a和commit-b提交 - 李四执行
第4、5步,进行代码回滚 - 张三继续在
develop分支上执行pull操作,命令行界面显示+ 7a6e40c...a113d93 develop -> origin/develop (forced update),此时本地的origin/develop上commit-a和commit-b提交消失,但develop上commit-a和commit-b提交并未消失 - 张三继续在
develop分支上执行git status操作,显示他的分支要领先于远程分支,可以执行git push - 张三继续在
develop分支上执行git push操作,则远程重新出现commit-a和commit-b提交)
假设一种更复杂的情况,替换掉第5步:
-
张三在
develop分支修改一些内容,提交了commit-张三,然后再push -
李四在
develop分支修改一些内容,提交了commit-李四(与commit-张三不冲突) -
李四在
develop分支上执行git pull操作,本地重新出现了commit-a和commit-b提交
结论
如果在push之后,回滚之前,其他人已经将该分支上进行了pull操作,则被回滚的内容将会出现在其他人的代码仓库里,并随着push被继续推送到远程仓库,此时回滚视为失败。如果他人只进行了fetch操作,则对回滚无影响,可视为回滚成功。
但关键在于,无法保证在push和回滚之间,其他人不在此分支上进行pull操作,所以对已经push的内容进行回滚是不安全的,应避免