← 上一章:【狀況題】啊!不小心把檔案或目錄刪掉了… 下一章:【狀況題】不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎? →


【狀況題】剛才的 Commit 後悔了,想要拆掉重做…

這個狀況很常見,雖然使用的指令 git reset 看起來很簡單,但因不少人誤解 Reset 指令的意思,所以反而是很多學習 Git 的人容易卡關的地方。

退一步海闊天空

先看一下我們目前的 Git 紀錄:

$ git log --oneline
e12d8ef (HEAD -> master) add database.yml in config folder
85e7e30 add hello
657fce7 add container
abb4f43 update index page
cef6e40 create index page
cc797cd init commit

如果想拆掉最後一次的 Commit,可以使用「相對」或「絕對」的做法。「相對」的做法可以這樣:

$ git reset e12d8ef^

在最後面的那個 ^ 符號,每一個 ^ 符號表示「前一次」的意思,所以 e12d8ef^ 是指在 e12d8ef 這個 Commit 的「前一次」,如果是 e12d8ef^^ 則是往前兩次,以此類推。不過如果要倒退五次,通常不會寫 e12d8ef^^^^^,而會寫成 e12d8ef~5

而且因為剛好 HEADmaster 目前都是指向 e12d8ef 這個 Commit,而且 e12d8ef 這個數字也不好記,所以上面這行,通常也會改寫成:

$ git reset master^

$ git reset HEAD^

以這個例子來說會得到一樣的結果。(分支以及什麼是 HEAD 將於後面的章節再做說明)

以上是「相對」的方式。如果你很清楚想要把目前的狀態退回到哪個 Commit,可以直接指明:

$ git reset 85e7e30

它就會切換到 85e7e30 這個 Commit 的狀態,因為 85e7e30 剛好就是 e12d8ef 的前一次 Commit,以這個例子來說也會達到跟「拆掉最後一次的 Commit」一樣的效果。

如果使用 SourceTree,可以選擇你想要 reset 到的 Commit,例如想要一口氣退 3 個 Commit,就在想要去的 Commit 上按滑鼠右鍵,選擇「Reset master to this commit」:

reset commit

接著會有個對話框要你選模式,這裡先選預設的「Mixed」:

reset commit

按下 OK 鈕之後就一口氣退掉 3 個 Commit 了。

是說,Commit 拆掉了,那拆出來的那些檔案跑哪去了?這問題的答案跟接下來要介紹的 Reset 模式有關。

Reset 的模式

git reset 指令可以搭配參數使用,常見到的三種參數,分別是 --mixed--soft 以及 --hard,不同的參數執行之後會有稍微不太一樣的結果。

mixed 模式

--mixed 是預設的參數,如果沒有特別加參數,git reset 指令將會使用 --mixed 模式。這個模式會把暫存區的檔案丟掉,但不會動到工作目錄的檔案,也就是說 Commit 拆出來的檔案會留在工作目錄,但不會留在暫存區。

soft 模式

這個模式下的 reset,工作目錄跟暫存區的檔案都不會被丟掉,所以看起來就只有 HEAD 的移動而已。也因此,Commit 拆出來的檔案會直接放在暫存區。

hard 模式

在這個模式下,不管是工作目錄以及暫存區的檔案都會丟掉。

畫個表格整理一下:

模式 mixed 模式 soft 模式 hard 模式
工作目錄 不變 不變 丟掉
暫存區 丟掉 不變 丟掉

如果上面的說明對你來說不容易想像到底發生什麼事,用白話一點的方式說明,你只要記這些不同的模式,將會決定「Commit 拆出來的那些檔案何去何從」,讓我再用另一個表格來解釋:

模式 mixed 模式(預設) soft 模式 hard 模式
Commit 拆出來的檔案 丟回工作目錄 丟回暫存區 直接丟掉

但是 Commit 拆掉之後又後悔了,可以再撿回來嗎?

當然可以,甚至是使用 --hard 模式拆掉的也都能撿回來,我們在下一個章節「【狀況題】不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎?」就會介紹如何撿回來。

【觀念】不要被 Reset 這個字給誤導了!

Reset 這個英文單字的翻譯是「重新設定」,但事實上 Git 的 Reset 指令用中文來說比較像是「前往」或「變成」,也就是「go to」或「become」的概念。當執行這個指令的時候:

$ git reset HEAD~2

這個指令你原本可能會解讀成「請幫我拆掉最後兩次的 Commit」,但其實用「拆」這個動詞只是我們比較容易理解而已,事實上並沒有真的把這個 Commit「拆掉」(放心,所有的 Commit 都還在)。

正確的說,上面這個指令應該要解讀成「我要前往兩個 Commit 之前的狀態」或是「我要變成兩個 Commit 之前的狀態」,而隨著使用不同的參數模式,原本的這些檔案就會丟去不同的區域。

因為實際上 git reset 指令也並不是真的刪除或是重新設定 Commit,只是「前往」到指定的 Commit,那些看起來好像不見的東西只是暫時看不到,但隨時都可以再撿回來。

Reset 是 Git 裡很常用的指令,所以一定要建立正確的觀念,操作 Git 才能真的達到隨心所欲的境界喔。


← 上一章:【狀況題】啊!不小心把檔案或目錄刪掉了… 下一章:【狀況題】不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎? →

Comments