git stash命令

git stash命令用於將更改儲藏在髒工作目錄中。

使用語法

git stash list [<options>]
git stash show [<stash>]
git stash drop [-q|--quiet] [<stash>]
git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]
git stash branch <branchname> [<stash>]
git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
         [-u|--include-untracked] [-a|--all] [<message>]
git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
         [-u|--include-untracked] [-a|--all] [-m|--message <message>]]
         [--] [<pathspec>…​]]
git stash clear
git stash create [<message>]
git stash store [-m|--message <message>] [-q|--quiet] <commit>

描述

當要記錄工作目錄和索引的當前狀態,但想要返回到乾淨的工作目錄時,則使用git stash。 該命令保存本地修改,並恢復工作目錄以匹配HEAD提交。

這個命令所儲藏的修改可以使用git stash list列出,使用git stash show進行檢查,並使用git stash apply恢復(可能在不同的提交之上)。調用沒有任何參數的git stash相當於git stash save。 默認情況下,儲藏列表爲「分支名稱上的WIP」,但您可以在創建一個消息時在命令行上給出更具描述性的消息。

創建的最新儲藏存儲在refs/stash中; 這個引用的反垃圾郵件中會發現較舊的垃圾郵件,並且可以使用通常的reflog語法命名(例如,stash@{0}是最近創建的垃圾郵件,stash@{1}stash@{2.hours.ago}之前也是可能的)。也可以通過指定存儲空間索引(例如整數n相當於儲藏stash@{n})來引用鎖存。

示例

以下是一些示例 -

1.拉取到一棵骯髒的樹

當你處於某種狀態的時候,你會發現有一些上游的變化可能與正在做的事情有關。當您的本地更改不會與上游的更改衝突時,簡單的git pull將讓您向前。

但是,有些情況下,本地更改與上游更改相沖突,git pull拒絕覆蓋您的更改。 在這種情況下,您可以將更改隱藏起來,執行git pull,然後解壓縮,如下所示:

 git pull
 ...
file foobar not up to date, cannot merge.
$ git stash
$ git pull
$ git stash pop

2.工作流中斷

當你處於某種狀態的時候,比如你的老闆進來,要求立即開會或處理非常緊急的事務。 傳統上,應該提交一個臨時分支來存儲您的更改,並返回到原始(original)分支進行緊急修復,如下所示:

# ... hack hack hack ...
$ git checkout -b my_wip
$ git commit -a -m "WIP"
$ git checkout master
$ edit emergency fix # 編輯內容
$ git commit -a -m "Fix in a hurry"
$ git checkout my_wip
$ git reset --soft HEAD^
# ... continue hacking ...

上面過程可以使用git stash來簡化上述操作,如下所示:

# ... hack hack hack ...
$ git stash
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
$ git stash pop
# ... continue hacking ...

3.測試部分提交

當要從工作樹中的更改中提交兩個或多個提交時,可以使用git stash save --keep-index,並且要在提交之前測試每個更改:

# ... hack hack hack ...
$ git add --patch foo            # add just first part to the index
$ git stash save --keep-index    # save all other changes to the stash
$ edit/build/test first part
$ git commit -m 'First part'     # commit fully tested change
$ git stash pop                  # prepare to work on all other changes
# ... repeat above five steps until one commit remains ...
$ edit/build/test remaining parts
$ git commit foo -m 'Remaining parts'

4.恢復被錯誤地清除/丟棄的垃圾

如果你錯誤地刪除或清除了垃圾,就不能通過正常的安全機制來恢復。 但是,您可以嘗試以下命令來獲取仍在存儲庫中但仍無法訪問的隱藏列表:

git fsck --unreachable |
grep commit | cut -d\  -f3 |
xargs git log --merges --no-walk --grep=WIP

5.儲藏你的工作

爲了演示這一功能,可以進入你的項目,在一些文件上進行工作,有可能還暫存其中一個變更。如果運行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 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 來重新應用儲藏,同時立刻將其從堆棧中移走。

6.取消儲藏

在某些情況下,可能想應用儲藏的修改,在進行了一些其他的修改後,又要取消之前所應用儲藏的修改。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

7.從儲藏中創建分支

如果儲藏了一些工作,暫時不去理會,然後繼續在你儲藏工作的分支上工作,在重新應用工作時可能會碰到一些問題。如果嘗試應用的變更是針對一個在那之後修改過的文件,會碰到一個歸併衝突並且必須去化解它。如果你想用更方便的方法來重新檢驗儲藏的變更,可以運行 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)