想成为Git大神?从学会reset开始
大家好,今天我们来着重介绍一个非常关键的功能就是reset。在上一篇文章介绍修改历史记录的时候曾经提到过,当我们需要拆分一个历史提交记录的时候需要使用reset。估计很多小伙伴不明白,reset究竟做了什么,所以在这篇文章当中我们来详细聊聊。
git reset功能整体的操作分为三个步骤,我们拆分开来详细介绍。
第一步(移动指针)
虽然reset有三个步骤,但是我们通过加入不同的参数,可以实现在不同的步骤退出。但是不管怎么操作,第一步都是一定会执行的。
reset的第一步就是移动HEAD指针,HEAD指针我们都知道就是当前的工作目录的指针。说到移动指针,我们可能会想起checkout,checkout的功能就是移动指针。我们不仅可以移动到另外的分支,也可以移动到之前某一次的提交记录。
这是我们这个git专题的目录,如果我们执行git checkout bee9ce,那么我们的工作目录会被重置到这个提交之后的状态。而最新的add article 17这个commit的所有改动都会不可见,就好像发生了时间倒流一样,我们回到了刚刚commit完add new articles的状态。
reset虽然也一样是移动HEAD指针,但是它对于移动之后的处理不同。reset之后我们的commit不是不可见而是被回滚了。
我们来做个实验,现在我们在目录当中创建一个test.txt文件,我们把它commit。
然后我们执行git reset --soft HEAD~。
这里的HEAD~我们应该都了解了,HEAD表示当前位置,~表示前一个位置。所以连起来就是表示reset到HEAD之前的一个提交。soft参数表示我们reset的时候只执行第一个步骤,也就是移动指针的步骤。
reset之后我们发现test.txt这个文件并没有消失,仍然还在暂存区当中,只不过还没有被commit。这就是reset回滚commit的操作,它不会把改动抹除,但是会把commit取消。
第二步(更新暂存区)
如果我们在reset的时候加上了--soft的参数,它会在执行第一步结束之后就退出,后面的第二步和第三步都不会执行。
如果想要执行第二步,我们可以不传任何参数,或者是指定--mixed。因为reset的默认参数就是--mixed。
第二个步骤是更新暂存区,前面我们看见了,如果只是移动指针,那么在移动的时候会把中间的commit全部取消。虽然这些提交被取消了,但是它们对应的改动仍然存在,并且一样存放在暂存区当中,相当于执行完git add之后的状态。
如果我们继续执行第二步,git会把暂存区也给重置,回到git add之前的状态。
如上图所示,我们执行了git reset HEAD~之后再执行git status可以看到test.txt回到了被add之前的状态。
第三步(回滚修改)
reset的最后一步是回滚修改,也就是在第二步的基础上,进一步把改动全部抹除,回滚到没有修改之前的状态。如果需要实现这一点,需要加上--hard参数。
这是一个非常危险的操作,它不仅会回滚已经被commit的所有改动,并且还会强制覆盖当前工作区,所有没有被提交的改动也一样会消失。只要是提交了的改动,即使reset了,也可以通过reflog找回来,但是如果没有提交的就没有办法了,所有的改动都会消失。对于开发者来说,这是一个巨大的打击,一定要切记慎重。
最后我们简单总结一下reset的用法。
git reset --soft,只会回滚commit操作,所有的改动都会保留在暂存区。相当于回到了执行git commit之前。
git reset --mixed,不仅会回滚commit操作,也会回滚暂存区内的内容。相当于回到了执行git add之前。
git reset --hard,会回滚一切,重置工作区。相当于回到了改动之前,没有被commit的内容会丢失。
reset是一个很好用的功能,使用熟练可以起到非常大的作用,实现一些炫酷的功能。但是它也有很大的隐患,如果一不小心使用了--hard可能会导致一些悲剧发生。我就有过几次不小心把刚写完的代码回滚了的经历,所以大家在使用的时候一定要千万小心。