设置和配置
获取和创建项目
基本快照
分支与合并
共享和更新项目
检查和比较
打补丁
调试
电子邮件
外部系统
服务器管理
- 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
功能命令。Only enable this option if you trust the program generating the fast-import stream! This option is enabled automatically for remote-helpers that use the `import` capability, as they are already trusted to run their own code.
标记文件的位置
- --export-marks=<file>
-
完成后将内部标记表转储到 <file>。标记以
:markid
SHA-1
的形式每行写入一个。前端可以使用此文件在导入完成后验证导入,或在增量运行中保存标记表。由于 <file> 仅在检查点(或完成)时打开和截断,因此相同的路径也可以安全地提供给 --import-marks。 - --import-marks=<file>
-
在处理任何输入之前,加载 <file> 中指定的标记。输入文件必须存在、可读,并且必须使用与 --export-marks 生成的相同格式。可以提供多个选项以导入多组标记。如果一个标记被定义为不同的值,则最后一个文件中的定义将生效。
- --import-marks-if-exists=<file>
-
与 --import-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> 中使用的值重写为 <file> 中使用的值。from 标记应由
git
fast-export
创建,而 to 标记应由git
fast-import
在导入同一子模块时创建。<name> 可以是任何不包含冒号字符的任意字符串,但在指定相应标记时,两个选项必须使用相同的值。可以使用不同的 <name> 值指定多个子模块。不将这些选项成对使用是错误的。
这些选项主要用于将仓库从一种哈希算法转换为另一种哈希算法;没有它们,fast-import 在遇到子模块时将失败,因为它无法将对象 ID 写入新的哈希算法中。
性能和压缩调优
- --active-branches=<n>
-
同时保持活动状态的最大分支数。详情请参阅下面的“内存使用”。默认为 5。
- --big-file-threshold=<n>
-
fast-import 将尝试为其创建增量的 blob 的最大大小,以字节表示。默认值为 512m (512 MiB)。一些导入器可能希望在内存受限的系统上降低此值。
- --depth=<n>
-
blob 和 tree deltification 的最大增量深度。默认为 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+ 个独立提交的项目,导入时间通常在相当普通的(约 2,000 美元)硬件上仅需 1-2 小时即可完成。
大多数瓶颈似乎出现在外部源数据访问(源无法足够快地提取修订)或磁盘 I/O(fast-import 写入数据的速度与磁盘接收数据的速度一样快)方面。如果源数据存储在与目标 Git 仓库不同的驱动器上,导入将运行得更快(由于 I/O 争用较少)。
开发成本
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 仓库,如 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 小时)将通过“-0500”在 <tz> 中表示,而 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
-
始终使用当前时间和时区。文字
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
命令行选项或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 <alg> 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 签名。
此处 <alg> 指定用于此签名的哈希算法,可以是 sha1
或 sha256
。
注意
|
这是一个高度实验性的功能,数据流的格式将来可能会更改,不保证兼容性。 |
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
:Git 链接,对象的 SHA-1 引用另一个仓库中的提交。Git 链接只能通过 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 签名,因为前端无法(轻易地)访问通常构成此类签名的完整字节集。如果需要签名,请在 fast-import 内部使用 reset
创建轻量级标签,然后使用标准的 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
此处的 mark 命令是可选的,因为一些前端选择自行生成 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,开始一个新的,并保存所有当前分支引用、标签和标记。
'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 仓库可以通过 fast-import 在大约 3 小时内加载到 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
-
要求后端支持 *notemodify* (N) 子命令作为 *commit* 命令的一部分。不支持备注的 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 并导出标记表。这允许前端开发人员检查仓库状态并从崩溃点恢复导入。在崩溃期间,修改的分支和标签不会更新,因为导入未成功完成。分支和标签信息可以在崩溃报告中找到,如果需要更新,必须手动应用。
一个崩溃示例
$ 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 输出的打包文件并非最优,在实际使用场景中是不会遇到的。
打包文件优化
在打包一个 blob 时,fast-import 总是尝试与最后写入的 blob 进行增量化处理。除非前端特别安排,否则这可能不会是同一文件的先前版本,因此生成的增量不会是最小的。最终的打包文件将是压缩的,但并非最优的。
能够高效访问单个文件所有修订版本的前端(例如,读取 RCS/CVS ,v 文件)可以选择将该文件的所有修订版本作为一系列连续的 blob
命令提供。这使得 fast-import 能够将不同的文件修订版本彼此进行增量化处理,从而节省最终打包文件中的空间。标记可以用于在后续的一系列 commit
命令中识别单个文件修订版本。
fast-import 创建的打包文件不利于良好的磁盘访问模式。这是因为 fast-import 按照从标准输入接收数据的顺序写入数据,而 Git 通常在打包文件中组织数据,使得最新(当前尖端)数据出现在历史数据之前。Git 还会将提交聚类,通过更好的缓存局部性加速修订遍历。
因此,强烈建议用户在 fast-import 完成后使用 git
repack
-a
-d
命令重新打包仓库,以允许 Git 重新组织打包文件以实现更快的数据访问。如果 blob 增量并非最优(参见上文),那么添加 -f
选项来强制重新计算所有增量,可以显著减小最终打包文件的大小(小 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 开销分摊到接近于零。
每个对象
fast-import 在本次执行中为写入的每个对象维护一个内存中结构。在 32 位系统上,该结构为 32 字节;在 64 位系统上,该结构为 40 字节(由于指针大小更大)。表中的对象在 fast-import 终止之前不会被释放。在 32 位系统上导入 200 万个对象大约需要 64 MiB 的内存。
对象表实际上是一个以对象名称(唯一的 SHA-1)为键的哈希表。这种存储配置允许 fast-import 重用现有或已写入的对象,并避免向输出打包文件写入重复内容。在导入中,重复的 blob 令人惊讶地常见,通常是由于源中的分支合并。
每个分支
分支分为活动分支和非活动分支。这两类分支的内存使用量显著不同。
非活动分支存储在一个结构中,每个分支占用 96 或 120 字节(分别为 32 位或 64 位系统),加上分支名称的长度(通常小于 200 字节)。fast-import 可以轻松处理多达 10,000 个非活动分支,内存占用不到 2 MiB。
活动分支具有与非活动分支相同的开销,但还包含在该分支上最近修改过的每个树的副本。如果自该分支变为活动状态以来,子树 include
未被修改,其内容将不会加载到内存中;但如果自该分支变为活动状态以来,子树 src
已通过提交被修改,那么其内容将加载到内存中。
由于活动分支存储了关于该分支中包含的文件元数据,它们的内存存储大小会增长到相当可观的程度(参见下文)。
fast-import 会根据一个简单的最近最少使用算法自动将活动分支转换为非活动状态。LRU 链在每个 commit
命令上更新。可以通过命令行上的 --active-branches= 参数增加或减少活动分支的最大数量。
信号
向 SIGUSR1 信号发送到 git fast-import 进程可以提前结束当前打包文件,模拟一个 checkpoint
命令。不耐烦的操作员可以使用此功能来查看正在进行导入的对象和引用,代价是增加一些运行时间和更差的压缩效果。
配置
本节中以下所有内容均从 git-config[1] 文档中选择性地包含。内容与彼处相同:
- fastimport.unpackLimit
-
如果 git-fast-import[1] 导入的对象数量低于此限制,则这些对象将被解包成松散对象文件。然而,如果导入的对象数量等于或超过此限制,则打包将作为一个整体存储。从 fast-import 存储打包文件可以使导入操作更快完成,尤其是在慢速文件系统上。如果未设置,则使用
transfer.unpackLimit
的值。