git fast-import

优质
小牛编辑
122浏览
2023-12-01

名称

git-fast-import - 用于快速Git数据导入器的后端

概要

frontend | git fast-import [options]

描述

这个程序通常不是最终用户想要直接运行的。大多数最终用户都希望使用现有的前端程序之一,该前端程序解析特定类型的外部源,并将存储在其中的内容提供给它们git fast-import

快速导入从标准输入读取混合命令/数据流,并将一个或多个包文件直接写入当前存储库。当在标准输入接收到EOF时,快速导入会写出更新的分支和标记参考,并使用新导入的数据完全更新当前存储库。

快速导入后端本身可以导入到一个空的存储库(已经初始化git init的存储库)或增量更新现有的已填充存储库。是否从特定的外部源支持增量导入取决于正在使用的前端程序。

选项

--force

强制更新已修改的现有分支,即使这样做会导致提交丢失(因为新提交不包含旧提交)。

--quiet

禁用所有非致命输出,在成功时快速导入无声。该选项禁用--stats显示的输出。

--stats

显示有关fast-import创建的对象的基本统计信息,它们存储到的包文件以及在此运行期间通过快速导入使用的内存。显示此输出目前是默认值,但可以使用--quiet禁用。

前端选项

--cat-blob-fd=<fd>

写响应get-markcat-blob以及ls查询到文件描述符<FD>代替stdout。允许progress将最终用户的输出与其他输出分离。

--date-format=<fmt>

指定日期的前端将供应给中快速导入的类型authorcommittertagger命令。有关支持哪些格式及其语法的详细信息,请参阅下面的“日期格式”。

--done

如果done流尾没有命令,则会终止并报错。此选项对于检测导致前端在开始写入流之前终止的错误可能很有用。

标记文件的位置

--export-marks=<file>

完成后将内部标记表转储到<file>。标记每行写成一个:markid SHA-1。前端可以使用此文件在导入完成后验证导入,或跨增量运行保存标记表。由于<file>仅在检查点(或完成)时打开并截断,因此同样的路径也可以安全地分配给--import-marks。

--import-marks=<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目录。但是,其他进口商可能会使用不同的地点。

相对标记和非相关标记可以通过交织 - (无 - ) - 相对标记与 - (import | export)-marks =选项进行组合。

性能和压缩调优

--active-branches=<n>

一次保持活动的最大分支数量。有关详细信息,请参阅下面的“内存使用率” 缺省值是5。

--big-file-threshold=<n>

快速导入将尝试创建增量的最大大小,以字节表示。默认值为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>

每个输出包文件的最大大小。默认值是无限的。

fastimport.unpackLimit

见git-config [1]

性能

快速导入的设计允许它以最少的内存使用量和处理时间导入大型项目。假设前端能够跟上快速导入并为其提供持续不断的数据流,对于持续10年以上历史并且包含100,000个以上单独提交的项目,导入时间通常仅需1-2小时即可完成(相当适中) 〜$ 2,000美元)硬件。

大多数瓶颈似乎在外部源数据访问(源代码无法足够快地提取修订版本)或磁盘IO(快速导入写入与磁盘接收数据一样快)。如果源数据存储在与目标Git存储库不同的驱动器上(由于较少的IO争用),导入将运行得更快。

开发成本

一个典型的快速导入前端往往会用大约200行的Perl / Python / Ruby代码进行权衡。大多数开发者在几个小时内就能创建工作导入者,尽管这是他们第一次接触快速导入,有时甚至是Git。这是一个理想的情况,因为大多数转换工具都是丢弃(使用一次,永远不会回头)。

并行操作

git push或者git fetch,通过快速导入处理的导入可以安全地与并行git repack -a -dgit gc调用或任何其他Git操作(包括git prune快速导入从不使用的松散对象)一起运行。

快速导入不锁定它正在主动导入的分支或标签。导入之后,在其ref引用更新阶段,快速导入测试每个现有的分支引用,以验证更新是否为快速更新(存储在ref中的提交包含在要写入的提交的新历史记录中)。如果更新不是快进更新,则快速导入将跳过更新该参考文件,而是输出警告消息。快速导入将始终尝试更新所有分支引用,并且不会在第一次失败时停止。

可以使用--force强制更新分支,但建议仅在安静的存储库上使用分支更新。初始导入到一个空的存储库时,使用--force不是必需的。

技术讨论

快速导入跟踪记忆中的一组分支。通过commit在输入流上发送命令,可以在导入过程中的任何时刻创建或修改任何分支。这种设计允许前端程序同时处理无限数量的分支,按照源数据可用的顺序生成提交。它也大大简化了前端程序。

快速导入不会使用或更改当前的工作目录或其中的任何文件。(但它会更新当前的Git存储库,如引用的那样)GIT_DIR。因此,导入前端可以将工作目录用于自己的目的,例如从外部源提取文件修订版。工作目录的这种无知还允许快速导入运行非常快,因为在分支之间切换时不需要执行任何代价高昂的文件更新操作。

