簡體   English   中英

使用 Git 和 Mercurial 進行部分克隆

[英]Partial clone with Git and Mercurial

是否可以在 Git 和 Mercurial 中僅克隆一個分支(或來自給定的提交)? 我的意思是,我想克隆一個中央倉庫,但由於它很大,我只想得到它的一部分,並且仍然能夠回饋我的更改。 是否可以? 比如,我只想要 Tag 130 或類似的東西?

如果是這樣,如何?

在Git土地中,您正在談論三種不同類型的部分克隆:

  • 淺克隆:我想要從修訂點X開始的歷史。

    git clone --depth <n> <url>使用git clone --depth <n> <url> ,但請記住,淺克隆在與其他存儲庫交互方面有些限制。 您將能夠生成補丁並通過電子郵件發送。

  • 通過filepath進行部分克隆:我希望在某個目錄/path所有修訂歷史記錄。

    在Git中不可能 使用現代Git,雖然你可以有稀疏結賬 ,即你有完整的歷史,但你檢查(有​​工作區)只有所有文件的子集。

  • 僅克隆選定的分支:我想只克隆一個分支(或選定的分支子集)。

    可能的,和

    在git 1.7.10之前並不簡單:你需要手動完成克隆所做的事情,即git init [<directory>] ,然后git remote add origin <url> ,在remote.origin.fetch編輯.git/config remote.origin.fetch *請求分支(可能是'master'),然后是git fetch

    從git 1.7.10開始, git clone提供了--single-branch選項,看起來它只是為了這個目的而添加,看起來很簡單。

    但請注意,由於分支通常共享其大部分歷史記錄,因此克隆僅一部分分支的收益可能比您想象的要小。

您還可以僅對選定的分支子集進行淺層克隆。

如果您知道人們希望如何通過文件路徑(同一存儲庫中的多個項目)來解決問題,則可以使用子模塊(類似於svn:externals)將repo預拆分為單獨的可復制部分。

在mercurial土地,你談論三種不同類型的部分克隆:

  • 淺克隆:我希望從修訂點X開始的歷史記錄使用remotefilelog擴展名
  • 文件路徑的部分克隆:我希望目錄/路徑中的所有修訂歷史記錄具有實驗性的narrowhg擴展名,或者我只希望目錄/路徑中的文件位於我的工作目錄中,並具有實驗稀疏擴展 (從4.3版本開始,請參閱hg help sparse )。
  • 分支部分克隆:我希望分支Y上的所有修訂歷史記錄: 使用clone -r

如果您知道人們希望如何通過文件路徑解決問題(同一個倉庫中的多個項目(羞辱你)),您可以使用子存儲庫(類似於svn externals)將repo預拆分為可單獨克隆的部分

此外,至於“如此巨大,我只想得到它的一部分”:你真的只需要這樣做一次。 只是在你吃午飯時克隆它,然后你永遠擁有它。 隨后你可以有效地pull和獲得增量。 如果你想要它的另一個克隆,只需克隆你的第一個克隆。 你得到克隆的地方並不重要(本地克隆不占用額外的磁盤空間,因為它們是封面下的硬鏈接)。

所選答案提供了一個很好的概述,但缺乏一個完整的例子。

最大限度地減少下載和結帳的足跡(a)(b)

git clone --no-checkout --depth 1 --single-branch --branch (name) (repo) (folder)
cd (folder)
git config core.sparseCheckout true
echo "target/path/1" >>.git/info/sparse-checkout
echo "target/path/2" >>.git/info/sparse-checkout
git checkout

定期優化本地存儲庫占用空間(c) (可選,小心使用):

git clean --dry-run # consider and tweak results then switch to --force
git gc
git repack -Ad
git prune

另請參見: 如何使用git處理大型存儲庫

此方法創建沒有子存儲庫的無版本存檔:

hg clone -U ssh://machine//directory/path/to/repo/project projecttemp

cd projecttemp

hg archive -r tip ../project-no-subrepos

