
前言
在實際開發(fā)中,常常會遇到這樣的情況,我們正在 dev 上開發(fā)一個功能,這個時候突然接到上級命令,需要修改一個緊急 bug-5501 ,當(dāng)然我們馬上想到的就是創(chuàng)建一個 branch bug-5501 的分支來修復(fù)它,但是這個時候我們在 dev 上的功能已經(jīng)寫了一半了,如果我們直接創(chuàng)建分支,并 chekcout branch bug-5501 的話,我們在 dev 上的修改的內(nèi)容,也會顯示在我們 branch bug-5501 上,這樣就會讓我們感覺到非?;靵y。我們也不能提交我們未完成的功能到 dev 上,那這個時候怎么辦呢?
在Git中,為我們提供了 git stash 命令,專門負(fù)責(zé)處理這種情況。讓我們一起來了解該命令吧。
git stash 指令介紹
為了演示具體效果,這里以下面例子為例,我們在dev開發(fā)的新功能,修改了Person.java,具體如下所示:

這個時候我們運行git staus指令,可以看到倉庫狀態(tài):
$ git status
Your branch is up to date with 'origin/master'.
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: src/main/java/Person.java
如果直接在當(dāng)前 dev 分支上直接直接執(zhí)行命令 git branch bug-5501 ,那么我們我們修改的內(nèi)容也也會在 bug-5501 分支上,如下所示:

那現(xiàn)在我們想要創(chuàng)建一個新的分支 branch bug-5501 ,但是不想包括我們之前修改的 Person.java 中的內(nèi)容,那么我們可以使用 git stash 或 git stash save 指令。
xuwentaodeMacBook-Pro:GitPracticetest xuwentao$ git stash
Saved working directory and index state WIP on master: 3d1d704 添加了person類
xuwentaodeMacBook-Pro:GitPracticetest xuwentao$ git status
On branch master
Your branch is up to date with 'origin/master'.
這個時候再使用 git status ,查看我們的倉庫狀態(tài):
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
我們發(fā)現(xiàn),我們的倉庫狀態(tài)是干凈的。那這個時候我們在創(chuàng)建,并切換到相應(yīng)分支上,那這個時候其他的分支是不包含之前我們修改的內(nèi)容的,也就是如下圖所示:

在上圖中,從上往下分別為兩個步驟:
- 步驟1:在
dev分支上,我們調(diào)用git stashorgit stash save message命令。 - 步驟2:當(dāng)執(zhí)行了步驟1后,我們在接著創(chuàng)建分支
bug-5501,并切換到該分支下。
通過上述兩個步驟后,那現(xiàn)在我們就可以開心的在我們的bug-5501分支開發(fā)啦。
git stash 與 git stash save 的區(qū)別
-
git stash會將當(dāng)前的存儲內(nèi)容,自動添加一條描述信息,且描述信息為當(dāng)前分支上最后一次 commit 的 message 。 -
git stash save需要你指定 stash 的描述信息,比如這樣:git stash save "創(chuàng)建了一條記錄"。
需要注意的是,每次調(diào)用 git stash or git stash save 的記錄都是以棧的形式存儲的。查看 stash 記錄我們可以通過 git stash list 指令來查看:
xuwentaodeMacBook-Pro:GitPracticetest xuwentao$ git stash list
stash@{0}: on master: 添加了Woman類
stash@{1}: on master: 添加了Person類
在上述記錄中,最后提交的 stash 記錄始終在棧頂也就是stash@{0},該棧的角標(biāo)是從零開始逐級遞增,并且棧頂?shù)慕菢?biāo)始終為零。
刪除 stash 記錄
刪除特定的 stash 記錄,我們可以通過 git stash list 指令找到我們想要刪除的記錄,然后調(diào)用 git stash drop 指令就行了,如我們想刪除 stash@{0} 這條記錄:
xuwentaodeMacBook-Pro:GitPracticetest xuwentao$ git stash list
stash@{0}: WIP on master: 3d1d704 添加了person類
xuwentaodeMacBook-Pro:GitPracticetest xuwentao$ git stash drop stash@{0}
當(dāng)然,如果你想刪除所有的stash記錄,我們也可以通過 git stash clear 指令。
恢復(fù) stash 所存儲的內(nèi)容
如果這個時候我們修改了 bug-5501 ,現(xiàn)在我們想切換回我們之前的 dev 分支,并恢復(fù)之前我們調(diào)用 git stash or git stash save 所存儲的內(nèi)容,那現(xiàn)在我們該怎么操作呢?我們可以先通過 git stash list 找到我們想要恢復(fù)的stash記錄,然后通過使用 git stash apply 指令來恢復(fù)我們想要的內(nèi)容。這里我們以記錄 stash@{0} 為例:
xuwentaodeMacBook-Pro:GitPracticetest xuwentao$ git stash list
stash@{0}: WIP on master: 3d1d704 添加了person類
xuwentaodeMacBook-Pro:GitPracticetest xuwentao$ git stash apply stash@{0}
具體場景如下所示:

