← 上一章:【狀況題】想要刪除某幾個 Commit 或是調整 Commit 的順序 下一章:使用標籤 →


Reset、Revert 跟 Rebase 指令有什麼差別?

在進入這個主題之前,先看一下 Revert 這個指令。

如果想要拆除已經完成的 Commit,在「【狀況題】剛才的 Commit 後悔了,想要拆掉重做…」章節介紹過可使用 Reset 指令來處理,在前幾章也有介紹過使用 Rebase 來修改歷史紀錄,例如把多個 Commit 併成一個、把一個拆成多個、刪除 Commit、調整 Commit 順序或是在指定的 Commit 之間再加入新的 Commit 等,接下來要介紹的 Revert 指令,也是另一可以用來「後悔」的指令。

使用 Revert 指令

來看一下怎麼使用 Revert 指令。假設目前的歷史紀錄是這樣:

revert

如果想要取消最後這次的 Commit(add dog 2),可以這樣做:

$ git revert HEAD --no-edit
[master f2c3e8b] Revert "add dog 2"
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 dog2.html

加上後面的 --no-edit 參數,表示不編輯 Commit 訊息。使用 SourceTree 可以在想要取消的 Commit 上按滑鼠右鍵,然後選擇「Revert Commit…」

revert

這樣就把最後一次 Commit 的內容給刪掉了…等等,檔案是不見了沒錯,但是好像有點怪怪的:

revert

Commit 怎麼增加了?而且原來的那個 add dog 2 的 Commit 也還在?原來,Revert 的指令是「再做一個新的 Commit,來取消你不要的 Commit」的概念,所以 Commit 數量才會增加。

那怎麼取消 Revert?

如果做出來的這個 Revert 你也不想要了,有幾個方式來處理它:

再開一次 Revert

是的,你可以再開一個新的 Revert,來 Revert 剛剛這個 Revert(有點饒口):

$ git revert HEAD --no-edit
[master e209455] Revert "Revert "add dog 2""
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 dog2.html

但剛剛被刪掉的 dog2.html 又復活了,但這樣 Commit 又變多了…

直接使用 Reset

如果是要「砍掉」這個 Revert,其實只要直接使用 Reset 指令就行了:

$ git reset HEAD^ --hard

這樣就可以回到 Revert 之前的狀態了。

什麼時候使用 Revert 指令?

如果是自己一個人做的專案,用 Revert 指令其實有點過於「禮貌」了,大部份都是直接使用 Reset 就好。但如果對於多人共同協作的專案,也許因為團隊開發的政策,你不一定有機會可以使用 Reset 指令,這時候就可以 Revert 指令來做出一個「取消」的 Commit,對其它人來說也不算是「修改歷史」,而是新增一個 Commit,只是剛好這個 Commit 是跟某個 Commit 反向的操作而已。

所以,這三個指令有什麼差別?

用個表格歸納一下:

指令 改變歷史紀錄 說明
Reset 把目前的狀態設定成某個指定的 Commit 的狀態,通常適用於尚未推出去的 Commit。
Rebase 不管是新增、修改、刪除 Commit 都相當方便,用來整理、編輯還沒有推出去的 Commit 相當方便,但通常也只適用於尚未推出去的 Commit。
Revert 新增一個 Commit 來反轉(或說取消)另一個 Commit 的內容,原本的 Commit 依舊還是會保留在歷史紀錄中。雖然會因此而增加 Commit 數,但通常比較適用於已經推出去的 Commit,或是不允許使用 Reset 或 Rebase 之修改歷史紀錄的指令的場合。

← 上一章:【狀況題】想要刪除某幾個 Commit 或是調整 Commit 的順序 下一章:使用標籤 →

Comments