簡體中文 ▾ 主題 ▾ 最新版本 ▾ git-fast-import 最後更新於 2.52.0

名稱

git-fast-import - 快速 Git 資料匯入器的後端

概要

frontend | git fast-import [<options>]

描述

此程式通常不是終端使用者希望直接執行的。大多數終端使用者希望使用現有的前端程式之一,這些程式會解析特定型別的外部源,並將其中儲存的內容饋送給 git fast-import

fast-import 從標準輸入讀取混合的命令/資料流,並將一個或多個 packfile 直接寫入當前倉庫。當從標準輸入接收到 EOF 時,fast-import 會寫出更新後的分支和標籤引用,從而用新匯入的資料完全更新當前倉庫。

fast-import 後端本身可以匯入到空倉庫(已由 git init 初始化過的倉庫),或增量更新現有已填充的倉庫。是否支援從特定外部源進行增量匯入取決於所使用的前端程式。

選項

--force

強制更新已修改的現有分支,即使這樣做會導致提交丟失(因為新提交不包含舊提交)。

--quiet

停用 --stats 顯示的輸出,使 fast-import 在成功時通常保持靜默。但是,如果匯入流中有旨在顯示使用者輸出的指令(例如 progress 指令),則相應的訊息仍會顯示。

--stats

顯示關於 fast-import 建立的物件、它們儲存到的 packfile 以及 fast-import 在此執行期間使用的記憶體的一些基本統計資訊。顯示此輸出是當前的預設設定,但可以透過 --quiet 停用。

--allow-unsafe-features

透過使用 featureoption 命令,可以將許多命令列選項作為 fast-import 流本身的一部分提供。但是,其中一些選項是不安全的(例如,允許 fast-import 訪問倉庫外部的檔案系統)。預設情況下停用這些選項,但可以透過在命令列中提供此選項來允許。這目前僅影響 export-marksimport-marksimport-marks-if-exists 功能命令。

僅當您信任生成 fast-import 流的程式時才啟用此選項!此選項會自動為使用 import 功能的遠端輔助程式啟用,因為它們已經被信任可以執行自己的程式碼。

--signed-tags=(verbatim|warn-verbatim|warn-strip|strip|abort)

指定如何處理已簽名的標籤。行為與 git-fast-export[1] 中相同的選項相同,只是預設值為 verbatim(而不是 abort)。

--signed-commits=(verbatim|warn-verbatim|warn-strip|strip|abort)

指定如何處理已簽名的提交。行為與 git-fast-export[1] 中相同的選項相同,只是預設值為 verbatim(而不是 abort)。

前端選項

--cat-blob-fd=<fd>

將對 get-markcat-blobls 查詢的響應寫入檔案描述符 <fd>,而不是 stdout。允許將 intended for the end-user 的 progress 輸出與其他輸出分開。

--date-format=<fmt>

指定前端將在 authorcommittertagger 命令中提供給 fast-import 的日期的型別。有關支援的格式及其語法的詳細資訊,請參見下面的“日期格式”。

--done

如果流末尾沒有 done 命令,則以錯誤終止。此選項可能有助於檢測導致前端在開始寫入流之前終止的錯誤。

標記檔案位置

--export-marks=<file>

完成後將內部標記錶轉儲到 <file>。標記以 :markid SHA-1 的形式每行寫入一個。前端可以使用此檔案在匯入完成後進行驗證,或在增量執行之間儲存標記表。由於 <file> 僅在檢查點(或完成)時開啟和截斷,因此可以安全地將相同的路徑提供給 --import-marks。

--import-marks=<file>

在處理任何輸入之前,載入 <file> 中指定的標記。輸入檔案必須存在、可讀,並且必須使用 --export-marks 生成的相同格式。可以提供多個選項來匯入多個標記集。如果一個標記被定義為不同的值,則最後一個檔案獲勝。

--import-marks-if-exists=<file>

類似於 --import-marks,但如果檔案不存在,則會靜默跳過該檔案,而不是報錯。

--relative-marks
--no-relative-marks

指定 --relative-marks 後,使用 --import-marks= 和 --export-marks= 指定的路徑相對於當前倉庫中的內部目錄。在 git-fast-import 中,這意味著路徑相對於 .git/info/fast-import 目錄。但是,其他匯入器可能使用不同的位置。

可以透過交錯 --(no-)-relative-marks 和 --(import|export)-marks= 選項來組合相對和非相對標記。

子模組重寫

--rewrite-submodules-from=<name>:<file>
--rewrite-submodules-to=<name>:<file>

將指定子模組 <name> 的物件 ID 從 中的值重寫為 中的值。from 標記應由 git fast-export 建立,to 標記應由 git fast-import 在匯入相同子模組時建立。

<name> 可以是任何不包含冒號的任意字串,但在指定相應標記時,必須使用相同的值。可以透過為 <name> 指定不同的值來指定多個子模組。不成對使用這些選項是錯誤。

這些選項主要在將倉庫從一種雜湊演算法轉換為另一種演算法時非常有用;沒有它們,fast-import 如果遇到子模組會失敗,因為它無法將物件 ID 寫入新的雜湊演算法。

效能和壓縮調優

--active-branches=<n>

一次要維護的最大活動分支數。有關詳細資訊,請參見下面的“記憶體使用”。預設值為 5。

--big-file-threshold=<n>

fast-import 嘗試為之建立 delta 的 blob 的最大大小,以位元組為單位。預設值為 512m (512 MiB)。一些匯入器可能希望在記憶體受限的系統上降低此值。

--depth=<n>

blob 和 tree 的最大 delta 深度。預設值為 50。

--export-pack-edges=<file>

建立 packfile 後,將一行資料列印到 <file>,列出 packfile 的檔名以及寫入該 packfile 的每個分支上的最後一個提交。在匯入的總物件集超過 4 GiB packfile 限制的專案後,此資訊可能很有用,因為這些提交可用作 git pack-objects 呼叫期間的邊緣點。

--max-pack-size=<n>

每個輸出 packfile 的最大大小。預設值為無限制。

fastimport.unpackLimit

參見 git-config[1]

效能

fast-import 的設計使其能夠以最小的記憶體使用量和處理時間匯入大型專案。假設前端能夠跟上 fast-import 的步伐併為其提供持續的資料流,那麼包含 10 多年曆史和 100,000 多個提交的專案,其匯入時間通常在相當普通的硬體(2007 年約 2,000 美元)上只需 1-2 小時。

大多數瓶頸似乎在於外部源資料訪問(源無法足夠快地提取修訂版)或磁碟 IO(fast-import 寫入速度與磁碟接收資料速度一樣快)。如果源資料儲存在與目標 Git 倉庫不同的驅動器上(由於 IO 爭用較少),匯入將執行得更快。

開發成本

