參考文章:git內部原理
git 是一套內容定址檔案系統,從內部來看,git 是簡單的 key-value 資料儲存。它允許插入任意型別的內容,並會返回一個鍵值,通過該鍵值可以在任何時候再取出該內容。
git的工作總共分四層,其中三層是在自己原生的git倉庫,包括了工作目錄,暫存區和本地倉庫,工作目錄就是我們執行命令git init
時所在的地方,也是執行一切檔案操作的地方,暫存區和本地倉庫都是在.git
目錄,因為它們只是用來存資料的。遠端倉庫在中心伺服器,也就是我們做好工作之後推播到遠端倉庫,或者從遠端倉庫更新下來最新程式碼到我們的git倉庫。git所儲存的都是一系列的檔案快照,然後git來跟蹤這些檔案快照,發現哪個檔案快照有變化它就會提示你需要新增到暫存區或是提交到本地倉庫來保證你的工作目錄是乾淨的。
這個怎麼理解呢,git中的檔案有兩種狀態,一種是被跟蹤的,也就是提交到本地倉庫的檔案,因為本地倉庫要保管它們,所以得跟蹤他們,第二種未被跟蹤的。那麼當我們新增新的檔案時,它不是被跟蹤的,因為本地倉庫裡面沒有這個檔案,它是外來的,在git commit
之前本地倉庫還不需要對他們負責。但是如果是對倉庫已經存在的檔案進行修改,那麼這些檔案就是被跟蹤的檔案,就可以通過git status
檢視他們的狀態來進行相應的操作。當然我們也可以生成一個.gitignore
檔案,裡面指定要忽略的檔案型別,然後這些檔案就不會被跟蹤,也不會被提交。
在工作目錄中進行檔案操作後,要先新增到暫存區,然後再將暫存區中剛新增的檔案快照提交到本地倉庫,然後再將本地倉庫的最新版本檔案快照推播到遠端倉庫。這個檔案快照其實就是各個檔案的在被新增到暫存區時的狀態,就和照相一樣的,留下每個不同時刻的快照,方便以後查詢,而git儲存的就是這些一系列的快照。說到這個快照就要說說git的物件了。
從根本上講,git是一套內容定址的檔案系統,它儲存的也是key-value鍵值對,然後根據key值來查詢value的,說到定址就會想到指標,git也是根據指標來定址的,這些指標就儲存在git的物件中。git一共有3種物件,commit物件,tree物件和blob物件。
blob是最小的儲存單元,對應的就是檔案快照中那些發生變化的檔案內容;tree物件則記錄了檔案快照中各個目錄和檔案的結構關係,它指向了被跟蹤的快照;commit物件則記錄了每次提交到本地倉庫的檔案快照。
從上圖看出commit會有兩個指標,一個指向tree物件,一個則指向上一個commit物件。在開發過程中,我們會提交很多次檔案快照,那麼第一次提交的內容會用一個commit來記錄,這個commit沒有指標指向上一個commit物件,因為沒有上一個commit,它是第一個,當第二次提交時,又會有另外一個commit物件來記錄,那麼這次commit物件中就會有一個指標指向上一次提交後的commit物件,經過很多次提交後就會有很多的commit物件,它們組成了一個連結串列,當我們要恢復哪個版本的時候,只要找到這個commit物件就能恢復那個版本的檔案。而我們所謂的HEAD物件其實就指向最近一個提交的commit物件,也就是最後一個commit物件。
commit:它儲存的是一個提交的資訊,包括對應目錄結構的快照tree的雜湊值,上一個提交的雜湊值(這裡由於是第一個提交,所以沒有父節點。在一個merge提交中還會出現多個父節點),提交的作者以及提交的具體時間,最後是該提交的資訊。
Tree:從它儲存的內容來看可以發現它儲存了一個目錄結構(類似於資料夾),以及每一個檔案(或者子資料夾)的許可權、型別、對應的身份證(SHA1值)、以及檔名
blob:它只儲存的是一個檔案的內容,不包括檔名等其他資訊。然後將這些資訊經過SHA1雜湊演演算法得到對應的雜湊值:a8b136da1d43a350901e4131bae78826d193d8
,作為這個object在Git倉庫中的唯一身份證。