← 上一章:【冷知識】標籤跟分支有什麼不一樣? 下一章:【狀況題】不小心把帳號密碼放在 Git 裡了,想把它刪掉… →


【狀況題】手邊的工作做到一半,臨時要切換到別的任務

在公司工作或多或少有經歷過這樣的情境:

你手邊的工作做到一半…

老闆:「那個誰誰誰,網站掛了,你趕快先來修一下這個功能…」

先不管心情好不好,既然老闆都開口了,為了生活只好暫時先乖乖聽話,先把手邊的進度放旁邊…

那就先 Commit 目前的進度吧!

簡單的做法,也是我常會做的做法,就是先不管那麼多,先把目前所有的修改先存下來。假設這是目前的狀況,而且我正在 cat 分支進行功能開發:

current commits

$ git add --all
$ git commit -m "not finish yet"
[cat 9bf1f43] not finish yet
 2 files changed, 1 insertion(+)
 create mode 100644 cat3.html

然後就可以切到有問題的分支先進行功能修復,待完成之後再切回原來做一半的 cat 分支,然後再 Reset 一下,把剛剛做一半的東西拆回來繼續做:

$ git reset HEAD^

然後就可以接著繼續做了。

使用 Stash

遇到這個情況,剛剛那個先 Commit,之後再 Reset 回來的做法是一種做法,另一種做法是使用 Git 的 Stash 功能。先看一下目前的狀態:

$ git status
On branch cat
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:   cat1.html
	modified:   cat2.html
	modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

目前的狀態正在修改 cat1.htmlcat2.html 以及 index.html 這幾個檔案。因為老闆急著召喚要去做別的事,這時候可使用 git stash 指令,把這些修改先「存」起來:

$ git stash
Saved working directory and index state WIP on cat: b174a5a add cat 2

注意!

Untracked 狀態的檔案預設沒辦法被 Stash,需要額外使用 -u 參數。

看一下目前的狀態:

$ git status
On branch cat
nothing to commit, working tree clean

好像跟剛 Commit 完一樣的乾淨了。

剛剛那些檔案存到哪去了?讓我們看一下:

$ git stash list
stash@{0}: WIP on cat: b174a5a add cat 2

看起來目前只有一份狀態被存起來,最前面的 stash@{0} 是這個 Stash 的代名詞,而後面的 WIP 字樣是「Work In Progress」,就是工作進行中的意思。Stash 可以放很多份,例如我再放一份到 Stash:

$ git stash list
stash@{0}: WIP on dog: 053fb21 add dog 2
stash@{1}: WIP on cat: b174a5a add cat 2

剛剛原來 stash@{0} 的現在變成 stash@{1} 了。

使用 SourceTree 也可以做這件事,在上方選單有一顆「Stash」按鈕,按下之後便會出現對話框

current commits

填寫後按下 OK 即可完成。在左邊側邊欄可以看到一個「STASHES」選單,裡面會放著目前所有的 Stash 的內容:

current commits

把 Stash 撿回來用

好啦,剛剛的修復任務完成了,可以繼續把剛剛存起來的東西再拿出來了。再次看一下目前的 Stash 列表:

$ git stash list
stash@{0}: On dog: not finish yet!
stash@{1}: WIP on dog: 053fb21 add dog 2
stash@{2}: WIP on cat: b174a5a add cat 2

這個 stash@{2} 應該是我剛剛最一開始做一半的進度,所以我要把它撿回來做:

$ git stash pop stash@{2}
On branch cat
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:   cat1.html
	modified:   cat2.html
	modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")
Dropped stash@{2} (80091001b2022e0fb3f8c7ee6cffcefa207d00be)

說明如下:

  1. 使用 pop 指令,可以把某個 Stash 拿出來並套用在目前的分支上。套用成功之後,那個套用過的 Stash 就會被刪除。
  2. 如果後面沒有指定要 pop 哪一個 Stash,會從編號最小的,也就是 stash@{0} 開始拿(也就是最後疊上去的那次)。

如果那個 Stash 確定不要,可以使用 drop 指令:

$ git stash drop stash@{0}
Dropped stash@{0} (87390c02bbfc8cf7a38fb42f6f3a357e51ce6cd1)

這樣就可以把那個 Stash 從列表裡刪掉了。

要把 Stash 撿回來用,除了 pop 之外,另一個指令是 apply

$ git stash apply stash@{0}

這是指會把 stash@{0} 這個 Stash 拿來套用在現在的分支上,但 Stash 不會刪除,還是會留在 Stash 列表上。所以你可把 pop 指令看成「apply Stash + drop Stash」。

使用 SourceTree 要套用 Stash 的話,就是在指定的 Stash 上按滑鼠右鍵,然後選擇「Apply Stash」功能即可:

current commits

所以,使用哪一種比較好?

其實都可,看每個人的習慣,還有對 Git 的熟悉程度會有不同的答案。如果你問我,我會跟你說我比較喜歡第一種,就是先 Commit 之後再 Reset 回來繼續做,對我個人而言,我覺得這樣相對比使用 Stash 來得直覺一些。


← 上一章:【冷知識】標籤跟分支有什麼不一樣? 下一章:【狀況題】不小心把帳號密碼放在 Git 裡了,想把它刪掉… →

Comments