输入格式

除了原始文件数据(Git没有解释)之外,快速导入输入格式是基于文本(ASCII)的格式。这种基于文本的格式简化了前端程序的开发和调试,特别是在使用诸如Perl,Python或Ruby的高级语言时。

快速进口对其投入非常严格。当我们说下面SP意味着我们正好有一个空格。同样,LF表示一个(且只有一个)换行符和HT一个(并且只有一个)水平制表符。提供额外的空白字符会导致意想不到的结果,例如分支名称或文件名称中包含前导或尾随空格,或者在遇到意外输入时提前终止快速导入。

Stream Comments

为了帮助快速调试前端,import-ignore会忽略以#(ASCII pound / hash)开头并包含行结尾的行LF。注释行可能包含任何不包含LF的字节序列,因此可用于包含任何可能特定于前端的详细调试信息,并且在检查快速导入数据流时很有用。

日期格式

支持以下日期格式。前端应通过将格式名称传递给--date-format = <fmt>命令行选项来选择将用于此导入的格式。

raw

这是Git本地格式,并且是<time> SP <offutc>。如果未指定--date-format,它也是快速导入的默认格式。

事件的时间由<time>自UNIX纪元(1970年1月1日午夜,UTC)以来的秒数指定,并写为ASCII十进制整数。

本地偏移<offutc>量由UTC 指定为正值或负值。例如,EST(UTC时间后5小时)将以<tz>“-0500” 表示,而UTC为“+0000”。本地抵消不影响<time>; 它仅用作帮助格式化例程显示时间戳的建议。

如果源材料中的本地偏移量不可用,请使用“+0000”或最常用的本地偏移量。例如,很多组织都有一个CVS存储库,它只能被位于相同位置和时区的用户访问。在这种情况下,可以假定与UTC的合理偏移。

rfc2822格式不同,这种格式非常严格。格式的任何变化都会导致快速导入拒绝该值。

rfc2822

这是RFC 2822所描述的标准电子邮件格式。

示例值为“2月6日11:22:18 2007年-0500”。Git解析器是准确的,但在宽松的一面。这是git am应用从电子邮件收到的补丁时使用的解析器。

一些格式错误的字符串可能被接受为有效日期。在某些情况下,Git仍然可以从格式不正确的字符串中获取正确的日期。也有一些类型的错误的字符串,Git会解析错误,但仍然认为是有效的。严重格式错误的字符串将被拒绝。

与上述raw格式不同,包含在RFC 2822日期字符串中的时区/ UTC偏移量信息用于在存储之前将日期值调整为UTC。因此,重要的是这些信息尽可能准确。

如果源材料使用RFC 2822风格的日期,则前端应该让快速导入处理分析和转换(而不是尝试自行完成),因为Git分析器已经得到了广泛的测试。

raw如果源代码材料已经使用UNIX-epoch格式,可以通过指定格式给出日期,或者可以很容易地将格式转换为格式,前端应该更喜欢这种格式,因为在解析时没有歧义。

now

始终使用当前时间和时区。文字now必须始终提供<when>

这是一种玩具格式。该系统的当前时间和时区在通过快速导入创建时总是被复制到标识字符串中。没有办法指定不同的时间或时区。

提供这种特定的格式是因为它实现起来很短,对于想要立即创建新提交的进程可能很有用,而无需使用工作目录或git update-index

如果单独的authorcommitter命令以使用commit时间戳可能不匹配,因为系统时钟将被轮询两次(一次对每个命令)。确保作者和提交者身份信息具有相同时间戳的唯一方法是省略author(从而复制committer)或使用除now。以外的日期格式。

命令

fast-import接受几个命令来更新当前的存储库并控制当前的导入过程。稍后会对每条命令进行更详细的讨论(附带示例)。

commit

通过创建新的提交并更新分支以指向新创建的提交,创建新分支或更新现有分支。

tag

从现有的提交或分支中创建一个带注释的标签对象。轻量级标记不受此命令支持,因为它们不建议用于及时记录有意义的点。

reset

将现有分支(或新分支)重置为特定修订。必须使用此命令将分支更改为特定的修订版,而无需对其进行提交。

blob

将原始文件数据转换为blob,以供将来在commit命令中使用。该命令是可选的,不需要执行导入。

checkpoint

强制快速导入以关闭当前的包文件,生成其独特的SHA-1校验和和索引,并启动新的包文件。该命令是可选的,不需要执行导入。

progress

导致快速导入将整个线路回显到其自己的标准输出。该命令是可选的,不需要执行导入。

done

标记流的结束。除非done使用--done命令行选项或feature done命令请求功能,否则此命令是可选的。

get-mark

导致fast-import将标记对应的SHA-1打印到设置的文件描述符中--cat-blob-fd,或者stdout未指定。

cat-blob

