亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Git的打包文件是增量文件,而不是快照?

Git的打包文件是增量文件,而不是快照?

Git
慕妹3242003 2019-11-11 14:20:27
Git與大多數其他版本控制系統之間的主要區別之一是,其他版本控制系統傾向于將提交存儲為一系列增量-一個提交與下一個提交之間的變更集。這似乎是合乎邏輯的,因為它是存儲有關提交的盡可能少的信息。但是提交歷史記錄越長,用于比較修訂范圍的計算就越多。相比之下,Git 在每個修訂版中存儲整個項目的完整快照。每次提交不會使repo的大小急劇增加的原因是項目中的每個文件都作為文件存儲在Git子目錄中,以其內容的哈希命名。因此,如果內容沒有更改,則哈希值也沒有更改,并且提交僅指向同一文件。并且還有其他優化。所有這些對我來說都是有意義的,直到我偶然發現了有關pack文件的信息,Git定期將數據放入其中以節省空間:為了節省空間,Git利用了packfile。這是一種格式,其中Git僅將更改過的部分保存在第二個文件中,并帶有指向該文件的指針。這基本上不是回到存儲增量嗎?如果沒有,那有什么不同?如何避免Git遭受其他版本控制系統所遇到的相同問題?例如,Subversion使用增量,而回滾50個版本意味著撤消50個差異,而使用Git,您只需獲取適當的快照即可。除非git也將50個差異存儲在packfile中...否則是否有某種機制說“在少量增量后,我們將存儲一個新快照”,這樣我們才不會堆積太大的變更集?Git還能如何避免三角洲的弊端?
查看完整描述

3 回答

?
ibeautiful

TA貢獻1993條經驗 獲得超6個贊

簡介:

Git的pack文件經過精心構造,可以有效地使用磁盤緩存,并為常用命令和讀取最近引用的對象提供“不錯”的訪問模式。


Git的包文件格式相當靈活(見文檔/技術/包,format.txt,或將打包文件在Git的社區圖書)。打包文件以兩種主要方式存儲對象:“未刪除”(獲取原始對象數據并進行壓縮壓縮)或“刪除”(針對某個其他對象形成增量,然后對生成的增量數據進行壓縮壓縮)。數據包中存儲的對象可以按任何順序排列(不必(不必)按對象類型,對象名稱或任何其他屬性排序),并且可以針對相同類型的其他任何合適的對象制作已刪除的對象。


Git的pack-objects命令使用了幾種啟發式方法,可以為常見命令提供出色的參考位置。這些啟發式方法既控制了已刪除對象的基礎對象的選擇,又控制了對象的順序。每種機制大部分都是獨立的,但是它們有一些共同的目標。


Git確實形成了增量壓縮對象的長鏈,但是試探法試圖確保只有“舊”對象在長鏈的末端。core.deltaBaseCacheLimit自動使用增量基本緩存(其大小由配置變量控制 ),并且可以大大減少需要讀取大量對象(例如git log

-p)的命令所需的“重建”次數。


增量壓縮啟發式

典型的Git存儲庫存儲大量對象,因此無法合理地比較所有對象以找到將產生最小增量表示形式的對(和鏈)。


增量基數選擇啟發式算法是基于這樣的思想,即可以在文件名和大小相似的對象中找到良好的增量基數。每種類型的對象都是單獨處理的(即,一種類型的對象永遠不會用作另一種類型的對象的增量基礎)。


出于增量基數選擇的目的,對象(主要)按文件名和大小排序。進入此排序列表的窗口用于限制被視為潛在增量基礎的對象數量。如果一個“足夠好” 1個沒有找到在其窗口中的對象之間的對象增量表示,則該對象將不被增量壓縮。


窗口的大小由的--window=選項 git pack-objects或pack.window配置變量控制。增量鏈的最大深度由的--depth= 選項git pack-objects或pack.depth配置變量控制。該--aggressive選項git gc極大地增加了窗口大小和最大深度,以嘗試創建較小的打包文件。


文件名排序會將名稱相同(或至少類似結尾(例如.c))的條目的對象聚在一起。大小排序從最大到最小,因此刪除數據的增量要優先于添加數據的增量(因為刪除增量具有較短的表示形式),因此較早,較大的對象(通常是較新的)傾向于以普通壓縮方式表示。


1 什么才算是“足夠好”取決于所討論對象的大小及其潛在的增量基數以及其產生的增量鏈的深度。


對象排序啟發式

對象以“最近引用”的順序存儲在打包文件中。重建最新歷史記錄所需的對象放在包裝中的較早位置,它們將靠近在一起。這通常適用于OS磁盤緩存。


所有提交對象均按提交日期排序(最新的優先),并存儲在一起。此放置和排序優化了遍歷歷史圖和提取基本提交信息(例如git log)所需的磁盤訪問。


從第一個存儲的(最新的)提交開始,從樹開始存儲tree和blob對象。每棵樹以深度優先的方式進行處理,存儲所有尚未存儲的對象。這會將重建最近提交所需的所有樹木和斑點都放在一個位置。接下來,將按照已排序的提交順序存儲尚未保存但以后提交需要的所有樹和Blob。


最終對象的排序受增量基本選擇的影響很小,因為如果為增量表示選擇了一個對象并且尚未存儲其基本對象,則將其基本對象存儲在已修改對象本身之前。這樣可以防止由于讀取基礎對象所需的非線性訪問而導致磁盤高速緩存丟失,而該基礎對象后來將“自然地”存儲在打包文件中。


查看完整回答
反對 回復 2019-11-11
?
猛跑小豬

TA貢獻1858條經驗 獲得超8個贊

打包文件中增量存儲的使用只是實現細節。在那個級別上,Git不知道為什么或從某一個修訂版本到下一個版本如何進行更改,而是只知道blob B與blob A非常相似,除了這些更改C。因此,它只會存儲blob A并更改C (如果選擇這樣做-它也可以選擇存儲Blob A和Blob)。

從打包文件中檢索對象時,增量存儲不會暴露給調用方。呼叫者仍然看到完整的斑點。因此,在不優化增量存儲的情況下,Git的工作方式與以往一樣。


查看完整回答
反對 回復 2019-11-11
?
鴻蒙傳說

TA貢獻1865條經驗 獲得超7個贊

正如我在“ git的瘦包是什么? ”中提到的那樣。


Git僅在packfile中進行刪除


我在“ git二進制差異算法(增量存儲)是否標準化? ”中詳細介紹了用于打包文件的增量編碼。

另請參閱“ git何時以及如何使用增量存儲? ”。


請注意core.deltaBaseCacheLimit,對于Git 2.0.x / 2.1(2014年第三季度),控制打包文件默認大小的配置很快將從16MB增加到96MB。


參見David Kastrup(2014年5月)的commit 4874f54:


將core.deltaBaseCacheLimit碰撞到96m

默認值16m會導致大型delta鏈和大型文件的嚴重抖動。


以下是一些基準測試(的pu變體git blame):


time git blame -C src/xdisp.c >/dev/null

用于git gc --aggressive在SSD驅動器上重新打包的Emacs存儲庫(v1.9,導致窗口大小為250)。

有問題的文件大約有30000行,大小為1Mb,歷史記錄約為2500次提交。


16m (previous default):

  real  3m33.936s

  user  2m15.396s

  sys   1m17.352s


96m:

  real  2m5.668s

  user  1m50.784s

  sys   0m14.288s


查看完整回答
反對 回復 2019-11-11
  • 3 回答
  • 0 關注
  • 1520 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號