部分克隆實現Git大文件倉庫的優雅管理

2020-12-06 蟲蟲搜奇

說到代碼版本管理,現在首屈一指的就是Git。感謝Linus教主於15年的創舉,從此碼農世界就改變了。Git千好萬好,就有一點不好,那就是對大型二進位文件不友好。對於一個有許多大型二進位文件的項目,比如視頻遊戲倉庫,對倉庫的管理和處理就非常頭疼。由於Git底層設計邏輯,每一次版本變化時候都是做全文件快照,如果如果一個大的二進位文件(比如視頻)有多次變化,那麼Git倉庫的大小將會是倍數級的增長,這樣在倉庫同步、團隊協作時候,尤其是成員初始Clone時候將一個噩夢。

當然針對這個問題Git開源社區也一直在想辦法解決,比如一個解決問題(不是根本)的辦法Git LFS。

還有一個比較優雅的辦法就是使用部分克隆(Partial Clone)

部分克隆Git的一項新功能,它用來取代了Git LFS,並通過控制Git下載(或者跳過)部分Git倉庫對象(快照)的方法從根本來是實現對大文件的管理。

部分克隆的發展受到業界的關注和參與包括Git翹楚GitHub和GitLab,以及IT巨頭微軟和谷歌。GitLab從12.4開始beta版本支持。

部分克隆可以大大加快獲取和克隆的速度,由於減少了Git對象的下載,可以節省網絡傳輸,也可以大大節約本地用戶的磁碟空間。

和部分克隆相伴隨著的還有一種選擇性下載方法,那就是稀疏籤出(Sparse Checkout),稀疏籤適合具有大量文件和版本的倉庫 。

Git大文件倉庫的探索史

git-annex

Git大文件倉庫的歷史要追溯到2010年的git-annex。git-annex 採用 Haskell Script 編寫,允許映射Git資料庫到文件,幫助用戶管理Git倉庫的文件,git-annex的設計中大文件是獨立於Git倉庫中保存的,在git倉庫中只保存文件名和文件元數據等信息用來實現大文件追蹤。

git-media

git-media 是使用 Ruby 語言開發的,和git-annex把大文件(media)存儲在本地定期同步的方法不同。 git-meida一個中心伺服器來存儲大文件的方案。用於通過git media sync命令進行同步

Git LFS

2015年,Git社區發布了自帶的解決方案Git LFS(Large File Storage),該方案類似於git-media。

Git LFS方案中可以把音樂、圖片、視頻等指定的大文件存在 Git 倉庫之外存儲,在 Git 倉庫中用一個元數據文件來代替(.gitattributes)。通過把大文件存儲在 Git 倉庫之外,可以減小 Git 倉庫本身的體積,使克隆 Git倉庫的速度加快,也使得 Git 不會因為倉庫中充滿大文件而損失性能。

目前Git LFS 已經被主流的Git服務商支持,GitHub 和 GitLab 都對其提供內置支持。

但是這些解決方案中,都是通過把大文件置於Git倉庫之外存儲的針對問題的臨時解決方案而不是根本的解決方法。方案中要單獨維護大文件管理,對其同步和下載管理都比較繁瑣,而且其對應存儲在git倉庫中的額外的元屬性文件也會干擾Git倉庫管理。

針對這些問題,部分克隆可以避免維護兩種存儲和元屬性文件的管理的問題,從而從根本上優雅的解決大文件的問題。

部分克隆入門

我們以Gitlab gitlab about文檔站點為例子介紹。該項目是gitlab在線文檔倉庫,倉庫中有很多圖像,3.5G的文件。使用部分克隆(--filter=blob:none)進行部分克隆至少可以加快要50%,下載的數據可以減少70%。

對於更倉庫庫,比如具有詳細紋理和模型的視頻遊戲倉庫,部分克隆的性能提高將更加明顯。

和傳統的git clone相比較,部分克隆提供一個過濾器規範,該規範可控制下載Git對象時要排除的內容。比如,本例中,我們想要排除大型二進位文件。我們使用--no-checkout對比顯示效果。

上面我們通過--no-checkout選項,制定Git不籤出默認分支。通常情況下checkout不需要從伺服器獲取任何數據,因為在clone本地已經下載了所有對象。上面使用部分克隆時,由於故意設置沒有下載所有內容,因此Git在後續checkout操作時候需要獲取所有本地不存在的對象。

我們繼續籤出其他分支或提交時,則需要下載更多不存在的快照對象。

Git可以記得在克隆倉庫時提供的過濾器規範,以便獲取更新還可以排除大型文件,只會在需要這些文件,才會下載對應的快照對象。

git config remote.origin.promisor

# true

git config remote.origin.partialclonefilter

# blob:none

提交更改時,只需和其文件一樣提交二進位文件。無需安裝或配置額外的工具,無需將大文件與小文件區別對待。

部分克隆深入

易用性

