在版本的迭代开发过程中,相信很多人都会提交错误(至少梁旭有过几次这样的经历)。在这种情况下,菜鸟程序员可能会感到震惊和不知所措。资深程序员会微微一笑,摸摸发亮的额头,然后默默回滚版本。对于版本回滚,我们经常会用到两个命令:gitresetgitrevert那么这两个命令有什么区别呢?别着急,我们稍后会详细介绍它们。gitreset假设我们的系统现在有如下提交:其中:A、B为正常提交,C、D为错误提交。现在,我们要回滚C和D,此时HEAD指针指向D提交(5lk4er)。我们只需将HEAD指针移动到提交B(a0fvf8)即可。有git基础的人肯定会想到gitreset这个命令。完整的命令如下:gitreset--harda0fvf8命令运行后,HEAD指针会移动到SubmitB,如下图:此时远程仓库的HEAD指针保持不变,依然亮着提交D。因此,如果直接使用gitpush命令,将无法将修改推送到远程仓库。此时只能使用-f选项强制提交到远程仓库:gitpush-f这种方式回滚代码的缺点很明显,就是会让HEAD指针后移,从而丢失后续提交信息。如果以后突然发现,C和D是多么美妙的点子,却早已消失在历史的长河中。而且有些公司(比如良旭的公司)明令禁止使用gitreset命令回滚代码,原因同上。所以,我们需要找到一个既能回滚代码又能保存错误提交的命令。这时候gitrevert命令就派上用场了。gitrevertgitrevert的作用是通过反向创建一个新版本。这个版本的内容和我们要回滚到的目标版本是一样的,只是HEAD指针指向的是这个新生成的版本,而不是目标版本。如果使用gitrevert命令来实现上面的例子,我们可以这样做:先revertD,再revertC(如果有多个提交需要回滚,需要从new回old):gitrevert5lk4ergitrevert76sdeb将这里生成两个新的提交:D'和C',如下图:需要回滚的提交只有两个,我们可以一个一个回滚。但是如果有几十个呢?一个一个回滚肯定是效率太低,容易出错。我们可以使用如下方法进行批量回滚:gitrevertOLDER_COMMIT^..NEWER_COMMIT此时,错误的commitC和D仍然保留,也有后续dumping之用。而且,如果这样做,HEAD指针会向后移动,可以直接使用gitpush命令推送到远程仓库。而这种做法正是公司所鼓励的。让我们举一个更难的例子。假设现在有三个提交,但不幸的是,错误的提交在中间。如下图所示:此时显然不能直接使用gitreset命令将HEAD指针重置为commitA,因为commitC是正确的,需要保留。先回滚提交C和批次B,然后使用cherry-pick命令从提交C''重新生成提交C'',从而完成回滚提交B的需要。完整流程如下:本文已授权转载自公众号《良序Linux》。世界500强外企Linux开发工程师梁旭,在公众号分享大量Linux干货,欢迎关注!
