《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是默認的),會改變版本庫引用的指向和重置暫存區,不改變工做區;
相關文章
相關標籤/搜索