.git目錄
下面就開始進入.git目錄,通過“ls”命令可以看到.git目錄中的文件和子目錄:
對於這些文件和目錄,下面給出了一些基本的描述。
- hooks:這個目錄存放一些shell腳本,可以設置特定的git命令後觸發相應的腳本;在搭建gitweb系統或其他git託管系統會經常用到hook script
- info:包含倉庫的一些信息
- logs:保存所有更新的引用記錄
- objects:所有的Git對象都會存放在這個目錄中,對象的SHA1哈希值的前兩位是文件夾名稱,後38位作爲對象文件名
- refs:這個目錄一般包括三個子文件夾,heads、remotes和tags,heads中的文件標識了項目中的各個分支指向的當前commit
- COMMIT_EDITMSG:保存最新的commit message,Git系統不會用到這個文件,只是給用戶一個參考
- config:這個是GIt倉庫的配置文件
- description:倉庫的描述信息,主要給gitweb等git託管系統使用
- index:這個文件就是我們前面提到的暫存區(stage),是一個二進制文件
- HEAD:這個文件包含了一個檔期分支(branch)的引用,通過這個文件Git可以得到下一次commit的parent
- ORIG_HEAD:HEAD指針的前一個狀態
Git引用
Git中的引用是一個非常重要的概念,對於理解分支(branch)、HEAD指針以及reflog非常有幫助。
Git系統中的分支名、遠程分支名、tag等都是指向某個commit的引用。比如master分支,origin/master遠程分支,命名爲V1.0.0.0的tag等都是引用,它們通過該保存某個commit的SHA1哈希值指向某個commit
重新認識HEAD
HEAD也是一個引用,一般情況下間接指向你當前所在的分支的最新的commit上。HEAD跟Git中一般的引用不同,它並不包含某個commit的SHA1哈希值,而是包含當前所在的分支,所有HEAD直接執行當前所在的分支,然後間接指向當前所在分支的最新提交。
爲了更形象的解釋上面的描述,我們首先查看“.git/HEAD”的內容:
這就表示HEAD是一個指向master分支的引用,然後我們可以根據引用路徑打開“refs/heads/master”文件,內容如下:
根據前面一片文章的介紹,我們通過這個哈希值查看對象的類型和雷人,可以看到這個哈希值對應着一個commit,並通過“git log”可以發現這個commit就是master分支上最新的提交。
所以可以看到,所有的內容都是環環相扣的,我們通過HEAD找到一個當前分支,然後通過當前分支的引用找到最新的commit,然後通過commit可以找到整個對象關係模型,看下圖:
引用和分支
直到現在我們都沒有開始介紹分支(branch),先大概展示一下引用和分支的關係。
假設我們現在除了master分支,又創建了一個release-1.0.0.1的分支,再次查看“.git/refs/heads/”目錄,可以看到除了master文件之外,又多了一個release-1.0.0.1文件,查看該文件的內容也是一個哈希值。
通過“git show-ref --heads”命令就可以查看所有的頭,這些都是HEAD的候選值:
HEAD文件的內容是commit的分支,當我們把分支切換到release-1.0.0.1的時候,HEAD文件的內容也會相應的變成:
ref: refs/heads/release-1.0.0.1
日誌
我們進入“.git/logs”文件夾,可以看到這個文件夾也有一個HEAD文件和refs目錄,這些就是記錄commit歷史記錄的地方。我們可以通過commit的哈希值,把repo退到一個指定的狀態。
Git索引index
前面文章我們也提到過index/stage,就是更新的暫存區,下面來看看index文件。
index(索引)是一個存放了已排序的路徑的二進制文件,並且每個路徑都對應一個SHA1哈希值。在Git系統中,可以通過“git ls-files --stage”來顯示index文件的內容:
從命令的輸出可以看到,所有的記錄都對應倉庫中的文件(包含全路徑)。上面顯示的哈希值就是abc.txt的blob對象的哈希值。
現在我們更新abc.txt文件,並通過“git add”添加到暫存區,這時發現index中的abc對象的哈希值已經變化了。
對象的存儲
前面提到所有的Git對象都會存放在“.git/objects”目錄中,對象SHA1哈希值的前兩位是文件夾名稱,後38位作爲對象文件名。下面是之前提到的master最新的commit對象的哈希值:
63a6ea8475b47078dee14ea8ff2c8731927ffbbf
在Git系統中有兩種對象存儲的方式,鬆散對象存儲和打包對象存儲
鬆散對象(loose object)
鬆散對象存儲就是前面提到的,每一個對象都被寫入一個單獨文件中,對象SHA1哈希值的前兩位是文件夾名稱,後38位作爲對象文件名。
打包對象(packed object)
對應鬆散存儲,把每個文件的每個版本都作爲一個單獨的對象,它的效率比較低,而且浪費空間。所以就有了通過打包文件(packfile)的存儲方式。
Git使用打包文件(packfile)去節省空間。在這個格式中,Git只會保存第二個文件中改變的部分,然後用一個指針指向相似的那個文件。
一般Git系統會自動完成打包的工作,在已經發生過打包的Git倉庫中,object/pack目錄下回成對出現很多“pack-***.idx”和“pack-***.pak”文件。