經常有這樣的事情發生,當你正在進行項目中某一部分的工作,里面的東西處于一個比較雜亂的狀態,而你想轉到其他分支上進行一些工作。問題是,你不想提交進行了一半的工作,否則以后你無法回到這個工作點。解決這個問題的辦法就是git stash命令。
“‘儲藏”“可以獲取你工作目錄的中間狀態——也就是你修改過的被追蹤的文件和暫存的變更——并將它保存到一個未完結變更的堆棧中,隨時可以重新應用。
## 儲藏你的工作
為了演示這一功能,你可以進入你的項目,在一些文件上進行工作,有可能還暫存其中一個變更。如果你運行 git status,你可以看到你的中間狀態:
~~~
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
#
# modified: lib/simplegit.rb
#
~~~
現在你想切換分支,但是你還不想提交你正在進行中的工作;所以你儲藏這些變更。為了往堆棧推送一個新的儲藏,只要運行 git stash:
~~~
$ git stash
Saved working directory and index state \
"WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
~~~
你的工作目錄就干凈了:
~~~
$ git status
# On branch master
nothing to commit, working directory clean
~~~
這時,你可以方便地切換到其他分支工作;你的變更都保存在棧上。要查看現有的儲藏,你可以使用 git stash list:
~~~
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
~~~
在這個案例中,之前已經進行了兩次儲藏,所以你可以訪問到三個不同的儲藏。你可以重新應用你剛剛實施的儲藏,所采用的命令就是之前在原始的 stash 命令的幫助輸出里提示的:git stash apply。如果你想應用更早的儲藏,你可以通過名字指定它,像這樣:git stash apply stash@{2}。如果你不指明,Git 默認使用最近的儲藏并嘗試應用它:
~~~
$ git stash apply
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
#
# modified: index.html
# modified: lib/simplegit.rb
#
~~~
你可以看到 Git 重新修改了你所儲藏的那些當時尚未提交的文件。在這個案例里,你嘗試應用儲藏的工作目錄是干凈的,并且屬于同一分支;但是一個干凈的工作目錄和應用到相同的分支上并不是應用儲藏的必要條件。你可以在其中一個分支上保留一份儲藏,隨后切換到另外一個分支,再重新應用這些變更。在工作目錄里包含已修改和未提交的文件時,你也可以應用儲藏——Git 會給出歸并沖突如果有任何變更無法干凈地被應用。
對文件的變更被重新應用,但是被暫存的文件沒有重新被暫存。想那樣的話,你必須在運行 git stash apply 命令時帶上一個 --index 的選項來告訴命令重新應用被暫存的變更。如果你是這么做的,你應該已經回到你原來的位置:
~~~
$ git stash apply --index
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
#
# modified: lib/simplegit.rb
#
~~~
apply 選項只嘗試應用儲藏的工作——儲藏的內容仍然在棧上。要移除它,你可以運行 git stash drop,加上你希望移除的儲藏的名字:
~~~
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)
~~~
你也可以運行 git stash pop 來重新應用儲藏,同時立刻將其從堆棧中移走。
## 取消儲藏(Un-applying a Stash)
在某些情況下,你可能想應用儲藏的修改,在進行了一些其他的修改后,又要取消之前所應用儲藏的修改。Git沒有提供類似于 stash unapply 的命令,但是可以通過取消該儲藏的補丁達到同樣的效果:
`$ git stash show -p stash@{0} | git apply -R`
同樣的,如果你沒有指定具體的某個儲藏,Git 會選擇最近的儲藏:
`$ git stash show -p | git apply -R`
你可能會想要新建一個別名,在你的 Git 里增加一個 stash-unapply 命令,這樣更有效率。例如:
~~~
$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash apply
$ #... work work work
$ git stash-unapply
~~~
## 從儲藏中創建分支
如果你儲藏了一些工作,暫時不去理會,然后繼續在你儲藏工作的分支上工作,你在重新應用工作時可能會碰到一些問題。如果嘗試應用的變更是針對一個你那之后修改過的文件,你會碰到一個歸并沖突并且必須去化解它。如果你想用更方便的方法來重新檢驗你儲藏的變更,你可以運行 git stash branch,這會創建一個新的分支,檢出你儲藏工作時的所處的提交,重新應用你的工作,如果成功,將會丟棄儲藏。
~~~
$ git stash branch testchanges
Switched to a new branch "testchanges"
# On branch testchanges
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
#
# modified: lib/simplegit.rb
#
Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)
~~~
這是一個很棒的捷徑來恢復儲藏的工作然后在新的分支上繼續當時的工作。
- 1. 起步
- 1.1 關于版本控制
- 1.2 Git 簡史
- 1.3 Git 基礎
- 1.4 安裝 Git
- 1.5 初次運行 Git 前的配置
- 1.6 獲取幫助
- 1.7 小結
- 2. Git基礎
- 2.1 取得項目的 Git 倉庫
- 2.2 記錄每次更新到倉庫
- 2.3 查看提交歷史
- 2.4 撤消操作
- 2.5 遠程倉庫的使用
- 2.6 打標簽
- 2.7 技巧和竅門
- 2.8 小結
- 3. Git分支
- 3.1 何謂分支
- 3.2 分支的新建與合并
- 3.3 分支的管理
- 3.4 利用分支進行開發的工作流程
- 3.5 遠程分支
- 3.6 分支的衍合
- 3.7 小結
- 4. 服務器上的Git
- 4.1 協議
- 4.2 在服務器上部署 Git
- 4.3 生成 SSH 公鑰
- 4.4 架設服務器
- 4.5 公共訪問
- 4.6 GitWeb
- 4.7 Gitosis
- 4.8 Gitolite
- 4.9 Git 守護進程
- 4.10 Git 托管服務
- 4.11 小結
- 5. 分布式Git
- 5.1 分布式工作流程
- 5.2 為項目作貢獻
- 5.3 項目的管理
- 5.4 小結
- 6. Git工具
- 6.1 修訂版本(Revision)選擇
- 6.2 交互式暫存
- 6.3 儲藏(Stashing)
- 6.4 重寫歷史
- 6.5 使用 Git 調試
- 6.6 子模塊
- 6.7 子樹合并
- 6.8 總結
- 7. 自定義Git
- 7.1 配置 Git
- 7.2 Git屬性
- 7.3 Git掛鉤
- 7.4 Git 強制策略實例
- 7.5 總結
- 8. Git與其他系統
- 8.1 Git 與 Subversion
- 8.2 遷移到 Git
- 8.3 總結
- 9. Git 內部原理
- 9.2 Git 對象
- 9.3 Git References
- 9.4 Packfiles
- 9.5 The Refspec
- 9.6 傳輸協議
- 9.7 維護及數據恢復
- 9.8 總結
- 9.1 底層命令 (Plumbing) 和高層命令 (Porcelain)