git reset的讲解
分支游标 master
我们仔细了解一下 git 的分支管理,就可以知道,其实 git 的所有管理都是通过 commit id 实现的,我们常用的 HEAD, master 以及分支名其实都只是代表的一个 commit id 而已,只不过是为了方便我们的记忆以比较 human
的方式表示。master 以及其他的 分支名对应的 commit id都存放在 .git/refs/heads 目录下,远程分支名存放在 .git/refs/remotes 目录下。
基本的三种reset 命令
首先讲三条不同参数下 reset 的命令,然后做一下个人的总结:
git reset –hard commit-id
这条命令是最凶狠的,这条命令会将游标指向 commit-id指向的那次提交,并且暂存区也会更新到指定的那次提交时的内容,更狠的是暂存区的内容也会被覆盖。
git reset –mixed commit-id
OK,这条命令没那么厉害,仓库和暂存区指向都会改变,不过工作区的内容不会改变。这也是默认的参数,–mixed可以不写。
git reset –soft commit-id
这条命令是最弱的,只会改变仓库的游标。
我们在使用reset的时候需要很小心,因为在使用了reset命令之后,我们的游标就发生了变化,而我们使用 git log 时则找不到之前最新修改的 commit id, 即表示我们回不到最新的修改了,特别是如果使用了 –hard 参数,则真的就无力回天了。(实际上通过其他的途径也可以找到这个commit id,下面会讲到一种方法)
用 reflog 挽救错误的重置
我们在上面说过用 reset 命令会导致通过 git log命令找不到 commit-id 的问题,这里提供了一种挽救的机制(但是再次重申一下,如果是使用了–hard 参数,则丢失的修改是怎么也找不回来的,只能节哀了)reflog。
cat .git/logs/refs/heads/master (我们这里以master作为分析,对应哪一条分支就找相应的分支路径)的内容,我们可以看到如下的一些内容
712c0af3a20d370417b2af9a1dc4cb69d457a32b dcc27a803507baa3bf84832134c2def2589b4d1f xiongxing <xiongxing@oppo.com> 1427540691 +0800 pull: Fast-forward
dcc27a803507baa3bf84832134c2def2589b4d1f 712c0af3a20d370417b2af9a1dc4cb69d457a32b xiongxing <xiongxing@oppo.com> 1427541028 +0800 reset: moving to HEAD^
712c0af3a20d370417b2af9a1dc4cb69d457a32b dcc27a803507baa3bf84832134c2def2589b4d1f xiongxing <xiongxing@oppo.com> 1427544280 +0800 pull origin: Fast-forward
dcc27a803507baa3bf84832134c2def2589b4d1f 712c0af3a20d370417b2af9a1dc4cb69d457a32b xiongxing <xiongxing@oppo.com> 1427549639 +0800 reset: moving to HEAD^
712c0af3a20d370417b2af9a1dc4cb69d457a32b c6c5d37b13d8bfc112ccfbf3a06353c5a1d136c0 xiongxing <xiongxing@oppo.com> 1427549663 +0800 reset: moving to HEAD^^
c6c5d37b13d8bfc112ccfbf3a06353c5a1d136c0 dcc27a803507baa3bf84832134c2def2589b4d1f xiongxing <xiongxing@oppo.com> 1427549710 +0800 reset: moving to dcc27a803507baa3bf84832134c2def2589b4d1f
不难看出的是这个文件的内容记录了我们的每一次提交 commit-id 的变迁,第一列表示的是上一次提交的id,第二列表示的是操作后的id,如果我们知道之前的head对应的是哪一种,那么就可以非常容易地回到开始的位置。
另一种方式,通过 git reflog
命令也可以打印出该文件的内容,并且显示方式更加友好,如果用git reflog show <分支名>
,则可以显示出具体分支的改动。
xing@ubuntu-15-121:~/work/GitTest/HelloWorld$ git reflog show master
3de57a5 master@{0}: reset: moving to HEAD@{2}
54c93a8 master@{1}: commit: add another line
6c16b56 master@{2}: reset: moving to HEAD^^
3de57a5 master@{3}: commit: add third line
109e443 master@{4}: commit: add second line
6c16b56 master@{5}: reset: moving to HEAD^
9eca0a6 master@{6}: commit: fifth file
6c16b56 master@{7}: reset: moving to HEAD^
2dfaece master@{8}: commit: delete all files
6c16b56 master@{9}: reset: moving to HEAD^
65cd018 master@{10}: commit: add second line
6c16b56 master@{11}: commit (initial): first add 1 2 3 4
并且使用 git reset master@{n} (n为上面数字中的一个)就可以回到对应的修改处。
git reset 的第二种用法
- git reset [-q] [<commit>] [–] <path>…
这种用法和上面介绍的用法的区别在于,这种用法可以在命令中包含路径。并且不会重置引用,更不会改变工作区,而只是用指定提交状态()下的文件()替换掉暂存区中的文件。
注意,这条命令是替换暂存区中的文件,工作区和仓库中的文件不会受到影响。-q 是表示
quiet
,只显示出错的信息。