导致fast-import将cat-file --batch格式打印到使用--cat-blob-fd或未指定的文件描述符stdout中。

ls

导致 fast-import 将描述目录条目的行以ls-tree格式打印到使用--cat-blob-fd或未指定的文件描述符stdout中。

feature

启用指定的功能。这要求快速导入支持指定的功能,如果不支持则中止。

option

指定OPTIONS下列出的任何不改变流语义以满足前端需求的选项。该命令是可选的,不需要执行导入。

commit

用新提交创建或更新分支,记录项目的逻辑更改。

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

其中<ref>是进行提交的分支的名称。通常分支名称以refs/heads/Git 作为前缀,因此导入CVS分支符号RELENG-1_0将用作refs/heads/RELENG-1_0<ref><ref>在Git中的值必须是有效的refname。由于LF在Git refname中无效,因此此处不支持引用或转义语法。

mark可以选择出现一个命令,请求快速导入以保存对新创建的提交的引用,以供将来前端使用(请参阅下面的格式)。前端非常常见的是标记他们创建的每个提交,从而允许从任何导入的提交创建未来的分支。

以下data命令committer必须提供提交消息(请参阅下面的data命令语法)。要导入一个空的提交消息,请使用长度为0的数据。提交消息是自由格式的,不被 Git 解释。目前它们必须以 UTF-8 编码,因为快速导入不允许指定其他编码。

零个或多个filemodifyfiledeletefilecopyfilerenamefiledeleteallnotemodify命令可以被包括到分支的内容创建的提交之前更新。这些命令可以以任何顺序提供。然而,建议一个filedeleteall命令优先于所有filemodifyfilecopyfilerenamenotemodify在相同的命令提交,作为filedeleteall擦拭干净分支(见下文)。

LF命令之后是可选的(它曾经是必需的)。

author

如果作者信息可能与提交者信息不同,则可以选择出现一条author命令。如果author省略,那么快速导入将自动使用提交者的信息作为提交的作者部分。请参阅下文中的字段说明author,因为它们与之相同committer

committer

committer命令表明是谁做出这个提交,以及何时提交。

<name>是人的显示名称(例如“ Com M itter ”),并且<email>是人的电子邮件地址(“cm@example.com”)。LT并且GT是文字小于(\ x3c)和大于(\ x3e)的符号。这些都需要从行中的其他字段分隔电子邮件地址。注意,<name><email>是自由形式,并且可以包含任何字节序列,不同之处LTGTLF<name>通常是 UTF-8 编码。

更改时间通过<when>使用由--date-format = <fmt> 命令行选项选择的日期格式指定。有关支持的一组格式及其语法,请参阅上面的“日期格式”。

from

from命令用于指定从该初始化分支的提交。这次修订将是新提交的第一个父类。在此提交中构建的树的状态将以from提交时的状态开始,并由此提交中的内容修改进行更改。

from在新分支的第一次提交中省略命令将导致快速导入来创建没有父类的提交。这往往只适用于项目的初始提交。如果前端在创建新分支时从头开始创建所有文件,merge则可以使用命令而不from是以空树开始提交。from通常需要省略现有分支上的命令,因为分支上的当前提交被自动假定为新提交的第一个父类。

由于LF在 Git refname 或 SHA-1 表达式中无效,因此在内部不支持引用或转义语法<commit-ish>

<commit-ish>是以下任何一项:

  • 已经在快速导入的内部分支表中的现有分支的名称。如果快速导入不知道名称,则将其视为 SHA-1 表达式。
  • 标记参考,标记号:<idnum>在哪里<idnum>。快速导入:用来表示标记引用的原因是该字符在Git分支名称中不合法。领先的:使得它很容易区分标志42(:42)和分支42(42refs/heads/42),或者是一个简单的 SHA-1,它恰好只包含了基数为10的数字。标记必须先声明(通过mark)才可以使用。
  • 完整的40字节或缩写的提交 SHA-1(十六进制)。
  • 任何有效的解析为提交的 Git SHA-1 表达式。有关详细信息,请参阅 gitrevisions [7] 中的“指定修订”。
  • 特殊的空 SHA-1(40个零)指定分支要被移除。

从当前分支值重新启动增量导入的特殊情况应写为:

        from refs/heads/branch^0

^0后缀是必需的,因为快速导入不允许一个分支,从自身做起,并在内存中创建from分支之前,即使从输入读取命令。添加^0将强制快速导入通过 Git 的修订解析库而不是其内部分支表来解析提交,从而加载分支的现有值。

merge

包含一个额外的父类提交。额外的父类链接不会改变在此提交时树状态的构建方式。如果from在创建新分支时省略该命令,则第一次merge提交将是当前提交的第一个祖先,并且分支将从没有文件开始。merge快速导入允许每次提交的命令数量不受限制,从而建立 n 路合并。

这里<commit-ish>是任何承诺规范表达式也被from接受(见上文)。

filemodify