fast-import 的典型前端通常由大約 200 行 Perl/Python/Ruby 程式碼組成。大多數開發人員能夠在短短幾個小時內建立可用的匯入器,即使這是他們第一次接觸 fast-import,有時甚至是 Git。考慮到大多數轉換工具都是一次性的(僅使用一次,然後不再使用),這是一個理想的情況。

並行操作

git pushgit fetch 一樣,由 fast-import 處理的匯入可以安全地與並行執行的 git repack -a -dgit gc 呼叫,或任何其他 Git 操作(包括 git prune,因為 loose objects 從不被 fast-import 使用)一起執行。

fast-import 不會鎖定它正在積極匯入的分支或標籤引用。匯入完成後,在引用更新階段,fast-import 會測試每個現有的分支引用,以驗證更新將是快進更新(引用中儲存的提交包含在新要寫入的提交的歷史中)。如果更新不是快進更新,fast-import 將跳過更新該引用,而是列印警告訊息。fast-import 始終會嘗試更新所有分支引用,並且不會在第一次失敗時停止。

可以使用 --force 強制更新分支,但建議僅在其他方面靜默的倉庫上使用。對於初始匯入到空倉庫,使用 --force 不是必需的。

技術討論

fast-import 在記憶體中跟蹤一組分支。在匯入過程的任何時候,都可以透過在輸入流上傳送 commit 命令來建立或修改任何分支。這種設計允許前端程式同時處理無限數量的分支,並按從源資料可用的順序生成提交。這也大大簡化了前端程式。

fast-import 不使用或修改當前工作目錄,或其中的任何檔案。(但它會更新當前 Git 倉庫,如 GIT_DIR 所引用。)因此,匯入前端可以使用工作目錄來實現其自身目的,例如從外部源提取檔案修訂版。這種對工作目錄的忽略也使得 fast-import 執行得非常快,因為它在切換分支時不需要執行任何耗時的檔案更新操作。

輸入格式

除了原始檔案資料(Git 不解釋)之外,fast-import 的輸入格式是基於文字(ASCII)的。這種基於文字的格式簡化了前端程式的開發和除錯,尤其是在使用 Perl、Python 或 Ruby 等更高階語言時。

fast-import 對其輸入非常嚴格。我們在下面提到 SP 時,表示精確一個空格。同樣,LF 表示一個(且僅一個)換行符,HT 表示一個(且僅一個)水平製表符。提供額外的空白字元將導致意外結果,例如分支名稱或檔名中帶有前導或尾隨空格,或者 fast-import 在遇到意外輸入時過早終止。

流注釋

為了幫助除錯前端,fast-import 會忽略任何以 #(ASCII 磅/雜湊)開頭直到幷包括行尾 LF 的行。註釋行可以包含任何不包含 LF 的位元組序列,因此可用於包含可能特定於前端並且在檢查 fast-import 資料流時可能很有用的任何詳細除錯資訊。

日期格式

支援以下日期格式。前端應透過 --date-format=<fmt> 命令列選項傳遞格式名稱來為此匯入選擇其將使用的格式。

raw

這是 Git 的原生格式,格式為 <time> SP <offutc>。如果未指定 --date-format,它也是 fast-import 的預設格式。

<time> 指的是自 UNIX 紀元(1970 年 1 月 1 日午夜,UTC)以來的秒數,並以 ASCII 十進位制整數的形式書寫。

<offutc> 指的是與 UTC 的正或負偏移量。例如,EST(比 UTC 晚 5 小時)在 <tz> 中將表示為“-0500”,而 UTC 為“+0000”。本地偏移量不影響 <time>;它僅用作提示,以幫助格式化例程顯示時間戳。

如果源材料中未提供本地偏移量,請使用“+0000”或最常見的本地偏移量。例如,許多組織擁有一個 CVS 倉庫,該倉庫僅被位於同一地點和時區的使用者訪問過。在這種情況下,可以假定一個合理的 UTC 偏移量。

rfc2822 格式不同,此格式非常嚴格。任何格式變化都會導致 fast-import 拒絕該值,並且還可能執行一些對數值的健全性檢查。

raw-permissive

raw 相同,只是不對紀元時間和本地偏移量進行健全性檢查。這在嘗試過濾或匯入具有例如錯誤時區值的現有歷史記錄時很有用。

rfc2822

這是 RFC 2822 所描述的標準日期格式。

示例值為“Tue Feb 6 11:22:18 2007 -0500”。Git 解析器是準確的,但有點寬鬆。它與 git am 在應用從電子郵件收到的補丁時使用的解析器相同。

一些格式錯誤的字串可能被接受為有效日期。在某些情況下,Git 仍然能夠從格式錯誤的字串中獲取正確的日期。還有一些格式錯誤的字串,Git 會解析錯誤,但仍認為它們有效。嚴重格式錯誤的字串將被拒絕。

與上面的 raw 格式不同,RFC 2822 日期字串中包含的時區/UTC 偏移量資訊用於在儲存日期值之前將其調整為 UTC。因此,此資訊儘可能準確非常重要。

如果源材料使用 RFC 2822 風格的日期,前端應讓 fast-import 處理解析和轉換(而不是試圖自己處理),因為 Git 解析器在實際應用中已經過充分測試。

如果源材料已使用 UNIX 紀元格式、可以被引導為使用該格式提供日期,或者其格式易於轉換為該格式,則前端應優先使用 raw 格式,因為解析沒有歧義。

now

始終使用當前時間和時區。對於 <when>,必須始終提供文字 now

這是一個玩具格式。在此身份字串由 fast-import 建立時,始終會複製該系統的當前時間和時區。無法指定不同的時間或時區。

此特定格式之所以提供,是因為其實現起來很短,並且可能對想要立即建立新提交但無需使用工作目錄或 git update-index 的程序有用。

如果在 commit 中使用了單獨的 authorcommitter 命令,則時間戳可能不匹配,因為系統時鐘將被輪詢兩次(每次命令一次)。確保作者和提交者身份資訊具有相同時間戳的唯一方法是省略 author(從而從 committer 複製)或使用 now 以外的日期格式。

命令

fast-import 接受多個命令來更新當前倉庫並控制當前的匯入過程。稍後將詳細討論(附帶示例)每個命令。

commit

建立新分支或更新現有分支,方法是建立新提交併將分支指向新建立的提交。

tag

從現有提交或分支建立帶註釋的標籤物件。不支援輕量級標籤,因為不建議使用它們來記錄有意義的時間點。

reset

將現有分支(或新分支)重置到特定修訂版。必須使用此命令將分支更改為特定修訂版而不對其進行提交。

blob

將原始檔案資料轉換為 blob,供將來在 commit 命令中使用。此命令是可選的,不需要執行匯入。

alias

記錄一個標記引用給定的物件,而不先建立任何新物件。使用 --import-marks 並引用不存在的標記將導致 fast-import 失敗,因此別名可以提供一種將已被修剪的提交設定為有效值(例如,最近的非修剪祖先)的方法。

checkpoint

強制 fast-import 關閉當前 packfile,生成其唯一的 SHA-1 校驗和和索引,並啟動一個新的 packfile。此命令是可選的,不需要執行匯入。

progress

導致 fast-import 將整行回顯到其自身的標準輸出。此命令是可選的,不需要執行匯入。

done

標記流的結束。除非使用 --done 命令列選項或 feature done 命令請求了 done 功能,否則此命令是可選的。

get-mark

導致 fast-import 將與標記對應的 SHA-1 列印到使用 --cat-blob-fd 設定的檔案描述符,或在未指定時列印到 stdout

cat-blob

導致 fast-import 以 cat-file --batch 格式將 blob 列印到使用 --cat-blob-fd 設定的檔案描述符,或在未指定時列印到 stdout

ls

導致 fast-import 將描述目錄條目的行以 ls-tree 格式列印到使用 --cat-blob-fd 設定的檔案描述符,或在未指定時列印到 stdout

feature

啟用指定的功能。這需要 fast-import 支援指定的功能,並且在不支援時會中止。

option

指定 OPTIONS 下列出的任何不改變流語義以適應前端需求的選項。此命令是可選的,不需要執行匯入。

commit

