设置和配置
获取和创建项目
基本快照
分支与合并
共享和更新项目
检查和比较
打补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
-
2.53.0
2026-02-02
-
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)-
指定如何处理签名标签。行为与下面的
--signed-commits=<mode> 相同,只是尚不支持strip-if-invalid模式。与签名提交一样,默认模式是verbatim。 --signed-commits=<mode>-
指定如何处理签名提交。支持以下 <mode>s
-
verbatim(默认)将静默导入提交签名。 -
warn-verbatim将导入它们,但会显示警告。 -
abort将使此程序在遇到签名提交时终止。 -
strip将静默使提交未签名。 -
warn-strip将使它们未签名,但会显示警告。 -
strip-if-invalid将检查签名,如果它们无效,将剥离它们并显示警告。验证方式与 git-verify-commit[1] 相同。
-
标记文件的位置
- --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 从 <file> 中使用的值重写为 to <file> 中使用的值。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 和树的增量化。默认值为 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,因为 fast-import 从不使用松散对象)一起运行。
fast-import 不会锁定它正在主动导入的分支或标签引用。导入后,在其引用更新阶段,fast-import 会测试每个现有分支引用,以验证更新是否将是快进更新(引用中存储的提交包含在要写入的提交的新历史记录中)。如果更新不是快进更新,fast-import 将跳过更新该引用并改为打印警告消息。fast-import 始终尝试更新所有分支引用,并且不会在第一次失败时停止。
分支更新可以使用 --force 强制执行,但建议仅在其他安静的仓库上使用。对于初始导入到空仓库,不需要使用 --force。
技术讨论
fast-import 在内存中跟踪一组分支。在导入过程中的任何时候,都可以通过在输入流上发送 commit 命令来创建或修改任何分支。这种设计允许前端程序同时处理无限数量的分支,按它们从源数据中可用的顺序生成提交。它还大大简化了前端程序。
fast-import 不使用或更改当前工作目录,或其中任何文件。(但是它会更新由 GIT_DIR 引用的当前 Git 仓库。)因此,导入前端可以将工作目录用于自己的目的,例如从外部源提取文件修订。这种对工作目录的忽略也使得 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-epoch 格式,或者可以诱导其以该格式提供日期,或者其格式易于转换为该格式,前端应优先使用
raw格式,因为解析没有歧义。 now-
始终使用当前时间和时区。
now字面值必须始终为 <when> 提供。这是一种玩具格式。此系统的当前时间和时区始终在 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 中有效的引用名称。由于 LF 在 Git 引用名称中无效,因此此处不支持任何引用或转义语法。
可以可选地出现 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 命令。如果省略 author,则 fast-import 将自动使用提交者的信息作为提交的作者部分。有关 author 中字段的描述,请参见下文,因为它们与 committer 相同。
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 盔甲来识别签名类型。
一个提交最多可以有一个 SHA-1 对象格式的签名(存储在“gpgsig”头部)和一个 SHA-256 对象格式的签名(存储在“gpgsig-sha256”头部)。
有关包含原始签名数据的 data 命令的详细描述,请参见下文。
然而,当前实现中尚未检查签名。(如果实现,可能已经设置 extensions.compatObjectFormat 配置选项可能有助于验证 SHA-1 和 SHA-256 对象格式签名。)
|
注意
|
这是高度实验性的,并且 gpgsig 命令的格式将来可能会更改,不保证兼容性。 |
from
from 命令用于指定初始化此分支的提交。此修订将是新提交的第一个祖先。在此提交处构建的树的状态将从 from 提交处的状态开始,并由此提交中的内容修改进行更改。
在新分支的第一次提交中省略 from 命令将导致 fast-import 创建没有祖先的提交。这通常仅在项目的初始提交时需要。如果前端在创建新分支时从头开始创建所有文件,则可以使用 merge 命令而不是 from 来启动具有空树的提交。通常希望在现有分支上省略 from 命令,因为该分支上的当前提交会自动假定为新提交的第一个祖先。
由于 LF 在 Git 引用名称或 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 引用另一个仓库中的提交。Gitlink 只能通过 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 为每个活动分支使用略多的内存(即使对于大多数大型项目,也小于 1 MiB);因此,鼓励前端如果能轻松获取提交中受影响的路径,则这样做。
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 将简单地忽略此指令,但在此流输入 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 将把相应的引用写入 refs/tags/RELENG-1_0-FINAL。
<name> 的值必须是 Git 中有效的引用名称,因此可能包含正斜杠。由于 LF 在 Git 引用名称中无效,因此此处不支持任何引用或转义语法。
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
将创建轻量级标签 refs/tags/938,指向标记 :938 引用的任何提交。
blob
请求将一个文件修订写入 packfile。此修订未连接到任何提交;此连接必须在随后的 commit 命令中通过引用所分配标记的 blob 来形成。
'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 流的调试更容易,因为即使 <raw> 没有以LF结尾,下一个命令也始终从下一行的第 0 列开始。 - 分隔符格式
-
使用分隔字符串来标记数据的末尾。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 时间和磁盘 IO(用于计算整个 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,以便后续提交可能希望在其提交消息中引用这些 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、树或提交对象,可在后续的 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) 子命令。不支持注释的 fast-import 版本将退出并显示相应的消息。
- done
-
如果流结束时没有 done 命令,则报错。如果没有此功能,导致前端在流中某个方便点突然终止的错误可能无法检测到。例如,如果导入前端在操作中途死亡而未向其子 git fast-import 实例发出 SIGTERM 或 SIGKILL,则可能会发生这种情况。
option
处理指定的选项,使 git fast-import 的行为方式适应前端的需求。请注意,前端指定的选项将被用户可能指定给 git fast-import 本身的任何选项覆盖。
'option' SP <option> LF
命令的 <option> 部分可以包含 OPTIONS 部分中列出的任何不更改导入语义的选项,不带前导 --,并以相同的方式处理。
选项命令必须是输入上的第一个命令(不包括功能命令),在任何非选项命令之后给出选项命令都是错误的。
以下命令行选项更改导入语义,因此不能作为选项传递
-
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 可以轻松处理多达 10,000 个非活动分支,内存占用不到 2 MiB。
活动分支具有与非活动分支相同的开销,但还包含在该分支上最近修改的每个树的副本。如果自该分支变为活动状态以来,子树 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的值。