设置和配置
获取和创建项目
基本快照
分支与合并
共享和更新项目
检查和比较
打补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
-
2.52.0
2025-11-17
- 2.51.2 无变更
-
2.51.1
2025-10-15
-
2.51.0
2025-08-18
- 2.50.1 无更改
-
2.50.0
2025-06-16
- 2.45.1 → 2.49.1 无更改
-
2.45.0
2024-04-29
- 2.44.1 → 2.44.4 无更改
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.7 无更改
-
2.43.0
2023-11-20
- 2.38.1 → 2.42.4 无更改
-
2.38.0
2022-10-02
- 2.29.1 → 2.37.7 无更改
-
2.29.0
2020-10-19
- 2.28.1 无更改
-
2.28.0
2020-07-27
- 2.27.1 无更改
-
2.27.0
2020-06-01
- 2.24.2 → 2.26.3 无变更
-
2.24.1
2019-12-06
-
2.24.0
2019-11-04
- 2.23.2 → 2.23.4 无变更
-
2.23.1
2019-12-06
-
2.23.0
2019-08-16
- 2.22.3 → 2.22.5 无变更
-
2.22.2
2019-12-06
- 2.22.1 无变更
-
2.22.0
2019-06-07
- 2.21.2 → 2.21.4 无变更
-
2.21.1
2019-12-06
-
2.21.0
2019-02-24
- 2.20.3 → 2.20.5 无变更
-
2.20.2
2019-12-06
- 2.20.1 无变更
- 2.20.0 无变更
- 2.19.4 → 2.19.6 无变更
-
2.19.3
2019-12-06
- 2.19.1 → 2.19.2 无变更
- 2.19.0 无变更
- 2.18.3 → 2.18.5 无变更
-
2.18.2
2019-12-06
- 2.18.1 无变更
-
2.18.0
2018-06-21
- 2.17.4 → 2.17.6 无变更
-
2.17.3
2019-12-06
- 2.17.1 → 2.17.2 无变更
- 2.17.0 无变更
- 2.15.4 → 2.16.6 无变更
-
2.14.6
2019-12-06
- 2.11.4 → 2.13.7 无变更
-
2.10.5
2017-09-22
-
2.9.5
2017-07-30
- 2.7.6 → 2.8.6 无更改
-
2.6.7
2017-05-05
- 2.5.6 无更改
-
2.4.12
2017-05-05
- 2.3.10 无更改
-
2.2.3
2015-09-04
-
2.1.4
2014-12-17
-
2.0.5
2014-12-17
描述
此程序通常不是最终用户希望直接运行的。大多数最终用户希望使用现有的前端程序之一,这些程序会解析特定类型的外部源,并将其中存储的内容馈送给 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
-
通过使用
feature或option命令,可以将许多命令行选项作为 fast-import 流本身的一部分提供。但是,其中一些选项是不安全的(例如,允许 fast-import 访问仓库外部的文件系统)。默认情况下禁用这些选项,但可以通过在命令行中提供此选项来允许。这目前仅影响export-marks、import-marks和import-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)。
标记文件位置
- --export-marks=<file>
-
完成后将内部标记表转储到 <file>。标记以
:markidSHA-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 标记应由 gitfast-export创建,to 标记应由gitfast-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
性能
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 push 或 git fetch 一样,由 fast-import 处理的导入可以安全地与并行运行的 git repack -a -d 或 git 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中使用了单独的author和committer命令,则时间戳可能不匹配,因为系统时钟将被轮询两次(每次命令一次)。确保作者和提交者身份信息具有相同时间戳的唯一方法是省略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命令行选项或featuredone命令请求了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 不允许指定其他编码。
可以包含零个或多个 filemodify、filedelete、filecopy、filerename、filedeleteall 和 notemodify 命令,以在创建提交之前更新分支的内容。这些命令可以按任何顺序提供。但是,建议 filedeleteall 命令出现在同一提交中的所有 filemodify、filecopy、filerename 和 notemodify 命令之前,因为 filedeleteall 会清空分支(参见下文)。
命令后的 LF 是可选的(以前是必需的)。请注意,出于向后兼容的原因,如果提交以 data 命令结尾(即,它没有 from、merge、filemodify、filedelete、filecopy、filerename、filedeleteall 或 notemodify 命令),则命令末尾可能出现两个 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 对象格式,可以是
sha1或sha256。这有助于了解签名的是提交的哪个表示形式(SHA-1 或 SHA-256 版本),这有助于进行签名验证以及不同哈希函数存储库之间的互操作性。 -
<signature-format> 指定签名的类型,例如
openpgp、x509、ssh或unknown。这对于处理流的工具来说是一个便利,这样它们就不必解析 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 (42或refs/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 只支持以下模式
-
100644或644:普通(非可执行)文件。大多数项目中的文件都使用此模式。如有疑问,这就是您想要的。 -
100755或755:普通但可执行的文件。 -
120000:符号链接,文件内容将是链接目标。 -
160000:gitlink,对象 SHA-1 指向另一个存储库中的提交。Git links 只能通过 SHA 或提交标记来指定。它们用于实现子模块。 -
040000:子目录。子目录只能通过 SHA 或使用--import-marks设置的树标记来指定。
在这两种格式中,<path> 是要添加(如果尚不存在)或修改(如果已存在)的文件的完整路径。
<path> 可以写成未加引号的字节或 C 风格的带引号字符串。
当 <path> 不以双引号(")开头时,它是未加引号的字符串,并被解析为不带任何转义序列的文字字节。但是,如果文件名包含 LF 或以双引号开头,则它无法表示为未加引号的字符串,必须加引号。此外,filecopy 或 filerename 中的源 <path> 如果包含 SP,则必须加引号。
当 <path> 以双引号(")开头时,它是 C 风格的带引号字符串,其中完整文件名用一对双引号括起来,并使用转义序列。某些字符必须通过在前面加上反斜杠来转义:LF 写为 \n,反斜杠写为 \\,双引号写为 \"。某些字符可以选择使用转义序列:\a 表示响铃,\b 表示退格,\f 表示换页符,\n 表示换行符,\r 表示回车符,\t 表示水平制表符,\v 表示垂直制表符。任何字节都可以用 3 位八进制码表示(例如 \033)。所有文件名都可以表示为带引号的字符串。
<path> 必须使用 UNIX 风格的目录分隔符(正斜杠 /),并且其值必须是规范形式。即它不能
-
包含空目录组件(例如
foo//bar无效), -
以目录分隔符结尾(例如
foo/无效), -
以目录分隔符开头(例如
/foo无效), -
包含特殊组件
.或..(例如foo/./bar和foo/../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 命令立即生效。一旦源位置已重命名为目标,对源位置的任何后续命令将在那里创建新文件,而不会影响重命名的目标。
请注意,filerename 与 filecopy 后跟 filedelete 源位置相同。使用 filerename 有轻微的性能优势,但优势如此之小,以至于将源材料中的删除/添加对转换为 fast-import 的重命名永远不值得。此 filerename 命令仅用于简化已经具有重命名信息但不想将其分解为 filecopy 后跟 filedelete 的前端。
filedeleteall
包含在 commit 命令中以删除分支中的所有文件(以及所有目录)。此命令将内部分支结构重置为没有任何文件,从而允许前端随后从头开始添加所有相关文件。
'deleteall' LF
如果前端不知道(或不关心知道)分支上当前有什么文件,因此无法生成正确的 filedelete 命令来更新内容,则此命令非常有用。
发出 filedeleteall 命令,然后是设置正确内容的所需 filemodify 命令,其结果与仅发送所需的 filemodify 和 filedelete 命令相同。然而,filedeleteall 方法可能需要 fast-import 为每个活动分支使用略多一些的内存(即使对于大多数大型项目,也少于 1MiB);因此,鼓励可以轻松获取提交受影响路径的前端这样做。
mark
安排 fast-import 保存对当前对象的引用,允许前端在未来某个时间点调用此对象,而无需知道其 SHA-1。此处当前对象是 mark 命令出现的对象创建命令。它可以是 commit、tag 和 blob,但 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> 的详细说明,请参阅上文 commit 和 from。
命令后的 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 指令出现的地方,从而允许在提交中间使用。
有关 <path> 的详细说明,请参阅上面的 filemodify。
输出使用与 git ls-tree <tree> -- <path> 相同的格式。
<mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF
<dataref> 代表 <path> 处的 blob、tree 或 commit 对象,可以在后续的 get-mark、cat-blob、filemodify 或 ls 命令中使用。
如果该路径下没有文件或子目录,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-mark、cat-blob 或 ls 命令。不支持指定命令的版本 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
对命令的响应
fast-import 写入的新对象并非立即可用。大多数 fast-import 命令在下一个检查点(或完成)之前不会产生可见的效果。前端可以发送命令来填充 fast-import 的输入管道,而无需担心它们生效的速度,这通过简化调度来提高性能。
然而,对于某些前端来说,能够在正在更新的当前存储库中读取回数据(例如,当源材料以应用于先前导入对象的补丁的形式描述对象时)是有用的。这可以通过双向管道连接前端和 fast-import 来实现。
mkfifo fast-import-output frontend <fast-import-output | git fast-import >fast-import-output
以这种方式设置的前端可以使用 progress、get-mark、ls 和 cat-blob 命令来读取正在进行的导入中的信息。
为避免死锁,此类前端在执行可能阻塞的写入 fast-import 的操作之前,必须完全消耗来自 progress、ls、get-mark 和 cat-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 内置倾向于表现得非常好,激活非活动分支的成本如此之低,以至于在分支之间跳跃几乎不会影响导入性能。
使用标签修复分支
其他一些 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 是非最优的,并且在实际使用情况中很少见到。
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= 进行增加或减少。
信号
向 git fast-import 进程发送 SIGUSR1 会提前结束当前 packfile,模拟 checkpoint 命令。急切的操作员可以使用此功能来查看正在进行的导入中的对象和引用,但代价是运行时间增加和压缩效果变差。
配置
本节中以下所有内容均从 git-config[1] 文档中选择性地包含。内容与彼处相同:
- fastimport.unpackLimit
-
如果 git-fast-import[1] 导入的对象数量低于此限制,则对象将被解压为松散的对象文件。但是,如果导入的对象数量等于或超过此限制,则 pack 将被存储为一个 pack。从 fast-import 存储 pack 可以使导入操作更快完成,尤其是在慢速文件系统上。如果未设置,则使用
transfer.unpackLimit的值。