咱们知道git在初始化时,会为咱们默认建立一个master分支,那这个master究竟是什么呢?其实它在.git目录下对应了一个引用文件-----.git/refs/heads/master文件,而该文件的内容即是该分支中最新的一次提交的ID:git
$ cat .git/refs/heads/master 22f8aae534916e1174711f138573acfbb47e489c $ git cat-file -t 22f8aae commit $ git log --oneline 22f8aae git ignore file added. 4e79a0b Rename third to third.txt 46ae7e3 remove branch_first.txt file from master branch 55d1e70 branch first file 545a382 Merge commit '35bbd32'
当咱们用以上查看master文件内容时,发现它果真记录了最新一次的提交。了解了这个前提,那咱们来分析下git reset到底作了什么?shell
以上面的例子为基础咱们来探讨reset命令的魔力,首先咱们来执行一个reset命令,reset到上一次提交3d
$ git reset --hard HEAD^ HEAD is now at 4e79a0b Rename third to third.txt Quadrangle@QUADRANGLE-PC /d/GitRepo/GitOne (master) $ git log --oneline 4e79a0b Rename third to third.txt 46ae7e3 remove branch_first.txt file from master branch 55d1e70 branch first file 545a382 Merge commit '35bbd32'
HEAD^的意思就是最新一次提交的父提交,reset后,咱们看一下提交日志,发现最新一次提交没了。到底git作了什么呢?咱们还能找回最新的一次提交吗?日志
回答上面两个问题,就用到上面就到的master引用文件了,这是咱们再看一下这个文件的内容有什么变化?code
$ cat .git/refs/heads/master 4e79a0ba92f1ae63dc661e29343fa0c369ca480d
发现了吧,里面记录了reset后的最后一次提交。这时或许咱们有所觉察了。先不急着下结论,咱们看怎么回到最新的提交呢?其实reset后,git没有删除最新提交的相关信息,包括目录树,所以只要咱们记住提交ID,即可以从新reset回来:图片
$ git reset --hard 22f8aae HEAD is now at 22f8aae git ignore file added. $ git log --oneline 22f8aae git ignore file added. 4e79a0b Rename third to third.txt 46ae7e3 remove branch_first.txt file from master branch 55d1e70 branch first file 545a382 Merge commit '35bbd32'
这样查看log,发现最新提交又回来了。可是若是咱们忘了最新提交ID 怎么办呢?好办,reflog命令能够最总引用变动的记录:rem
Quadrangle@QUADRANGLE-PC /d/GitRepo/GitOne (master) $ git reflog 22f8aae HEAD@{0}: reset: moving to 22f8aae 4e79a0b HEAD@{1}: reset: moving to HEAD^ 22f8aae HEAD@{2}: reset: moving to 22f8aae 4e79a0b HEAD@{3}: reset: moving to HEAD^
咱们能够找到前面任意操做的记录,而且能够reset到任意提交。it
以前咱们看到了reset后master文件的内容发生了变化,其实这就是reset命令的本质,但结合不一样的参数,会有额外的工做:如--hard --soft --mixed等,他们决定了是否重置暂存区或工做区。ast
咱们来看下面图片class
其实reset命令有两种用法:
git reset [-q] [commit] [--] <paths>
git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
第一种用法是不会重置引用的,即不会修改master文件。只是用某一次提交的文件提交暂存区的文件
第二种用法不使用<paths> 则会重置引用,而且参数不一样决定是否覆盖暂存区和工做区:
--hard参数会执行途中1,2,3 所有动做,即暂存区,工做区所有用指定提交版本的目录树替换掉
--soft 参数只执行1, 不进行暂存区和工做区的覆盖
--mixed或不使用参数,执行1,2覆盖暂存区,但不覆盖工做区
这样一来相信对reset的理解会用更深入的理解了吧。
图片来源:机械工业出版社,蒋鑫 《Git权威指南》