Try   HackMD

March 09, 2023 | Created

用 git stash pop 取回檔案失敗

前言提醒

暫存後會需要修改相同檔案的狀況下,不建議使用 stash,使用 commit 直接推到遠端分支會更安全,除了可以正常取回檔案外,也不用擔心本機電腦出問題而沒有任何備份資料。

git stash pop command is not working

我剛剛使用 git stash -u,現在想要 git stash pop
但指令輸入完後,用 git status 確認,並沒有看見剛剛想要 pop 出來的檔案!
花這麼多心力的檔案不見了嗎!?

首先,先別著急。
使用 git stash list,查看一下剛剛 stash 的分支在不在,真的被 drop 掉了嗎?

若真的 drop 掉了,則此篇不適用於你的問題。

正常來說,只要 git stash -u 有成功,在使用 git stash drop 前,暫存都不會消失。

既然沒有消失,為何無法 pop 取回資料呢?

比較常見的狀況是,該分支曾經使用 git pull 取得並更新至最新的分支狀態,導致 stash 中的檔案有衝突。

git pull 時造成的 Conflict 不同,當 stash 檔案有衝突時,便會取消 pop 動作,導致指令輸入完後,git status 結果並未改變。

那該怎麼辦?

stash 中的檔案花了我很多心思,而且我當前有檔案異動,這些檔案我也想留。如果可以,我還是希望把檔案取回來

首先為了雙方有共識,先假設:

當前有異動檔案的分支: A分支
專案最新檔案所在的分支: develop
當前異動檔:當前異動檔
stash 拋不回的檔案:暫存檔

開始前,先了解一下接下來我們大概要做些什麼:

  1. 保留 A分支 當前異動檔
  2. 保留 A分支 的狀態,讓當前異動檔隨時可以取回
  3. 切換至 develop 並建立 B分支 取回暫存檔
  4. B分支 取回檔案後,先處理完並 push 上 遠端B分支
  5. 回到 A分支 取回當前異動檔
  6. pull 遠端B分支,使其產生 Conflict 並解掉
  7. 恭喜你暫存檔當前異動檔都回來了

如果這個流程可以理解每個環節該怎麼做,就可以不用繼續往下看囉。

若還無法,接下來會告訴你各環節為什麼要這麼做,那我們就開始吧!


首先必須瞭解,在 git stash pop 前,分支最好保持乾淨。

不過既然現在問題已經發生了,就必須思考:

在不影響當前異動檔分支的前提下,應該如何處理

因此,我們最好另外開一個乾淨的分支來處理暫存檔

為了開一個乾淨的分支,我們就需要執行 1.保留 A分支 當前異動檔

保留 A分支 當前異動檔

git stash -u # 暫存檔案 git stash list # 確認檔案確實有暫存成功 git status # 確認分支狀態無任何異動檔案

保留 A分支 的狀態,讓當前異動檔隨時可以取回

現在 A分支 乾淨囉。

當然,這代表可以處理暫存檔的問題了,但是同時也會導致當前異動檔會 pop 不回來。

那麼問題還是沒有解決,對吧?

所以這個分支別再做任何異動,包含:檔案異動、git pull 等,會更新分支狀態的行為。

務必維持分支的狀態,之後要回來處理當前異動檔,才能夠無後顧之憂的 pop 回來。

切換至 develop 並建立 B分支 取回暫存檔

前面都瞭解後,就可以開始準備取回暫存檔囉!

請務必留意!切換回 develop ,絕對不要 pull!

很有可能會因為最新的檔案又造成衝突。
不過若不慎發生這種事,也還是可以利用 git reset HEAD^ 的方式回到前一個 commit,就不再此文贅述了

git checkout develop # 切換回 develop git checkout -b B分支 # 建立 B分支,分支名稱請自行更換 git stash list # 確認暫存清單

到這裡,你會發現暫存清單中有兩筆暫存,清單依照 stash 順序,最後推入的暫存為 stash@{0},舊的暫存序號會依序往後推1號。

因此依照這個規則,當前異動檔是最後推入的:

當前異動檔:stash@{0}
暫存檔:stash@{1}

那麼我們就將暫存檔取回來吧

git stash pop stash@{1}

OS 如果是 win7,會因為作業系統限制,只能安裝較舊的 npm 及相關環境,導致此語法有錯,此處只須加上雙引號即可:
git stash pop "stash@{1}"

B分支 取回檔案後,先處理完並 push 上遠端B分支

一般而言,分支都需要經過 code review 後才會 merge 進 develop。

此步驟重點:

將檔案推到遠端分支,利用解 Conflict 的方式,來取代 stash pop 因衝突而無法順利取回資料的狀況。

因此你也可以直接推到遠端建立 B分支

git add . git commit -m "你的commit描述" git push origin B分支

回到 A分支 取回當前異動檔

剛剛 push 完,現在 B分支 就結束他的任務囉!

讓我們回到 A分支 ,並將當前異動檔取回來

git checkout A分支 git stash list # 此時只剩 1 個暫存資料 git stash pop stash@{0} # 取回當前異動檔

pull 遠端B分支,使其產生 Conflict 並解掉

現在我們的 A分支 恢復到一開始有當前異動檔的狀態,接下來就可以將暫存檔遠端B分支 找回來了

git pull origin B分支

接著一定會產生 Conflict!
畢竟一開始就是因為檔案衝突才會無法 pop 檔案,那麼就耐心解決掉所有的衝突吧~

最後,

恭喜你暫存檔與當前異動檔都回來了

什麼? 還沒有? 或許再回頭看看有沒有什麼步驟漏掉了
或是留言給我,我可以試著通靈看看~


tags: git git stash
文章若有任何錯誤,也請不吝給予留言指正,謝謝大家!