從根本上來(lái)講柬唯,Git是一個(gè)內(nèi)容尋址文件系統(tǒng)揭北,并在此之上提供了一個(gè)版本控制系統(tǒng)的用戶界面隐砸,它是一個(gè)非常強(qiáng)大且易用的工具之碗,理解Git的工作原理,能夠幫助我們更容易學(xué)習(xí)和使用Git季希。
本文不會(huì)像書籍里那樣褪那,一條條討論checkout、branch式塌、remote等諸如此類動(dòng)詞形式的高層命令和底層命令博敬,本文主要從宏觀方向傳達(dá)Git的思想和工作原理,能夠使初學(xué)者更加理解峰尝,更利于學(xué)習(xí)偏窝。

直接記錄快照,而非差異比較
Git 和其他版本控制系統(tǒng)的主要差別在于武学,Git 只關(guān)心文件數(shù)據(jù)的整體是否發(fā)生變化祭往,而大多數(shù)其他系統(tǒng)則只關(guān)心文件內(nèi)容的具體差異。這類系統(tǒng)(CVS火窒,Subversion硼补,Perforce,Bazaar 等等)每次記錄有哪些文件作了更新熏矿,以及都更新了哪些行的什么內(nèi)容:
Git 并不保存這些前后變化的差異數(shù)據(jù)已骇。實(shí)際上缆八,Git 更像是把變化的文件作快照后,記錄在一個(gè)微型的文件系統(tǒng)中疾捍。每次提交更新時(shí)奈辰,它會(huì)縱覽一遍所有文件的指紋信息并對(duì)文件作一快照,然后保存一個(gè)指向這次快照的索引乱豆。為提高性能奖恰,若文件沒(méi)有變化,Git 不會(huì)再次保存宛裕,而只對(duì)上次保存的快照作一鏈接瑟啃。Git 的工作方式就如下圖所示。
這是 Git 同其他系統(tǒng)的重要區(qū)別揩尸。它完全顛覆了傳統(tǒng)版本控制的套路蛹屿,并對(duì)各個(gè)環(huán)節(jié)的實(shí)現(xiàn)方式作了新的設(shè)計(jì)。Git 更像是個(gè)小型的文件系統(tǒng)岩榆,但它同時(shí)還提供了許多以此為基礎(chǔ)的超強(qiáng)工具错负,而不只是一個(gè)簡(jiǎn)單的 VCS。
工作區(qū)和暫存區(qū)
Git 和其他版本控制系統(tǒng)的一個(gè)不同之處就是有暫存區(qū)的概念勇边。
工作區(qū)(Working Directory)
在電腦中能看到的目錄犹撒,比如我建立的gittest就是一個(gè)工作區(qū)
版本庫(kù)(Repository)
工作區(qū)中的隱藏目錄.git
,就是Git的版本庫(kù)粒褒。
Git的版本庫(kù)里存了很多東西识颊,其中最重要的就是稱為stage(或者叫index)的暫存區(qū),還有Git為我們自動(dòng)創(chuàng)建的第一個(gè)分支master奕坟,以及指向master的一個(gè)指針叫HEAD祥款。
回憶在我上一篇博客中提到的將文件添加到版本庫(kù)的流程圖:
通過(guò)以上兩幅圖不難看出,需要提交的文件經(jīng)過(guò)add后先都放到暫存區(qū)index(或者叫stage)中月杉,然后經(jīng)過(guò)commit指令刃跛,一次性提交暫存區(qū)的所有修改到head。一旦提交后沙合,暫存區(qū)清空奠伪,同時(shí)若對(duì)工作區(qū)沒(méi)有做任何修改,那么工作區(qū)就是干凈的(working directory clean)
文件的三種狀態(tài)
對(duì)任何一個(gè)文件首懈,在Git內(nèi)都有三種狀態(tài):
- 已提交(committed):表示該文件已經(jīng)被安全的保存在本地?cái)?shù)據(jù)庫(kù)中了
- 已修改(modified):表示修改了某個(gè)文件,但還沒(méi)有提交保存
- 已暫存(staged):表示把已修改的文件放在下次提交時(shí)要保存的清單中
所謂的暫存區(qū)域只不過(guò)是個(gè)簡(jiǎn)單的文件谨敛,一般都放在 Git 目錄中究履。有時(shí)候人們會(huì)把這個(gè)文件叫做索引文件,不過(guò)標(biāo)準(zhǔn)說(shuō)法還是叫暫存區(qū)域脸狸。
我們可以從文件所處的位置來(lái)判斷狀態(tài):
- Git 目錄中保存著的特定版本文件----->已提交狀態(tài)
- 作了修改并已放入暫存區(qū)域----->已暫存狀態(tài)
- 自上次取出后最仑,作了修改但還沒(méi)有放到暫存區(qū)域----->已修改狀態(tài)
重要的 .git 目錄
當(dāng)一個(gè)新目錄或已有目錄執(zhí)行git init
時(shí)藐俺,Git會(huì)創(chuàng)建一個(gè).git
目錄。這個(gè)目錄包含了幾乎所有Git存儲(chǔ)和操作的對(duì)象泥彤。若想備份或復(fù)制一個(gè)版本庫(kù)欲芹,只需把這個(gè)目錄拷貝至另一處即可。對(duì)于一個(gè)全新的版本庫(kù)吟吝,該目錄結(jié)構(gòu)如下所示:
- description文件:僅供GitWeb程序使用
- config文件:包含項(xiàng)目特有的配置選項(xiàng)
- info目錄:包含一個(gè)全局性排除(global exclude)文件菱父,用以放置那些不希望被記錄在 .gitignore文件中的忽略模式(ignored patterns)
- hooks目錄:包含客戶端或服務(wù)端的鉤子腳本(hook scripts)
- HEAD文件:指示目前被檢出的分支
- index文件:保存暫存區(qū)信息
- objects目錄:存儲(chǔ)所有數(shù)據(jù)內(nèi)容
- refs 目錄:存儲(chǔ)指向數(shù)據(jù)(分支)的提交對(duì)象的指針
關(guān)于Git底層命令和高層命令的原理討論,很大一部分都在這個(gè)目錄中剑逃,要想了解具體的原理浙宜,可以看這本書,這里僅僅列出了每部分的功能蛹磺,有個(gè)大體了解粟瞬。
基本的 Git 工作流程
- 在工作目錄中修改某些文件。
- 對(duì)修改后的文件進(jìn)行快照萤捆,然后保存到暫存區(qū)域裙品。
- 提交更新,將保存在暫存區(qū)域的文件快照永久轉(zhuǎn)儲(chǔ)到 Git 目錄中俗或。
分析 Git 命令
有了上述介紹清酥,我們可以對(duì) Git 的命令有更深的理解,這里以將文件添加到代碼庫(kù)為例進(jìn)行分析:我們都知道需要兩步蕴侣,第一步add焰轻,第二步commit,但為什么要分兩步呢昆雀?每一步都做了什么呢辱志?
(1)git commit -a:相當(dāng)于運(yùn)行 git add 把所有當(dāng)前目錄下的文件加入暫存區(qū)域再運(yùn)行 git commit
(2)git commit <file_name>:進(jìn)行一次包含最后一次提交加上工作目錄中文件快照的提交,并且文件被添加到暫存區(qū)域
(3)git checkout HEAD -- <file_name>:回滾到復(fù)制最后一次提交
以上僅僅分析了添加文件到代碼庫(kù)的過(guò)程狞膘,更多命令詳解看這里