git學習之一:內部對象工作原理

版本控制在於文件的控制,git的控制方法在於爲每個文件生成(key,object)的結構。git利用sha-1加密算法,對每一個文件生成一個唯一的字符序列(明文大小不超過2^64位,對於普通文件,這個大小都可以滿足)作爲hash_key。對於sha-1算法,明文(對於git來講,就是我們的文件內容)不變,其sha-1值不會改變,所以只要文件改變,就會生成一對新的(key,object)[對於key,當中還有一些細微的處理,不僅僅只是sha-1算法,這裏我們只是需要理解,git爲一個文件生成了一個唯一的key]。

使用git init初始化一個本地倉庫,打開隱藏目錄.git,其內容如下圖。可以看到一個objects的目錄,裏面只有info和pack兩個空文件夾。初始化的時候不存在任何object,也就是沒有任何文件被記錄下來。

1.blob對象

我們在工作目錄下添加一個文件file_1.txt,裏面只要一個字符串"file1 content",使用git hash-object [文件名],可以查看其經過算法生成的hash-key.這個一個40個字符長度的序列。其序列爲d9039017ab6c958678a334446aadfe5047266027

這個時候object目錄下還是空,使用git add file_1.txt之後,object裏會多一個對象,下面詳細來解析這個對象。首先看看object目錄發生了什麼事情

多了一個d9的目錄


d9目錄下

可以看到40位的hash-key 前兩位作爲目錄名,後38位作爲文件名,標識了這個object對象,這個對象裏面的內容就是剛纔file_1.txt裏的內容,可以查看這個對象的內容和對象類型:

git cat-file -p [hash-key] 可以查看已經存在的object對象內容

git cat-file -t [hash-key] 可以查看已經存在的object對象類型

git object有四種類型,這是目前我們接觸到的第一種類型blob,用來儲存文件類容,它的具體內容就是剛剛新建的txt裏的字符串file1 content。


2.tree對象

blob對應文件的內容,tree對象可以理解爲目錄,它的樹節點信息包含文件名,hash-key,文件類型、權限等等。這樣就可以組織整個需要控制文件的結構

下面我們再往工作目錄下添加一個目錄dir_1,在dir_1添加一個文件1.txt,類容爲"1.txt content"。使用git add 將內容加入到暫存區(也稱index,目前不是本文的重點,會在後續章節中詳解)。使用git hash-object來查看生成的key值。

對於文件可以看到生成了hash-key,但是對於目錄很明顯沒有達到預期的效果。我們看看object目錄

只存在一個6d的目錄,也就是6dc2bcda0c359c6dbb917dec90ca4a8d078ff789對應的1.txt文件,這時我們的目錄並沒有生成tree對象,tree對象是在commit的過程中生成的,其生成會根據.git目錄下的index文件的內容來創建。git add的操作就是將文件的信息保存到index文件中,在commit時,根據index的內容來生成tree對象。

使用git ls-files --stage命令,我們看看index裏的類容

可以看到index包含了創建tree對象的信息 文件類型(100644),ash-key,目錄結構和文件名。

下面我們進行第一次commit,生成commit對象,同時生成tree對象。我們這裏具體看看tree對象,master是分支名,master^{tree},表示master分支所指向的tree對象。

可以看到這個tree對象是我們的工作目錄,目錄下還有一個dir_1的tree對象,和file_1的blob對象,下面看看dir_1對應的tree對象的內容,這個tree對象只包含1.txt的信息。

目前我們的git倉庫的內部結構如下:

3.commit對象

介紹tree對象時,提到過commit,只有在commit的時候,纔會根據index記錄的內容生成tree對象,那麼commit對象裏只有兩個類容:1.代表工作目錄的tree對象的key,上一個commit的key。

現在看看我們的object目錄:

目前我們的對象數量還不多,每個目錄裏有一個對象,就是五個對象,剛纔的總體tree圖,只包含了四個對象,我們使用git log查看commit的歷史

90對應的文件夾裏面的文件就是我們的commit對象,它指向工作目錄tree,和上一次的commit,這是第一個commit ,所以上一個commit不存在。

對象類型爲commit 內容指向工作目錄tree,所以能獲取到一個commit,就可以完整得到當前的文件狀況,現在我們的完整的object圖如下:

現在我們在工作加入一個新的目錄dir_2,和該目錄下文件2.txt,內容爲"content 2",在add和commit之後,我們在看看新的commit的信息

的commit指向了上一個commit,還指向了一個新生成的tree,這個tree表示了新的工作目錄情況,看看這tree的類容:

這個tree包含了當前的文件目錄和內容,現在我們的對象完整的圖如下:

可以看到commit對象指向了工作目錄tree,這樣只要切換commit,就可以隨意切換我們的版本類容。現有有9個object對象了,我們來看看.git/objects目錄,對象還很少,沒有在出現同一目錄下的兩個文件的情況。


上述三種對象:blob(記錄文件內容),tree(目錄結構),commit(工作目錄tree,提交歷史),git版本控制圍繞這三類對象展開。



小結:本文通過講解git內部的三種對象來解釋git的內部工作機制,對於熟悉git使用的人,可以幫助其深入理解。對於版本控制的初學者,只需要瞭解大概,可以在瞭解其他章節之後再進一步理解




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章