Git LFS的缺點之一是它需要安裝其他工具。而部分克隆不需要任何其他工具。只需更新git版本,並學習git已有命令的一些新的選項。比如git clone的--filter選項。需要自己確定過濾器最佳的Blob大小或其他過濾器的參數。

網絡和存儲

如果使用過LFS的同學可能知道大文件的存儲和傳輸方式與常規Git對象是不一樣的,他們都是額外存儲的。由於要兼顧大存儲,所以最終的存儲媒介和一般文件不一樣(SSD),所以下載要慢一點。而部分存儲則是完全存在Git對象中,可以完全享受Git快速存儲的優勢。以Gitlab的部分存儲為例,他們可以支持多區域伺服器,可以根據自己的位置選擇離自己較近位置的區域服務,這樣可以實現更好的下載性能。

性能優化

當使用過濾器規範從Git伺服器排除部分對象的下載時,Git會檢查每個對象並排除任何與過濾規範匹配的對象。Git最新版本2.25中,尚未針對性能優化過濾性能優勢不明顯。但是Git開源社區也在促進這部分優化完善,Jeff King提交提交了一個部分克隆Blob大小過濾的性能改進補丁,該補丁可以極大提高性能,預計會在Git 2.26中發布。伺服器側GitLab預計在4月22的12.10版本中會引入。

對--filter:sparse基於文件路徑進行過濾的稀疏過濾器的優化則更複雜,由於包含文件內容的Blob不包含文件路徑信息,存儲庫的目錄結構存儲在樹對象中。

文件鎖定和工具集成

對大倉庫的管理,還有一個需要考慮的問題就是對客戶端用戶文件鎖定和工具集成的。和純文本原始碼不同,解決二進位文件不同版本之間的衝突通常是不可能的。為了防止二進位文件編輯中的衝突,一般會使用排他文件鎖定,這意味著一次只能由一個人編輯文件,而與分支無關。如果無法解決衝突,則允許在不同分支上並行創建文件的多個版本會報錯。Git伺服器端已經具有基本的文件鎖定支持,但只對對純文本有用,也僅適用於默認分支,並且還不能與任何本地工具集成。

本地工具集成對於二進位文件工作流,自動將文件鎖傳播到本地開發環境以及允許設計人員無需在命令行上使用Git的需求非常重要。將文件鎖快速傳播到本地開發環境也很重要,因為它可以防止在工作發生之前就浪費工作。

結論

大文件對於許多項目來說是必需的。儘管部分克隆還是一種實驗性功能,但是其基於git根本解決方案,具有天然的優勢,開源社區也對該功能進行不斷地優化和完善。一個功能成熟、高性能的Git大文件優雅管理的解決方案預計很快就有了。

