[英]Shallow AND Sparse GIT Repository Clone
我有一個超過 1 GB 的淺克隆 git 存儲庫。 我對所需的文件/目錄使用稀疏簽出。
如何將存儲庫克隆減少為稀疏的簽出文件/目錄?
最初,我能夠通過在克隆時禁用簽出來將克隆的存儲庫限制為僅稀疏簽出。 然后在進行初始結帳之前設置稀疏結帳。 這將存儲庫限制為僅約 200 MB。 更易於管理。 但是,在將來的某個時間更新遠程分支信息會導致其余文件和目錄包含在存儲庫克隆中。 將 repo 克隆大小發送回超過 1 GB,我不知道如何只處理稀疏的簽出文件和目錄。
簡而言之,我想要的是一個淺而稀疏的存儲庫克隆。 不僅僅是淺層回購克隆的稀疏結帳。 完整的回購是對空間的浪費,並且某些任務的性能會受到影響。
希望有人可以分享解決方案。 謝謝。
淺而稀疏的意思是“部分”或“狹窄”。
部分克隆(或“狹義克隆”)在理論上是可行的,並於 2017 年 12 月首次使用 Git 2.16 實現,如此處所示。
但:
這在 Git 2.20(2018 年第四季度)中得到了進一步優化,因為在將從原始存儲庫中延遲補充的部分克隆中,我們通常希望避免“這個對象是否存在(本地)?” 在我們創建(部分/稀疏)克隆時故意省略的對象上。
然而,緩存樹代碼路徑(用於從索引中寫入樹對象)堅持該對象存在,即使對於部分檢出區域之外的路徑也是如此。
代碼已更新以避免此類檢查。
請參閱Jonathan Tan ( jhowtan
)的提交 2f215ff (2018 年 10 月 9 日)。
(由Junio C Hamano -- gitster
--在提交 a08b1d6中合並,2018 年 10 月 19 日)
cache-tree
:在部分克隆中跳過一些 blob 檢查
在部分克隆中,每當發生稀疏檢出時,都會驗證索引中所有 blob 的存在,無論它們是否被
.git/info/sparse-checkout
規范包含或排除。
這會顯着降低性能,因為每當檢查是否存在丟失的 blob 時就會發生延遲提取。
在 Git 2.24(2019 年第四季度)中, cache-tree
代碼被教導在嘗試查看它計算的樹對象是否已存在於存儲庫中時不那么激進。
請參閱Jonathan Tan ( jhowtan
)的提交 f981ec1 (2019 年 9 月 3 日)。
(由Junio C Hamano -- gitster
--在提交 ae203ba中合並,2019 年 10 月 7 日)
cache-tree
: 不要延遲獲取暫定樹
cache-tree
結構用於加速 HEAD 和 index 之間的比較,當索引由櫻桃選擇更新時(例如),表示目錄中索引中路徑的樹對象是在內核中構造,以查看對象存儲中是否已經存在這樣的樹對象。當引入惰性獲取機制時,我們轉換了這個“樹存在嗎?” 錯誤地檢查“如果沒有,如果我們懶惰地克隆,看看遠程是否有它”調用。
由於這個檢查的重點是通過機會性地記錄一個已經存在的樹對象來修復緩存樹,我們甚至不應該嘗試從遠程獲取一個。傳遞
OBJECT_INFO_SKIP_FETCH_OBJECT
標志以確保我們只檢查本地對象存儲中的存在而不觸發延遲獲取機制。
在 Git 2.25(2020 年第一季度)中,“ git fetch
”代碼路徑有一個很大的“當我詢問是否存在某些東西時不要懶惰地獲取丟失的對象”開關。
這已通過標記“這件事存在嗎?”得到糾正。 帶有“如果不是請不要懶惰地獲取它”標志的調用。
請參閱Jonathan Tan ( jhowtan
)的提交 603960b 、 提交 e362fad (2019 年 11 月 13 日)和提交 6462d5e (2019 年 11 月 5 日)。
(由Junio C Hamano -- gitster
--在提交 fce9e83中合並,2019 年 12 月 1 日)
clone
:刪除fetch_if_missing=0
簽字人:Jonathan Tan
提交6462d5eb9a ("fetch: remove
fetch_if_missing=0",
2019-11-08) 努力從獲取機制中刪除對fetch_if_missing=0
的需求,因此嘗試從克隆中刪除fetch_if_missing=0
也是合理的。 但是這樣做會暴露一個錯誤——當服務器沒有發送一個由 ref 直接指向的對象時,這應該是一個錯誤,而不是延遲獲取的觸發器。 (獲取機制中的這種情況被使用“git clone”而不是“git fetch”的測試覆蓋,這就是上述提交沒有發現錯誤的原因。)可以通過在連接檢查期間抑制延遲獲取來修復該錯誤。 修復此錯誤,並從克隆中刪除
fetch_if_missing
。
和:
promisor
promisor-remote
: 移除fetch_if_missing=0
簽字人:Jonathan Tan
提交6462d5eb9a ("fetch: remove
fetch_if_missing=0",
2019-11-08) 努力從獲取機制中刪除對fetch_if_missing=0
的需要,因此嘗試從promisor-remote
中的惰性獲取機制中刪除fetch_if_missing=0
是合理的promisor-remote
也是如此。但是這樣做會暴露一個錯誤——當服務器沒有發送一個標簽對象指向的對象時,就會發生一個無限循環:Git 嘗試獲取丟失的對象,這會導致所有 refs 的延遲(用於協商),這會導致懶惰地獲取那個丟失的對象,等等。
這個錯誤是因為在延遲獲取期間不必要地使用了 fetch negotiator - 它在初始化后沒有使用,但它仍然被初始化(這會導致所有 refs 的取消引用)。因此,當在獲取期間不使用協商器時,請避免對其進行初始化。 然后,從 promisor
promisor-remote
中刪除fetch_if_missing
。
使用Derrick Stolee的“ 通過稀疏結賬縮小您的 monorepo 規模”了解更多信息
將稀疏結帳與部分克隆功能配對可以進一步加速這些工作流程。
這種組合加快了數據傳輸過程,因為您不需要每個可訪問的 Git 對象,而是可以只下載您需要的那些以填充工作目錄的錐體
$ git clone --filter=blob:none --no-checkout https://github.com/derrickstolee/sparse-checkout-example
Cloning into 'sparse-checkout-example'...
Receiving objects: 100% (373/373), 75.98 KiB | 2.71 MiB/s, done.
Resolving deltas: 100% (23/23), done.
$ cd sparse-checkout-example/
$ git sparse-checkout init --cone
Receiving objects: 100% (3/3), 1.41 KiB | 1.41 MiB/s, done.
$ git sparse-checkout set client/android
Receiving objects: 100% (26/26), 985.91 KiB | 5.76 MiB/s, done.
在 Git 2.25.1(2020 年 2 月)之前, has_object_file()
表示“ no
”給定一個通過 fake_object_file( pretend_object_file()
注冊到系統的對象,使其與read_object_file()
不一致,導致延遲獲取嘗試從承諾者遠程獲取空樹.
見討論。
我試圖用
empty_tree=$(git mktree </dev/null) git init --bare x git clone --filter=blob:none file://$(pwd)/xy cd y echo hi >README git add README git commit -m 'nonempty tree' GIT_TRACE=1 git diff-tree "$empty_tree" HEAD
事實上,看起來 Git 甚至可以從不包含它的存儲庫中為空樹提供服務。
請參閱Jonathan Tan ( jhowtan
)的提交 9c8a294 (2020 年 1 月 2 日)。
(由Junio C Hamano -- gitster
--在提交 e26bd14中合並,2020 年 1 月 22 日)
sha1-file
:刪除OBJECT_INFO_SKIP_CACHED
簽字人:Jonathan Tan
在部分克隆中,如果用戶將空樹的哈希(“
git mktree
</dev/null
” - 對於 SHA-1,這是 4b825d...)提供給需要解析該對象的命令,例如例子:git diff-tree 4b825d <a non-empty tree>
然后 Git 將不必要地懶惰地獲取空樹,因為對該對象的解析會調用
repo_has_object_file()
,這不會對空樹進行特殊處理。相反,教
repo_has_object_file()
查閱find_cached_object()
(它處理空樹),從而使其與其余的object-store-accessing
函數保持一致。
代價是repo_has_object_file()
現在需要在每次調用時進行oideq
,但這與文件系統查找或所需的包索引搜索相比是微不足道的。 (如果find_cached_object()
需要做更多的事情,因為之前調用了pretend_object_file()
,那么在我們是否呈現緩存對象方面更有理由保持一致。)作為歷史記錄,現在稱為
repo_read_object_file()
的函數在346245a1bb (“硬編碼空樹對象”,2008-02-13,Git v1.5.5-rc0 -- merge )中被教授了空樹,並且現在稱為oid_object_info()
的函數在c4d9986f5f中被教導了空樹(“sha1_object_info
:也檢查cached_object
存儲”,2011-02-07,Git v1.7.4.1)。
repo_has_object_file()
從未更新,可能是由於疏忽。
標志OBJECT_INFO_SKIP_CACHED,
稍后在dfdd4afcf9 (“sha1_file
:教sha1_object_info_extended
更多標志”,2017-06-26,Git v2.14.0-rc0)中引入並用於e83e71c5e1 (“sha1_file
:重構has_sha1_file_with_flags
”,2017-06-26,Git v2.14.0-rc0),被引入以保留空樹處理中的這種差異,但現在可以將其刪除。
Git 2.25.1 還將警告程序員有關允許代碼暫時使用核心對象的假裝對象文件pretend_object_file()
。
請參閱Jonathan Nieder ( artagnon
)的提交 60440d7 (2020 年 1 月 4 日)。
(由Junio C Hamano -- gitster
--在提交 b486d2e中合並,2020 年 2 月 12 日)
sha1-file
: 記錄如何使用pretend_object_file
靈感來源:Junio C Hamano
簽字人:喬納森·尼德
與內存中的替代品一樣,
pretend_object_file
對象文件包含一個粗心的陷阱:粗心的調用者可以使用它來創建對磁盤對象存儲中不存在的對象的引用。添加注釋以記錄如何使用該功能而不冒此類問題的風險。
當前唯一的調用者是 blame,它使用
pretend_object_file
創建一個代表工作樹狀態的內存提交。 在討論如何在“git merge”之類的操作中安全地使用此功能時注意到,與責備不同,它不是只讀的。
所以現在的評論是:
/*
* Add an object file to the in-memory object store, without writing it
* to disk.
*
* Callers are responsible for calling write_object_file to record the
* object in persistent storage before writing any other new objects
* that reference it.
*/
int pretend_object_file(void *, unsigned long, enum object_type,
struct object_id *oid);
Git 2.25.1(2020 年 2 月)包括一個 Futureproofing,以確保測試不依賴於當前的實現細節。
請參閱Jonathan Tan ( jhowtan
)的提交 b54128b (2020 年 1 月 13 日)。
(由Junio C Hamano -- gitster
--在提交 3f7553a中合並,2020 年 2 月 12 日)
t5616
: 使增量基礎更改變得健壯簽字人:Jonathan Tan
提交6462d5eb9a ("fetch: remove
fetch_if_missing=0",
2019-11-08) 包含一個依賴於必須延遲獲取 blob 的增量基礎的測試,但假設要獲取的樹(作為測試的一部分)是作為非增量對象發送。
這個假設在未來可能不成立; 例如,對象散列長度的變化可能會導致樹被作為增量發送。通過依賴於必須懶惰地獲取樹的增量基礎,並且不對 blob 是作為增量還是非增量發送的假設,使測試更加健壯。
Git 2.25.2(2020 年 3 月)修復了最近更改為將協議 v2 設為默認值所揭示的錯誤。
請參閱Derrick Stolee ( derrickstolee
) 的commit 3e96c66和commit d0badf8 (2020 年 2 月 21 日)。
(由Junio C Hamano -- gitster
--在提交 444cff6中合並,2020 年 3 月 2 日)
partial-clone
:在查找對象時避免獲取簽字人:Derrick Stolee
在測試部分克隆時,我注意到一些奇怪的行為。 我正在測試一種運行“
git init
”的方法,然后手動配置遠程以進行部分克隆,然后運行“git fetch
”。
令人驚訝的是,我看到 'git fetch
' 進程開始向服務器詢問多輪包文件下載! 當稍微調整一下情況時,我發現我可能會導致遙控器因錯誤而掛斷。添加兩個測試來演示這兩個問題。
在第一個測試中,我們發現當使用 blob 過濾器從以前沒有任何標簽的存儲庫中提取時,'
git fetch --tags
origin' 命令失敗,因為服務器發送“多個過濾器規格無法組合”。 這僅在使用協議 v2 時發生。在第二個測試中,我們看到帶有多個 ref 更新的“
git fetch
origin”請求會導致多個包文件下載。
這一定是由於 Git 試圖在 refs 指向的對象中出錯。 讓這件事特別討厭的是,它通過do_oid_object_info_extended()
方法,因此在協商中沒有“擁有”。
這導致遠程從每個新的 ref 發送每個可達的提交和樹,提供二次數據傳輸! 如果我們恢復6462d5eb9a (fetch: removefetch_if_missing=0,
2019-11-05, Git v2.25.0-rc0),這個測試是固定的,但是恢復會導致其他測試失敗。
真正的修復需要更多的關注。
使固定:
使用部分克隆時,
builtin/fetch.c
中的find_non_local_tags()
會檢查每個遠程標記以查看其對象是否也在本地存在。 不期望對象在本地存在,但是如果對象不存在,此函數仍然會觸發延遲獲取。 當請求提交時,這可能會非常昂貴,因為我們完全從不存在的對象的上下文中刪除,因此在請求中不提供“擁有”。6462d5eb9a (
fetch
: removefetch_if_missing=0,
2019-11-05, Git v2.25.0-rc0, , Git v2.25.0-rc0) 刪除了一個全局變量,該變量阻止了這些提取,以支持位標志。 但是,某些對象存在檢查未更新為使用此標志。更新
find_non_local_tags()
以使用OBJECT_INFO_SKIP_FETCH_OBJECT
和OBJECT_INFO_QUICK
。
_QUICK
選項僅防止重新准備包文件結構。 當我們期望一個對象由於更新的 refs 而不存在時,我們需要非常小心地提供_SKIP_FETCH_OBJECT
。這解決了
t5616-partial-clone.sh.
通過“ git clone --single-branch
”自動跟蹤標簽的邏輯不小心避免延遲獲取不必要的標簽,這已在 Git 2.27(2020 年第二季度)中得到糾正,
請參閱Jeff King ( peff
)的提交 167a575 (2020 年 4 月 1 日)。
(由Junio C Hamano -- gitster
--在提交 3ea2b46中合並,2020 年 4 月 22 日)
clone
:在跟蹤標簽時使用“快速”查找簽字人:傑夫·金
當使用
--single-branch
進行克隆時,我們實現了git fetch
的通常的標簽跟隨行為,抓取指向我們本地對象的任何標簽對象。但是,當我們是部分克隆時,我們的
has_object_file()
檢查實際上會延遲獲取每個標簽。這不僅違背了
--single-branch
的目的,而且執行起來非常緩慢,可能會為每個標簽啟動新的提取。
這對於淺克隆來說更糟糕,這意味着--single-branch
,因為即使是彼此超集的標簽也會被單獨獲取。我們可以通過將
OBJECT_INFO_SKIP_FETCH_OBJECT
傳遞給調用來解決這個問題,這就是git fetch
在這種情況下所做的。同樣,讓我們包含
OBJECT_INFO_QUICK,
因為這就是git fetch
所做的。
基本原理在5827a03545中進行了討論(獲取:使用“快速”has_sha1_file
進行標記跟蹤,2016-10-13,Git v2.10.2),但這里的權衡將更加適用,因為克隆不太可能與另一個進程競爭重新打包我們新創建的存儲庫。即使在非部分情況下,這也可能提供非常小的加速,因為我們會避免為每個標簽調用
reprepare_packed_git()
(盡管在實踐中,我們只有一個包文件,所以 reprepare 應該很便宜) .
在 Git 2.27(2020 年第二季度)之前,當客戶端需要制作時,使用在線協議版本 2 通過“ git://
”和“ ssh://
”協議為“ git fetch
”客戶端提供服務在服務器端存在錯誤對自動關注標簽等的后續請求。
請參閱Christian Couder ( chriscool
)的提交 08450ef (2020 年 5 月 8 日)。
(由Junio C Hamano -- gitster
--在提交 a012588中合並,2020 年 5 月 13 日)
upload-pack
:為每個 v2 fetch 命令清除filter_options
幫助者:Derrick Stolee
幫助者:傑夫·金
幫助者:Taylor Blau
簽字人:Christian Couder
由於協議 v2 的請求/響應模型,
upload_pack_v2()
函數有時會在同一進程中調用兩次,而 'structlist_objects_filter_options
filter_options
在'upload-pack.c
' 的開頭被聲明為靜態。這使得由
process_args()
調用的list_objects_filter_die_if_populated()
中的檢查在第二次upload_pack_v2()
時失敗,因為第一次已經填充了filter_options
。為了解決這個問題,
filter_options
不再是靜態的。 它現在由upload_pack()
直接擁有。 它現在也是 'structupload_pack_data
' 的一部分,因此它由upload_pack_v2()
間接擁有。從長遠來看,我們的目標是讓
upload_pack()
也使用 'struct upload_pack_data ',因此將upload_pack_data
filter_options
到這個結構比讓它直接由upload_pack_v2()
擁有更有意義。這修復了d0badf8797記錄的 2 個錯誤中的第一個(“
partial-clone
:演示部分提取中的錯誤”,2020 年 2 月 21 日,Git v2.26.0-rc0 - 批次 #8中列出的合並)。
在 Git 2.29(2020 年第四季度)中, pretend-object
機制會在決定將數據保留在核心之前檢查給定對象是否已存在於對象存儲中,但該檢查會觸發從承諾者遠程延遲獲取此類對象.
請參閱Jonathan Tan ( jhowtan
)的提交 a64d2aa (2020 年 7 月 21 日)。
(由Junio C Hamano -- gitster
--在提交 5b137e8中合並,2020 年 8 月 4 日)
sha1-file
:使pretend_object_file()
不預取簽字人:Jonathan Tan
當使用不存在的對象調用
pretend_object_file()
時(如典型情況),無需從承諾者遠程獲取任何內容,因為調用者已經知道該對象應該包含什么。 因此,抑制取指。 (出於同樣的原因,添加了OBJECT_INFO_QUICK
標志。)在
$DAYJOB
,當在未提交修改的文件上運行“blame
”時,就會注意到這一點。
在 Git 2.37(2022 年第三季度)中,“ git mktree --missing
” ( man )懶惰地從本地對象存儲中獲取缺少的對象,這對於從其輸入創建樹對象來說是完全沒有必要的。
請參閱Richard Oliver ( RichardBray
)的commit 817b0f6 (2022 年 6 月 21 日)。
(由Junio C Hamano -- gitster
--在提交 6fccbda中合並,2022 年 7 月 13 日)
mktree
:不檢查遠程對象的類型簽字人:理查德·奧利弗
使用31c8221 ("
mktree
: validate entry type in input", 2009-05-14, Git v1.6.4-rc0 -- merge ),我們調用sha1_object_info()
API 來獲取類型信息,但允許調用靜默失敗當對象在本地丟失時,以便我們可以在對象確實存在時機會性地檢查類型。該實現是可以理解的,因為當時沒有從承諾者遙控器延遲/按需下載單個對象,這會導致長時間延遲並使對象具體化,因此無法使用“
--missing
”。
設計現在正在傷害我們。當給出“
--missing
”時,我們可以完全繞過機會類型/模式一致性檢查,而是使用oid_object_info_extended()
API 並告訴它我們只對本地存在並且通過傳遞OBJECT_INFO_SKIP_FETCH_OBJECT
位立即可用的對象感興趣給它。
這樣,我們仍將保留對本地對象的廉價且機會主義的健全性檢查。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.