鍍金池/ 教程/ Java/ 版本回退
操作標簽
多人協(xié)作
解決沖突
Git 的誕生
工作區(qū)和暫存區(qū)
搭建 Git 服務(wù)器
Bug 分支
配置別名
從遠程庫克隆
分支
添加遠程庫
分支管理策略
撤銷修改
安裝 Git
管理修改
生成 SSH key
GitHub
倉庫狀態(tài)
忽略特殊文件
刪除文件
Feature 分支
創(chuàng)建與合并分支
創(chuàng)建版本庫
創(chuàng)建標簽
版本回退
集中式 vs 分布式

版本回退

現(xiàn)在,你已經(jīng)學(xué)會了修改文件,然后把修改提交到 Git 版本庫,現(xiàn)在,再練習(xí)一次,修改 readme.txt 文件如下:

Git is a distributed version control system.
Git is free software distributed under the GPL.

然后嘗試提交:

$ git add readme.txt
$ git commit -m "append GPL"
[master 3628164] append GPL
 1 file changed, 1 insertion(+), 1 deletion(-)

像這樣,你不斷對文件進行修改,然后不斷提交修改到版本庫里,就好比玩 RPG 游戲時,每通過一關(guān)就會自動把游戲狀態(tài)存盤,如果某一關(guān)沒過去,你還可以選擇讀取前一關(guān)的狀態(tài)。有些時候,在打 Boss 之前,你會手動存盤,以便萬一打 Boss 失敗了,可以從最近的地方重新開始。Git 也是一樣,每當你覺得文件修改到一定程度的時候,就可以“保存一個快照”,這個快照在 Git 中被稱為 commit。一旦你把文件改亂了,或者誤刪了文件,還可以從最近的一個 commit 恢復(fù),然后繼續(xù)工作,而不是把幾個月的工作成果全部丟失。

現(xiàn)在,我們回顧一下 readme.txt 文件一共有幾個版本被提交到 Git 倉庫里了:

版本1:wrote a readme file

Git is a version control system.
Git is free software.

版本2:add distributed

Git is a distributed version control system.
Git is free software.

版本3:append GPL

Git is a distributed version control system.
Git is free software distributed under the GPL.

當然了,在實際工作中,我們腦子里怎么可能記得一個幾千行的文件每次都改了什么內(nèi)容,不然要版本控制系統(tǒng)干什么。版本控制系統(tǒng)肯定有某個命令可以告訴我們歷史記錄,在 Git 中,我們用git log命令查看:

$ git log
commit 3628164fb26d48395383f8f31179f24e0882e1e0
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Tue Aug 20 15:11:49 2013 +0800

    append GPL

commit ea34578d5496d7dd233c827ed32a8cd576c5ee85
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Tue Aug 20 14:53:12 2013 +0800

    add distributed

commit cb926e7ea50ad11b8f9e909c05226233bf755030
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Mon Aug 19 17:51:55 2013 +0800

    wrote a readme file

git log命令顯示從最近到最遠的提交日志,我們可以看到 3 次提交,最近的一次是append GPL,上一次是add distributed,最早的一次是wrote a readme file。 如果嫌輸出信息太多,看得眼花繚亂的,可以試試加上--pretty=oneline參數(shù):

$ git log --pretty=oneline
3628164fb26d48395383f8f31179f24e0882e1e0 append GPL
ea34578d5496d7dd233c827ed32a8cd576c5ee85 add distributed
cb926e7ea50ad11b8f9e909c05226233bf755030 wrote a readme file

需要友情提示的是,你看到的一大串類似3628164...882e1e0的是commit id(版本號),和 SVN 不一樣,Git 的 commit id 不是 1,2,3……遞增的數(shù)字,而是一個 SHA1 計算出來的一個非常大的數(shù)字,用十六進制表示,而且你看到的 commit id 和我的肯定不一樣,以你自己的為準。為什么 commit id 需要用這么一大串數(shù)字表示呢?因為 Git 是分布式的版本控制系統(tǒng),后面我們還要研究多人在同一個版本庫里工作,如果大家都用 1,2,3……作為版本號,那肯定就沖突了。

每提交一個新版本,實際上 Git 就會把它們自動串成一條時間線。如果使用可視化工具查看 Git 歷史,就可以更清楚地看到提交歷史的時間線:

http://wiki.jikexueyuan.com/project/git-tutorial/images/git6.jpg" alt="" />

