本文主要是對git-scm上的一篇博客的總結(jié)與補充,有說的不清楚的地方希望讀者能讀一下原博客
git的三個空間
在設(shè)計上,git將傳統(tǒng)的工作空間,也就是工作目錄,劃分為三個層次:

由右往左分別為:工作目錄,暫存區(qū)和版本庫。中文翻譯版本眾多,我們就用它的英文版本好了。那么,平時我們工作于Working Directory,作出一部分修改后,我們會git add來將我們的修改暫存,也就是加入Index,最后使用git commit完成一次提交,也就是將當(dāng)前Index中的文件加入到版本庫,并移動HEAD指針指向當(dāng)前提交。如下圖:



git reset
git reset指令主要用來恢復(fù)文件,撤銷提交。
對整個工程使用reset
不指定特定文件時,git reset指令會進(jìn)行如下3步操作:
- 修改HEAD(與其指向的分枝)指針,讓它(們)指向指定版本。這一步reset了版本庫,僅影響到HEAD(與其指向的分枝)指針。
- 用指定版本的工程文件還原Index區(qū)。
- 用指定版本的工程文件還原Working Directory。
而git reset命名后面帶的三種參數(shù)則分別表示reset過程進(jìn)展到上面的三個階段:



指定文件的reset
既然指定了reset特定文件,那就說明使用者的意圖不在于修改版本庫,因此指定文件的reset命令都不會執(zhí)行階段1,也就是不會修改HEAD指針。實際上在指定文件的情況下,reset指令只會用版本庫中指定版本的文件還原Index區(qū)。


git checkout
git checkout在功能上與reset命令很相似,但是二者確實是被設(shè)計用于不同場合的,下面來討論它們的區(qū)別。
不指定文件的checkout
效果上,不指定特定文件,git checkout與git reset --hard幾乎完全一樣,區(qū)別在于:
-
git checkout在對Working Directory進(jìn)行“安全檢查”。它會嘗試對你當(dāng)前Working Directory中的文件與指定checkout的版本進(jìn)行一次簡單合并,如果在運行git checkout之前,你改動了工作區(qū)的文件,checkout操作不會覆蓋你當(dāng)前修改過的文件;而git reset --hard操作則僅僅簡單粗暴的覆蓋整個工作區(qū)。所以git checkout操作是安全的。 - 我們知道HEAD作為頭指針實際上指向了版本庫當(dāng)中的分支指針,而分支指針才實際的指向某次提交,比如
HEAD->master->8bcea這種結(jié)構(gòu)。git reset --hard命令實際是修改了上面例子中的master分支指針的指向;git checkout命令修改的則是HEAD指針的指向:

因此,checkout更多的用于分支切換等非破壞性操作,而reset則用于還原等破壞性操作。
指定文件的checkout
有沒有覺得剛剛在討論指定文件的reset操作時,似乎漏了點功能?指定文件的reset只還原了Index區(qū),可是如何還原Working Directory?是的,指定文件的checkout操作可以還原當(dāng)前工作目錄。
也就是說,可以簡單的理解為,指定文件的git checkout實現(xiàn)了指定文件的git reset --hard操作,它首先用特定文件還原Index區(qū),再還原Working Directory。
git revert
git revert命令可以被認(rèn)為是安全的reset操作。它會用指定版本的版本庫狀態(tài)在當(dāng)前的HEAD指針后面添加一個提交,并移動HEAD指針。
也就是說,git會取出你指定的版本,“覆蓋”你的Working Directory,然后執(zhí)行:
git add .
git commit -m "Revert xxx"
這個操作的安全性在于:
- 不像reset那樣有可能修改提交歷史,而是增加了提交,符合git的設(shè)計思想,可逆操作。
- “覆蓋”Working Directory的過程與checkout指令類似,會進(jìn)行安全檢查。
下面是一個例子:

git rm
*nix的軟件思想有一條是不做重復(fù)的工作,因此git rm與/bin/rm功能是不同的:
- 默認(rèn)情況下,
git rm會講文件同時從版本庫、Index和Working Directory刪除 - 加上
--cached參數(shù)時,rm操作會保留Working Directory中的文件,而將其它兩個區(qū)域中的指定文件刪除。
而刪除文件操作在git中也有安全限制,因此,如果Index或Working Directory中的指定文件與版本庫中的校驗和不一致,git rm操作就會報錯,而-f參數(shù)可以指定強制刪除。