git-fast-import

原文: https://git-scm.com/docs/git-fast-import

名称

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

概要

  1. frontend | git fast-import [<options>]

描述

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

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

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

OPTIONS

  1. --force

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

  1. --quiet

禁用—stats显示的输出,快速导入通常在成功时保持静默。但是,如果导入流具有旨在显示用户输出的指令(例如progress指令),则仍将显示相应的消息。

  1. --stats

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

前端的选项

  1. --cat-blob-fd=<fd>

将对get-markcat-blobls查询的响应写入文件描述符< fd>而不是stdout。允许最终用户的progress输出与其他输出分开。

  1. --date-format=<fmt>

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

  1. --done

如果流末尾没有done命令,则终止并出错。此选项可用于检测导致前端在开始编写流之前终止的错误。

标记文件的位置

  1. --export-marks=<file>

将内部标记表转储到< file>完成后。标记每行写为:markid SHA-1。前端可以使用此文件在完成导入后验证导入,或者在增量运行中保存标记表。作为< file>仅在检查点(或完成)处打开和截断,同样的路径也可以安全地给予—import-marks。

  1. --import-marks=<file>

在处理任何输入之前,请加载< file>中指定的标记。输入文件必须存在,必须是可读的,并且必须使用与—export-marks生成的格式相同的格式。可以提供多个选项来导入多组标记。如果标记定义为不同的值,则最后一个文件获胜。

  1. --import-marks-if-exists=<file>

像—import-marks但不是错误输出,如果文件不存在,则以静默方式跳过该文件。

  1. --[no-]relative-marks

指定—relative-marks后,使用—import-marks =和—export-marks =指定的路径相对于当前存储库中的内部目录。在git-fast-import中,这意味着路径相对于.git / info / fast-import目录。但是,其他进口商可能会使用其他位置。

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

性能和压缩调整

  1. --active-branches=<n>

一次保持活动的最大分支数。有关详细信息,请参阅下面的“内存使默认值为5。

  1. --big-file-threshold=<n>

快速导入将尝试创建增量的blob的最大大小,以字节为单位表示。默认值为512米(512 MiB)。一些进口商可能希望在具有受限内存的系统上降低此值。

  1. --depth=<n>

最大增量深度,用于blob和树木划分。默认值为50。

  1. --export-pack-edges=<file>

创建包文件后,将一行数据打印到< file>列出packfile的文件名以及写入该packfile的每个分支上的最后一次提交。导入总对象集超过4 GiB packfile限制的项目后,此信息可能很有用,因为这些提交可以在调用 git pack-objects 时用作边缘点。

  1. --max-pack-size=<n>

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

  1. fastimport.unpackLimit

git-config [1]

性能

快速导入的设计允许它以最小的内存使用量和处理时间导入大型项目。假设前端能够跟上快速导入并为其提供恒定的数据流,那么拥有10年以上历史且包含100,000多个单独提交的项目的导入时间通常只需1-2小时即可完成( 〜$ 2,000 USD)硬件。

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

发展成本

快速导入的典型前端往往占据大约200行Perl / Python / Ruby代码。大多数开发人员能够在短短几个小时内创建工作进口商,即使这是他们第一次快速导入,有时甚至是Git。这是一个理想的情况,因为大多数转换工具都是丢弃的(使用一次,永不回头)。

并行操作

git pushgit fetch 一样,快速导入处理的导入可以安全地与并行git repack -a -dgit gc调用或任何其他Git操作(包括)一起运行git prune ,因为松散的对象永远不会被快速导入使用)。

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

可以使用—force强制分支更新,但建议仅在其他安静的存储库上使用它。初始导入空存储库不需要使用—force。

技术讨论

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

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

输入格式

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

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

流评论

为了帮助调试前端,快速导入忽略以#(ASCII磅/散列)开头直到并包括以LF结束的行的任何行。注释行可以包含不包含LF的任何字节序列,因此可以用于包括可能特定于前端的任何详细调试信息,并且在检查快速导入数据流时非常有用。

日期格式

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

  1. raw

这是Git原生格式,是&lt;time&gt; SP &lt;offutc&gt;。如果未指定—date-format,它也是快速导入的默认格式。

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

本地偏移由&lt;offutc&gt;指定为UTC的正偏移或负偏移。例如,EST(比UTC晚5小时)将在&lt;tz&gt;中用“-0500”表示,而UTC是“+0000”。局部偏移不会影响&lt;time&gt;;它仅用作帮助格式化例程显示时间戳的建议。

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

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

  1. rfc2822

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

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

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

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