沒有子存儲庫的無版本源代碼位於project-no-subrepos目錄中

關於Git,Linus Torvalds可能具有歷史意義,從2007年的概念角度回答了這個問題,在一個有記錄並可在線獲取的演講中。

問題是是否有可能僅從Git存儲庫中檢出一些文件。

技術講座:Linus Torvalds on git t = 43:10

總而言之,他說Git的設計決策之一就是將其與其他源管理系統區分開來(他引用BitKeeper和SVN)是Git管理內容而不是文件。 其含義是,例如,通過首先獲取整個差異然后僅將其修剪到所請求的文件來計算兩個修訂中的文件子集的差異。 另一個是你必須查看整個歷史; 以一種全有或全無的方式。 出於這個原因,他建議在多個存儲庫之間拆分松散相關的組件,並提到當時正在努力實現用於管理存儲庫的用戶界面,該存儲庫被構造為包含較小存儲庫的超級項目。

據我所知,這個基本的設計決定今天仍然是蘋果。 超級項目的東西可能成為現在的子模塊

如果像Brent Bradburn回答一樣,您在 Git 部分克隆中重新打包,請確保:

git clone --filter=blob:none --no-checkout https://github.com/me/myRepo
cd myRepo
git sparse-checkout init
# Add the expected pattern, to include just a subfolder without top files:
git sparse-checkout set /mySubFolder/

# populate working-tree with only the right files:
git read-tree -mu HEAD

關於部分克隆中的局部優化,如:

git clean --dry-run # consider and tweak results then switch to --force
git gc
git repack -Ad
git prune

使用 Git 2.32(2021 年第 2 季度),其中部分克隆中的“ git repack -A -dman在 2.32 之前不必要地松開承諾包中的對象:已修復。

請參閱Rafael Silva ( raffs )提交 a643157 (2021 年 4 月 21 日)。
(由Junio C Hamano 合並gitster 提交 a0f521b ,2021 年 5 月 10 日)

repack :避免松散部分克隆中的承諾對象

報告人:SZEDER Gábor
幫助者:Jeff King
幫助:Jonathan Tan
簽字人:Rafael Silva

git repack -A -d ( man )在部分克隆中運行時,將調用pack-objects兩次:一次重新打包所有承諾對象,一次重新打包所有非承諾對象。
后一個pack-objects調用是使用--exclude-promisor-objects--unpack-unreachable ,它釋放了在此調用期間未使用的所有對象。
不幸的是,這包括允諾對象。

因為git repack ( man )-d參數隨后刪除了包中的所有松散對象,這些剛剛松散的承諾對象將被立即刪除。
然而,這種額外的磁盤攪動首先是不必要的。
例如,在過濾所有 blob 對象(例如--filter=blob:none )的新克隆的部分 repo 中, repack最終會解壓縮所有樹並提交到文件系統中,因為在這種特殊情況下,每個 object 都是承諾者 object .
根據存儲庫大小,這會大大增加磁盤使用量:在我的 linux.git 副本中,object 目錄的磁盤使用量達到 26GB 的峰值。

為了避免這種額外的磁盤變動,將承諾者包文件的名稱作為--keep-pack arguments 傳遞給pack-objects的第二次調用。
這會通知pack-objects promisor objects 已經在安全的 packfile 中,因此不需要松動。

為了測試,我們需要驗證是否有任何 object 被松動。
但是,“證據”(松動的對象)在此過程中被刪除,這使我們無法檢查 object 目錄。
相反,讓我們教pack-objects計算松散的對象並通過 trace2 發出,從而允許在過程完成后檢查調試事件。
這個新事件用於添加的回歸測試。

最后,添加一個新的性能測試來評估此更改對性能的影響(在git.git上測試):

 Test HEAD^ HEAD ---------------------------------------------------------- 5600.3: gc 134.38(41.93+90.95) 7.80(6.72+1.35) -94.2%

對於更大的存儲庫,例如 linux.git,改進更大:

 Test HEAD^ HEAD ------------------------------------------------------------------- 5600.3: gc 6833.00(918.07+3162.74) 268.79(227.02+39.18) -96.1%

這些改進特別大,因為新克隆的部分存儲庫中的每個 object 都是一個 promisor object。


如 Git 2.33(2021 年第 3 季度)所述, git-repack ( man )文檔明確指出它確實對承諾包文件(在單獨的分區中)進行操作,並指定了“ -a ”。

大概這里的陳述已經過時,因為它們來自 2017 年的第一個文檔(並且在 2018 年添加了重新打包支持)

請參閱Tao Klerks ( TaoK )提交 ace6d8e (2021 年 6 月 2 日)。
(由Junio C Hamano 合並gitster 提交 4009809,2021年 7 月 8 日)

簽字人:Tao Klerks
審核人:Taylor Blau
確認人:Jonathan Tan

請參見technical/partial-clone 手冊頁

另外,仍然是 Git 2.33(2021 年第 3 季度),“ git read-tree( man )有一個代碼路徑,其中 blob 是從 promisor remote 一個接一個地獲取的,它已被更正為批量獲取

請參閱Jonathan Tan ( jhowtan )提交 d3da223提交 b2896d2 (2021 年 7 月 23 日)。
(由Junio C Hamano 合並gitster 提交 8230107,2021年 8 月 2 日)

cache-tree :在部分克隆讀取樹中預取

簽字人:Jonathan Tan

git read-tree( man )檢查給定樹引用的 blob 是否存在,但不批量預取它們。
添加批量預取。

在涉及某些特定提交的合並期間,在$DAYJOB注意到這里缺少預取,但我找不到一個最小合並也不會觸發unpack-trees.c中的check_updates()中的預取(以及所有這些在某些情況下, cache-tree.c中缺少預取並不重要,因為到那時所有相關的 blob 都已經預取了)。
這就是為什么我在這里使用 read-tree 來練習這段代碼路徑。


Git 2.39(2022 年第 4 季度)避免調用“ cache_tree_update() ”,因為這樣做是多余的。

請參閱Victoria Dye ( vdye )提交 652bd02提交 dc5d40f提交 0e47bca提交 68fcd48提交 94fcf0e (2022 年 11 月 10 日)。
(由Taylor Blau 合並ttaylorr 提交 a92fce4,2022年 11 月 18 日)

read-tree :使用“ skip_cache_tree_update ”選項

簽字人:Victoria Dye
簽字人:Taylor Blau

當使用單個樹且沒有前綴運行“read-tree”時,在解包樹后調用“ prime_cache_tree() ”。
在這種情況下,通過啟用“ skip_cache_tree_update ”解包選項,在“ unpack_trees() )”中跳過對“ cache_tree_update() ”的冗余調用。

刪除冗余緩存樹更新為“ git read-tree( man ) <tree-ish>提供了實質性的性能改進,如添加到“p0006-read-tree-checkout.sh”的測試所示:

 Test before after ---------------------------------------------------------------------- read-tree `br_ballast_plus_1` 3.94(1.80+1.57) 3.00(1.14+1.28) -23.9%

請注意,“ t1022-read-tree-partial-clone.sh ”中的“ read-tree ”已更新為讀取兩棵樹,而不是一棵。
該測試首先在d3da223中引入(“ cache-tree : prefetch in partial clone read-tree”,2021-07-23, Git v2.33.0-rc0 -- merge )以執行' cache_tree_update() '代碼路徑,如用於' git merge ' ( man )
由於此補丁在單樹“ git read-tree ”中刪除了對“ cache_tree_update() ”的調用,因此更改測試以使用雙樹變體,以便按預期調用“ cache_tree_update() ”。

在mercurial中,您應該可以使用以下方法:

hg convert --banchmap FILE SOURCEDEST REVMAP

您可能還需要:

--config convert.hg.startrev=REV

源可以是git,mercurial或其他各種系統。

我沒有嘗試過,但轉換非常豐富。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM