鍍金池/ 教程/ Java/ Git 是如何存儲(chǔ)對(duì)象的
儲(chǔ)藏
Git 樹名
子模塊
使用 Git Grep 進(jìn)行搜索
建立一個(gè)私有倉庫
追蹤分支
Git 的撤消操作 - 重置,簽出和撤消
Git 和 Email
定制 Git
查看 Git 對(duì)象
Git 是如何存儲(chǔ)對(duì)象的
Git 標(biāo)簽
交互式 rebase
獲得一個(gè) Git 倉庫
高級(jí)分支與合并
Git 對(duì)象模型
Git 日志
建立一個(gè)公共倉庫
分布式的工作流程
交互式添加
維護(hù) Git
安裝與初始化
安裝 Git
更底層的 Git
歡迎使用 Git
查找問題的利器 - Git Blame
找回丟失的對(duì)象
比較提交
創(chuàng)建新的空分支
查找問題的利器 - Git Bisect
Git 引用
忽略某些文件
傳輸協(xié)議
打包文件
Git 索引
rebase
正常的工作流程
分支合并
Git 目錄與工作目錄

Git 是如何存儲(chǔ)對(duì)象的

這一章會(huì)詳細(xì)講解 Git 如何物理存儲(chǔ)各對(duì)象。

所有的對(duì)象都以 SHA 值為索引用 gzip 格式壓縮存儲(chǔ),每個(gè)對(duì)象都包含了對(duì)象類型,大小和內(nèi)容。

Git 中存在兩種對(duì)象 - 松散對(duì)象(loose object)和打包對(duì)象(packed object)。

松散對(duì)象

松散對(duì)象是一種比較簡(jiǎn)單格式。它就是磁盤上的一個(gè)存儲(chǔ)壓縮數(shù)據(jù)的文件。每一個(gè)對(duì)象都被寫入一個(gè)單獨(dú)文件中。

如果你對(duì)象的 SHA 值是 ab04d884140f7b0cf8bbf86d6883869f16a46f65,那么對(duì)應(yīng)的文件會(huì)被存儲(chǔ)在:

GIT_DIR/objects/ab/04d884140f7b0cf8bbf86d6883869f16a46f65

Git 使用 SHA 值的前兩個(gè)字符作為子目錄名字,所以一個(gè)目錄中永遠(yuǎn)不會(huì)包含過多的對(duì)象。文件名則是余下的 38 個(gè)字符。

可以用下面的 Ruby 代碼說明對(duì)象數(shù)據(jù)是如何存儲(chǔ)的:

def put_raw_object(content, type)
  size = content.length.to_s

  header = "#{type} #{size}\0" # type(space)size(null byte)
  store = header + content

  sha1 = Digest::SHA1.hexdigest(store)
  path = @git_dir + '/' + sha1[0...2] + '/' + sha1[2..40]

  if !File.exists?(path)
    content = Zlib::Deflate.deflate(store)

    FileUtils.mkdir_p(@directory+'/'+sha1[0...2])
    File.open(path, 'w') do |f|
      f.write content
    end
  end
  return sha1
end

打包對(duì)象

另外一種對(duì)象存儲(chǔ)方式是使用打包文件(packfile)。由于 Git 把每個(gè)文件的每個(gè)版本都作為一個(gè)單獨(dú)的對(duì)象,它的效率可能會(huì)十分的低。設(shè)想一下在一個(gè)數(shù)千行的文件中改動(dòng)一行,Git 會(huì)把修改后的文件整個(gè)存儲(chǔ)下來,很浪費(fèi)空間。

Git 使用打包文件(packfile)去節(jié)省空間。在這個(gè)格式中,Git 只會(huì)保存第二個(gè)文件中改變了的部分,然后用一個(gè)指針指向相似的那個(gè)文件(譯注:即第一個(gè)文件)。

對(duì)象通常是以松散格式寫到磁盤上,因?yàn)檫@個(gè)格式的訪問代價(jià)比較低。然后,你最終會(huì)需要把對(duì)象存放到打包格式中去節(jié)省磁盤空間 - 這個(gè)工作可以通過 git gc 來完成。它使用一個(gè)相當(dāng)復(fù)雜的啟發(fā)式算法去決定哪些文件是最相似的,然后基于此分析去計(jì)算差異??梢源嬖诙鄠€(gè)打包文件,在必要情況下,它們可被解包(git unpack-objects)成為松散對(duì)象或者重新打包(git repack)。

Git 會(huì)為每一個(gè)打包文件創(chuàng)建一個(gè)較小的索引文件。索引文件中包含了對(duì)象在打包文件中的偏移,以便于通過 SHA 值來快速找到特定的對(duì)象。

打包文件的實(shí)現(xiàn)細(xì)節(jié)會(huì)在稍后的‘打包文件’(Packfile)一章中講述。