Git 工作區(qū)、暫存區(qū)和版本庫zz
來源:http://www.worldhello.net/2010/11/30/2166.html
暫存區(qū)(stage, index)是 Git 最重要的概念之一,理解了這個(gè)概念很多 Git 命令就不再那么神秘了。 今天在寫這部分的內(nèi)容,畫了一個(gè)圖,看看有沒有什么問題。 理解 Git 暫存區(qū)(stage) 把上面的“實(shí)踐二”從頭至尾走一遍,不知道您的感想如何?
- —— “被眼花繚亂的 Git 魔法徹底搞糊涂了?”
- —— “Git 為什么這么折磨人,修改的文件直接提交不就完了么?”
- —— “看不出 Git 這么做有什么好處?”
在“實(shí)踐二”的過程中,我有意無意的透漏了“暫存區(qū)”的概念,為了避免用戶被新概念嚇壞,在暫存區(qū)出現(xiàn)的地方用同時(shí)使用了“提交任務(wù)”這一更易理解 的概念,但是暫存區(qū)(stage, 或稱為 index)才是其真正的名稱。我認(rèn)為 Git 暫存區(qū)(stage, 或稱為 index)的設(shè)計(jì)是 Git 最成功的設(shè)計(jì)之一,也是最難理解的一個(gè)設(shè)計(jì)。 在版本庫(.git)目錄下,有一個(gè) index 文件,我們針對(duì)這個(gè)文件做一個(gè)有趣的試驗(yàn)。 首先我們執(zhí)行 "git checkout" 命令撤銷工作區(qū)中 welcome.txt 文件尚未提交的修改。
$ git checkout -- welcome.txt $ git status -s
我們通過狀態(tài)輸出,看以看到工作區(qū)已經(jīng)沒有改動(dòng)了。我們查看一下 .git/index 文件,注意該文件的時(shí)間戳(19:37:44):
$ ls --full-time .git/index -rw-r--r-- 1 jiangxin jiangxin 112 2010-11-29 19:37:44.625246224 +0800 .git/index
我們?cè)俅螆?zhí)行 "git status" 命令,然后顯示 .git/index 文件的時(shí)間戳(19:37:44),和上面的一樣。
$ git status -s $ ls --full-time .git/index -rw-r--r-- 1 jiangxin jiangxin 112 2010-11-29 19:37:44.625246224 +0800 .git/index
現(xiàn)在我們更改一下 welcome.txt 的時(shí)間戳,但是不改變它的內(nèi)容。然后再執(zhí)行 "git status" 命令,然后查看 .git/index 文件時(shí)間戳(19:42:06)。
$ touch welcome.txt $ git status -s $ ls --full-time .git/index -rw-r--r-- 1 jiangxin jiangxin 112 2010-11-29 19:42:06.980243216 +0800 .git/index
看到了么,時(shí)間戳改變了! 這個(gè)試驗(yàn)說明當(dāng)執(zhí)行 "git status" 命令掃描工作區(qū)改動(dòng)的時(shí)候,先依據(jù) .git/index 文件中記錄的(工作區(qū)跟蹤文件的)時(shí)間戳、長度等信息判斷工作區(qū)文件是否改變。如果工作區(qū)的文件時(shí)間戳改變,說明文件的內(nèi)容可能 被改變了,需要要打開文件,讀取文件內(nèi)容,和更改前的原始文件相比較,判斷文件內(nèi)容是否被更改。如果文件內(nèi)容沒有改變,則將該文件新的時(shí)間戳記錄到 .git/index 文件中。因?yàn)榕袛辔募欠窀模褂脮r(shí)間戳、文件長度等信息進(jìn)行比較要比通過文件內(nèi)容比較要快的多,所以 Git 這樣的實(shí)現(xiàn)方式可以讓工作區(qū)狀態(tài)掃描更快速的執(zhí)行,這也是 Git 高效的因素之一。
文件 .git/index 實(shí)際上就是一個(gè)包含文件索引的目錄樹,像是一個(gè)虛擬的工作區(qū)。在這個(gè)虛擬工作區(qū)的目錄樹中,記錄了文件名、文件的狀態(tài)信息(時(shí)間戳、文件長度等),文件的 內(nèi)容并不存儲(chǔ)其中,而是保存在 Git 對(duì)象庫(.git/objects)中,文件索引建立了文件和對(duì)象庫中對(duì)象實(shí)體之間的對(duì)應(yīng)。下面這個(gè)圖展示了工作區(qū)、版本庫中的暫存區(qū)和版本庫之間的關(guān) 系。
工作區(qū)、版本庫、暫存區(qū)原理圖
在這個(gè)圖中,我們可以看到部分 Git 命令是如何影響工作區(qū)和暫存區(qū)(stage, index)的。
- 圖中左側(cè)為工作區(qū),右側(cè)為版本庫。在版本庫中標(biāo)記為 "index" 的區(qū)域是暫存區(qū)(stage, index),標(biāo)記為 "master" 的是 master 分支所代表的目錄樹。
- 圖中我們可以看出此時(shí) "HEAD" 實(shí)際是指向 master 分支的一個(gè)“游標(biāo)”。所以圖示的命令中出現(xiàn) HEAD 的地方可以用 master 來替換。
- 圖中的 objects 標(biāo)識(shí)的區(qū)域?yàn)?Git 的對(duì)象庫,實(shí)際位于 ".git/objects" 目錄下,我們會(huì)在后面的章節(jié)重點(diǎn)介紹。
- 當(dāng)對(duì)工作區(qū)修改(或新增)的文件執(zhí)行 "git add" 命令時(shí),暫存區(qū)的目錄樹被更新,同時(shí)工作區(qū)修改(或新增)的文件內(nèi)容被寫入到對(duì)象庫中的一個(gè)新的對(duì)象中,而該對(duì)象的ID 被記錄在暫存區(qū)的文件索引中。
- 當(dāng)執(zhí)行提交操作(git commit)時(shí),暫存區(qū)的目錄樹寫到版本庫(對(duì)象庫)中,master 分支會(huì)做相應(yīng)的更新。即 master 指向的目錄樹就是提交時(shí)暫存區(qū)的目錄樹。
- 當(dāng)執(zhí)行 "git reset HEAD" 命令時(shí),暫存區(qū)的目錄樹會(huì)被重寫,被 master 分支指向的目錄樹所替換,但是工作區(qū)不受影響。
- 當(dāng)執(zhí)行 "git rm --cached <file>" 命令時(shí),會(huì)直接從暫存區(qū)刪除文件,工作區(qū)則不做出改變。
- 當(dāng)執(zhí)行 "git checkout ." 或者 "git checkout -- <file>" 命令時(shí),會(huì)用暫存區(qū)全部或指定的文件替換工作區(qū)的文件。這個(gè)操作很危險(xiǎn),會(huì)清除工作區(qū)中未添加到暫存區(qū)的改動(dòng)。
- 當(dāng)執(zhí)行 "git checkout HEAD ." 或者 "git checkout HEAD <file>" 命令時(shí),會(huì)用 HEAD 指向的 master 分支中的全部或者部分文件替換暫存區(qū)和以及工作區(qū)中的文件。這個(gè)命令也是極具危險(xiǎn)性的,因?yàn)椴坏珪?huì)清除工作區(qū)中未提交的改動(dòng),也會(huì)清除暫存區(qū)中未提交的改 動(dòng)。
posted on 2012-06-20 16:35 大寶pku 閱讀(377) 評(píng)論(0) 收藏 舉報(bào)

浙公網(wǎng)安備 33010602011771號(hào)