如果源材料使用RFC 2822样式日期,前端应该让快速导入处理解析和转换(而不是尝试自己做),因为Git解析器已在野外进行了很好的测试。

如果源材料已经使用UNIX-epoch格式,前端应该更喜欢raw格式,可以通过哄骗来提供该格式的日期,或者其格式可以轻松转换为格式,因为解析时没有歧义。

  1. now

始终使用当前时间和时区。必须始终为&lt;when&gt;提供文字now

这是一种玩具形式。此系统的当前时间和时区始终在通过快速导入创建时复制到标识字符串中。无法指定不同的时间或时区。

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

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

命令

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

  1. commit

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

  1. tag

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

  1. reset

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

  1. blob

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

  1. checkpoint

强制快速导入以关闭当前packfile,生成其唯一的SHA-1校验和和索引,并启动新的packfile。此命令是可选的,不需要执行导入。

  1. progress

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

  1. done

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

  1. get-mark

导致快速导入将对应于标记的SHA-1打印到使用--cat-blob-fd设置的文件描述符,或者如果未指定则打印stdout

  1. cat-blob

导致快速导入将 cat-file —batch 格式的blob打印到使用--cat-blob-fdstdout设置的文件描述符(如果未指定)。

  1. ls

导致快速导入将以 ls-tree 格式描述目录条目的行打印到使用--cat-blob-fdstdout设置的文件描述符(如果未指定)。

  1. feature

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

  1. option

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

