设置和配置
获取和创建项目
基本快照
分支和合并
共享和更新项目
检查和比较
补丁
调试
外部系统
服务器管理
指南
管理
底层命令
- 2.45.1 → 2.49.0 无更改
-
2.45.0
2024-04-29
- 2.44.1 → 2.44.3 无更改
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.6 无更改
-
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 从 from <file> 中使用的值重写为 to <file> 中使用的值。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 和树 deltification 的最大 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 并为其提供恒定的数据流,则在相当适中的(约 2,000 美元)硬件上,通常只需 1-2 小时即可完成包含 10 多年历史和包含 100,000 多个单独提交的项目的导入。
大多数瓶颈似乎在于外部源数据访问(源无法足够快地提取修订)或磁盘 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 纪元格式,可以被诱导以该格式给出日期,或者其格式易于转换为该格式,则前端应首选
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
命令行选项或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 ('encoding' SP <encoding>)? 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
命令。如果省略 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> 命令行选项选择的日期格式。有关支持的格式及其语法,请参见上面的“日期格式”。
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] 中的“指定修订”。
-
特殊的 null 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
设置的标记引用。 - 内联数据格式
-
尚未提供文件的数据内容。前端希望将其作为此 modify 命令的一部分提供。
'M' SP <mode> SP 'inline' SP <path> LF data
有关
data
命令的详细说明,请参见下文。
在这两种格式中,<mode>
都是文件条目的类型,以八进制指定。Git 仅支持以下模式
-
100644
或644
:一个普通(不可执行)文件。大多数项目中的大多数文件都使用此模式。如有疑问,这就是您想要的。 -
100755
或755
:一个普通但可执行的文件。 -
120000
:一个符号链接,文件的内容将是链接目标。 -
160000
:一个 gitlink,对象的 SHA-1 指的是另一个存储库中的提交。Git 链接只能通过 SHA 或通过提交标记来指定。它们用于实现子模块。 -
040000
:一个子目录。子目录只能通过 SHA 或通过使用--import-marks
设置的树标记来指定。
在这两种格式中,<path>
都是要添加(如果尚不存在)或修改(如果已存在)的文件的完整路径。
<path>
可以写为未加引号的字节或 C 风格的带引号的字符串。
当 <path>
不以双引号 ("
) 开头时,它是一个未加引号的字符串,并被解析为不带任何转义序列的字面字节。但是,如果文件名包含 LF
或以双引号开头,则不能将其表示为未加引号的字符串,并且必须加引号。此外,如果源 <path>
在 filecopy
或 filerename
中包含 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 将把相应的 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
将创建轻量级标签 refs/tags/938
,该标签引用 mark :938
引用的任何提交。
blob
请求将一个文件修订写入到 packfile 中。 此修订未连接到任何提交; 此连接必须在后续的 commit
命令中通过引用分配的标记来形成。
'blob' LF mark? original-oid? data
此处的 mark 命令是可选的,因为某些前端已选择自行生成 blob 的 Git SHA-1,并将其直接提供给 commit
。 但是,这通常比值得做的工作更多,因为标记的存储成本很低并且易于使用。
data
将原始数据(用于 blob/文件内容、提交消息或带注释的标签消息)提供给 fast-import。 可以使用精确的字节计数或以终止行分隔来提供数据。 旨在用于生产质量转换的真实前端应始终使用精确的字节计数格式,因为它更可靠且性能更好。 分隔格式主要用于测试 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 进程访问分支时,发出检查点。 但是,鉴于可以通过 fast-import 在大约 3 小时内将 30 GiB 的 Subversion 存储库加载到 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、树或提交对象,并且可以在以后的 *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 部分中列出的任何不更改导入语义的选项,而无需前导 --
,并且以相同的方式处理。
Option 命令必须是输入中的第一个命令(不包括 feature 命令),在任何非 option 命令之后给出 option 命令都是错误的。
以下命令行选项会更改导入语义,因此不能作为 option 传递
-
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
)。
在提交 fixup 时,考虑使用 merge
将提供文件修订版本的提交连接到 fixup 分支。这样做可以使诸如 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 中组织数据,以使最新的(当前 tip)数据出现在历史数据之前。Git 还将提交聚集在一起,通过更好的缓存局部性来加速修订遍历。
因此,强烈建议用户在 fast-import 完成后使用 git repack -a -d
重打包仓库,以便 Git 可以重新组织 packfile 以实现更快的数据访问。如果 blob 增量不是最优的(见上文),那么添加 -f
选项以强制重新计算所有增量也可以显著减少最终 packfile 的大小(通常可以小 30-50%)。
除了运行 git repack
之外,你还可以运行 git gc --aggressive
,它还将在导入后优化其他内容(例如,打包松散的 refs)。正如 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] 导入的对象数量低于此限制,则这些对象将解包到松散对象文件中。但是,如果导入对象的数量等于或超过此限制,则该包将存储为一个包。存储来自 fast-import 的包可以使导入操作完成得更快,尤其是在慢速文件系统上。如果未设置,则改为使用
transfer.unpackLimit
的值。
GIT
属于 git[1] 套件