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 掉了嗎? ![](https://i.imgur.com/aKeVjXj.png) 若真的 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分支 當前異動檔 ```bash= git stash -u # 暫存檔案 git stash list # 確認檔案確實有暫存成功 git status # 確認分支狀態無任何異動檔案 ``` ### 保留 A分支 的狀態,讓當前異動檔隨時可以取回 現在 `A分支` 乾淨囉。 *當然,這代表可以處理**暫存檔**的問題了,但是同時也會導致**當前異動檔**會 pop 不回來。* **那麼問題還是沒有解決,對吧?** 所以這個分支別再做任何異動,包含:檔案異動、`git pull` 等,會更新分支狀態的行為。 務必維持分支的狀態,之後要回來處理**當前異動檔**,才能夠無後顧之憂的 pop 回來。 ### 切換至 develop 並建立 B分支 取回暫存檔 前面都瞭解後,就可以開始準備取回暫存檔囉! #### 請務必留意!切換回 develop ,絕對不要 pull! > 很有可能會因為最新的檔案又造成衝突。 > 不過若不慎發生這種事,也還是可以利用 `git reset HEAD^` 的方式回到前一個 commit,就不再此文贅述了 ```bash= git checkout develop # 切換回 develop git checkout -b B分支 # 建立 B分支,分支名稱請自行更換 git stash list # 確認暫存清單 ``` 到這裡,你會發現暫存清單中有兩筆暫存,清單依照 stash 順序,最後推入的暫存為 `stash@{0}`,舊的暫存序號會依序往後推1號。 因此依照這個規則,**當前異動檔**是最後推入的: > 當前異動檔:stash@{0} > 暫存檔:stash@{1} 那麼我們就將暫存檔取回來吧 ```bash= git stash pop stash@{1} ``` > OS 如果是 win7,會因為作業系統限制,只能安裝較舊的 npm 及相關環境,導致此語法有錯,此處只須加上雙引號即可: > `git stash pop "stash@{1}"` ### B分支 取回檔案後,先處理完並 push 上遠端B分支 一般而言,分支都需要經過 code review 後才會 merge 進 develop。 此步驟重點: > 將檔案推到遠端分支,利用解 Conflict 的方式,來取代 stash pop 因衝突而無法順利取回資料的狀況。 因此你也可以直接推到遠端建立 `B分支` ```bash= git add . git commit -m "你的commit描述" git push origin B分支 ``` ### 回到 A分支 取回當前異動檔 剛剛 push 完,現在 `B分支` 就結束他的任務囉! 讓我們回到 `A分支` ,並將**當前異動檔**取回來 ```bash= git checkout A分支 git stash list # 此時只剩 1 個暫存資料 git stash pop stash@{0} # 取回當前異動檔 ``` ### pull 遠端B分支,使其產生 Conflict 並解掉 現在我們的 `A分支` 恢復到一開始有**當前異動檔**的狀態,接下來就可以將**暫存檔**從 `遠端B分支` 找回來了 ```bash= git pull origin B分支 ``` 接著一定會產生 Conflict! 畢竟一開始就是因為檔案衝突才會無法 pop 檔案,那麼就耐心解決掉所有的衝突吧~ 最後, ### 恭喜你暫存檔與當前異動檔都回來了 什麼? 還沒有? 或許再回頭看看有沒有什麼步驟漏掉了 或是留言給我,我可以試著通靈看看~ --- ###### tags: [`git`](https://hackmd.io/@elzuoc?tags=%5B%22git%22%5D) [`git stash`](https://hackmd.io/@elzuoc?tags=%5B%22git+stash%22%5D) ###### 文章若有任何錯誤,也請不吝給予留言指正,謝謝大家!