《Git權威指南》讀書筆記 第九章 恢復進度

9.1 恢復保存的進度git

查看第五章保存的進度:app

$ git stash list
stash@{0}: WIP on master: 326f237 which version checked in?

恢復進度:測試

$ git stash pop
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   a/b/c/hello.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   welcome.txt

Dropped refs/stash@{0} (eca70a6e0ecccaddf3641263eb341c4541779ae9)

查看工做區狀態,進度已經找回了:ui

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   a/b/c/hello.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   welcome.txt

對找回進度的工做區作如下處理:3d

(1)對當前的暫存區進行提交:日誌

$ git commit -m "add new file: a/b/c/hello.txt, but leave welcome.txt alone"
[master 9e5eaa3] add new file: a/b/c/hello.txt, but leave welcome.txt alone
 1 file changed, 2 insertions(+)
 create mode 100644 a/b/c/hello.txt

$ git status -s
 M welcome.txt

(2)撤銷以前的提交,工做區和暫存區的狀態也都維持在原來的狀態:code

$ git reset --soft HEAD^

$ git log -1 --pretty=oneline
0463e7ae492200b77525642fb77d8f8fa03913c1 Merge commit '64cc27237'

$ git status -s
A  a/b/c/hello.txt
 M welcome.txt

(3)將welcome.txt的修改提交到暫存區:開發

$ git add welcome.txt

$ git status -s
A  a/b/c/hello.txt
M  welcome.txt

(4)將a/b/c/hello.txt撤出暫存區:rem

$ git reset HEAD a/b/c

$ git status -s
M  welcome.txt
?? a/

(5)將全部內容存暫存區中撤出:it

$ git reset
Unstaged changes after reset:
M       welcome.txt

(6)清除welcome.txt個改動:

$ git checkout -- welcome.txt

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

        a/

nothing added to commit but untracked files present (use "git add" to track)

(7)刪除目錄a,刪除本地多餘的目錄和文件,可使用git clean命令。先運行測試命令查看哪些文件和目錄會被刪除以避免形成誤刪:

$ git clean -nd
Would remove a/

使用-f參數強制刪除文件和目錄:

$ git clean -fd
Removing a/

9.2 git stash命令

一、git stash

保存當前的工做進度,會分別對暫存區和工做區的狀態進行保存;

二、git stash list

顯示進度列表。

三、git stash pop [--index] [<stash>]

若是不使用任何參數,會恢復最新保存的工做進度,並將恢復的工做進度從存儲的工做進度列表中清除。

若是提供<stash>參數(來自於git stash list顯示的列表),則從該<stash>中恢復。恢復完畢也將從進度列表中刪除<stash>。

若是帶有選項--index除了恢復工做區的文件外,還嘗試恢復暫存區。

四、git stash [save [--patch] [-k|--[no-] keep-index] [-q|--quiet] [<message>] ]

這條命令其實是第一條git stash命令的完整版。若是須要在保存進度的時候添加說明,必須使用以下格式:

git stash save "message..."

使用參數--patch會顯示工做區和HEAD的差別,經過對差別文件的編輯決定在進度中最終要保存的工做區的內容,經過編輯差別文件能夠在進度中排除無關內容。

使用-k或--keep-index參數,在保存進度後不會將暫存區重置。默認會將暫存區和工做區強制重置。

五、git stash apply [--index] [<stash>]

除了不刪除恢復的進度以外,其他和git stash pop命令同樣。

六、git stash drop [<stash>]

刪除一個存儲的進度。默認刪除最新的進度。

七、git stash clear

刪除全部存儲的進度。

八、git stash branch <branchname> <strach>

基於進度建立分支。

9.3 git stash深刻

在執行git stash命令時,Git實際調用了一個腳本文件實現相關的功能,這個腳本的文件名是git-stash。使用下面的命令查看git-stash的安裝位置:

$ git --exec-path
C:\Program Files\Git\mingw64/libexec/git-core

這個目錄下包含了Git命令腳本,最初這些命令都是用Shell或Perl腳本語言開發的,在Git發展中一些對運行效率要求高的命令用C語言改寫。在Git 1.7.4版本以前git-stash仍是使用Shell腳本開發的。

查看當前的進度保存列表是空的:

$ git stash list

在工做區作一些改動:

$ echo Bye-Bye. >> welcome.txt

$ echo hello. > hack-1.txt

$ git add hack-1.txt

$ git status -s
A  hack-1.txt
 M welcome.txt

執行git stash保存工做進度:

$ git stash save "hack-1: hacked welcome.txt, newfile hack-1.txt"
Saved working directory and index state On master: hack-1: hacked welcome.txt, newfile hack-1.txt
HEAD is now at 0463e7a Merge commit '64cc27237'

$ git status -s

$ ls
detached-commit.txt  new-commit.txt  welcome.txt

保存完成後工做區恢復了修改前的原貌(實際上用了git reset --hard HEAD命令),文件welcome.txt的修改不見了,文件hack-1.txt整個不見了。

再作一個修改,並嘗試保存進度:

$ echo fix. > hack-2.txt

$ git stash
No local changes to save

進度保存失敗。可見暫存區沒有更新不能保存進度。

執行添加操做後再執行git stash命令:

$ git add hack-2.txt

$ git stash
Saved working directory and index state WIP on master: 0463e7a Merge commit '64cc27237'
HEAD is now at 0463e7a Merge commit '64cc27237'

工做區又恢復了原狀。查看進度保存狀況:

