在Git中進行版本回退需要使用git reset
命令。
以前面文章中的示例為例,當我準備在V4
版本,回退到V3
版本的時候,分支中的提交和工作目錄中檔案的狀態,如下圖所示:
我們分別執行了三種回退方式:
git reset --soft HEAD^
:溫柔的回退。git reset --mixed HEAD^
:中等回退。git reset --hard HEAD^
:強硬的回退。
(我們從英文中就可以看出,一個比一個回退的多。)
下面我們一一進行總結。
1、--soft
回退說明
當我在V4
版本的時候,執行git reset --soft HEAD^
命令回退到V3
版本。
Git中發生的變化如下圖所示:
依據上圖,理解一下發生的事情:本質上就發生了,把HEAD指標指向了V3
版本。而工作區和暫存區中的readme.txt
檔案是沒有做任何變動的。
所以你檢視本地版本庫中的readme.txt
檔案是V3
版本,工作區和暫存區中的readme.txt
檔案是V4
版本。
就等於回滾到了git commit
之前的狀態。
(我前面文章中有詳細的演示)
擴充:
當我繼續修改readme.txt
檔案之後,再次提交,會在V3
版本之上在建立一個新的commit
提交,並移動HEAD指標指向的分支來使其指向該commit
提交,這樣依次提交下去,如下圖所示:
如果我們使用git log
命令檢視本地版本庫的歷史提交資訊的時候,就不會出現V4版本提交的資訊。會是V1
、V2
、V3
、V5
。(我們從前面文章中已經演示了)
但是V4
版本是不會在Git中刪除的,會永遠的儲存在Git的本地版本庫中。我們可以使用git reflog
命令,可以檢視該V4
版本的提交資訊。
提示:只要是本地版本庫中
HEAD
有過的變化,那麼git reflog
命令就能夠顯示出來。
(關於這點,下面同理,所以下面就不說了。)
2、--mixed
回退說明
當我在V4
版本的時候,執行git reset --mixed HEAD^
命令回退到V3
版本。
Git中發生的變化,如下圖所示:
理解一下發生的事情,我們可以看到上圖中,完成了兩步操作:
- 把HEAD指標指向了
V3
版本(也就是版本庫回退了)。 - 把暫存區中的
readme.txt
檔案也回退到了V3
版本。
而只有工作區中的readme.txt
檔案內容沒有變化。
這說明git reset --mixed
命令比git reset --soft
命令,多回退了暫存區中的內容。
就等於回滾到了git commit
和git add
之前的狀態。
(我前面文章中有詳細的演示)
提示:因為
--mixed
引數是git reset
命令的預設選項,也就是不寫任何引數就預設使用--mixed
引數。即git reset HEAD^
等同於git reset --mixed HEAD^
命令
3、--hard
回退說明
當我在V4版本的時候,執行git reset --hard HEAD^
命令回退到V3
版本。
Git中發生的變化,如下圖所示:
理解一下發生的事情,我們可以看到上圖中,完成了三步操作:
- 把HEAD指標指向了
V3
版本(也就是版本庫回退了)。 - 把暫存區中的
readme.txt
檔案也回退到了V3
版本。 - 把工作區中
readme.txt
檔案的修改也復原了。
所以執行完git reset --hard HEAD^
命令,是完全回退一個版本。
此時工作區、暫存區、本地版本庫中的檔案狀態都是一致的,都是V3
版本。
就等於回滾了一個“編輯檔案,新增到暫存區,提交版本庫”的整個流程。
(我前面文章中有詳細的演示)
4、總結
必須注意:
--hard
引數是git reset
命令唯一的危險用法,是能夠使Git會真正地銷燬資料的僅有的幾個操作之一。
其他任何形式的git reset
操作都可以輕鬆撤消,但是--hard
選項不能,因為它強制覆蓋了工作目錄中的檔案。
在這種特殊情況下,我們的Git資料庫中的一個提交內,還留有該檔案的V4
版本,我們可以通過git reflog
來找回它。但是若該檔案還未提交,Git仍會覆蓋它從而導致無法恢復。