相關焦點

  • Git入門篇:常用命令以及遠程倉庫使用
    用Git管理文件的話,更新的歷史會保存在Git,所以,不需要備份文件,非常的方便。git --version管理歷史記錄的倉庫倉庫 (Repository)是記錄文件或目錄狀態的地方,存儲著內容修改的歷史記錄。在倉庫的管理下,把文件和目錄修改的歷史記錄放在對應的目錄下。
  • Git使用全解
    如果幾萬人的大公司呢?git倉庫的那些文件,而未跟蹤的文件是指還沒被提交到Git倉庫中的那些非Git忽略的文件(Git可以通過在項目根目錄下產生一個.gitignore文件,在裡面指定要忽略的文件類型,這樣Git就不會去監視這些文件的變化)git通過文件名來進行跟蹤
  • 跟蹤多個 Git 遠程倉庫
    3、在你的開發系統中,使用你複製的 URI 克隆倉庫:$ git clone git@example.git這將以默認名稱 origin 來克隆 Git 倉庫,作為你的 pbench 倉庫復刻副本。找到 「Clone」 按鈕或面板,複製克隆地址。在軟體開發中,這通常被稱為「上遊」,因為(理論上)這是大多數提交發生的地方,而你打算讓這些提交流向下遊的倉庫。6、將 URI 添加到你的本地倉庫中。
  • 程式設計師需要了解的8種Git技術
    是一個開源的分布式版本控制系統,可以有效、高速地處理從很小到非常大的項目版本管理。對於程式設計師來說它是加入開發團隊之前必須熟悉的技術。接下來我們一起看一下必須掌握的8種Git相關的技術。二、在Git中管理遙控器克隆存儲庫後,它仍然維護著指向源的指針。該指針是Git中遙控器的一個示例。遠程是指向同一存儲庫的另一個副本的指針。克隆存儲庫時,將origin自動創建一個指向源的指針。
  • 玩轉Git就這麼簡單!這些常用命令你確定都用過嗎?
    git checkout HEAD .或git checkout HEAD <file>,用 HEAD 指向的 master 分支中的全部或者部分文件替換暫存區和以及工作區中的文件。這個命令也是極具危險性的,因為不但會清除工作區中未提交的改動,也會清除暫存區中未提交的改動。
  • 程式設計師值得收藏的Git常用命令與操作,這篇足夠了!
    初始倉庫常用命令1,git init:Git是使用git init命令來初始化一個Git倉庫的,安裝完Git時第一個使用命令就是Git init命令。2,git clone:使用該命令的時候,是從Git倉庫拷貝項目,常見的是我們經常去GitHub下載開源項目,就相當克隆項目到本地,正確使用命令格式是git clone <repo> <dirrectory>,repo表示Git倉庫,directory表示本地目錄。
  • Git 在 Windows 克隆的時候提示錯誤 Filename too long
    從 GitHub 克隆一個項目下發出現了錯誤:error: unable to createfile spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test
  • git解決衝突操作 - CSDN
    init命令把這個目錄變成Git可以管理的倉庫$ git initInitialized empty Git repository in C:/Users/userAccount/Desktop/test/.git/ps:目錄下會自動生成.git,誤刪,畢竟全靠它做版本管理
  • Git入門實戰教程
    Git對於代碼項目的管理是具有劃時代意義的,向Linus致敬,不但寫出了可以與Windows爭鋒的Linux系統,還設計實現了如此強大的版本管理工具。當我了解Git後,真後悔沒有早一點學習它,那樣寫論文就不用反反覆覆的修修改改了,能省去多少無用功呀。
  • Git基礎知識總結
    --global user.email email-address # 查看文件狀態 git status # 對比文件修改前和修改後的變化 git diff # 添加文件 git add filename # 批量添加目錄下文件
  • 從工作到現在Git操作總結
    將所有改動放進暫存區git commit -m "描述" 提交並附帶概要信息git pull 從遠程倉庫拉去代碼git push 推送代碼到遠程倉庫(master
  • 我到底應該用git-merge還是git-rebase呢?
    git merge是我們在git操作中頻繁會用到的一個命令,它主要實現的功能便是為我們進行分支代碼的合併,也就是將兩個或兩個以上的開發歷史合併在一起的操作。它有以下兩種用途:更新代碼時,整合另一個代碼倉庫中的變化,也就是git pull命令中,我們使用git pull命令時,實際上相當於git fetch+git merge,進行了遠程倉庫代碼的拉取,以及整合另一代碼倉庫中的變化用於從一個分支到另一個分支的合併
  • 前端面試題:git reset、git revert 和 git checkout 有什麼區別
    Web前端面試題解析:這個問題同樣也需要先了解 git 倉庫的三個組成部分:作區(Working Directory)、作區:在 git 管理下的正常錄都算是作區,我們平時的編輯作都是在作區完成 暫存區:臨時區,存放將要提交件的快照 ;歷史記錄區:git commit 後的記錄區 ;
  • 詳解如何使用Angular規範來統一多人的git提交記錄
    前言程式設計師在開發完代碼後都需要向代碼倉庫提交代碼,通常我們會使用下面的Git命令git commit -m '此次代碼的說明'但是很多時候我們都沒有一個統一的約定去規範commit描述,這就導致提交的歷史信息不能被很好查閱而且也不容易辨認commit信息與代碼變動之間的聯繫。這篇文章我們聊一下Augular提交規範。
  • 這個GitHub 1400星的Git魔法書火了,斯坦福校友出品丨有中文版
    由史丹福大學CS校友Ben Lynn編寫,2007年出品的Git Magic,如今已經有12國語言編譯,包括中文、法語、德語、義大利語、韓語……此外還有5個版本:單個網頁版、PDF版、可用作電子閱讀器的EPUB文件,可快速本地拷貝的Debian
  • git的幾個常用基本操作
    需求一:如何把stage中的修改還原到work dir中這個需求很常見,也很重要,比如我先將當前work dir中的修改添加到stage中,然後又對work dir中的文件進行了修改,但是又後悔了,如何把work dir中的全部或部分文件還原成stage中的樣子呢?
  • 這7個常用Git命令或概念你都知道嗎?
    --pretty=oneline (列印提交日誌的命令)別名為show-graph:3.名為『 .git』的隱藏文件夾隱藏的.git文件夾包含提交、分支和文件的歷史記錄。因此,需要複製.git 文件夾並複製整個應用程式及git歷史記錄(提交歷史等)。
  • git fetch & pull詳解
    而git pull 則是將遠程主機的最新內容拉下來後直接合併,即:git pull = git fetch + git merge,這樣可能會產生衝突,需要手動解決。下面我們來詳細了解一下git fetch 和git pull 的用法。
  • 工作流一目了然,看小姐姐用動圖展示10大Git命令
    、git reset、git revert、git fetch、git pull、git reflog……你知道這些 git 命令執行的究竟是什麼任務嗎?沒什麼大不了的,完美的合併!現在,我們在 dev 分支上所做的所有改變都合併到了 master 分支上。合併衝突儘管 Git 能夠很好地決定如何合併分支以及如何向文件添加修改,但它並不總是能完全自己做決定。