$ git stash list
stash@{0}: WIP on master: 0463e7a Merge commit '64cc27237'
stash@{1}: On master: hack-1: hacked welcome.txt, newfile hack-1.txt

每一個進度的標識都是stash@[<n>]格式,與reflog的格式很類似。實際上,git stash就是用前面介紹的引用和引用變動日誌(reflog)來實現的。有關進度的文件:

$ ls -l .git/refs/stash .git/logs/refs/stash
-rw-r--r-- 1 x250 197121 360 七月 18 21:45 .git/logs/refs/stash
-rw-r--r-- 1 x250 197121  41 七月 18 21:45 .git/refs/stash

使用git reflog能夠查看進度狀況:

$ git reflog show refs/stash
04cae38 refs/stash@{0}: WIP on master: 0463e7a Merge commit '64cc27237'
43f13c7 refs/stash@{1}: On master: hack-1: hacked welcome.txt, newfile hack-1.txt

對照git reflog的結果和前面git stash list的結果,能夠確定git stash保存進度,實際上會將進度保存在引用refs/stash所指向的提交中。屢次的進度保存,實際上至關於引用refs/stash一次又一次的變化(refs/stash只記錄一次進度的ID),而refs/stash引用的變化由reflog(.git/logs/refs/stash)所記錄下來。

如何在引用refs/stash中同時保存暫存區的進度和工做區中的進度?

查看引用refs/stash的提交歷史:

$ git log --graph --pretty=raw refs/stash -2
*   commit 04cae38d64c6c6cc7e7421c08349c8a3b75ae7dd
|\  tree 7032578d4dd41c43b4e62c8806e4b7ad3f9a54e6
| | parent 0463e7ae492200b77525642fb77d8f8fa03913c1
| | parent de586678f3ac0d423a469b6e26968741b6e46344
| | author jiangzhi <ivanjz93@163.com> 1468849531 +0800
| | committer jiangzhi <ivanjz93@163.com> 1468849531 +0800
| |
| |     WIP on master: 0463e7a Merge commit '64cc27237'
| |
| * commit de586678f3ac0d423a469b6e26968741b6e46344
|/  tree 7032578d4dd41c43b4e62c8806e4b7ad3f9a54e6
|   parent 0463e7ae492200b77525642fb77d8f8fa03913c1
|   author jiangzhi <ivanjz93@163.com> 1468849531 +0800
|   committer jiangzhi <ivanjz93@163.com> 1468849531 +0800
|
|       index on master: 0463e7a Merge commit '64cc27237'

從提交歷史中能夠看到進度保存的最新提交時一個合併提交。最新的提交說明中有WIP字樣(Work In Proress),表明了工做區進度。最新提交的第二個父提交有index on master標記,說明這個提交表明暫存區的進度。

但提交歷史中的兩個提交都指向了同一個樹,這是由於最後一次作進度保存時工做區相對暫存區沒有改變。

第一次進度的保存工做區、暫存區和版本庫的各不相同。第一次進度保存可使用reflog中的語法,即用refs/stash@{1}來訪問,也能夠簡寫成stash@{1}。

$ git log --graph --pretty=raw stash@{1} -3
*   commit 43f13c7c4b13f480032c64b9375f97d16931ba35
|\  tree 3cd11ce48979a5f97e28304b1237cfb6d4a8cf7e
| | parent 0463e7ae492200b77525642fb77d8f8fa03913c1
| | parent 7b3bef783f4d0900b185c4ba4b33646a1090660a
| | author jiangzhi <ivanjz93@163.com> 1468831199 +0800
| | committer jiangzhi <ivanjz93@163.com> 1468831199 +0800
| |
| |     On master: hack-1: hacked welcome.txt, newfile hack-1.txt
| |
| * commit 7b3bef783f4d0900b185c4ba4b33646a1090660a
|/  tree 9c34579bf4f5504b9b0376097814d5c1cdb8bbdc
|   parent 0463e7ae492200b77525642fb77d8f8fa03913c1
|   author jiangzhi <ivanjz93@163.com> 1468831198 +0800
|   committer jiangzhi <ivanjz93@163.com> 1468831198 +0800
|
|       index on master: 0463e7a Merge commit '64cc27237'
|
*   commit 0463e7ae492200b77525642fb77d8f8fa03913c1
|\  tree ad4eca82e587a477b91a4f7bbfef97c7921e52cc
| | parent 1ce417a21fcd936e333db5f56a79a04ae2785a08
| | parent 64cc27237267d702e31e34fe0b75db97f5171001
| | author jiangzhi <ivanjz93@163.com> 1468822001 +0800
| | committer jiangzhi <ivanjz93@163.com> 1468822001 +0800
| |     Merge commit '64cc27237'

第一個表明保存時工做區的狀態(原工做區),第二個表明保存時暫存區的狀態(原暫存區),第三個表明保存時版本庫的狀態(原基線)。

用stash@{1}來恢復進度:

$ git stash apply stash@{1}
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   hack-1.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   welcome.txt

顯示進度列表,而後清空進度列表:

$ git stash list
stash@{0}: WIP on master: 0463e7a Merge commit '64cc27237'
stash@{1}: On master: hack-1: hacked welcome.txt, newfile hack-1.txt

$ git stash clear

清空後stash相關的引用和reflog被刪除了:

$ ls -l .git/refs/stash .git/logs/refs/stash
ls: cannot access '.git/refs/stash': No such file or directory
ls: cannot access '.git/logs/refs/stash': No such file or directory
相關文章
相關標籤/搜索