提交能够经过对父提交的关联实现对提交历史的追溯。能够使用下面的命令对提交进程追溯:git
$ git log --graph --oneline * 326f237 which version checked in? * 32d79d5 who does commit? * 4f804c3 initialized.
7.1 分支游标master缓存
当有新的提交发生时,文件.git/refs/head/master的内容如何改变?this
首先建立一个新文件,提交到版本库中:3d
$ touch new-commit.txt $ git add new-commit.txt $ git commit -m "does master follow this new commit?" [master 1ce417a] does master follow this new commit? 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 new-commit.txt
而后查看版本库引用空间下master文件的内容:日志
$ cat .git/refs/heads/master 1ce417a21fcd936e333db5f56a79a04ae2785a08
再用git log 查看提交日志:code
$ git log --graph --oneline * 1ce417a does master follow this new commit? * 326f237 which version checked in? * 32d79d5 who does commit? * 4f804c3 initialized.
能够看到master文件内容发生了改变,指向了新的提交。进程
引用refs/heads/master像是一个游标,在有新的提交发生的时候指向新的提交。Git提供了git reset命令,能够将游标指向任意一个存在的提交ID。it
$ git reset --hard HEAD^ HEAD is now at 326f237 which version checked in?
查看master文件的内容,已经发生了更改:io
$ cat .git/refs/heads/master 326f2370369566e4cacc4c149e612adaba378716
查看demo目录的内容发现新提交的new-commit.txt文件丢失了:ast
$ ls welcome.txt
git reset --hard参数会重置版本库、暂存区和工做区。
重置命令不只能够重置到前一次提交,并且还能够直接使用提交ID重置到任何一次提交:
$ git log --graph --oneline * 326f237 which version checked in? * 32d79d5 who does commit? * 4f804c3 initialized. $ git reset --hard 4f804c3 HEAD is now at 4f804c3 initialized. $ cat welcome.txt Hello $ git log commit 4f804c3948640ce146e48f0ff7c4d4592693df87 Author: ivanjz93 <ivanjz93@163.com> Date: Wed Jul 13 11:13:10 2016 +0800 initialized.
使用重置命令很危险,会完全丢弃历史。不能经过浏览提交历史的办法找到丢弃的提交ID再用重置命令恢复历史。由于重置让提交历史也发生了改变。
7.2 用reflog挽救错误的重置
Git提供了挽救机制,经过.git/logs目录下日志文件记录了分支的变动。默认非裸版本库(带有工做区)都提供分支日志功能,由于带有工做区的版本库都有以下设置:
$ git config core.logallrefupdates true
查看master分支的日志文件.git/logs/refs/heads/master文件最后5行的内容:
$ tail -5 .git/logs/refs/heads/master 76491e8212a2ddb2684565621c89d6ad3c968a1d 32d79d5cf6e6eac8c95b7978588e4f9db3139a45 jiangzhi <ivanjz93@163.com> 1468585955 +0800 commit (amend): who does commit? 32d79d5cf6e6eac8c95b7978588e4f9db3139a45 326f2370369566e4cacc4c149e612adaba378716 jiangzhi <ivanjz93@163.com> 1468591788 +0800 commit: which version checked in? 326f2370369566e4cacc4c149e612adaba378716 1ce417a21fcd936e333db5f56a79a04ae2785a08 jiangzhi <ivanjz93@163.com> 1468792789 +0800 commit: does master follow this new commit? 1ce417a21fcd936e333db5f56a79a04ae2785a08 326f2370369566e4cacc4c149e612adaba378716 jiangzhi <ivanjz93@163.com> 1468793836 +0800 reset: moving to HEAD^ 326f2370369566e4cacc4c149e612adaba378716 4f804c3948640ce146e48f0ff7c4d4592693df87 jiangzhi <ivanjz93@163.com> 1468794293 +0800 reset: moving to 4f804c3
能够看出这个文件记录了master分支指向的变迁。第一列是变化前指向的ID,第二列是变化后指向的ID。
git reflog命令对这个文件进行操做。使用show子命令能够显示此文件的内容:
$ git reflog show master | head -5 4f804c3 master@{0}: reset: moving to 4f804c3 326f237 master@{1}: reset: moving to HEAD^ 1ce417a master@{2}: commit: does master follow this new commit? 326f237 master@{3}: commit: which version checked in? 32d79d5 master@{4}: commit (amend): who does commit?
git reflog show和查看日志文件的输出最大的不一样在于显示顺序,git reflog把最新改变放在了最前面显示。输出的第二列的格式为<refname>@{<n>},意思是引用refname以前第n此改变。
这样将引用master切换到两次变动以前的值,能够使用下面的命令:
$ git reset --hard master@{2} HEAD is now at 1ce417a does master follow this new commit? $ ls new-commit.txt welcome.txt $ git log --oneline 1ce417a does master follow this new commit? 326f237 which version checked in? 32d79d5 who does commit? 4f804c3 initialized. $ git reflog show master | head -5 1ce417a master@{0}: reset: moving to master@{2} 4f804c3 master@{1}: reset: moving to 4f804c3 326f237 master@{2}: reset: moving to HEAD^ 1ce417a master@{3}: commit: does master follow this new commit? 326f237 master@{4}: commit: which version checked in?
查看工做区目录new-commit.txt文件又回来了;提交历史也回来了。
7.3 git reset命令详解
git reset的命令的用法:
用法一:git reset [-q] [<commit>] [--] <paths> ... 用法二:git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
命令中的<commit>是可选项,能够使用引用或者提交ID,若是省略它则至关于使用了HEAD的指向做为提交ID。
第一种用法在命令中包含路径<paths>。为了不路径和引用同名而发生冲突,能够在<paths>前用两个连续的减号做为分隔。
第一种用法不会重置引用,更不会改变工做区,而是用指定自交状态(<commit>)下的文件(<paths>)替换掉暂存区中的文件。例如git reset HEAD <paths>至关于取消以前执行的git add <paths>命令时改变的缓存区。
第二种用法则会重置引用。根据不一样的选项能够对暂存区或工做区进行重置: