Git
英文 ▾ 主題 ▾ 最新版本 ▾ git-sparse-checkout 最後更新於 2.42.0

名稱

git-sparse-checkout - 將您的工作目錄縮減為追蹤檔案的子集

概要

git sparse-checkout (init | list | set | add | reapply | disable | check-rules) [<options>]

描述

此命令用於建立稀疏檢出 (sparse checkouts),這會將工作目錄從擁有所有追蹤檔案變更為僅擁有這些檔案的子集。它也可以切換哪個檔案子集存在,或還原並回到在工作副本中擁有所有追蹤檔案的狀態。

檔案的子集是透過在錐形模式 (預設) 中提供目錄列表,或透過在非錐形模式中提供模式列表來選擇。

當處於稀疏檢出狀態時,其他 Git 命令的行為會略有不同。例如,切換分支將不會更新稀疏檢出目錄/模式之外的路徑,而 git commit -a 將不會記錄稀疏檢出目錄/模式之外的路徑為已刪除。

此命令為實驗性質。其行為以及在存在稀疏檢出的情況下其他命令的行為,未來可能會變更。

命令

list

描述稀疏檢出檔案中的目錄或模式。

set

啟用必要的稀疏檢出配置設定 (core.sparseCheckoutcore.sparseCheckoutConeindex.sparse),如果它們尚未設定為所需的值,則從 set 子命令之後的引數列表填入稀疏檢出檔案,並更新工作目錄以符合。

為確保在工作樹中調整稀疏檢出設定不會變更其他工作樹中的稀疏檢出設定,如果尚未存在,set 子命令將會升級您的儲存庫配置以使用工作樹特定的配置。set 子命令的引數所定義的稀疏性會儲存在工作樹特定的稀疏檢出檔案中。請參閱 git-worktree[1]git-config[1]extensions.worktreeConfig 的文件,以取得更多詳細資訊。

當提供 --stdin 選項時,目錄或模式會從標準輸入中讀取為換行符號分隔的列表,而不是從引數中讀取。

預設情況下,輸入列表會被視為目錄列表,與 git ls-tree -d --name-only 的輸出相符。這包括將以雙引號 (") 開頭的路徑名稱解釋為 C 樣式引號字串。請注意,指定目錄下的所有檔案 (在任何深度) 都將包含在稀疏檢出中,以及指定目錄或其任何祖先的同層級檔案 (請參閱下面的錐形模式集以取得更多詳細資訊)。過去,這不是預設行為,需要指定 --cone 或啟用 core.sparseCheckoutCone

當傳遞 --no-cone 時,輸入列表會被視為模式列表。此模式有許多缺點,包括無法使用某些選項,例如 --sparse-index。如下面的「非錐形問題」部分所述,我們不建議使用它。

使用 --[no-]sparse-index 選項來使用稀疏索引 (預設是不使用)。稀疏索引會縮減索引的大小,使其更符合您的稀疏檢出定義。對於 git statusgit add 等命令,這可能具有顯著的效能優勢。此功能仍在實驗階段。在與該功能正確整合之前,某些命令可能會因使用稀疏索引而變慢。

警告: 使用稀疏索引需要以外部工具無法完全理解的方式修改索引。如果您在此相容性方面遇到問題,請執行 git sparse-checkout init --no-sparse-index 以重新寫入您的索引,使其不為稀疏索引。舊版的 Git 將無法理解稀疏目錄條目索引擴充功能,並且可能會無法與您的儲存庫互動,直到停用該功能為止。

add

更新稀疏檢出檔案以包含其他目錄 (在錐形模式中) 或模式 (在非錐形模式中)。預設情況下,這些目錄或模式會從命令列引數中讀取,但可以使用 --stdin 選項從 stdin 中讀取。

reapply

將稀疏模式規則重新套用至工作樹中的路徑。合併或變基等命令可以將路徑實體化以執行其工作 (例如,為了向您顯示衝突),而其他稀疏檢出命令可能無法稀疏化個別檔案 (例如,因為它具有未暫存的變更或衝突)。在這種情況下,在清理受影響的路徑後 (例如,解決衝突、復原或提交變更等),稍後執行 git sparse-checkout reapply 可能會有意義。

reapply 命令也可以採用 --[no-]cone--[no-]sparse-index 旗標,其含義與 set 命令中的旗標相同,以便在不需要重新指定所有稀疏路徑的情況下變更您正在使用的稀疏模式。

disable

停用 core.sparseCheckout 配置設定,並還原工作目錄以包含所有檔案。

init

已棄用的命令,其行為與未指定路徑的 set 類似。未來可能會移除。

從歷史上看,set 並未處理所有必要的配置設定,這表示必須同時呼叫 initset。同時呼叫兩者表示 init 步驟將首先移除幾乎所有追蹤的檔案 (在錐形模式下,也會移除忽略的檔案),然後 set 步驟會將許多追蹤的檔案 (但不包含忽略的檔案) 加回。除了遺失的檔案之外,此組合的效能和 UI 都很差。

此外,從歷史上看,如果稀疏檢出檔案已存在,init 實際上不會初始化該檔案。這表示有可能在不記得要傳遞給後續 setadd 命令的路徑的情況下返回稀疏檢出。但是,--cone--sparse-index 選項不會在停用命令之間被記住,因此呼叫純 init 的輕鬆還原減少了實用性。

check-rules

檢查稀疏規則是否符合一個或多個路徑。

預設情況下,check-rules 會從 stdin 讀取路徑列表,並僅輸出與目前稀疏規則相符的路徑。輸入預期為每行一個路徑,與 git ls-tree --name-only 的輸出相符,包括將以雙引號 (") 開頭的路徑名稱解釋為 C 樣式引號字串。

當使用 --rules-file <file> 旗標呼叫時,輸入檔案會與在 <file> 中找到的稀疏檢出規則進行比對,而不是與目前的規則進行比對。檔案中的規則預期與 git sparse-checkout set --stdin 接受的格式相同 (特別是,它們必須以換行符號分隔)。

預設情況下,傳遞給 --rules-file 選項的規則會被解釋為錐形模式目錄。若要使用 --rules-file 傳遞非錐形模式模式,請將選項與 --no-cone 選項結合。

當使用 -z 旗標呼叫時,stdin 上輸入的路徑格式以及輸出路徑都是以 \0 終止,而不是加上引號。請注意,這不適用於使用 --rules-file 選項傳遞的規則格式。

範例

git sparse-checkout set MY/DIR1 SUB/DIR2

變更為稀疏檢出,其中工作副本中存在 MY/DIR1/ 和 SUB/DIR2/ 下的所有檔案 (在任何深度) (加上 MY/ 和 SUB/ 下的所有檔案以及最上層目錄)。如果已經處於稀疏檢出狀態,請將工作副本中存在的檔案變更為此新選取項目。請注意,此命令也會刪除任何目錄中不再具有追蹤檔案或非忽略的未追蹤檔案的所有忽略檔案。

git sparse-checkout disable

使用所有檔案重新填入工作目錄,停用稀疏檢出。

git sparse-checkout add SOME/DIR/ECTORY

將 SOME/DIR/ECTORY/ 下的所有檔案 (在任何深度) 以及 SOME/DIR/ 下的所有檔案和 SOME/ 下的所有檔案新增至稀疏檢出。使用此命令之前,必須已處於稀疏檢出狀態。

git sparse-checkout reapply

有些指令可能會以不遵守所選稀疏目錄的方式來更新工作樹。這可能是因為 Git 外部的工具寫入檔案,甚至影響 Git 指令,原因可能是特殊情況(例如合併/變基時遇到衝突),或是某些指令沒有完全支援稀疏檢出(例如舊的 recursive 合併後端僅有有限的支援)。此指令會重新套用現有的稀疏目錄規格,使工作目錄符合規範。

內部機制 — 稀疏檢出

「稀疏檢出」允許以稀疏的方式填充工作目錄。它使用 skip-worktree 位元(請參閱 git-update-index[1])來告知 Git 工作目錄中的檔案是否值得關注。如果設定了 skip-worktree 位元,且該檔案不存在於工作樹中,則會忽略其不存在的情況。Git 會避免填充這些檔案的內容,這使得稀疏檢出在處理具有許多檔案的儲存庫時非常有用,但只有少數檔案對目前的使用者而言是重要的。

$GIT_DIR/info/sparse-checkout 檔案用於定義 skip-worktree 參考點陣圖。當 Git 更新工作目錄時,它會根據此檔案更新索引中的 skip-worktree 位元。符合檔案中模式的檔案將會出現在工作目錄中,其餘的則不會。

內部機制 — 非錐形問題

setadd 子指令填充的 $GIT_DIR/info/sparse-checkout 檔案被定義為一組模式(每行一個),使用與 .gitignore 檔案相同的語法。在錐形模式中,這些模式被限制為僅匹配目錄(使用者只需要提供或看到目錄名稱),而在非錐形模式中,允許使用任何 gitignore 風格的模式。在非錐形模式中使用完整的 gitignore 風格模式存在許多缺點

  • 從根本上來說,它使各種工作樹更新程序(pull、merge、rebase、switch、reset、checkout 等)需要 O(N*M) 的模式匹配,其中 N 是模式的數量,M 是索引中路徑的數量。這種方式擴展性不佳。

  • 要避免擴展性問題,必須透過指定前導目錄名稱或 glob 來限制模式的數量。

  • 在命令列上傳遞 glob 容易出錯,因為使用者可能會忘記引用 glob,導致 shell 將其展開為所有匹配的檔案,並將它們個別傳遞給 sparse-checkout set/add。雖然這也可能是 e.g. "git grep — *.c" 的問題,但 grep/log/status 的錯誤會立即顯示在輸出中。而使用 sparse-checkout,錯誤會在執行 sparse-checkout 指令時被記錄下來,並且可能直到使用者稍後切換分支或變基或合併時才會出現問題,因此使用者錯誤和他們有機會捕捉/注意到的時間之間會出現延遲。

  • 與前一個項目相關的是,sparse-checkout 有一個 add 子指令,但沒有 remove 子指令。即使新增了 remove 子指令,撤銷意外的未引用 glob 也會面臨「移除過多」的風險,因為它可能會移除在意外新增之前就已包含的條目。

  • 非錐形模式使用 gitignore 風格的模式來選擇要包含的內容(否定模式除外),而 .gitignore 檔案使用 gitignore 風格的模式來選擇要排除的內容(否定模式除外)。關於 gitignore 風格模式的說明文件通常不會談論匹配或不匹配,而是談論使用者想要「排除」的內容。這可能會讓嘗試學習如何指定 sparse-checkout 模式以獲得所需行為的使用者感到困惑。

  • 其他想要提供某種「特殊路徑模式匹配」的 git 子指令都使用路徑規範,但 sparse-checkout 的非錐形模式使用 gitignore 模式,這讓人感覺不一致。

  • 它有一些邊緣情況,其中「正確」的行為不明確。以下是兩個範例

    First, two users are in a subdirectory, and the first runs
       git sparse-checkout set '/toplevel-dir/*.c'
    while the second runs
       git sparse-checkout set relative-dir
    Should those arguments be transliterated into
       current/subdirectory/toplevel-dir/*.c
    and
       current/subdirectory/relative-dir
    before inserting into the sparse-checkout file?  The user who typed
    the first command is probably aware that arguments to set/add are
    supposed to be patterns in non-cone mode, and probably would not be
    happy with such a transliteration.  However, many gitignore-style
    patterns are just paths, which might be what the user who typed the
    second command was thinking, and they'd be upset if their argument
    wasn't transliterated.
    Second, what should bash-completion complete on for set/add commands
    for non-cone users?  If it suggests paths, is it exacerbating the
    problem above?  Also, if it suggests paths, what if the user has a
    file or directory that begins with either a '!' or '#' or has a '*',
    '\', '?', '[', or ']' in its name?  And if it suggests paths, will
    it complete "/pro" to "/proc" (in the root filesystem) rather than to
    "/progress.txt" in the current directory?  (Note that users are
    likely to want to start paths with a leading '/' in non-cone mode,
    for the same reason that .gitignore files often have one.)
    Completing on files or directories might give nasty surprises in
    all these cases.
  • 過多的彈性使得其他擴充基本上不切實際。在非錐形模式中,--sparse-index 幾乎不可能實現;即使以某種方式可行,也需要更多的工作來實現,並且在實務上可能太慢。一些關於在部分複製和稀疏檢出之間增加耦合的想法,也只有在路徑集更受限制的情況下才可行。

由於所有這些原因,非錐形模式已被棄用。請切換到使用錐形模式。

內部機制 — 錐形模式處理

預設的「錐形模式」允許您僅指定要包含的目錄。對於指定的任何目錄,將會包含該目錄下的所有路徑,並且也會包含前導目錄(包括頂層目錄)下的所有路徑。因此,如果您指定了目錄 Documentation/technical/,則您的稀疏檢出將包含

  • 頂層目錄中的所有檔案

  • Documentation/ 下的所有檔案

  • Documentation/technical/ 下任何深度的所有檔案

此外,在錐形模式中,即使未指定任何目錄,也會包含頂層目錄中的檔案。

當變更錐形模式中的稀疏檢出模式時,Git 將會檢查每個不在稀疏檢出錐形範圍內的追蹤目錄,以查看它是否包含任何未追蹤的檔案。如果所有這些檔案都因為 .gitignore 模式而被忽略,則會刪除該目錄。如果該目錄內的任何未追蹤的檔案未被忽略,則不會在該目錄中進行刪除,並且會顯示警告訊息。如果這些檔案很重要,請重設您的稀疏檢出定義,以便將它們包含在內,使用 git addgit commit 來儲存它們,然後手動移除任何剩餘的檔案,以確保 Git 可以最佳地運作。

另請參閱「內部機制 — 錐形模式集」章節,以了解目錄是如何在底層轉換為稀疏檢出的完整模式集的子集的。

內部機制 — 完整模式集

完整模式集允許任意模式匹配和複雜的包含/排除規則。當更新索引時,這些規則可能會導致 O(N*M) 的模式匹配,其中 N 是模式的數量,M 是索引中路徑的數量。為了應對此效能問題,當啟用 core.sparseCheckoutCone 時,允許使用更受限制的模式集。

稀疏檢出檔案使用與 .gitignore 檔案相同的語法;請參閱 gitignore[5] 以了解詳細資訊。不過,這裡的模式通常用於選擇要包含的檔案,而不是要排除的檔案。(但是,這可能會讓人感到有些困惑,因為 gitignore 風格的模式具有以 ! 開頭的模式定義的否定,因此您也可以選擇包含的檔案。)

例如,要選擇所有內容,然後移除檔案 unwanted(以便除了名為 unwanted 的檔案之外,所有檔案都會出現在您的工作樹中)

git sparse-checkout set --no-cone '/*' '!unwanted'

這些模式只是按原樣放入 $GIT_DIR/info/sparse-checkout 中,因此此時該檔案的內容將為

/*
!unwanted

另請參閱 git-read-tree[1] 的「稀疏檢出」章節,以了解更多關於稀疏檢出中使用的 gitignore 風格模式的資訊。

內部機制 — 錐形模式集

在錐形模式中,僅接受目錄,但它們會被轉換為完整模式集中使用的相同 gitignore 風格模式。我們將這些模式稱為以下兩種型別之一

  1. 遞迴:包含目錄內的所有路徑。

  2. 父系:包含目錄內的所有檔案。

由於錐形模式始終包含頂層的檔案,因此當在未指定任何目錄的情況下執行 git sparse-checkout set 時,頂層目錄會新增為父系模式。此時,稀疏檢出檔案包含以下模式

/*
!/*/

這表示「包含頂層目錄下的所有內容,但不包含任何較低層級的內容」。

在錐形模式中,git sparse-checkout set 子指令會接受目錄列表。指令 git sparse-checkout set A/B/C 會將目錄 A/B/C 設定為遞迴模式,目錄 AA/B 會新增為父系模式。產生的稀疏檢出檔案現在為

/*
!/*/
/A/
!/A/*/
/A/B/
!/A/B/*/
/A/B/C/

在此,順序很重要,因此否定模式會被檔案中較後面的肯定模式覆蓋。

除非將 core.sparseCheckoutCone 明確設定為 false,否則 Git 會解析稀疏檢出檔案,期望使用這些型別的模式。如果模式不匹配,Git 會發出警告。如果模式與預期的格式匹配,則 Git 會使用更快的基於雜湊的演算法來計算稀疏檢出中的包含內容。如果它們不匹配,則 Git 的行為將如同 core.sparseCheckoutCone 為 false 一樣,而不管其設定。

在錐形模式的情況下,儘管完整模式會寫入 $GIT_DIR/info/sparse-checkout 檔案,但 git sparse-checkout list 子指令會列出定義遞迴模式的目錄。對於上面的稀疏檢出檔案範例,輸出如下

$ git sparse-checkout list
A/B/C

如果 core.ignoreCase=true,則模式匹配演算法將使用不區分大小寫的檢查。這可以修正 git sparse-checkout set 命令中大小寫不符的檔案名稱,以反映工作目錄中的預期錐形。

內部機制 — 子模組

如果您的儲存庫包含一個或多個子模組,則會根據與 git submodule 指令的互動來填充子模組。具體來說,git submodule init -- <path> 將確保 <path> 中的子模組存在,而 git submodule deinit [-f] -- <path> 將會移除 <path> 中子模組的檔案(包括任何未追蹤的檔案、未提交的變更和未推送的歷史記錄)。與稀疏檢出從工作樹中移除檔案但仍然在索引中保留條目的方式類似,已取消初始化的子模組會從工作目錄中移除,但仍然在索引中具有條目。

由於子模組可能具有未推送的變更或未追蹤的檔案,因此移除它們可能會導致資料遺失。因此,變更稀疏包含/排除規則不會導致已檢出的子模組從工作副本中移除。換句話說,正如即使在切換會移除或新增子模組的分支時,checkout 也不會導致子模組自動移除或初始化,使用 sparse-checkout 來縮減或擴大「感興趣」的檔案範圍也不會導致子模組自動取消初始化或初始化。

此外,上述事實意味著「已追蹤」的檔案可能因為多種原因而未出現在工作副本中:稀疏檢出(sparse-checkout)套用的稀疏模式,以及子模組的初始化狀態。因此,像是 git grep 這種在工作副本中對已追蹤檔案進行操作的指令,其結果可能會受到這兩種限制中的一種或兩種的影響。

GIT

屬於 git[1] 工具套件的一部分

scroll-to-top