筆者在本地終端進行 git 工作目錄的相關處理時,遇到由於某種情況需要使用 git checkout 命令切換到其他分支的情景。此時,若已經對當前分支做了一定的修改,則直接切換分支時 git 會提示錯誤信息。本文即總結下筆者目前了解和使用的 git 切換到其他分支沖突時的解決方案。
問題
當本地遇到特殊情況,需要切換到其他分支時,當前分支可能會存在以下兩種可能:
(1) 對當前分支並未進行任何修改,從而可以直接使用 git checkout 命令切換到其他分支。
git checkout test //切換到 test 分支
(2) 若當前的分支已經做了一定的修改,則直接進行分支切換時,git 會產生如下錯誤信息。這是由於已經對當前分支進行了修改,但尚未保存而導致的。
error: Your local changes to the following files would be overwritten by checkout : xxxx
Please commit your changes or stash them before you switch branches
下面描述當前分支存在修改時,切換到其他分支的解決方案。具體而言,選擇包括簡單的丟棄當前分支的修改和保存當前分支信息,待其他分支完成后再進行恢復等,用戶可根據不同的需要選用不同的方案。
丟棄本分支的修改
下面的方法直接將當前分支相對上一次提交時的修改丟棄,從而可以從當前分支切換至其他分支,主要適合於對當前分支的改動較少,且不存在丟棄修改產生的問題的情況。用戶可以使用不同的命令實現丟棄本地分支的修改。
通過 git checkout -f 命令強制切換分支
當用戶對當前分支的修改不是特別重要或覺得沒有保留的必要時,可以使用 git checkout 命令強制切換到其他分支。再切換回該分支時,會直接退回到該分支上一次提交時的數據版本。
git checkout -f test //強制切換至 test 分支,丟棄當前分支的修改
通過 git reset --hard 回退至某次提交時的數據
如果只需要保持當前分支上一次提交時的數據,而不需要目前添加的任何修改,可以使用 git log 查看當前分支的提交記錄。再通過 git reset --hard 命令將當前分支回退到前一次提交時的數據,此時當前分支針對上一次提交的修改均被抹除,注意 git reset --hard 在運行時不會有提示,所以使用前請保證新增的修改是可丟棄的。
通過 git log 查看當前分支的提交記錄。
git log //當前分支的提交記錄,信息包括提交對應的 哈希值 作者 郵箱 日期 描述 等
通過 git reset --hard 命令回退到某一次提交的版本,上述命令只需要使用特定提交的哈希值的開始若干位作為參數,即可退回該提交時的數據。
git reset --hard a13f52f3 //當前分支數據重置到哈希值開始部分為 a13f52f3 的提交的數據,git reset --hard 參數為某次提交時的哈希值的開始部分
當重置完成后,當前分支的數據即為被 git 記錄的未經修改的數據,此時可以直接通過 git checkout 命令切換到其他分支,而不會再產生報錯。
通過 git checkout -- 命令忽略文件的修改
當使用 git status 查看當前分支的文件狀態時,對於不同的文件狀態,git status 會提示該狀態下的文件可以使用的對應 git 命令,如下圖所示。
可以看到,對於處於 Changes to be commited 狀態的文件( 該狀態的文件在使用 git commit 命令時即被提交 ),可以通過 git reset HEAD 命令將文件從 Changes to be commited 狀態退出。
git reset HEAD test.txt //將 test.txt 從 Changes to be committed 狀態退出
對於 Changes not staged for commit 狀態的文件,表示這些文件雖然被修改,但並沒有被加入 Changes to be commited 狀態,即使用 git commit 命令提交時,這些修改不會被記錄。針對這類文件可以有兩種選擇。可以使用 git add 命令將這些修改放入 Changes to be committd 狀態,或者通過 git checkout -- 命令忽略該文件的修改,使其回退到上一次提交時的狀態。( git 中不同文件的狀態可以參見筆者的另一篇筆記git 學習記錄—— git 中的倉庫、文件狀態、修改和提交操作等 )
git add test.txt //將 test.txt 文件加入 Changes to be committed 狀態,在使用 git commit 命令時上述修改即被提交 git checkout -- test.txt //丟棄對 test.txt 的修改,其內容回退到上一次提交時的狀態
無法直接切換其他分支的原因即是存在未被保存的修改。此時若想要丟棄當前分支的修改,直接使用 git checkout -- 命令將文件修改丟棄即可。該方法主要適用於產生的改動比較少且相對不重要的情況。
git checkout -- test.txt //丟掉 test.txt 文件新增的修改
保留當前分支的修改
另外一種進行切換的選擇是先將當前分支的修改保存,再切換到其他分支,這樣在其他分支的任務完成后,重新切換至當前分支時,可以繼續當前分支的工作。
直接提交當前分支
最簡單粗暴的方法即通過 git commit 命令將當前分支的修改進行提交。首先通過 git status 命令查看當前分支各個文件的狀態,git status 命令還會顯示不同文件狀態下 git 可執行的命令,用戶可以直接參考。
git status //當前分支各文件的狀態
通過 git add 命令將修改后的文件轉化為 staged 狀態,即文件的修改將處於 Changes to be committed 狀態,再通過 git commit 命令將本分支的修改提交。
git add test.txt //將此時的 test.txt 文件添加至 Changes to be committed 狀態
在所需的修改均加入 Changes to be committed 狀態后,可以通過 git commit 命令將本分支的修改提交。不需要的修改通過上文提到的 git checkout -- 命令重置即可。
git commit -m "description for this commit" //提交本次修改
將當前分支修改暫存
在任務推進過程中,可能遇到需要切換到其他分支進行處理的情況。但是對應的,對於當前分支的修改可能並不足以達到需要進行一次提交的程度,此時更合適的方案是將本分支修改暫存,然后切換到其他分支進行工作,待其他分支的任務完成后,再切換回本分支,並將暫存的方案恢復,進而繼續本分支的修改。
git 中提供 git stash 命令來完成上述功能,也就是上文提到的錯誤提示中 "Please commit your changes or stash them before you switch branches" 中所提到的 stash 修改的方案。
暫存修改
通過 git stash 命令將當前分支的修改暫存。經過 git stash 命令暫存修改的數據后,再使用 git status 命令可以看到文件的狀態均處於未修改的狀態( 而不再是修改未提交狀態 )。
git stash //暫存本分支的修改
如筆者通過 git stash 命令,會顯示對應的 "Saved working directory and index state WIP on master :xxxxxxx" 信息。用戶可以多次使用 git stash 命令,暫存的狀態會以棧的形式存放。
查看暫存信息
可以通過命令 git stash list 查看已經暫存的數據。 可以看到暫存的數據通過 stash@{n} 的形式索引已經存儲的修改數據。
git stash list //顯示所有 stash 的數據
恢復修改
當在其他分支的任務完成切換回當前分支后,可以使用 git stash apply 命令恢復之前被暫存的數據。
git stash apply //恢復最近一次暫存的修改 git stash apply stash@{2} //恢復索引 stash@{2} 對應的暫存的修改,索引可以通過 git stash list 進行查看
這里需要注意的是,通過 git stash apply 命令只會將暫存的數據恢復至 "Changes not staged for committed" 狀態,即使之前修改狀態中已經有文件處於 staged 狀態( Changes to be committed ).為了 git 能夠將文件盡可能恢復至暫存之前的狀態,可以加入 --index 參數。
git stash apply --index //在恢復暫存數據時盡量恢復至原狀態( 已經 staged 狀態的文件仍恢復為 staged 狀態 )
刪除修改
可以通過 git stash pop 或者 drop 命令刪除對應的緩存數據。
git stash drop stash@{1} //刪除 stash@{1} 分支對應的緩存數據 git stash pop //將最近一次暫存數據恢復並從棧中刪除
git stash 將用戶做過的修改存放在本次 git stash 產生的暫存數據中,並將已經修改的文件恢復至未修改狀態。當用戶恢復暫存數據時,則將上述修改應用到當前分支上。
在本文的情景中,即將當前分支的修改通過 git stash 保存,此時當前分支恢復至未被修改之前的狀態,而修改被 git stash 以棧的方式保存,可通過索引的方式訪問。用戶此時可以沒有錯誤的切換至其他分支( 文件均處於未修改狀態 ),待其他分支的任務完成后,再切換回本分支。此時通過 git stash apply 將被暫存的修改應用到當前分支,則當前分支的數據即被恢復至離開當前分支前的狀態。
從原理也可以看出,git stash apply 實際是可以應用到任意分支的,此時執行的操作是將 git stash 保存的修改合並到 git stash apply 時用戶所在的分支和文件,當合並存在問題時,git 會產生報錯。
參考資料