《Git权威指南》读书笔记 第七章 Git重置

提交能够经过对父提交的关联实现对提交历史的追溯。能够使用下面的命令对提交进程追溯: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>命令时改变的缓存区。

第二种用法则会重置引用。根据不一样的选项能够对暂存区或工做区进行重置:

  • 使用--hard参数会同时修改工做区、暂存区和版本库;
  • 使用--soft参数只会替换版本库的引用,不改变暂存区和工做区;
  • 使用--mixed或不使用参数(--mixed是默认的),会改变版本库引用的指向和重置暂存区,不改变工做区;
相关文章
相关标签/搜索