git reset 和 git revert

Clloz · · 417次浏览 ·

前言

git中的撤销操作是我们经常要用到的操作,比如说当我们add某个文件到暂存区后可能想要撤回,或者是我们已经commit了但是push的时候想取消这次commit,这是主要是用git resetgit checkoutgit revert三个命令。

git reset

Git的分支本质上是指向提交对象的可变指针,比如master分支你多次提交后就会有一个指向最后一个提交对象的指针,每一个提交对象都包含一个指向上一个提交对象的指针,这就是git分支的本质。而如何确定我们当前在哪个分支上呢?git给出了一个特殊的HEAD指针,他指向当前所在的本地分支。比如说我们现在在master分支,我们知道master指针指向的是该分支的最后一个提交,而HEAD指针此时也指向该处,所以我们可以理解HEAD指针为当前所在分支的别名。如下图:
progit

理解了这些内容,我们就可以来理解git reset是如何工作的了。我们把git工作的空间分为两个区域:
1. 已经commit的文件和修改后未add的文件,这一类文件都在工作目录(Working Dictionary)
2. 已经add还未commit的文件在暂存区(Index)

还有一个Head指针指向当前所在分支的最后一次提交对象。比如上图中的HEAD和master指针本来是指向34ac2对象,此时f30ab对象正在暂存区,当f30ab提交完成以后,HEAD和master的指针就指向了新的提交,而34ac2则成为了最新提交的父节点。而我们的git reset指令就是操作HEAD指针,移动它的位置来实现撤销。下面我们用一个具体的例子来说明。

我们在一个空的git仓库中新建一个文件:file.txt。用vim编辑当前文件在当中输入字符串first,提交文件。此时我们用git log --decorate --oneline可以看到我们的master指针和HEAD指针都指向我们的第一次提交对象。
reset1

然后我们再次修改文件,在文件中加入字符串second,再次提交文件,调用上面的指令,我们会发现此时HEAD和master指针都指向我们的第二次提交。
reset2

再次重复上述操作,第三次修改提交。
reset3

此时我们的整个git树应该是这样的:
reset4

此时我们开始执行reset指令:
首先执行git reset --soft HEAD~: 我们发现HEAD和master指针指向了second,并且查看我们的file.txt文件,我们会发现文件中依然保持这第三次修改,只不过文件从已经commit的状态被重新拉到了缓存区,所以我们可以看出--soft下的指令只是向后倒退了一小步,把我们最后一个commit给取消了。
reset5

然后我们重新提交文件,让git状态重新进入到三次提交的状态。然后执行git reset HEAD~指令(这条指令没有加参数,其实有一个默认参数–mixed):执行完指令后,我们发现HEAD和master指针又是指向了我们的第二次提交对象,而我们的file文件依然没有改变,但是这次它从没有commit的状态变成了没有add的状态,我们可以看出--mixed--soft又向后倒退了一小步,把git状态回复到了我们刚刚修改完文件还没有加入暂存区的状态。
reset6

最后我们依然重新回到三次提交的状态然后执行git reset --hard HEAD~指令:我们发现这次HEAD和master指针依然是指向我们第二次的提交对象,我们检查git status发现没有任何状态,在查看file.txt,我们发现我们第三次的修改消失了,也就是说--hard指令把我们的状态直接从第三次提交完成回退到了第二次提交刚刚完成的状态,我们刚刚最后一次做的修改也消失了。

综合上面的测试,做一个总结:

  • --soft – 缓存区和工作目录都不会被改变
  • --mixed – 默认选项。缓存区和你指定的提交同步,但工作目录不受影响
  • --hard – 缓存区和工作目录都同步到你指定的提交

git revert

git revert我们用相同的方法进行测试,我们可以发现git revert并不是后退,而是把文件回到要回退的状态重新提交,如刚刚我们一共执行了三次提交,git revert HEAD~以后会将文件回复到第二次提交的状态,重新提交,也就变成了第四次提交,可见revert还是比较安全的,我们没有丢失任何历史记录,而reset将我们回滚的记录丢掉了。

需要注意的是,当revert同一个文件的时候会出现冲突,需要手动修改冲突,然后手动提交


Clloz

人生をやり直す

发表评论

电子邮件地址不会被公开。 必填项已用*标注

我不是机器人*

EA PLAYER &

历史记录 [ 注意:部分数据仅限于当前浏览器 ]清空

      00:00/00:00