包含在commit添加新文件或更改现有文件内容的命令中。该命令有两种不同的方式来指定文件的内容。

外部数据格式

文件的数据内容已由先前的blob命令提供。前端只需要连接它。

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

这里通常<dataref>必须是:<idnum>由先前blob命令设置的标记引用()或现有 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 链接只能由 SHA 或通过提交标记指定。它们用于实现子模块。
  • 040000:一个子目录。子目录只能通过 SHA 或通过设置树标记来指定--import-marks

两种格式<path>都是要添加的文件的完整路径(如果尚不存在)或修改(如果已经存在)。

<path>字符串必须使用 UNIX 风格的目录分隔符(正斜杠/),可能包含除了以外的任何字节LF,并且不得以双引号(")开头。

一个路径可以使用 C 风格的字符串引用; 这在所有情况下都被接受,并且如果文件名以双引号或包含开头则是强制性的LF。在 C 风格的引用中,完整名称应该用双引号括起来,并且任何LF反斜杠或双引号字符都必须用反斜杠(例如,"path/with\n, \\ and \" in it")在前面进行转义。

价值<path>必须是规范形式。这不是:

  • 包含一个空目录组件(例如foo//bar无效),
  • 以目录分隔符结束(例如foo/无效),
  • 以目录分隔符开始(例如/foo无效),
  • 包含特殊组件...(例如foo/./barfoo/../bar无效)。

树的根可以用空字符串表示<path>

建议<path>始终使用 UTF-8 编码。

filedelete

包含在commit删除文件的命令中或递归地从分支中删除整个目录。如果文件或目录删除使其父目录为空,则父目录也会自动删除。这会级联树直到达到第一个非空目录或根目录。

        'D' SP <path> LF

这里<path>是从分支中删除的文件或子目录的完整路径。请参阅filemodify上面的详细说明<path>

filecopy

递归地将现有文件或子目录复制到分支内的其他位置。现有的文件或目录必须存在。如果目标存在,它将被从源复制的内容完全替换。

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

这里第一个<path>是源位置,第二个<path>是目的地。有关可能的外观filemodify的详细说明,请参阅上文<path>。要使用包含 SP 的源路径,必须引用该路径。

一条filecopy命令立即生效。一旦将源位置复制到目标位置,将来应用于源位置的任何命令都不会影响副本的目标位置。

filerename

将现有文件或子目录重命名为分支中的其他位置。现有的文件或目录必须存在。如果目标存在,它将被源目录取代。

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

这里第一个<path>是源位置,第二个<path>是目的地。有关可能的外观filemodify的详细说明,请参阅上文<path>。要使用包含 SP 的源路径,必须引用该路径。

filerename命令立即生效。一旦源位置已被重命名为目标,任何应用于源位置的命令都将在那里创建新文件,而不会影响重命名的目标。

请注意,filerename与源位置filecopy后跟的filedelete是一样的。使用filerename时有一个轻微的性能优势,但优点非常小,因此永远不值得尝试将源资料中的删除/添加对转换为重命名以快速导入。提供filerename命令只是为了简化已经具有重命名信息的前端,并且不希望将filecopy分解为后面的filedelete

filedeleteall

包含在commit从分支中删除所有文件(以及所有目录)的命令中。该命令重置内部分支结构以使其中没有文件,从而允许前端从头开始添加所有有趣的文件。

        'deleteall' LF

如果前端不知道(或不在乎知道)分支上当前有哪些文件,则该命令非常有用,因此无法生成filedelete更新内容的正确命令。

发出一个filedeleteall后面紧跟着所需的filemodify命令来设置正确的内容将产生与只发送所需命令filemodifyfiledelete命令相同的结果。filedeleteall但是,这种方法可能需要快速导入,以便在每个活动分支中使用更多的内存(即使是大多数大型项目也少于1 MiB); 因此鼓励那些只能轻松获得提交的受影响路径的前端这样做。

notemodify

包含在commit <notes_ref>添加注释a <commit-ish>或更改此注释内容的新注释的命令中。它在内部与<commit-ish>路径上的 filemodify 100644 类似(可能拆分成子目录)。建议不要使用任何其他命令来写入<notes_ref>树,除非filedeleteall删除此树中的所有现有笔记。该命令有两种不同的方式来指定音符的内容。

外部数据格式

笔记的数据内容已由先前的blob命令提供。前端只需要将其连接到将被注释的提交。

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

<dataref>可以是:<idnum>由先前blob命令设置的标记引用(),也可以是现有 Git Blob 对象的完整40字节 SHA-1。

内联数据格式

笔记的数据内容尚未提供。前端想要提供它作为这个修改命令的一部分。

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

请参阅下面的data命令的详细说明。

在这两种格式<commit-ish>中,任何提交规范表达式也被接受from(参见上文)。

mark

安排快速导入以保存对当前对象的引用,允许前端在未来的时间点调用此对象,而无需知道其 SHA-1 。这里的当前对象是mark命令出现的对象创建命令。这可能是committagblob,但是commit是最常见的用法。

        'mark' SP ':' <idnum> LF

<idnum>前端分配给此标记的号码在哪里。该值<idnum>用 ASCII 十进制整数表示。值 0 保留,不能用作标记。只有大于或等于 1 的值才可以用作标记。

新标记会自动创建。只需<idnum>在另一个mark命令中重复使用相同的标记,就可以将现有的标记移动到另一个对象。

tag

创建一个引用特定提交的注释标签。要创建轻量级(未注释)标签,请参阅reset下面的命令。

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

其中<name>是要创建的标记的名称。

标记名称会自动用前缀refs/tags/时,存储在 Git 的,所以在导入 CVS 分支符号RELENG-1_0-FINAL将只使用RELENG-1_0-FINAL<name>,并快速导入会写相应的裁判作为refs/tags/RELENG-1_0-FINAL

<name>必须是 Git 中的有效 refname,因此可能包含正斜杠。由于LF在 Git refname 中无效,因此此处不支持引用或转义语法。

from命令与commit命令中的命令相同; 详情见上文。

tagger命令使用与之committer内相同的格式commit; 再次参见上面的细节。

以下data命令tagger必须提供带注释的标记消息(请参阅下面的data命令语法)。要导入空标签消息,请使用长度为0的数据。标记消息是自由格式的,不被 Git 解释。目前它们必须以 UTF-8 编码,因为快速导入不允许指定其他编码。

不支持在快速导入过程中从导入过程中签署带注释的标签。不建议尝试包含您自己的 PGP / GPG 签名,因为前端不能轻松访问通常进入此签名的完整字节集。如果需要签名,请使用快速导入功能创建轻量级标记reset,然后使用标准git tag过程在离线情况下创建这些标记的注释版本。

reset

创建(或重新创建)指定的分支,可以从特定修订开始。reset 命令允许前端from为现有分支发出新命令,或者从现有提交创建新分支而不创建新提交。

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

为的详细说明<ref><commit-ish>参见上述下commitfrom

LF命令之后是可选的(它曾经是必需的)。

reset命令也可用于创建轻量级(未注释)标签。例如:

reset refs/tags/938from :938

将创建refs/tags/938引用任何提交标记:938引用的轻量级标记。

blob

请求将一个文件修订版写入 packfile 。该修订与任何提交都没有关联; 这个连接必须在随后的commit命令中通过指定的标记引用 blob 来形成。

        'blob' LF
        mark?
        data

标记命令在这里是可选的,因为一些前端已经选择为 blob 自己生成 Git SHA-1 ,并直接提供给它commit。然而,这通常比它的价值更大,因为商标价格低廉,易于使用。

data

提供原始数据(用作 blob /文件内容,提交消息或注释标记消息)以快速导入。可以使用确切的字节数提供数据,也可以使用终止线来分隔数据。用于生产质量转换的真正前端应始终使用确切的字节计数格式,因为它更健壮,性能更好。分隔格式主要用于测试快速导入。

<raw>部分data命令中出现的注释行总是被视为数据主体的一部分,因此不会被快速导入忽略。这可以安全地导入任何可能以其开头的文件/消息内容#

确切的字节计数格式

前端必须指定数据的字节数。

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

<count>确切的字节数出现在哪里<raw>。值<count>用 ASCII 十进制整数表示。所述LF的任一侧<raw>不包含在<count>,并且将不被包括在导入的数据。

LF之后<raw>是可选的(它使用的需要),但建议。总是包含它使得调试快速导入流变得更容易,因为下一个命令总是从下一行的第0列开始,即使<raw>没有结束LF

Delimited format

分隔符字符串用于标记数据的结尾。快速导入将通过搜索分隔符来计算长度。这种格式主要用于测试,不建议用于真实数据。

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

<delim>选择的分隔符字符串在哪里。字符串<delim>不能出现在一行内<raw>,否则快速导入会认为数据比实际更早结束。LF立即尾随<raw>的一部分<raw>。这是分隔格式的限制之一,不可能提供没有LF作为其最后一个字节的数据块。

LF<delim> LF是可选的(它用于需要)。

checkpoint

强制快速导入以关闭当前 packfile,启动一个新文件,并保存所有当前分支引用,标记和标记。

        'checkpoint' LF
        LF?

请注意,当前包文件达到--max-pack-size 或4 GiB 时,快速导入会自动切换包文件,无论哪个限制较小。在自动打包文件切换期间,快速导入不会更新分支引用,标记或标记。

由于checkpoint需要大量的CPU时间和磁盘 IO(为了计算总体包 SHA-1 校验和,生成相应的索引文件并更新参考文件),单个checkpoint命令可以轻松完成几分钟。

前端可能会选择在非常大且长时间运行的导入期间发出检查点,或者当他们需要允许其他 Git 进程访问分支时。但是,考虑到一个30 GiB Subversion 版本库可以在大约3小时内通过快速导入加载到Git中,显式检查点可能不是必需的。

LF命令之后是可选的(它曾经是必需的)。

progress

当从输入流处理命令progress时,导致 fast-import 将未修改的整行打印到其标准输出通道(文件描述符1)。命令对当前导入或任何快速导入的内部状态都没有影响。

        'progress' SP <any> LF
        LF?

<any>命令的一部分可能包含任何不包含的字节序列LF。该LF命令后是可选的。呼叫者可能希望通过 sed 等工具处理输出,以删除线路的前端部分,例如:

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

checkpoint之后立即发出命令progress通知阅将读器何时完成checkpoint,并且它可以安全地访问快速更新的参考文献。

get-mark

导致 fast-import 将与标记对应的 SHA-1 打印到标准输出或先前以--cat-blob-fd参数排列的文件描述符。该命令对当前的导入没有影响; 其目的是检索稍后提交的 SHA-1 可能希望在其提交消息中引用的 SHA-1 。

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

命令可以在接受评论的流中的任何地方使用。特别是,get-mark命令可以在提交过程中使用,但不能在data命令中使用。

有关如何安全读取此输出的详细信息,请参阅下面的“对命令的响应”。

cat-blob

导致 fast-import 将一个 blob 打印到先前按照--cat-blob-fd参数排列的文件描述符中。该命令对当前的导入没有影响; 其主要目的是检索可能位于快速导入内存中但不能从目标存储库访问的 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

命令可以在接受评论的流中的任何地方使用。特别是,cat-blob命令可以在提交过程中使用,但不能在data命令中使用。

有关如何安全读取此输出的详细信息,请参阅下面的“对命令的响应”。

ls

在先前按--cat-blob-fd参数排列的文件描述符的路径上打印关于对象的信息。这允许从活动提交(with cat-blob)中打印 blob,或者复制之前提交中的blob或树以用于当前提交(with filemodify)。

ls命令可以在接受评论的流中的任何位置使用,包括提交的中间。

从活动提交中读取

这种形式只能用在一个中间commit。该路径在快速导入的活动提交中命名目录条目。在这种情况下必须引用路径。

        'ls' SP <path> LF

从命名树中读取

<dataref>可以是标记引用(:<idnum>),也可以是预先存在或等待写入的 Git 标记,提交或树对象的完整40字节 SHA-1。该路径相对于名为的树的顶层<dataref>

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

请参阅filemodify上面的详细说明<path>

输出使用与以下相同的格式git ls-tree <tree> -- <path>

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

<dataref>代表斑点、树,或在<路径> commit 对象,并且可以在稍后被用于get-markcat-blobfilemodify,或ls命令。

如果在路径上没有文件或子树,git fast-import则会报告

missing SP <path> LF

有关如何安全读取此输出的详细信息,请参阅下面的“对命令的响应”。

feature

要求快速导入支持指定的功能,或者如果不支持则中止。

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

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

日期格式 导出标记 相对标记 无相对标记约束

就像在命令行上--传递带有前导的相应命令行选项一样(请参阅上面的 OPTIONS)。

import-marks import-marks-if-exists

与--import-marks一样,除了两个方面:首先,每个流只能使用一个“功能 import-marks” 或“ feature import-marks-if-exists ”命令; 第二,--import-marks =或--import-marks-if-exists 命令行选项将覆盖流中的任何“特征”命令; 第三,“功能 import-marks-if-exists” 就像一个相应的命令行选项,悄无声息地跳过一个不存在的文件。

get-mark cat-blob ls

要求后端支撑get-markcat-blob或者ls分别命令。不支持指定命令的快速导入版本将退出并显示一条消息。这样可以提前清除导入错误并显示明确的消息,而不会在检测到不支持的命令之前浪费导入的早期时间。

notes

要求后端支持notemodify命令的(N)子commit命令。快速导入不支持笔记的版本将退出,并显示一条消息。

done

如果流没有done命令而结束,则返回错误。如果没有此功能,导致前端在流中便利点突然结束的错误可能无法检测到。例如,如果导入前端在中间操作中死掉,而在其下级 git 快速导入实例中未发出 SIGTERM 或 SIGKILL,则可能发生这种情况。

option

处理指定的选项,以便 git fast-import 以符合前端需求的方式运行。请注意,前端指定的选项将被用户可能指定的用于快速导入自身的任何选项覆盖。

    'option' SP <option> LF

<option>命令的一部分可能包含 OPTIONS 部分中列出的任何不改变导入语义的选项,没有前导--并且以相同的方式处理。

选项命令必须是输入中的第一个命令(不包括功能命令),以便在任何非选项命令发生错误后给出选项命令。

以下命令行选项更改导入语义,因此可能不会作为选项传递:

  • date-format
  • import-marks
  • export-marks
  • cat-blob-fd
  • force

done

如果done功能未被使用,则视为已读取 EOF 。这可以用来告诉快速导入提前完成。

如果--done命令行选项或feature done命令正在使用,则该done命令是强制性的,并标记流的结束。

对命令的响应

通过快速导入写入的新对象不可立即使用。大多数快速导入命令直到下一个检查点(或完成)才会有明显效果。前端可以发送命令来填充快速导入的输入管道,而不用担心它们的生效速度,通过简化调度来提高性能。

然而,对于某些前端,能够从当前存储库更新数据时(例如,当源材料按照要应用于先前导入的对象的修补程序描述对象时)读取数据很有用。这可以通过连接前端和通过双向管道快速导入来完成:

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

一个前端设置了这种方式可以使用progressget-markls,和cat-blob命令来读取从正在进行的进口信息。

为了避免死锁,例如前端必须完全消耗任何未决的输出progresslsget-mark,和cat-blob之前执行写入可能会阻止快速导入。

崩溃报告

如果快速导入提供了无效输入,它将以非零退出状态终止,并在其导入到的 Git 存储库顶层创建崩溃报告。崩溃报告包含内部快速导入状态的快照以及导致崩溃的最新命令。

所有最近的命令(包括流注释,文件更改和进度命令)都显示在崩溃报告中的命令历史记录中,但原始文件数据和提交消息从崩溃报告中排除。此排除可节省报告文件内的空间,并减少快速导入在执行过程中必须执行的缓冲量。

写入崩溃报告后,快速导入将关闭当前的包文件并导出标记表。这允许前端开发人员检查存储库状态并从其崩溃点恢复导入。由于导入未成功完成,修改的分支和标签在崩溃期间未更新。分支和标签信息可以在崩溃报告中找到,并且必须在需要更新时手动应用。

一个崩溃示例:

$ 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 <<EOFthis is my commit
EOF
M 644 inline .gitignore
data <<EOF.gitignore
EOF
M 777 inline bob
END_OF_INPUT
$ git fast-import <infatal: 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

技巧和窍门

从快速导入的各种用户收集了以下提示和技巧,并将其作为建议提供给您。

每个提交使用一个标记

在执行存储库转换时,请为每个提交(mark :<n>)使用一个唯一标记,并在命令行上提供--export-marks 选项。快速导入会转储一个文件,其中列出了每个标记以及与其对应的 Git 对象 SHA-1。如果前端可以将标记绑定回源存储库,那么通过将每个 Git 提交与相应的源修订版进行比较,可以很容易地验证导入的准确性和完整性。

来自诸如 Perforce 或 Subversion 之类的系统应该非常简单,因为快速导入标记也可以是 Perforce 变更集编号或 Subversion 修订版编号。

Freely Skip Around Branches

在进口期间,不要试图优化前端来一次坚持一个分支。虽然这样做对于快速导入可能会稍微快一些,但这往往会显着增加前端代码的复杂性。

内部快速导入的分支 LRU 往往表现得非常好,激活非活动分支的成本非常低,以至于在分支间跳动几乎不会影响导入性能。

Handling Renames

在导入重命名文件或目录时,只需删除旧名称并在相应的提交期间修改新名称即可。Git 会在事后执行重命名检测,而不是在提交期间显式检测。

使用标签修复分支

一些其他 SCM 系统允许用户从不同于提交/变更集的多个文件创建标签。或者创建标签,这些标签是存储库中可用文件的子集。

如果不进行至少一次“修复”文件以匹配标签内容的提交,那么将这些标签原样导入 Git 是不可能的。使用 fast-import reset命令将正常分支空间外的虚拟分支重置为标记的基本提交,然后提交一个或多个文件修复提交,最后标记虚拟分支。

例如,因为所有正常的分支都refs/heads/以标签修正分支的名字存储TAG_FIXUP。这样,导入器使用的 fixup 分支不可能与从源导入的实际分支产生命名空间冲突(该名称TAG_FIXUP不是refs/heads/TAG_FIXUP)。

在提交 fixup 时,考虑使用merge将提供文件修订的提交连接到 fixup 分支。这样做可以让工具git blame跟踪真实的提交历史记录并正确注释源文件。

在快速导入终止后,前端将需要rm .git/TAG_FIXUP去除虚拟分支。

立即导入,稍后重新打包

只要快速导入完成,Git 存储库就完全有效并可以使用。通常这只需要很短的时间,即使是相当大的项目(100,000+次提交)。

但是重新包装存储库对于提高数据本地化和访问性能是必需的。它也可能需要数小时才能完成大型项目(特别是如果使用-f和大型窗口参数)。由于重新包装可以安全地与读者和作者一起运行,因此在后台运行重新包装并在完成时让它完成。没有理由等待探索你的新 Git 项目!

如果您选择等待重新包装,在重新包装完成之前不要尝试运行基准测试或性能测试。快速导入输出次优包装文件,这些包装文件在实际使用情况下根本不会出现。

重新包装历史数据

如果您要重新包装非常旧的导入数据(例如比去年早),请考虑花费一些额外的 CPU 时间并在运行时提供--window = 50(或更高)git repack。这将花费更长时间,但也会产生一个较小的 packfile。您只需花费一次工作量,而使用您项目的每个人都将受益于较小的存储库。

包含一些进度信息

每隔一段时间你的前端都会发出一条progress消息来快速导入。这些消息的内容完全是自由格式,因此每次当前提交日期进入下个月时,一个建议就是输出当前的月份和年份。知道有多少数据流已被处理,您的用户会感觉更好。

Packfile优化

当快速打包 blob 时,import 总是试图对最后一个 blob 进行分层。除非前端特别安排,否则这可能不会是同一文件的先前版本,因此生成的增量不会尽可能小。生成的 packfile 将被压缩,但不会是最佳的。

有效访问单个文件的所有修订(例如读取 RCS / CVS,v 文件)的前端可以选择将该文件的所有修订作为一系列连续blob命令提供。这允许快速导入将不同的文件修订彼此分开,从而节省最终包文件中的空间。标记可用于稍后在一系列commit命令中识别单个文件修订版。

通过快速导入创建的包文件不会鼓励良好的磁盘访问模式。这是由于快速导入将数据按标准输入接收的顺序写入数据,而 Git 通常会在数据包文件中组织数据以使最新(当前提示)数据出现在历史数据之前。Git 还将提交进行集群,通过更好的缓存局部性加快修订遍历。

出于这个原因,强烈建议用户在快速导入完成后使用git repack -a -d重新打包存储库,以便 Git 能够重新组织文件包以加快数据访问速度。如果 blob deltas 不理想(参见上文),那么添加-f选项以强制所有delta的重新计算可以显着减少最终的 packfil e 大小(小30-50%可能非常典型)。

内存利用率

有许多因素会影响快速导入执行导入所需的内存量。像核心 Git 的关键部分一样,快速导入使用自己的内存分配器来分摊与 malloc 相关的任何开销。在实践中,由于使用大块分配,快速导入倾向于将任何 malloc 开销分摊到0。

每个对象

快速导入为在此执行中写入的每个对象维护一个内存中结构。在32位系统上,结构为32字节,在64位系统上,结构为40字节(由于指针大小较大)。除非快速导入终止,否则表中的对象不会解除分配。在32位系统上导入200万个对象需要大约64 MiB 的内存。

对象表实际上是一个在对象名称(唯一的 SHA-1)上键入的散列表。此存储配置允许快速导入重用现有或已写入的对象,并避免将重复项写入输出包文件。重复的斑点在导入中非常常见,通常是由于源中的分支合并。

每个标记

标记存储在稀疏数组中,每个标记使用1个指针(4个字节或8个字节,取决于指针大小)。虽然数组很稀疏,但前端仍强烈建议使用1到 n 之间的标记,其中 n 是此导入所需的标记总数。

每个分支

分支被分类为活动和非活动。这两个类的内存使用情况明显不同。

非活动分支存储在使用96或120个字节(分别为32位或64位系统)的结构中,以及每个分支的分支名称长度(通常小于200字节)。快速导入可轻松处理 2M 以下内存中多达10,000个不活动的分支。

活动分支与非活动分支具有相同的开销,但也包含该分支上最近修改的每个树的副本。如果子树include自分支变为活动状态以来未被修改,则其内容不会被加载到内存中,但如果子树src由于分支变为活动状态而被修改了,则其内容将被加载到内存中。

由于活动分支存储有关该分支中包含的文件的元数据,因此其内存中的存储容量可能会增长到相当大的规模(请参见下文)。

基于简单的最近最少使用的算法,快速导入会自动将活动分支移至非活动状态。LRU链在每个commit命令上更新。使用 --active-branches = 可以在命令行上增加或减少活动分支的最大数量。

每个活动树

树(又名目录)在其条目所需内存的顶部只使用12个字节的内存(请参阅下面的“每个活动文件”)。一棵树的成本几乎为零,因为它的开销分摊在单个文件条目上。

每个活动文件条目

Files (and pointers to subtrees) within active trees require 52 or 64 bytes (32/64 bit platforms) per entry. To conserve space, file and tree names are pooled in a common string table, allowing the filename “Makefile” to use just 16 bytes (after including the string header overhead) no matter how many times it occurs within the project.

活动分支 LRU 与文件名字符串池和子树的延迟加载结合使用,可以在非常有限的内存占用(每个活动分支小于2.7 MiB)的情况下,快速导入以有效导入2,000+个分支和45,114+个文件的项目。

信号

向进程发送 SIGUSR1 可以git fast-import提前结束当前的 packfile,模拟一条checkpoint命令。不耐烦的操作员可以使用此工具来查看正在进行的导入中的对象和引用,但需要花费一些额外的运行时间和更差的压缩。