Git基本介紹(三大分區及核心內部構造)


1. Git三大工作區(工作區、暫存區和版本庫)

  

  工作區(WORKING DIRECTORY): 直接編輯文件的地方,肉眼可見直接操作;

  暫存區(STAGIN AREA):數據(快照)暫時存放的地方;

  版本庫(GIT DIRECTORT(RESPOSITORY)):存放已經提交的數據,push 的時候,就是把這個區的數據 push 到遠程git倉庫了。

  git add就是將工作區的修改緩存在暫存區,git commit就是將暫存區的數據快照提交到本地庫

  這就是為什么 git commit 之前要先執行 git add 的原因,如果不先執行add,那么直接執行commit時不會把當前的修改內容提交到代碼庫中的。

 

2. Git 基本概念(實體、引用和索引)

實體:

  提交到 git 代碼倉庫中的所有文件,包括每個提交的說明信息,目錄結構等都會轉換成 git 實體

  所有實體均存在於.git/objects/目錄中

  git中每一個實體以一個40字符長度的十六進制字符串來唯一標識

  git中包括4種類型的實體:

    1.blob-存儲文件內容

    2.tree-存儲目錄結構和文件名

    3.commit-存儲提交的作者、日期、說明等

    4.tag- 存儲指向特定提交對象的引用

引用:

  Git 中,一個分支(branch)、遠程分支(remote branch)或一個標簽(tag)(也稱為輕量標簽)僅是指向一個實體的一個指針,這里的實體通常是一個commit實體。這些引用以文本文件的形式存儲在目錄 .git/refs/ 中符號引用(Symbolic References)Git 有一種特殊的引用,稱為符號引用。它並不直接指向一個實體,而是指向另一個引用。舉例說,.git/HEAD就是一個符號引用。它指向你正在工作的當前分支。

索引:  

  索引是一個暫存區,以二進制文件的形式存儲為文件 .git/index 中當git add 一個文件,git 將該文件的信息添加到索引中當git commit時,git 僅提交索引文件中列出的文件到 git 本地倉庫

 

實體、引用和索引之間的關系:

 

測試說明:

  1. 新建一個readme,txt並提交到本地庫

git add readme.txt
git commit -m 'first commit'

   2. git log查看commit實體,可以看出對於的SHA1值為999976c43b0e684f1bf7af4bed1acd11b3afa636

  

  3. git cat-file目錄查看該commit實體的內容, 可以看出該commit實體包含了提交的作者及郵箱等全局信息,除此之外還包括了一個tree實體, 該實體的SHA1值為bb527569763dcd71a5dcd4b9a4ba692f1ebb56c0

  

  4. 使用git ls-tree查看該tree實體, 發現tree實體中包含了一個blob實體, 該實體的的SHA1值為0cce6dff89d87d991136ad27e18c928eb65f5bb3

  

   5. 使用git cat-file -p XXX查看blob實體內容, 可以發現blob實體存儲的就是readme.txt文件內容

  

  6. 此時我們查看.git/refs/heads/master文件內容,可以發現其剛好為commit實體的SHA1值,也就說明 master 為一個 引用 ,並且指向最后一個 commit 實體

  

  7. 在剛剛介紹中,我們知道了tag實體存儲了指向指定commit實體的引用,下面來創建一個標簽"version1.1", 通過git rev-parse tagname來查看tag實體的SHA1值,再通過git cat-file -p XXXX可以發現該tag內部即為commit實體,且該commit實體為最后一次提交的實體

  

  8. 至此我們生成了四個實體,分別為

    999976c43b0e684f1bf7af4bed1acd11b3afa636  ----commit實體

    bb527569763dcd71a5dcd4b9a4ba692f1ebb56c0   ---tree實體

    0cce6dff89d87d991136ad27e18c928eb65f5bb3   ---blob實體 

    50e5866a324c6e2afaf6374c39b4b93d394b504a  --tag實體

  8. 查看各實體、引用、索引的儲存位置

    實體(.git/objects/):以SHA1頭兩位作為文件名

    

    引用(.git/refs): heads下存儲歷史commit實體, tags下存儲每一個標簽

    

    索引(.git/index):

     

    通過git ls-files --stage查看.git/index文件內容,可以發現並非存儲着最新commit實體的SHA1值而是其commit實體關聯的blob實體SHA1值

    

    再次測試.git/index中文件內容, 我們新建一個文件index並提交到本地庫

    

    

 

 3. Git SHA1

  git 為每一個實體生成一個160位的散列值,通常使用40個字符長度的16進制字符串表示

散列碰撞:

  幾乎不會出現散列碰撞情況(相同SHA1,出現沖突)

  通常情況下你不需要擔心該散列值會產生碰撞,對於 160 位數,你有 2160 或者大約 1048 種可能的 SHA1 散列值。這個數有多么巨大,你可以簡單感受下,即使你雇一萬億人來每秒產生一萬億個新的唯一 blob 對象,持續一萬億年,你也只有 1043 個 blob 對象,所以你基本不用擔心該散列值會產生碰撞,而且只有當不同的內容產生了相同的 SHA1 散列值才能稱為碰撞。

git 基於內容的 SHA1:

  對應相同的內容得到的永遠是相同的 SHA1

  之前已經提到過 git 會為每個實體生成一個唯一的 SHA1 值來標識該實體,並且 git 會將生成的實體以二進制文件的形式保存在 .git/objets 目錄下,但是 git 在生成 SHA1 時並不是簡單地基於文件名、文件路徑、創建者及創建時間組合起來,相反 git 是基於內容來生成 SHA1,試想一下,如果我們項目中有一個 a.txt 文件,分別存放在 dir1,dir2 目錄下,這時候 git 並不會為 dir1/a.txt 和 dir2/a.txt 文件創建兩個 blob 實體,因為 a.txt 雖然在兩個目錄下,但是他們的內容是完全一樣的,所以 git 在生成實體時,通過散列算法,git 會發現這兩個文件得出的 SHA1 值是完全一樣的,所以 git 只會保存一個 blob 實體。這樣可以避免當我們再重命名文件,或者移動文件所在目錄時,生成重復的 blob 實體,這也得益於 git 基於內容的散列算法可以很好地發現這兩個文件其實是同一個文件。

測試:

  

 

4. git 特殊符號引用介紹

git 自動維護了幾個用於特定目的的特殊符號引用。這些引用可以在使用提交的任何地方使用。

  • HEAD 始終指向當前分支最終提交。當切換分支時 HEAD 會更新為指向新分支的最新提交。
  • ORIG_HEAD 某些操作,例如 merage / reset 會把 merge 之前的 HEAD 保存到 ORIG_HEAD 中,以便在 merge 之后可以使用 ORIG_HEAD 來回滾到合並之前的狀態(在分支合並的時候,產生了沖突,如果已經修改了沖突,並產生了新的提交,但是沖突解決的有問題,想要還原之前的狀態重新合並,這時可以使用 git reset --hard ORIG_HEAD 來還原到合並之前的狀態)。
  • FETCH_HEAD 當使用命令 git fetch 抓取遠程倉庫更新時,FETCH_HEAD 保存着最近抓取的分支的 HEAD。
  • MERGE_HEAD 當一個合並正在進行時,其他分支的頭暫時記錄在 MERGE_HEAD 中,換言之, MERGE_HEAD 是正在合並進 HEAD 的提交。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM