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