7.2 用reflog挽救错误的重置

如果没有记下重置前master分支指向的提交ID,想要重置回原来的提交似乎是一件麻烦的事情(去对象库中一个一个地找)。幸好Git提供了一个挽救机制,通过.git/logs目录下日志文件记录了分支的变更。默认非裸版本库(带有工作区)都提供分支日志功能,这是因为带有工作区的版本库都有如下设置:


$git config core.logallrefupdates

true


查看一下master分支的日志文件.git/logs/refs/heads/master中的内容。下面的命令显示了该文件的最后几行。为了排版的需要,还将输出中的40位的SHA1提交ID缩短。


$tail-5.git/logs/refs/heads/master

dca47ab a0c641e Jiang Xin<…>1290999606+0800commit(amend):who does commit?

a0c641e e695606 Jiang Xin<…>1291022581+0800commit:which version checked in?

e695606 4902dc3 Jiang Xin<…>1291435985+0800commit:does master follow…

4902dc3 e695606 Jiang Xin<…>1291436302+0800HEAD^:updating HEAD

e695606 9e8a761 Jiang Xin<…>1291436382+08009e8a761:updating HEAD


可以看出这个文件记录了master分支指向的变迁,最新的改变追加到文件的末尾,因此最后出现。最后一行可以看出因为执行了git reset—hard命令,指向的提交ID由e695606改变为9e8a761。

Git提供了一个git reflog命令,对这个文件进行操作。使用show子命令可以显示此文件的内容。


$git reflog show master|head-5

9e8a761 master@{0}:9e8a761:updating HEAD

e695606 master@{1}:HEAD^:updating HEAD

4902dc3 master@{2}:commit:does master follow this new commit?

e695606 master@{3}:commit:which version checked in?

a0c641e master@{4}:commit(amend):who does commit?


查看git reflog的输出和直接查看日志文件最大的不同在于显示顺序的不同,即最新改变放在了最前面显示,而且只显示每次改变的最终的SHA1哈希值。还有个重要的区别在于git reflog命令的输出中还提供了一个方便易记的表达式:<refname>@{<n>}。这个表达式的含义是引用<refname>之前第<n>次改变时的SHA1哈希值。

那么将引用master切换到两次变更之前的值,可以使用下面的命令。

重置master为两次改变之前的值。


$git reset—hard master@{2}

HEAD is now at 4902dc3 does master follow this new commit?


重置后工作区中的文件new-commit.txt又回来了。


$ls

new-commit.txt welcome.txt


提交历史也回来了。


$git log—oneline

4902dc3 does master follow this new commit?

e695606 which version checked in?

a0c641e who does commit?

9e8a761 initialized.


此时如果再用git reflog查看,会看到恢复master的操作也记录在日志中了。


$git reflog show master|head-5

4902dc3 master@{0}:master@{2}:updating HEAD

9e8a761 master@{1}:9e8a761:updating HEAD

e695606 master@{2}:HEAD^:updating HEAD

4902dc3 master@{3}:commit:does master follow this new commit?

e695606 master@{4}:commit:which version checked in?