注意:當(dāng)你調(diào)用
git stash apply并不指定具體的stash記錄時,默認(rèn)會恢復(fù)棧頂?shù)膕tash記錄。也就是等同于git stash apply stash@{0}。
git stash save --keep-index
在上中我們已經(jīng)講解了如何使用stash并恢復(fù)等一系列操作,現(xiàn)在我們來講解在命令 git stash save 中的選填參數(shù), --keep-index,默認(rèn)情況下使用 git stash save 命令是不帶這個選項的,下面我們就看看這個參數(shù)的具體使用意義。
不添加 --keep-index

解釋一下上圖的流程:
- 上圖中我們在dev中開發(fā)新功能,
修改(modify)Person類,并新建(add)Woman.java 這個文件(該文件已經(jīng)被添加到暫存區(qū)了)。 - 這個時候上級命令我們改 bug-5501 ,這個時候,如果我們調(diào)用
git save stash命令,這個時候dev分支上就只會有沒有修改的Person類。Person 類的修改與 Woman.java 兩個更改都放入stash記錄棧中。 - 這個時候我們新建
bug-5501分支,去改我們的bug,當(dāng)我們修改bug完畢后,我們check out 到dev分支上來,并想恢復(fù)之前我們存儲的內(nèi)容,那么我們調(diào)用git stash apply時,之前我們修改的person 類與新建的 Woman.java 文件就又會回到我們的dev分支上。
添加 --keep-index
如果我們使用git stash meessage --keep-index,我們看看又是什么效果呢?,具體如下圖所示:

觀察上圖,我們會發(fā)現(xiàn),使用了--keep-index參數(shù)后,在stash記錄棧中是不會存儲 git add 命令已暫存的東西,也就是不會存儲 Woman.java 文件。
需要注意的是,當(dāng)我們使用
--keep-index參數(shù)時,因為不會stasht記錄棧中是不會存儲git add命令已暫存的東西,故如果我們創(chuàng)建新分支時,我們之前git add的文件也會在新分支中。是否添加該參數(shù),由大家需要而定。
IntelliJ IDEA or Android Sutdio 圖形化界面使用stash
了解了Git的存儲與清理的相關(guān)命令后,我們來了解一下,在 IntelliJ IDEAor Android Sutdio中Git存儲與清理的圖形化界面的對應(yīng)流程。雖然命令行非常牛逼,但是有時候我們也想偷個懶對吧。
創(chuàng)建 stash 流程
首先我們來看一下創(chuàng)建一個 stash 在 IntelliJ IDEA 中的流程,首先點擊鼠標(biāo)右鍵。依次選擇下圖中紅色箭頭所指內(nèi)容。

按照上圖的指示,依次點擊,我們能得到下圖:

上圖中:
- Keep index:就是創(chuàng)建 stash 時,是否添加
--keep-index參數(shù)。選中添加,反之不添加。 - Message:我們創(chuàng)建的stash的描述。
- Creat Stash:創(chuàng)建stash
如果你已經(jīng)熟悉了Git的創(chuàng)建 stash 的指令,我相信這里對你沒有什么難度啦。
清理 stash 流程
還是點擊鼠標(biāo)右鍵,依次選擇下圖中紅色箭頭所指內(nèi)容。

按照上圖的指示,依次點擊,我們能得到下圖:

- Stashes:顯示了我們所有創(chuàng)建的 stash
- View:查看 stash 所存儲的內(nèi)容
- Drop:刪除棧中對應(yīng)的 stash
- Clear:清除棧中所有的 stash
- Pop stash:應(yīng)用選中的 stash,然后立即從棧上刪除它。
- As new Branch:將當(dāng)前 stash 所存儲的內(nèi)容作為一個分支并checkout。也就是如果你在 master 創(chuàng)建一個stash,并設(shè)置了As new branch的 為 LoginBranch,那么你會馬上切換到 LoginBranch 分支中。
- Apply Stash:應(yīng)用你選中的stash,但是不會刪除stash。
總結(jié)
下面簡單的總結(jié)一下:
-
git stash會將當(dāng)前的存儲內(nèi)容,自動添加一條描述信息,且描述信息為當(dāng)前分支上最后一次 commit 的 message 。 -
git stash save message需要你指定 stash 的描述信息。 -
git stash list:查看所有的 stash 記錄。 -
git stash apply:應(yīng)用某個 stash ,但不會把存儲從存儲列表中刪除,默認(rèn)使用棧頂?shù)?stash 即stash@{0},如果要使用其他 stash 需要調(diào)用git stash apply stash@{$num}, 比如第二個:git stash apply stash@{1}。 -
git stash pop:將 stash 棧中的對應(yīng) stash 記錄刪除,并將對應(yīng)修改應(yīng)用到當(dāng)前的工作目錄下,默認(rèn)為第一個 stash 即stash@{0},如果要應(yīng)用并刪除其他stash,命令:git stash pop stash@{$num},比如應(yīng)用并刪除第二個:git stash pop stash@{1}。 -
git stash drop stash@{$num}:刪除對應(yīng) stash 棧中的 stash 記錄。比如刪除第二個:git stash drop stash@{1} -
git stash clear:刪除所有 stash 。
參考
站在巨人的肩膀上,才能看的更遠(yuǎn)~