建立或更新分支,並建立一個新提交,記錄專案的一個邏輯更改。

	'commit' SP <ref> LF
	mark?
	original-oid?
	('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
	'committer' (SP <name>)? SP LT <email> GT SP <when> LF
	('gpgsig' SP <algo> SP <format> LF data)?
	('encoding' SP <encoding> LF)?
	data
	('from' SP <commit-ish> LF)?
	('merge' SP <commit-ish> LF)*
	(filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
	LF?

其中 <ref> 是要建立提交的分支名稱。通常 Git 中的分支名稱以 refs/heads/ 開頭,因此匯入 CVS 分支符號 RELENG-1_0 將使用 refs/heads/RELENG-1_0 作為 <ref> 的值。<ref> 的值必須是 Git 中有效的 refname。由於 LF 在 Git refname 中無效,此處不支援任何引號或轉義語法。

可以選擇新增 mark 命令,要求 fast-import 儲存新建立提交的引用以供前端將來使用(格式參見下文)。前端通常會標記它們建立的每個提交,從而允許將來從任何匯入的提交建立分支。

committer 命令後的 data 命令必須提供提交訊息(有關 data 命令語法,請參見下文)。要匯入空提交訊息,請使用 0 長度的資料。提交訊息是自由形式的,Git 不會解釋它們。目前它們必須編碼為 UTF-8,因為 fast-import 不允許指定其他編碼。

可以包含零個或多個 filemodifyfiledeletefilecopyfilerenamefiledeleteallnotemodify 命令,以在建立提交之前更新分支的內容。這些命令可以按任何順序提供。但是,建議 filedeleteall 命令出現在同一提交中的所有 filemodifyfilecopyfilerenamenotemodify 命令之前,因為 filedeleteall 會清空分支(參見下文)。

命令後的 LF 是可選的(以前是必需的)。請注意,出於向後相容的原因,如果提交以 data 命令結尾(即,它沒有 frommergefilemodifyfiledeletefilecopyfilerenamefiledeleteallnotemodify 命令),則命令末尾可能出現兩個 LF 命令而不是一個。

作者

可以新增可選的 author 命令,以防作者資訊可能與提交者資訊不同。如果省略 author,則 fast-import 將自動使用提交者的資訊作為提交的作者部分。有關 author 中欄位的描述,請參見下文,它們與 committer 相同。

提交者

committer 命令指示誰進行了此提交以及何時進行的。

其中 <name> 是該人員的顯示名稱(例如“Com M Itter”),<email> 是該人員的電子郵件地址(“cm@example.com”)。<lt> 和 <gt> 是字面上的小於 (\x3c) 和大於 (\x3e) 符號。這些是必需的,用於界定電子郵件地址與其他欄位。請注意,<name> 和 <email> 是自由格式的,可以包含除 <lt>、<gt> 和 <lf> 之外的任何位元組序列。<name> 通常是 UTF-8 編碼的。

更改的時間由 <when> 使用 --date-format=<fmt> 命令列選項選擇的日期格式指定。有關支援的格式集及其語法,請參見上文“日期格式”。

gpgsig

可選的 gpgsig 命令用於包含對提交資料進行簽名的 PGP/GPG 簽名或其他加密簽名。

	'gpgsig' SP <git-hash-algo> SP <signature-format> LF data

gpgsig 命令接受兩個引數

  • <git-hash-algo> 指定此簽名適用於哪種 Git 物件格式,可以是 sha1sha256。這有助於瞭解簽名的是提交的哪個表示形式(SHA-1 或 SHA-256 版本),這有助於進行簽名驗證以及不同雜湊函式儲存庫之間的互操作性。

  • <signature-format> 指定簽名的型別,例如 openpgpx509sshunknown。這對於處理流的工具來說是一個便利,這樣它們就不必解析 ASCII armor 來識別簽名型別。

每個提交最多可以有一個用於 SHA-1 物件格式(儲存在“gpgsig”頭中)的簽名和一個用於 SHA-256 物件格式(儲存在“gpgsig-sha256”頭中)的簽名。

有關包含原始簽名資料的 data 命令的詳細描述,請參見下文。

當前實現尚未檢查簽名。(在實現時,設定 extensions.compatObjectFormat 配置選項可能有助於驗證 SHA-1 和 SHA-256 物件格式簽名。)

注意
這是高度實驗性的,並且 gpgsig 命令的格式可能會在未來更改,而沒有相容性保證。

編碼

可選的 encoding 命令指示提交訊息的編碼。大多數提交都是 UTF-8,並且省略了編碼,但這允許在不重新編碼的情況下將提交訊息匯入 git。

from

from 命令用於指定要從中初始化此分支的提交。此修訂版將是新提交的第一個祖先。在此提交處構建的樹的狀態將以 from 提交時的狀態開始,並由此提交中的內容修改進行更改。

在新分支的第一個提交中省略 from 命令將導致 fast-import 建立一個沒有祖先的提交。這通常只對專案的初始提交是期望的。如果前端在建立新分支時從頭開始建立所有檔案,則可以使用 merge 命令而不是 from 來使提交以空樹開始。在現有分支上省略 from 命令通常是期望的,因為該分支上的當前提交自動假定為新提交的第一個祖先。

由於 LF 在 Git refname 或 SHA-1 表示式中無效,因此在 <commit-ish> 中不支援任何引號或轉義語法。

此處 <commit-ish> 是以下任一項

  • fast-import 內部分支表中已存在的分支的名稱。如果 fast-import 不知道該名稱,則將其視為 SHA-1 表示式。

  • 標記引用,:<idnum>,其中 <idnum> 是標記的編號。

    fast-import 使用 : 來表示標記引用的原因是該字元在 Git 分支名稱中是非法的。前導的 : 使得很容易區分標記 42 (:42) 和分支 42 (42refs/heads/42),或者一個碰巧只包含十進位制數字的縮寫 SHA-1。

    標記在使用前必須(透過 mark)宣告。

  • 完整的 40 位元組或縮寫的十六進位制提交 SHA-1。

  • 任何可以解析為提交的有效 Git SHA-1 表示式。詳情請參閱 gitrevisions[7] 中的“指定修訂”。

  • 特殊的空 SHA-1(40 個零)指定要刪除該分支。

從當前分支值重新啟動增量匯入的特殊情況應寫為

	from refs/heads/branch^0

^0 字尾是必需的,因為 fast-import 不允許分支從自身開始,並且在甚至讀取輸入中的 from 命令之前,該分支已在記憶體中建立。新增 ^0 將強制 fast-import 透過 Git 的修訂解析庫解析提交,而不是其內部分支表,從而載入該分支的現有值。

merge

包括一個額外的祖先提交。額外的祖先連結不改變此提交中樹狀態的構建方式。如果在建立新分支時省略了 from 命令,則第一個 merge 提交將是當前提交的第一個祖先,並且該分支將從沒有檔案開始。fast-import 允許每個提交有無限數量的 merge 命令,從而建立 n 路合併。

此處 <commit-ish>from 也接受的任何提交規範表示式(參見上文)。

filemodify

包含在 commit 命令中以新增新檔案或更改現有檔案內容。此命令有兩種不同的指定檔案內容的方式。

外部資料格式

檔案的資料內容已由之前的 blob 命令提供。前端只需連線它。

	'M' SP <mode> SP <dataref> SP <path> LF

此處通常 <dataref> 必須是之前由 blob 命令設定的標記引用(:<idnum>),或現有 Git blob 物件的完整 40 位元組 SHA-1。如果 <mode>040000,則 <dataref> 必須是現有 Git 樹物件的完整 40 位元組 SHA-1 或使用 --import-marks 設定的標記引用。

內聯資料格式

檔案的資料內容尚未提供。前端希望將其作為此修改命令的一部分提供。

	'M' SP <mode> SP 'inline' SP <path> LF
	data

下面將詳細描述 data 命令。

在這兩種格式中,<mode> 都是檔案條目的型別,以八進位制指定。Git 只支援以下模式

  • 100644644:普通(非可執行)檔案。大多數專案中的檔案都使用此模式。如有疑問,這就是您想要的。

  • 100755755:普通但可執行的檔案。

  • 120000:符號連結,檔案內容將是連結目標。

  • 160000:gitlink,物件 SHA-1 指向另一個儲存庫中的提交。Git links 只能透過 SHA 或提交標記來指定。它們用於實現子模組。

  • 040000:子目錄。子目錄只能透過 SHA 或使用 --import-marks 設定的樹標記來指定。

在這兩種格式中,<path> 是要新增(如果尚不存在)或修改(如果已存在)的檔案的完整路徑。

<path> 可以寫成未加引號的位元組或 C 風格的帶引號字串。

<path> 不以雙引號(")開頭時,它是未加引號的字串,並被解析為不帶任何轉義序列的文字位元組。但是,如果檔名包含 LF 或以雙引號開頭,則它無法表示為未加引號的字串,必須加引號。此外,filecopyfilerename 中的源 <path> 如果包含 SP,則必須加引號。

<path> 以雙引號(")開頭時,它是 C 風格的帶引號字串,其中完整檔名用一對雙引號括起來,並使用轉義序列。某些字元必須透過在前面加上反斜槓來轉義:LF 寫為 \n,反斜槓寫為 \\,雙引號寫為 \"。某些字元可以選擇使用轉義序列:\a 表示響鈴,\b 表示退格,\f 表示換頁符,\n 表示換行符,\r 表示回車符,\t 表示水平製表符,\v 表示垂直製表符。任何位元組都可以用 3 位八進位制碼錶示(例如 \033)。所有檔名都可以表示為帶引號的字串。

<path> 必須使用 UNIX 風格的目錄分隔符(正斜槓 /),並且其值必須是規範形式。即它不能

  • 包含空目錄元件(例如 foo//bar 無效),

  • 以目錄分隔符結尾(例如 foo/ 無效),

  • 以目錄分隔符開頭(例如 /foo 無效),

  • 包含特殊元件 ...(例如 foo/./barfoo/../bar 無效)。

樹的根目錄可以表示為空字串作為 <path>

<path> 不能包含 NUL,無論是字面量還是轉義為 \000。建議 <path> 始終使用 UTF-8 編碼。

filedelete

包含在 commit 命令中以刪除檔案或遞迴刪除分支中的整個目錄。如果檔案或目錄的刪除使父目錄為空,則父目錄也將被自動刪除。這會一直向上級聯,直到達到第一個非空目錄或根目錄。

	'D' SP <path> LF

此處 <path> 是要從分支中刪除的檔案或子目錄的完整路徑。有關 <path> 的詳細說明,請參閱上面的 filemodify

filecopy

將現有檔案或子目錄遞迴地複製到分支內的不同位置。現有檔案或目錄必須存在。如果目標已存在,它將被複制源的內容完全替換。

	'C' SP <path> SP <path> LF

此處第一個 <path> 是源位置,第二個 <path> 是目標位置。有關 <path> 可能外觀的詳細說明,請參閱上面的 filemodify。要使用包含 SP 的源路徑,該路徑必須加引號。

filecopy 命令立即生效。一旦源位置已複製到目標,對源位置的任何後續命令都不會影響複製的目標。

filerename

將現有檔案或子目錄重新命名為分支內的不同位置。現有檔案或目錄必須存在。如果目標已存在,它將被源目錄替換。

	'R' SP <path> SP <path> LF

此處第一個 <path> 是源位置,第二個 <path> 是目標位置。有關 <path> 可能外觀的詳細說明,請參閱上面的 filemodify。要使用包含 SP 的源路徑,該路徑必須加引號。

filerename 命令立即生效。一旦源位置已重新命名為目標,對源位置的任何後續命令將在那裡建立新檔案,而不會影響重新命名的目標。

請注意,filerenamefilecopy 後跟 filedelete 源位置相同。使用 filerename 有輕微的效能優勢,但優勢如此之小,以至於將源材料中的刪除/新增對轉換為 fast-import 的重新命名永遠不值得。此 filerename 命令僅用於簡化已經具有重新命名資訊但不想將其分解為 filecopy 後跟 filedelete 的前端。

filedeleteall

包含在 commit 命令中以刪除分支中的所有檔案(以及所有目錄)。此命令將內部分支結構重置為沒有任何檔案,從而允許前端隨後從頭開始新增所有相關檔案。

	'deleteall' LF

如果前端不知道(或不關心知道)分支上當前有什麼檔案,因此無法生成正確的 filedelete 命令來更新內容,則此命令非常有用。

發出 filedeleteall 命令,然後是設定正確內容的所需 filemodify 命令,其結果與僅傳送所需的 filemodifyfiledelete 命令相同。然而,filedeleteall 方法可能需要 fast-import 為每個活動分支使用略多一些的記憶體(即使對於大多數大型專案,也少於 1MiB);因此,鼓勵可以輕鬆獲取提交受影響路徑的前端這樣做。

notemodify

包含在 commit <notes-ref> 命令中,用於新增一個新註釋來註解一個 <commit-ish> 或更改該註釋的內容。在內部,它類似於在 <commit-ish> 路徑上進行 filemodify 100644(可能已分割到子目錄)。不建議使用任何其他命令向 <notes-ref> 樹寫入,除了 filedeleteall 以刪除此樹中所有現有的註釋。此命令有兩種不同的方式來指定註釋的內容。

外部資料格式

註釋的資料內容已由之前的 blob 命令提供。前端只需將其連線到要註解的提交。

	'N' SP <dataref> SP <commit-ish> LF

此處 <dataref> 可以是之前由 blob 命令設定的標記引用(:<idnum>),或現有 Git blob 物件的完整 40 位元組 SHA-1。

內聯資料格式

註釋的資料內容尚未提供。前端希望將其作為此修改命令的一部分提供。

	'N' SP 'inline' SP <commit-ish> LF
	data

下面將詳細描述 data 命令。

在這兩種格式中,<commit-ish>from 也接受的任何提交規範表示式(參見上文)。

mark

安排 fast-import 儲存對當前物件的引用,允許前端在未來某個時間點呼叫此物件,而無需知道其 SHA-1。此處當前物件是 mark 命令出現的物件建立命令。它可以是 committagblob,但 commit 是最常見的用法。

	'mark' SP ':' <idnum> LF

其中 <idnum> 是前端為此標記指定的編號。 <idnum> 的值表示為 ASCII 十進位制整數。值 0 是保留的,不能用作標記。只能使用大於或等於 1 的值作為標記。

新標記會自動建立。透過在另一個 mark 命令中重用相同的 <idnum>,可以簡單地將現有標記移動到另一個物件。

original-oid

提供原始原始碼控制系統中的物件名稱。fast-import 將簡單地忽略此指令,但在此之前對流進行操作和修改的過濾器程序可能會利用此資訊。

	'original-oid' SP <object-identifier> LF

其中 <object-identifier> 是任何不包含 LF 的字串。

tag

建立指向特定提交的帶註釋的標籤。要建立輕量級(非帶註釋)標籤,請參閱下面的 reset 命令。

	'tag' SP <name> LF
	mark?
	'from' SP <commit-ish> LF
	original-oid?
	'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
	data

其中 <name> 是要建立的標籤的名稱。

標籤名稱在儲存在 Git 中時會自動加上 refs/tags/ 字首,因此匯入 CVS 分支符號 RELENG-1_0-FINAL 將僅使用 RELENG-1_0-FINAL 作為 <name>,fast-import 將對應的 ref 寫入為 refs/tags/RELENG-1_0-FINAL

<name> 的值必須是 Git 中的有效 refname,因此可能包含正斜槓。由於 LF 在 Git refname 中無效,因此此處不支援任何引用或轉義語法。

from 命令與 commit 命令相同;請參閱上文了解詳情。

tagger 命令使用的格式與 commit 中的 committer 相同;請再次參閱上文了解詳情。

tagger 後面的 data 命令必須提供帶註釋的標籤訊息(有關 data 命令語法的詳細資訊,請參閱下文)。要匯入空標籤訊息,請使用長度為 0 的資料。標籤訊息是自由格式的,Git 不會對其進行解釋。目前它們必須以 UTF-8 編碼,因為 fast-import 不允許指定其他編碼。

不支援在 fast-import 內部從內部簽名帶註釋的標籤。不建議包含您自己的 PGP/GPG 簽名,因為前端(不容易)無法訪問通常用於此類簽名的完整位元組集。如果需要簽名,請使用 reset 在 fast-import 內部建立輕量級標籤,然後使用標準的 git tag 過程在外部建立這些標籤的帶註釋版本。

reset

建立(或重新建立)指定的已命名分支,可選地從特定修訂開始。reset 命令允許前端為現有分支發出新的 from 命令,或在不建立新提交的情況下從現有提交建立新分支。

	'reset' SP <ref> LF
	('from' SP <commit-ish> LF)?
	LF?

有關 <ref><commit-ish> 的詳細說明,請參閱上文 commitfrom

命令後的 LF 是可選的(以前是必需的)。

reset 命令也可用於建立輕量級(非帶註釋)標籤。例如

reset refs/tags/938
from :938

將建立指向 :938 標記所引用的任何提交的輕量級標籤 refs/tags/938

blob

請求將一個檔案修訂寫入 packfile。該修訂與任何提交都沒有關聯;必須在後續的 commit 命令中透過引用分配的標記來形成此關聯。

	'blob' LF
	mark?
	original-oid?
	data

此處標記命令是可選的,因為一些前端選擇自行生成 blob 的 Git SHA-1,並將其直接饋送給 commit。但這通常比它本身更有價值,因為標記儲存成本低廉且易於使用。

data

向 fast-import 提供原始資料(用於 blob/檔案內容、提交訊息或帶註釋的標籤訊息)。資料可以使用確切的位元組計數提供,或用終止行分隔。旨在用於生產質量轉換的實際前端應始終使用確切的位元組計數格式,因為它更健壯且效能更好。分隔格式主要用於測試 fast-import。

data 命令的 <raw> 部分中出現的註釋行始終被視為資料正文的一部分,因此 fast-import 永遠不會忽略它們。這使得匯入任何行可能以 # 開頭的檔案的內容/訊息內容成為安全的。

精確位元組計數格式

前端必須指定資料的位元組數。

	'data' SP <count> LF
	<raw> LF?

其中 <count><raw> 中的確切位元組數。 <count> 的值表示為 ASCII 十進位制整數。 <raw> 兩側的 LF 不包含在 <count> 中,也不會包含在匯入的資料中。

<raw> 後的 LF 是可選的(以前是必需的),但推薦使用。始終包含它使除錯 fast-import 流更容易,因為下一個命令總是從下一行的第 0 列開始,即使 <raw> 不以 LF 結尾。

分隔格式

使用分隔符字串來標記資料的結束。fast-import 將透過查詢分隔符來計算長度。此格式主要用於測試,不推薦用於實際資料。

	'data' SP '<<' <delim> LF
	<raw> LF
	<delim> LF
	LF?

其中 <delim> 是選定的分隔符字串。字串 <delim> 不能出現在 <raw> 中單獨的一行上,否則 fast-import 會認為資料提前結束。緊隨 <raw>LF<raw> 的一部分。這是分隔格式的一個限制,無法提供不以 LF 作為最後一個位元組的資料塊。

<delim> LF 後的 LF 是可選的(以前是必需的)。

alias

記錄一個標記引用給定的物件,而不先建立任何新物件。

	'alias' LF
	mark
	'to' SP <commit-ish> LF
	LF?

有關 <commit-ish> 的詳細說明,請參閱上文 from

checkpoint

強制 fast-import 關閉當前 packfile,啟動一個新的 packfile,並儲存所有當前的分支引用、標籤和標記。

	'checkpoint' LF
	LF?

請注意,噹噹前 packfile 達到 --max-pack-size 或 4 GiB 時(以較小者為準),fast-import 會自動切換 packfile。在自動 packfile 切換期間,fast-import 不會更新分支引用、標籤或標記。

由於 checkpoint 可能需要大量的 CPU 時間和磁碟 I/O(計算整個 pack 的 SHA-1 校驗和、生成相應的索引檔案以及更新引用),單個 checkpoint 命令可能需要幾分鐘才能完成。

前端可以選擇在非常大且長時間執行的匯入過程中發出檢查點,或者當它們需要允許另一個 Git 程序訪問分支時。然而,考慮到一個 30 GiB 的 Subversion 儲存庫可以在大約 3 小時內透過 fast-import 載入到 Git 中,明確的檢查點可能不是必需的。

命令後的 LF 是可選的(以前是必需的)。

progress

導致 fast-import 在從輸入流處理命令時,將整個 progress 行未經修改地列印到其標準輸出通道(檔案描述符 1)。該命令對當前匯入或 fast-import 的任何內部狀態都沒有其他影響。

	'progress' SP <any> LF
	LF?

命令的 <any> 部分可以包含任何不包含 LF 的位元組序列。命令後的 LF 是可選的。呼叫者可能希望透過 sed 等工具處理輸出以刪除行的前導部分,例如

frontend | git fast-import | sed 's/^progress //'

checkpoint 命令之後立即放置一個 progress 命令將通知讀者 checkpoint 已完成,並且可以安全地訪問 fast-import 更新的引用。

get-mark

導致 fast-import 將與標記對應的 SHA-1 列印到 stdout 或先前使用 --cat-blob-fd 引數安排的檔案描述符。該命令對當前匯入沒有其他影響;其目的是檢索稍後提交可能希望在其提交訊息中引用的 SHA-1。

	'get-mark' SP ':' <idnum> LF

有關如何安全讀取此輸出的詳細資訊,請參閱下面的“命令響應”。

cat-blob

導致 fast-import 將 blob 列印到先前使用 --cat-blob-fd 引數安排的檔案描述符。該命令對當前匯入沒有其他影響;其主要目的是檢索可能存在於 fast-import 記憶體中但無法從目標儲存庫訪問的 blob。

	'cat-blob' SP <dataref> LF

<dataref> 可以是之前設定的標記引用(:<idnum>)或 Git blob 的完整 40 位元組 SHA-1,可以是預先存在的或準備寫入的。

輸出使用與 git cat-file --batch 相同的格式。

<sha1> SP 'blob' SP <size> LF
<contents> LF

此命令可以在 filemodify 指令出現的地方使用,從而允許在提交中間使用。對於使用內聯指令的 filemodify,它也可以出現在 data 指令之前。

有關如何安全讀取此輸出的詳細資訊,請參閱下面的“命令響應”。

ls

將有關路徑處物件的資訊列印到先前使用 --cat-blob-fd 引數安排的檔案描述符。這允許列印活動提交中的 blob(使用 cat-blob)或從之前的提交複製 blob 或樹以用於當前提交(使用 filemodify)。

ls 命令也可以出現在 filemodify 指令出現的地方,從而允許在提交中間使用。

從活動提交讀取

此形式只能在 commit 的中間使用。路徑指向 fast-import 的活動提交中的目錄條目。在這種情況下,路徑必須加引號。

	'ls' SP <path> LF
從命名樹讀取

<dataref> 可以是標記引用(:<idnum>)或 Git 標籤、提交或樹物件的完整 40 位元組 SHA-1,可以是預先存在的或等待寫入的。路徑相對於 <dataref> 命名的樹的頂層。

	'ls' SP <dataref> SP <path> LF

有關 <path> 的詳細說明,請參閱上面的 filemodify

輸出使用與 git ls-tree <tree> -- <path> 相同的格式。

<mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF

<dataref> 代表 <path> 處的 blob、tree 或 commit 物件,可以在後續的 get-markcat-blobfilemodifyls 命令中使用。

如果該路徑下沒有檔案或子目錄,git fast-import 將報告

missing SP <path> LF

有關如何安全讀取此輸出的詳細資訊,請參閱下面的“命令響應”。

feature

要求 fast-import 支援指定的特性,否則中止。

	'feature' SP <feature> ('=' <argument>)? LF

命令的 <feature> 部分可以是以下任何一項

date-format
export-marks
relative-marks
no-relative-marks
force

表現得就像在命令列上傳遞了帶有前導 -- 的相應命令列選項(參見上面的 OPTIONS)。

import-marks
import-marks-if-exists

與 --import-marks 類似,除了兩點:首先,每個流只允許一個“feature import-marks”或“feature import-marks-if-exists”命令;其次,--import-marks= 或 --import-marks-if-exists 命令列選項將覆蓋流中的任何這些“feature”命令;第三,“feature import-marks-if-exists”就像相應的命令列選項一樣,會默默地跳過不存在的檔案。

get-mark
cat-blob
ls

要求後端支援 get-markcat-blobls 命令。不支援指定命令的版本 fast-import 將退出並顯示相應訊息。這可以使匯入在早期出現錯誤,並帶有清晰的訊息,而不是在檢測到不受支援的命令之前在匯入的早期浪費時間。

notes

要求後端支援 commit 命令的 notemodify (N) 子命令。不支援 notes 的 fast-import 版本將退出並顯示相應訊息。

done

如果流在沒有 done 命令的情況下結束,則報錯。沒有此特性,導致前端在流的方便點突然結束的錯誤可能會被忽略。例如,如果一個匯入前端在操作過程中死亡,而沒有向其附屬的 git fast-import 例項發出 SIGTERM 或 SIGKILL,則可能會發生這種情況。

option

處理指定的選項,以便 git fast-import 的行為方式能夠滿足前端的需求。請注意,前端指定的選項會被使用者自己為 git fast-import 指定的任何選項所覆蓋。

    'option' SP <option> LF

命令的 <option> 部分可以包含“OPTIONS”部分中列出的任何不改變匯入語義的選項,不帶前導 --,並且以相同方式處理。

選項命令必須是輸入中的第一個命令(不計算 feature 命令),在任何非選項命令之後發出選項命令是錯誤的。

以下命令列選項會改變匯入語義,因此不能作為選項傳遞

  • date-format

  • import-marks

  • export-marks

  • cat-blob-fd

  • force

done

如果未使用 done 功能,則假定已讀取 EOF。這可用於告知 fast-import 提前完成。

如果使用了 --done 命令列選項或 feature done 命令,則 done 命令是必需的,並標誌著流的結束。

對命令的響應

fast-import 寫入的新物件並非立即可用。大多數 fast-import 命令在下一個檢查點(或完成)之前不會產生可見的效果。前端可以傳送命令來填充 fast-import 的輸入管道,而無需擔心它們生效的速度,這透過簡化排程來提高效能。

然而,對於某些前端來說,能夠在正在更新的當前儲存庫中讀取回資料(例如,當源材料以應用於先前匯入物件的補丁的形式描述物件時)是有用的。這可以透過雙向管道連線前端和 fast-import 來實現。

mkfifo fast-import-output
frontend <fast-import-output |
git fast-import >fast-import-output

以這種方式設定的前端可以使用 progressget-marklscat-blob 命令來讀取正在進行的匯入中的資訊。

為避免死鎖,此類前端在執行可能阻塞的寫入 fast-import 的操作之前,必須完全消耗來自 progresslsget-markcat-blob 的任何待處理輸出。

崩潰報告

如果 fast-import 收到無效輸入,它將以非零退出狀態終止,並在它正在匯入的 Git 儲存庫的頂層建立一個崩潰報告。崩潰報告包含 fast-import 內部狀態的快照以及導致崩潰的最近命令。

所有最近的命令(包括流注釋、檔案更改和進度命令)都顯示在崩潰報告中的命令歷史記錄中,但原始檔案資料和提交訊息不包括在崩潰報告中。排除這些內容可以節省報告檔案內的空間,並減少 fast-import 在執行期間必須執行的緩衝量。

在寫入崩潰報告後,fast-import 將關閉當前 packfile 並匯出 marks 表。這允許前端開發人員檢查儲存庫狀態並從崩潰點恢復匯入。在崩潰期間,修改後的分支和標籤不會被更新,因為匯入未成功完成。分支和標籤資訊可以在崩潰報告中找到,如果需要更新,則必須手動應用。

一個崩潰示例

$ cat >in <<END_OF_INPUT
# my very first test commit
commit refs/heads/master
committer Shawn O. Pearce <spearce> 19283 -0400
# who is that guy anyway?
data <<EOF
this is my commit
EOF
M 644 inline .gitignore
data <<EOF
.gitignore
EOF
M 777 inline bob
END_OF_INPUT
$ git fast-import <in
fatal: Corrupt mode: M 777 inline bob
fast-import: dumping crash report to .git/fast_import_crash_8434
$ cat .git/fast_import_crash_8434
fast-import crash report:
    fast-import process: 8434
    parent process     : 1391
    at Sat Sep 1 00:58:12 2007
fatal: Corrupt mode: M 777 inline bob
Most Recent Commands Before Crash
---------------------------------
  # my very first test commit
  commit refs/heads/master
  committer Shawn O. Pearce <spearce> 19283 -0400
  # who is that guy anyway?
  data <<EOF
  M 644 inline .gitignore
  data <<EOF
* M 777 inline bob
Active Branch LRU
-----------------
    active_branches = 1 cur, 5 max
pos  clock name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1)      0 refs/heads/master
Inactive Branches
-----------------
refs/heads/master:
  status      : active loaded dirty
  tip commit  : 0000000000000000000000000000000000000000
  old tree    : 0000000000000000000000000000000000000000
  cur tree    : 0000000000000000000000000000000000000000
  commit clock: 0
  last pack   :
-------------------
END OF CRASH REPORT

技巧和竅門

以下技巧和竅門是從 fast-import 的各種使用者那裡收集來的,在此提供建議。

每個提交使用一個標記

在進行儲存庫轉換時,為每個提交使用一個唯一的標記(mark :<n>),並在命令列上提供 --export-marks 選項。fast-import 將轉儲一個檔案,該檔案列出了每個標記以及與之對應的 Git 物件 SHA-1。如果前端可以將標記與源儲存庫關聯起來,則可以透過將每個 Git 提交與相應的源修訂進行比較來輕鬆驗證匯入的準確性和完整性。

從 Perforce 或 Subversion 等系統遷移而來,這應該相當簡單,因為 fast-import 標記也可以是 Perforce 變更集編號或 Subversion 修訂編號。

自由跳過分支

不要試圖最佳化前端,使其在匯入期間一次只專注於一個分支。雖然這樣做可能對 fast-import 來說稍快一些,但它會大大增加前端程式碼的複雜性。

fast-import 的分支 LRU 內建傾向於表現得非常好,啟用非活動分支的成本如此之低,以至於在分支之間跳躍幾乎不會影響匯入效能。

處理重新命名

匯入重新命名的檔案或目錄時,只需刪除舊名稱,並在相應的提交中修改新名稱。Git 在提交之後進行重新命名檢測,而不是在提交期間顯式進行。

使用標籤修復分支

其他一些 SCM 系統允許使用者從多個不來自同一提交/變更集的檔案建立標籤。或者建立標籤,這些標籤是儲存庫中可用檔案的一個子集。

直接在 Git 中匯入這些標籤是不可能的,除非至少進行一次“修復”檔案的提交,使其內容與標籤匹配。使用 fast-import 的 reset 命令將一個位於正常分支空間之外的虛擬分支重置為標籤的基礎提交,然後提交一個或多個檔案修復提交,最後為虛擬分支打上標籤。

例如,由於所有正常分支都儲存在 refs/heads/ 下,因此將標籤修復分支命名為 TAG_FIXUP。這樣,匯入器使用的修復分支就不可能與從源匯入的實際分支發生名稱空間衝突(名稱 TAG_FIXUP 不是 refs/heads/TAG_FIXUP)。

提交修復時,請考慮使用 merge 將提供檔案修訂的提交連線到修復分支。這樣做將允許像 git blame 這樣的工具跟蹤真實的提交歷史,並正確地註釋原始檔。

fast-import 終止後,前端需要執行 rm .git/TAG_FIXUP 來刪除虛擬分支。

立即匯入,稍後重新打包

fast-import 完成後,Git 儲存庫立即是完全有效的,並且可以投入使用。通常,即使對於相當大的專案(100,000+ 提交),這也只需要很短的時間。

然而,重新打包儲存庫對於提高資料區域性性和訪問效能是必要的。對於非常大的專案(尤其是使用 -f 和較大的 --window 引數時),這可能需要數小時。由於重新打包可以與讀取器和寫入器並行執行,因此在後臺執行重新打包並讓它完成。沒有理由等待探索你的新 Git 專案!

如果你選擇等待重新打包,請不要在重新打包完成之前嘗試執行基準測試或效能測試。fast-import 輸出的 packfile 是非最優的,並且在實際使用情況中很少見到。

重新打包歷史資料

如果你正在重新打包非常舊的匯入資料(例如,一年以上),請考慮在執行 git repack 時花費一些額外的 CPU 時間並提供 --window=50(或更高)。這會花費更長的時間,但也會產生更小的 packfile。你只需要一次付出努力,專案中的每個人都會受益於更小的儲存庫。

包含一些進度訊息

時不時地讓你的前端向 fast-import 發出 progress 訊息。訊息的內容完全自由格式,因此一個建議是在當前提交日期進入下一個月時輸出當前的月份和年份。你的使用者會更好地瞭解有多少資料流已被處理。

PACKFILE 最佳化

在打包 blob 時,fast-import 總是嘗試與寫入的最後一個 blob 進行增量打包。除非前端特別安排,否則這可能不是同一個檔案的先前版本,因此生成的增量可能不是最小的。生成的 packfile 將被壓縮,但不會是最佳的。

能夠高效訪問單個檔案所有修訂版的前端(例如,讀取 RCS/CVS ,v 檔案)可以選擇將該檔案的所有修訂版作為一系列連續的 blob 命令提供。這允許 fast-import 在不同的檔案修訂之間進行增量打包,從而節省最終 packfile 中的空間。之後可以使用標記在 commit 命令序列中識別單個檔案修訂。

fast-import 建立的 packfile 不利於良好的磁碟訪問模式。這是因為 fast-import 按接收順序寫入標準輸入資料,而 Git 通常會在 packfile 中組織資料,使最近(當前提示)的資料出現在歷史資料之前。Git 還將提交分組在一起,透過更好的快取區域性性來加速修訂遍歷。

因此,強烈建議使用者在 fast-import 完成後使用 git repack -a -d 重新打包儲存庫,允許 Git 重新組織 packfile 以加快資料訪問。如果 blob 增量是非最優的(見上文),則新增 -f 選項強制重新計算所有增量可以顯著減小最終 packfile 的大小(通常可以減小 30-50%)。

除了執行 git repack,你還可以執行 git gc --aggressive,它在匯入後還會最佳化其他內容(例如,打包鬆散的引用)。如 git-gc[1] 的“AGGRESSIVE”部分所述,--aggressive 選項會使用 git-repack[1]-f 選項查詢新的增量。鑑於上述原因,在 fast-import 後使用 --aggressive 是少數已知有益的情況之一。

記憶體利用率

有許多因素會影響 fast-import 執行匯入所需的記憶體量。與核心 Git 的關鍵部分一樣,fast-import 使用自己的記憶體分配器來分攤與 malloc 相關的任何開銷。實際上,由於 fast-import 使用大塊記憶體分配,因此它傾向於將任何 malloc 開銷分攤到 0。

每個物件

fast-import 為本次執行中寫入的每個物件維護一個記憶體結構。在 32 位系統上,該結構為 32 位元組,在 64 位系統上,該結構為 40 位元組(由於指標大小更大)。表中的物件在 fast-import 終止之前不會被釋放。在 32 位系統上匯入 200 萬個物件大約需要 64 MiB 記憶體。

物件表實際上是一個以物件名稱(唯一的 SHA-1)為鍵的雜湊表。這種儲存配置允許 fast-import 重用現有或已寫入的物件,並避免將重複項寫入輸出 packfile。在匯入中,重複的 blob 出奇地常見,通常是由於源中的分支合併。

每個標記

標記儲存在稀疏陣列中,每個標記使用 1 個指標(4 位元組或 8 位元組,取決於指標大小)。儘管陣列是稀疏的,但仍然強烈建議前端使用介於 1 和 n 之間的標記,其中 n 是本次匯入所需的總標記數。

每個分支

分支分為活動和非活動。兩類記憶體使用量差異很大。

非活動分支儲存在一個結構中,該結構每個分支使用 96 或 120 位元組(分別為 32 位或 64 位系統),加上分支名稱的長度(通常在 200 位元組以下)。fast-import 可以在 2 MiB 以下的記憶體中輕鬆處理多達 10,000 個非活動分支。

活動分支具有與非活動分支相同的開銷,但還包含該分支上最近修改的所有樹的副本。如果子目錄 include 自分支變為活動狀態以來未被修改,則其內容不會載入到記憶體中;但如果子目錄 src 自分支變為活動狀態以來已被提交修改,則其內容將載入到記憶體中。

由於活動分支儲存有關該分支上檔案的元資料,因此其記憶體儲存大小可能會變得相當大(見下文)。

fast-import 根據簡單的最近最少使用演算法自動將活動分支移至非活動狀態。LRU 鏈在每次 commit 命令時更新。活動分支的最大數量可以在命令列上使用 --active-branches= 進行增加或減少。

每個活動樹

樹(又稱目錄)除了其條目所需的記憶體外,僅使用 12 位元組記憶體(見下文的“每個活動檔案條目”)。樹的成本幾乎為 0,因為其開銷在各個檔案條目上分攤。

每個活動檔案條目

活動樹中的檔案(和指向子樹的指標)每個條目需要 52 或 64 位元組(32/64 位平臺)。為了節省空間,檔案和樹名被集中到一個公共字串表中,允許檔名“Makefile”在使用(包括字串頭部開銷後)無論在專案中出現多少次,都只佔用 16 位元組。

活動分支 LRU,結合檔名字串池和子樹的惰性載入,使得 fast-import 能夠在非常有限的記憶體佔用(每個活動分支低於 2.7 MiB)下高效地匯入具有 2,000 多個分支和 45,114 多個檔案的專案。

訊號

git fast-import 程序傳送 SIGUSR1 會提前結束當前 packfile,模擬 checkpoint 命令。急切的操作員可以使用此功能來檢視正在進行的匯入中的物件和引用,但代價是執行時間增加和壓縮效果變差。

配置

本節中以下所有內容均從 git-config[1] 文件中選擇性地包含。內容與彼處相同:

fastimport.unpackLimit

如果 git-fast-import[1] 匯入的物件數量低於此限制,則物件將被解壓為鬆散的物件檔案。但是,如果匯入的物件數量等於或超過此限制,則 pack 將被儲存為一個 pack。從 fast-import 儲存 pack 可以使匯入操作更快完成,尤其是在慢速檔案系統上。如果未設定,則使用 transfer.unpackLimit 的值。

另請參閱

GIT

Git[1] 套件的一部分