commit

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

  1. 'commit' SP <ref> LF
  2. mark?
  3. original-oid?
  4. ('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
  5. 'committer' (SP <name>)? SP LT <email> GT SP <when> LF
  6. data
  7. ('from' SP <commit-ish> LF)?
  8. ('merge' SP <commit-ish> LF)?
  9. (filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
  10. LF?

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

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

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

可以包括零个或多个filemodifyfiledeletefilecopyfilerenamefiledeleteallnotemodify命令以在创建提交之前更新分支的内容。可以按任何顺序提供这些命令。但是,建议filemodify命令在同一次提交中的所有filemodifyfilecopyfilerenamenotemodify命令之前,因为filedeleteall擦除分支清除(见下文)。

命令后的LF是可选的(以前是必需的)。

author

如果作者信息可能与提交者信息不同,则可以选择显示author命令。如果省略author,则fast-import将自动使用提交者作者部分的提交者信息。有关author中字段的说明,请参见下文,因为它们与committer相同。

committer

committer命令指示谁进行了此提交,以及何时进行此提交。

这里&lt;name&gt;是此人的显示名称(例如“Com M Itter”),&lt;email&gt;是该人的电子邮件地址(“cm@example.com”)。 LTGT是文字小于(\ x3c)和大于(\ x3e)的符号。这些是从行中的其他字段分隔电子邮件地址所必需的。注意&lt;name&gt;&lt;email&gt;是自由形式的,可以包含任何字节序列,LTGTLF除外。 &lt;name&gt;通常是UTF-8编码的。

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

from

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

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

由于LF在Git refname或SHA-1表达式中无效,因此&lt;commit-ish&gt;中不支持引用或转义语法。

这里&lt;commit-ish&gt;是以下任何一种:

  • 已存在于fast-import的内部分支表中的现有分支的名称。如果快速导入不知道名称,则将其视为SHA-1表达式。

  • 标记参考:&lt;idnum&gt;,其中&lt;idnum&gt;是标记号。

    快速导入使用:表示标记引用的原因是此字符在Git分支名称中不合法。前导:可以很容易地区分标记42(:42)和分支42(42refs/heads/42),或简化的SHA-1,它恰好只包含10位数字。

    必须先声明标记(通过mark)才能使用它们。

  • 完整的40字节或缩写提交SHA-1(十六进制)。

  • 任何解析为提交的有效Git SHA-1表达式。有关详细信息,请参阅 gitrevisions [7] 中的“指定修订”。

  • 特殊的空SHA-1(40个零)指定要删除分支。

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

  1. from refs/heads/branch^0

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

merge

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

这里&lt;commit-ish&gt;from也接受的任何提交规范表达式(见上文)。

filemodify

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

  1. External data format

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

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

这里通常&lt;dataref&gt;必须是先前blob命令设置的标记引用(:&lt;idnum&gt;),或者是现有Git blob对象的完整40字节SHA-1。如果&lt;mode&gt;040000``,则<dataref>必须是现有Git树对象的完整40字节SHA-1或使用—import-marks`设置的标记引用。

  1. Inline data format

尚未提供该文件的数据内容。前端想要将其作为此修改命令的一部分提供。

  1. 'M' SP <mode> SP 'inline' SP <path> LF
  2. data

有关data命令的详细说明,请参见下文。

在两种格式中,&lt;mode&gt;是以八进制指定的文件条目类型。 Git仅支持以下模式:

  • 100644644:普通(不可执行)文件。大多数项目中的大多数文件都使用此模式。如果有疑问,这就是你想要的。

  • 100755755:正常但可执行的文件。

  • 120000:符号链接,文件内容将是链接目标。

  • 160000:gitlink,对象的SHA-1引用另一个存储库中的提交。 Git链接只能由SHA或提交标记指定。它们用于实现子模块。

  • 040000:一个子目录。子目录只能由SHA或通过--import-marks设置的树标记指定。

在两种格式中,&lt;path&gt;是要添加的文件的完整路径(如果尚未存在)或已修改(如果已存在)。

&lt;path&gt;字符串必须使用UNIX样式的目录分隔符(正斜杠/),可以包含LF以外的任何字节,并且不能以双引号(")开头。

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

&lt;path&gt;的值必须是规范形式。那不是:

  • 包含一个空目录组件(例如foo//bar无效),

  • 以目录分隔符结束(例如foo/无效),

  • 从目录分隔符开始(例如/foo无效),

  • 包含特殊组件...(例如foo/./barfoo/../bar无效)。

树的根可以用空字符串表示为&lt;path&gt;

建议始终使用UTF-8对&lt;path&gt;进行编码。

filedelete

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

  1. 'D' SP <path> LF

这里&lt;path&gt;是要从分支中删除的文件或子目录的完整路径。有关&lt;path&gt;的详细说明,请参见上面的filemodify

filecopy

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

  1. 'C' SP <path> SP <path> LF

这里第一个&lt;path&gt;是源位置,第二个&lt;path&gt;是目的地。有关&lt;path&gt;的详细描述,请参见上面的filemodify。要使用包含SP的源路径,必须引用该路径。

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

filerename

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

  1. 'R' SP <path> SP <path> LF

这里第一个&lt;path&gt;是源位置,第二个&lt;path&gt;是目的地。有关&lt;path&gt;的详细描述,请参见上面的filemodify。要使用包含SP的源路径,必须引用该路径。

filerename命令立即生效。将源位置重命名为目标后,应用于源位置的任何将来命令都将在其中创建新文件,而不会影响重命名的目标。

请注意,filerenamefilecopy后跟源位置的filedelete相同。使用filerename有一个轻微的性能优势,但优势是如此之小,以至于永远不值得尝试将源材料中的删除/添加对转换为重命名以进行快速导入。提供此filerename命令只是为了简化已经具有重命名信息的前端,并且不希望将其分解为filecopy后跟filedelete

filedeleteall

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

  1. 'deleteall' LF

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

发出filedeleteall后跟所需的filemodify命令来设置正确的内容将产生与仅发送所需的filemodifyfiledelete命令相同的结果。然而,filedeleteall方法可能需要快速导入,以便为每个活动分支使用稍多的内存(即使是大多数大型项目也不到1 MiB);鼓励这样做的前端只能轻松获取提交的受影响路径。

notemodify

包含在commit &lt;notes_ref&gt;命令中,用于添加注释&lt;commit-ish&gt;的新注释或更改此注释内容。在内部,它类似于&lt;commit-ish&gt;路径上的filemodify 100644(可能拆分为子目录)。除了filedeleteall之外,不建议使用任何其他命令写入&lt;notes_ref&gt;树以删除此树中的所有现有注释。此命令有两种不同的方法来指定注释的内容。

  1. External data format

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

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

这里&lt;dataref&gt;可以是先前blob命令设置的标记引用(:&lt;idnum&gt;),也可以是现有Git blob对象的完整40字节SHA-1。

  1. Inline data format

该笔记的数据内容尚未提供。前端想要将其作为此修改命令的一部分提供。

  1. 'N' SP 'inline' SP <commit-ish> LF
  2. data

有关data命令的详细说明,请参见下文。

在两种格式中,&lt;commit-ish&gt;from也接受的任何提交规范表达式(见上文)。

mark

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

  1. 'mark' SP ':' <idnum> LF

其中&lt;idnum&gt;是前端指定给该标记的数字。 &lt;idnum&gt;的值表示为ASCII十进制整数。值0保留,不能用作标记。只有大于或等于1的值才可用作标记。

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

original-oid

提供原始源代码管理系统中对象的名称。快速导入将简单地忽略该指令,但是在进行快速导入之前对进行操作和修改流的过滤进程可能会使用此信息

  1. 'original-oid' SP <object-identifier> LF

其中&lt;object-identifer&gt;是任何不包含LF的字符串。

tag

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

  1. 'tag' SP <name> LF
  2. 'from' SP <commit-ish> LF
  3. original-oid?
  4. 'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
  5. data

其中&lt;name&gt;是要创建的标记的名称。

当存储在Git中时,标签名称会自动以refs/tags/为前缀,因此导入CVS分支符号RELENG-1_0-FINAL将仅使用RELENG-1_0-FINAL作为&lt;name&gt;,快速导入会将相应的ref写为refs/tags/RELENG-1_0-FINAL

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

from命令与commit命令相同;见上文了解详情。

tagger命令使用与commitcommitter相同的格式;再看上面的细节。

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

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

reset

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

  1. 'reset' SP <ref> LF
  2. ('from' SP <commit-ish> LF)?
  3. LF?

有关&lt;ref&gt;&lt;commit-ish&gt;的详细说明,请参见上文commitfrom

命令后的LF是可选的(以前是必需的)。

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

  1. reset refs/tags/938
  2. from :938

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

blob

请求将一个文件修订版写入packfile。修订与任何提交无关;必须通过指定标记引用blob,在后续commit命令中形成此连接。

  1. 'blob' LF
  2. mark?
  3. original-oid?
  4. data

mark命令在这里是可选的,因为一些前端选择为它们自己生成blob的Git SHA-1,并直接将其提供给commit。然而,这通常比它的价值更多,因为标记的存储成本低且易于使用。

data

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

出现在data命令的&lt;raw&gt;部分中的注释行始终被视为数据主体的一部分,因此永远不会被快速导入忽略。这样可以安全地导入任何行可能以#开头的文件/消息内容。

  1. Exact byte count format

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

  1. 'data' SP <count> LF
  2. <raw> LF?

其中&lt;count&gt;&lt;raw&gt;中出现的确切字节数。 &lt;count&gt;的值表示为ASCII十进制整数。 &lt;raw&gt;两侧的LF不包含在&lt;count&gt;中,不会包含在导入的数据中。

&lt;raw&gt;之后的LF是可选的(以前是必需的),但建议使用。始终包含它会使调试快速导入流更容易,因为下一个命令总是从下一行的第0列开始,即使&lt;raw&gt;没有以LF结束。

  1. Delimited format

分隔符字符串用于标记数据的结尾。 fast-import将通过搜索分隔符来计算长度。此格式主要用于测试,不建议用于实际数据。

  1. 'data' SP '<<' <delim> LF
  2. <raw> LF
  3. <delim> LF
  4. LF?

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

&lt;delim&gt; LF之后的LF是可选的(曾经是必需的)。

checkpoint

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

  1. 'checkpoint' LF
  2. LF?

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

由于checkpoint可能需要大量的CPU时间和磁盘IO(要计算整个包SHA-1校验和,生成相应的索引文件,并更新refs),单个checkpoint可能需要几分钟命令完成。

前端可能会选择在极大且长时间运行的导入期间发出检查点,或者当他们需要允许另一个Git进程访问分支时。然而,鉴于可以通过快速导入在大约3小时内将30 GiB Subversion存储库加载到Git中,可能不需要显式检查点。

命令后的LF是可选的(以前是必需的)。

progress

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

  1. 'progress' SP <any> LF
  2. LF?

命令的&lt;any&gt;部分可以包含不包含LF的任何字节序列。命令后的LF是可选的。调用者可能希望通过诸如sed之类的工具处理输出以删除行的前导部分,例如:

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

checkpoint之后立即放置progress命令将在checkpoint完成时通知读者,并且可以安全地访问快速导入更新的参考。

get-mark

导致快速导入将对应于标记的SHA-1打印到stdout或先前使用--cat-blob-fd参数排列的文件描述符。否则该命令对当前导入没有影响;它的目的是检索稍后提交可能要在其提交消息中引用的SHA-1。

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

此命令可以在流中接受注释的任何位置使用。特别是,get-mark命令可以在提交过程中使用,但不能在data命令的中间使用。

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

cat-blob

导致快速导入将blob打印到先前使用--cat-blob-fd参数排列的文件描述符。否则该命令对当前导入没有影响;其主要目的是检索可能位于快速导入内存但无法从目标存储库访问的blob。

  1. 'cat-blob' SP <dataref> LF

&lt;dataref&gt;可以是先前设置的标记参考(:&lt;idnum&gt;),也可以是预先存在或准备写入的Git blob的完整40字节SHA-1。

输出使用与git cat-file --batch相同的格式:

  1. <sha1> SP 'blob' SP <size> LF
  2. <contents> LF

此命令可以在流中接受注释的任何位置使用。特别是,cat-blob命令可以在提交过程中使用,但不能在data命令的中间使用。

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

ls

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

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

  1. Reading from the active commit

此表单只能在commit的中间使用。该路径在fast-import的活动提交中命名目录条目。在这种情况下必须引用该路径。

  1. 'ls' SP <path> LF
  1. Reading from a named tree

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

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

有关&lt;path&gt;的详细说明,请参见上面的filemodify

输出使用与git ls-tree &lt;tree&gt; -- &lt;path&gt;相同的格式:

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

< dataref>表示< path>处的blob,树或提交对象并且可以在以后的 get-markcat-blobfilemodifyls 命令中使用。

如果该路径中没有文件或子树, git fast-import 将改为报告

  1. missing SP <path> LF

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

feature

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

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

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

  1. date-format
  1. export-marks
  1. relative-marks
  1. no-relative-marks
  1. force

好像在命令行上传递了带有前导--的相应命令行选项(参见上面的OPTIONS)。

  1. import-marks
  1. import-marks-if-exists

像—import-marks一样,除了两个方面:首先,每个流只允许一个“feature import-marks”或“feature import-marks-if-exists”命令;第二, - import-marks =或—import-marks-if-exists命令行选项会覆盖流中的任何这些“功能”命令;第三,“功能import-marks-if-exists”就像相应的命令行选项一样,会以静默方式跳过不存在的文件。

  1. get-mark
  1. cat-blob
  1. ls

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

  1. notes

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

  1. done

如果流没有完成命令结束,则输出错误。如果没有此功能,导致前端突然在流中方便的位置结束的错误可能无法检测到。例如,如果导入前端在中间操作中死亡而不在其下级git快速导入实例中发出SIGTERM或SIGKILL,则可能发生这种情况。

option

处理指定的选项,以便git fast-import以适合前端需要的方式运行。请注意,前端指定的选项会被用户指定用于git快速导入的任何选项覆盖。

  1. 'option' SP <option> LF

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

选项命令必须是输入上的第一个命令(不计算功能命令),以便在任何非选项命令出错后给出选项命令。

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

  • 日期格式

  • 进口标志

  • 出口标志

  • 猫BLOB-FD

done

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

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

对命令的回应

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

但是,对于某些前端,能够在更新时从当前存储库中读回数据非常有用(例如,当源材料根据要应用于先前导入的对象的补丁描述对象时)。这可以通过连接前端和通过双向管道快速导入来实现:

  1. mkfifo fast-import-output
  2. frontend <fast-import-output |
  3. git fast-import >fast-import-output

以这种方式设置的前端可以使用progressget-marklscat-blob命令从正在进行的导入中读取信息。

为避免死锁,在执行可能阻塞的快速导入写入之前,此类前端必须完全使用progresslsget-markcat-blob的任何挂起输出。

崩溃报告

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

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

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

崩溃示例:

  1. $ cat >in <<END_OF_INPUT
  2. # my very first test commit
  3. commit refs/heads/master
  4. committer Shawn O. Pearce <spearce> 19283 -0400
  5. # who is that guy anyway?
  6. data <<EOF
  7. this is my commit
  8. EOF
  9. M 644 inline .gitignore
  10. data <<EOF
  11. .gitignore
  12. EOF
  13. M 777 inline bob
  14. END_OF_INPUT
  1. $ git fast-import <in
  2. fatal: Corrupt mode: M 777 inline bob
  3. fast-import: dumping crash report to .git/fast_import_crash_8434
  1. $ cat .git/fast_import_crash_8434
  2. fast-import crash report:
  3. fast-import process: 8434
  4. parent process : 1391
  5. at Sat Sep 1 00:58:12 2007
  1. fatal: Corrupt mode: M 777 inline bob
  1. Most Recent Commands Before Crash
  2. ---------------------------------
  3. # my very first test commit
  4. commit refs/heads/master
  5. committer Shawn O. Pearce <spearce> 19283 -0400
  6. # who is that guy anyway?
  7. data <<EOF
  8. M 644 inline .gitignore
  9. data <<EOF
  10. * M 777 inline bob
  1. Active Branch LRU
  2. -----------------
  3. active_branches = 1 cur, 5 max
  1. pos clock name
  2. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3. 1) 0 refs/heads/master
  1. Inactive Branches
  2. -----------------
  3. refs/heads/master:
  4. status : active loaded dirty
  5. tip commit : 0000000000000000000000000000000000000000
  6. old tree : 0000000000000000000000000000000000000000
  7. cur tree : 0000000000000000000000000000000000000000
  8. commit clock: 0
  9. last pack :
  1. -------------------
  2. END OF CRASH REPORT

技巧和窍门

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

每个提交使用一个标记

进行存储库转换时,每次提交使用唯一标记(mark :&lt;n&gt;)并在命令行上提供—export-marks选项。 fast-import将转储一个文件,该文件列出了每个标记和与之对应的Git对象SHA-1。如果前端可以将标记绑定到源存储库,则可以通过将每个Git提交与相应的源修订进行比较来轻松验证导入的准确性和完整性。

来自Perforce或Subversion等系统,这应该非常简单,因为快速导入标记也可以是Perforce变更集编号或Subversion版本号。

自由地跳过分支机构

在导入过程中,不要试图优化前端以一次粘贴到一个分支。尽管快速导入可能会稍快一些,但它往往会大大增加前端代码的复杂性。

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

处理重命名

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

使用标记修复分支

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

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

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

提交修正时,请考虑使用merge将提交文件修订的提交连接到fixup分支。这样做将允许诸如 git blame 之类的工具跟踪真实的提交历史并正确地注释源文件。

快速导入终止后,前端需要执行rm .git/TAG_FIXUP以删除虚拟分支。

立即导入,稍后重新包装

一旦快速导入完成,Git存储库就完全有效并可以使用了。通常这只需要非常短的时间,即使对于相当大的项目(100,000多次提交)也是如此。

但是,重新打包存储库对于改善数据位置和访问性能是必要的。在极大的项目上也可能需要数小时(特别是如果使用-f和大的—window参数)。由于重新打包可以安全地与读者和作者一起运行,因此在后台运行重新打包并在完成后完成。没有理由等待探索你的新Git项目!

如果您选择等待重新包装,请不要尝试运行基准测试或性能测试,直到重新打包完成。快速导入输出次优的包文件,这些包装文件在实际使用情况下从未见过。

重新包装历史数据

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

包括一些进度消息

每隔一段时间,您的前端会发出progress消息以快速导入。消息的内容完全是自由格式的,因此一个建议是每当当前提交日期进入下个月时输出当前月份和年份。了解已处理了多少数据流后,您的用户会感觉更好。

包装优化

打包blob时,fast-import总是试图对写入的最后一个blob进行处理。除非前端特别安排,否则这可能不是同一文件的先前版本,因此生成的delta不会是最小的。生成的packfile将被压缩,但不是最佳的。

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

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

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

记忆利用

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

每个对象

fast-import为在此执行中编写的每个对象维护一个内存中结构。在32位系统上,结构是32字节,在64位系统上,结构是40字节(由于指针大小较大)。在快速导入终止之前,表中的对象不会被释放。在32位系统上导入200万个对象将需要大约64 MiB的内存。

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

每个标记

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

每个分支

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

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

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

由于活动分支存储有关该分支上包含的文件的元数据,因此它们的内存存储大小可以增长到相当大的大小(见下文)。

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

每活动树

树(aka目录)在其条目所需的内存之上仅使用12个字节的内存(请参阅下面的“每个活动文件”)。树的成本实际上是0,因为它的开销在各个文件条目上摊销。

每个活动文件条目

活动树中的文件(和指向子树的指针)每个条目需要52或64个字节(32/64位平台)。为了节省空间,文件和树名称汇集在一个公共字符串表中,允许文件名“Makefile”仅使用16个字节(在包括字符串头开销之后),无论它在项目中出现多少次。

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

SIGNALS

SIGUSR1 发送到 git fast-import 进程会提前结束当前的packfile,模拟checkpoint命令。不耐烦的操作员可以使用此工具来查看对象并从正在进行的导入中复制,但代价是增加了一些运行时间和更差的压缩。

也可以看看

git-fast-export [1]

GIT

部分 git [1] 套件