好了,現(xiàn)在我們啟動時光穿梭機,準備把 readme.txt 回退到上一個版本,也就是 “add distributed” 的那個版本,怎么做呢?

首先,Git 必須知道當前版本是哪個版本,在 Git 中,用 HEAD 表示當前版本,也就是最新的提交3628164...882e1e0(注意我的提交 ID 和你的肯定不一樣),上一個版本就是HEAD^,上上一個版本就是HEAD^^,當然往上 100 個版本寫 100 個^比較容易數(shù)不過來,所以寫成 HEAD~100。

現(xiàn)在,我們要把當前版本“append GPL”回退到上一個版本“add distributed”,就可以使用git reset命令:

$ git reset --hard HEAD^
HEAD is now at ea34578 add distributed

--hard參數(shù)有啥意義?這個后面再講,現(xiàn)在你先放心使用。

看看 readme.txt 的內(nèi)容是不是版本add distributed

$ cat readme.txt
Git is a distributed version control system.
Git is free software.

果然。

還可以繼續(xù)回退到上一個版本wrote a readme file,不過且慢,然我們用git log再看看現(xiàn)在版本庫的狀態(tài):

$ git log
commit ea34578d5496d7dd233c827ed32a8cd576c5ee85
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Tue Aug 20 14:53:12 2013 +0800

    add distributed

commit cb926e7ea50ad11b8f9e909c05226233bf755030
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Mon Aug 19 17:51:55 2013 +0800

    wrote a readme file

最新的那個版本append GPL已經(jīng)看不到了!好比你從 21 世紀坐時光穿梭機來到了 19 世紀,想再回去已經(jīng)回不去了,腫么辦?

辦法其實還是有的,只要上面的命令行窗口還沒有被關(guān)掉,你就可以順著往上找啊找啊,找到那個append GPLcommit id3628164...,于是就可以指定回到未來的某個版本:

$ git reset --hard 3628164
HEAD is now at 3628164 append GPL

版本號沒必要寫全,前幾位就可以了,Git 會自動去找。當然也不能只寫前一兩位,因為 Git 可能會找到多個版本號,就無法確定是哪一個了。

再小心翼翼地看看 readme.txt 的內(nèi)容:

$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.

果然,又回來了。

Git 的版本回退速度非??欤驗?Git 在內(nèi)部有個指向當前版本的 HEAD 指針,當你回退版本的時候,Git 僅僅是把 HEAD 從指向append GPL

http://wiki.jikexueyuan.com/project/git-tutorial/images/git7.jpg" alt="" />

改為指向 add distributed:

http://wiki.jikexueyuan.com/project/git-tutorial/images/git8.jpg" alt="" />

然后順便把工作區(qū)的文件更新了。所以你讓 HEAD 指向哪個版本號,你就把當前版本定位在哪。

http://wiki.jikexueyuan.com/project/git-tutorial/images/git-reset.gif" alt="" />

現(xiàn)在,你回退到了某個版本,關(guān)掉了電腦,第二天早上就后悔了,想恢復(fù)到新版本怎么辦?找不到新版本的 commit id 怎么辦?

在 Git 中,總是有后悔藥可以吃的。當你用$ git reset --hard HEAD^回退到add distributed版本時,再想恢復(fù)到append GPL,就必須找到append GPLcommit id。Git 提供了一個命令git reflog用來記錄你的每一次命令:

$ git reflog
ea34578 HEAD@{0}: reset: moving to HEAD^
3628164 HEAD@{1}: commit: append GPL
ea34578 HEAD@{2}: commit: add distributed
cb926e7 HEAD@{3}: commit (initial): wrote a readme file

終于舒了口氣,第二行顯示append GPLcommit id3628164,現(xiàn)在,你又可以乘坐時光機回到未來了。

http://wiki.jikexueyuan.com/project/git-tutorial/images/git-reflog-reset.gif" alt="" />

小結(jié)

現(xiàn)在總結(jié)一下:

HEAD 指向的版本就是當前版本,因此,Git 允許我們在版本的歷史之間穿梭,使用命令git reset --hard commit_id

穿梭前,用git log可以查看提交歷史,以便確定要回退到哪個版本。

要重返未來,用git reflog查看命令歷史,以便確定要回到未來的哪個版本。

上一篇:Feature 分支下一篇:生成 SSH key