Git 中文参考(六)(6)https://developer.aliyun.com/article/1565807
data
提供原始数据(用作 blob /文件内容,提交消息或带注释的标记消息)以快速导入。可以使用精确的字节计数提供数据,也可以使用终止线分隔数据。用于生产质量转换的真正前端应始终使用精确的字节数格式,因为它更强大且性能更好。分隔格式主要用于测试快速导入。
出现在data
命令的部分中的注释行始终被视为数据主体的一部分,因此永远不会被快速导入忽略。这样可以安全地导入任何行可能以
#
开头的文件/消息内容。
Exact byte count format
前端必须指定数据的字节数。
'data' SP <count> LF <raw> LF?
其中是
中出现的确切字节数。
的值表示为 ASCII 十进制整数。
两侧的
LF
不包含在中,不会包含在导入的数据中。
之后的
LF
是可选的(以前是必需的),但建议使用。始终包含它会使调试快速导入流更容易,因为下一个命令总是从下一行的第 0 列开始,即使没有以
LF
结束。
Delimited format
分隔符字符串用于标记数据的结尾。 fast-import 将通过搜索分隔符来计算长度。此格式主要用于测试,不建议用于实际数据。
'data' SP '<<' <delim> LF <raw> LF <delim> LF LF?
其中是选定的分隔符字符串。字符串
不能在
中单独出现在一行上,否则快速导入会认为数据比实际更早结束。
LF
立即尾随是
的一部分。这是分隔格式的限制之一,不可能提供没有 LF 作为其最后一个字节的数据块。
LF
之后的LF
是可选的(曾经是必需的)。
checkpoint
强制快速导入以关闭当前的 packfile,启动一个新文件,并保存所有当前的分支引用,标记和标记。
'checkpoint' LF 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)。否则,该命令对当前导入或任何快速导入的内部状态没有影响。
'progress' SP <any> LF LF?
命令的部分可以包含不包含
LF
的任何字节序列。命令后的LF
是可选的。调用者可能希望通过诸如 sed 之类的工具处理输出以删除行的前导部分,例如:
frontend | git fast-import | sed 's/^progress //'
在checkpoint
之后立即放置progress
命令将在checkpoint
完成时通知读者,并且可以安全地访问快速导入更新的参考。
get-mark
导致快速导入将对应于标记的 SHA-1 打印到 stdout 或先前使用--cat-blob-fd
参数排列的文件描述符。否则该命令对当前导入没有影响;它的目的是检索稍后提交可能要在其提交消息中引用的 SHA-1。
'get-mark' SP ':' <idnum> LF
此命令可以在流中接受注释的任何位置使用。特别是,get-mark
命令可以在提交过程中使用,但不能在data
命令的中间使用。
有关如何安全读取此输出的详细信息,请参阅下面的“对命令的响应”。
cat-blob
导致快速导入将 blob 打印到先前使用--cat-blob-fd
参数排列的文件描述符。否则该命令对当前导入没有影响;其主要目的是检索可能位于快速导入内存但无法从目标存储库访问的 blob。
'cat-blob' SP <dataref> LF
可以是先前设置的标记参考(
:
),也可以是预先存在或准备写入的 Git blob 的完整 40 字节 SHA-1。
输出使用与git cat-file --batch
相同的格式:
<sha1> SP 'blob' SP <size> LF <contents> LF
此命令可以在流中接受注释的任何位置使用。特别是,cat-blob
命令可以在提交过程中使用,但不能在data
命令的中间使用。
有关如何安全读取此输出的详细信息,请参阅下面的“对命令的响应”。
ls
在先前使用--cat-blob-fd
参数排列的文件描述符的路径上打印有关对象的信息。这允许从活动提交(使用cat-blob
)打印 blob 或从先前提交中复制 blob 或树以在当前提交中使用(使用filemodify
)。
ls
命令可以在流中接受注释的任何位置使用,包括提交的中间位置。
Reading from the active commit
此表单只能在commit
的中间使用。该路径在 fast-import 的活动提交中命名目录条目。在这种情况下必须引用该路径。
'ls' SP <path> LF
Reading from a named tree
可以是标记引用(
:
)或 Git 标记,提交或树对象的完整 40 字节 SHA-1,预先存在或等待写入。该路径相对于命名的树的顶层。
'ls' SP <dataref> SP <path> LF
有关的详细说明,请参见上面的
filemodify
。
输出使用与git ls-tree --
相同的格式:
<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
要求快速导入支持指定的功能,如果不支持,则中止。
'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 命令行选项会覆盖流中的任何这些“功能”命令;第三,“功能 import-marks-if-exists”就像相应的命令行选项一样,会以静默方式跳过不存在的文件。
get-mark
cat-blob
ls
要求后端分别支持 get-mark , cat-blob 或 ls 命令。不支持指定命令的快速导入版本将退出并显示一条消息。这样可以使用明确的消息提前导出错误,而不是在检测到不支持的命令之前在导入的早期浪费时间。
notes
要求后端支持 commit (N)子命令到 commit 命令。快速导入不支持注释的版本将退出,并显示一条消息。
done
如果流没有 _ 完成 _ 命令结束,则输出错误。如果没有此功能,导致前端突然在流中方便的位置结束的错误可能无法检测到。例如,如果导入前端在中间操作中死亡而不在其下级 git 快速导入实例中发出 SIGTERM 或 SIGKILL,则可能发生这种情况。
option
处理指定的选项,以便 git fast-import 以适合前端需要的方式运行。请注意,前端指定的选项会被用户指定用于 git 快速导入的任何选项覆盖。
'option' SP <option> LF
命令的部分可能包含 OPTIONS 部分中列出的任何不改变导入语义的选项,没有前导
--
并且以相同的方式处理。
选项命令必须是输入上的第一个命令(不计算功能命令),以便在任何非选项命令出错后给出选项命令。
以下命令行选项更改导入语义,因此不能作为选项传递:
- 日期格式
- 进口标志
- 出口标志
- 猫 BLOB-FD
- 力
done
如果未使用done
功能,则将其视为已读取 EOF。这可以用来告诉快速导入提前完成。
如果正在使用--done
命令行选项或feature done
命令,则done
命令是必需的,并标记流的结束。
对命令的回应
快速导入写入的新对象不能立即使用。大多数快速导入命令在下一个检查点(或完成)之前没有可见效果。前端可以发送命令来填充快速导入的输入管道,而不必担心它们将如何快速生效,从而通过简化调度来提高性能。
但是,对于某些前端,能够在更新时从当前存储库中读回数据非常有用(例如,当源材料根据要应用于先前导入的对象的补丁描述对象时)。这可以通过连接前端和通过双向管道快速导入来实现:
mkfifo fast-import-output frontend <fast-import-output | git fast-import >fast-import-output
以这种方式设置的前端可以使用progress
,get-mark
,ls
和cat-blob
命令从正在进行的导入中读取信息。
为避免死锁,在执行可能阻塞的快速导入写入之前,此类前端必须完全使用progress
,ls
,get-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 <<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
技巧和窍门
从快速导入的各种用户收集了以下提示和技巧,并在此处作为建议提供。
每个提交使用一个标记
进行存储库转换时,每次提交使用唯一标记(mark :
)并在命令行上提供–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
部分 git [1] 套件
git-clean
名称
git-clean - 从工作树中删除未跟踪的文件
概要
git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>…
描述
通过从当前目录开始递归删除不受版本控制的文件来清除工作树。
通常,只删除 Git 未知的文件,但如果指定了-x
选项,则也会删除被忽略的文件。例如,这可以用于删除所有构建产品。
如果给出任何可选的...
参数,则只会影响这些路径。
Git 中文参考(六)(8)https://developer.aliyun.com/article/1565809