Skip to content

git-maintenance

运行任务以优化 Git 仓库数据。

概要

txt
'git maintenance' run [<options>]
'git maintenance' start [--scheduler=<scheduler>]
'git maintenance' (stop|register|unregister) [<options>]
'git maintenance' is-needed [<options>]

描述

运行任务以优化 Git 仓库数据,加速其他 Git 命令并减少仓库的存储需求。

添加仓库数据的 Git 命令(如 git addgit fetch)针对响应式用户体验进行了优化。这些命令不会花时间优化 Git 数据,因为此类优化的规模与仓库的完整大小成正比,而这些用户命令各自执行相对较小的操作。

git maintenance 命令为如何优化 Git 仓库提供了灵活性。

子命令

run

:运行一个或多个维护任务。如果指定了一个或多个 --task 选项,则按该顺序运行这些任务。否则,任务由哪些 maintenance.<task>.enabled 配置选项为 true 决定。默认情况下,只有 maintenance.gc.enabled 为 true。

start

:开始在当前仓库上运行维护。这执行与 register 子命令相同的配置更新,然后更新后台调度程序以每小时运行 git maintenance run --scheduled

stop

:停止后台维护计划。当前仓库不会从维护仓库列表中移除,以防以后重新启动后台维护。

register

:初始化 Git 配置值,以便任何计划维护将开始在此仓库上运行。这将仓库添加到当前用户全局配置或 --config-file 选项指定的配置中的 maintenance.repo 配置变量,并为 maintenance.<task>.schedule 启用一些推荐的配置值。启用的任务在后台运行时是安全的,不会干扰前台进程。 register 子命令还会将 maintenance.strategy 配置值设置为 incremental(如果此值之前未设置)。incremental 策略对每个维护任务使用以下计划:

  • gc:禁用。
  • commit-graph:每小时。
  • prefetch:每小时。
  • loose-objects:每天。
  • incremental-repack:每天。 git maintenance register 还将通过在当前仓库中设置 maintenance.auto = false 来禁用前台维护。此配置设置将在 git maintenance unregister 命令后保留。

unregister

:从后台维护中移除当前仓库。这仅从配置列表中移除仓库。它不会停止后台维护进程的运行。 如果当前仓库尚未注册,unregister 子命令将报告错误。使用 --force 选项即使当前仓库未注册也返回成功。

is-needed

:检查是否需要运行维护而不实际运行它。如果需要运行维护则以 0 状态代码退出,否则以 1 退出。最好与 '--auto' 标志一起使用。 如果指定了一个或多个 --task 选项,则按该顺序检查这些任务。否则,任务由哪些 maintenance.<task>.enabled 配置选项为 true 决定。默认情况下,只有 maintenance.gc.enabled 为 true。

任务

commit-graph

commit-graph 任务增量更新 commit-graph 文件,然后验证写入的数据是否正确。增量写入在并发 Git 进程旁边运行是安全的,因为它不会过期之前 commit-graph-chain 文件中的 .graph 文件。它们将在后续运行中根据过期延迟被删除。

prefetch

prefetch 任务使用来自所有注册远程的最新对象更新对象目录。对每个远程运行 git fetch 命令。配置的 refspec 被修改以将所有请求的引用放在 refs/prefetch/ 内。此外,标签不会被更新。 这样做是为了避免干扰远程跟踪分支。最终用户期望这些引用保持不动,除非他们发起获取。然而,通过预取任务,完成后续实际获取所需的对象将已经获得,使实际获取更快。在理想情况下,它将只成为对一堆远程跟踪分支的更新,无需任何对象传输。 remote.<name>.skipFetchAll 配置可用于排除特定远程不被预取。

gc

:清理不必要的文件并优化本地仓库。"GC" 代表 "garbage collection"(垃圾回收),但此任务执行许多较小的任务。此任务对大型仓库来说可能很耗时,因为它将所有 Git 对象重新打包到单个包文件中。在某些情况下也可能具有破坏性,因为它会删除过时的数据。有关 Git 中垃圾回收的更多详细信息,请参阅 git-gc(1)

loose-objects

loose-objects 任务清理松散对象并将它们放入包文件中。为了防止与并发 Git 命令的竞争条件,它遵循两步过程。首先,它删除已存在于包文件中的任何松散对象;并发 Git 进程将检查包文件中的对象数据而不是松散对象。其次,它创建一个包含一批松散对象的新包文件(以 "loose-" 开头)。 批次大小默认为五万个对象,以防止任务在具有许多松散对象的仓库上花费太长时间。使用 maintenance.loose-objects.batchSize 配置选项调整此大小,包括值 0 以移除限制。 gc 任务将不可达对象写为松散对象,以便后续步骤清理,仅当它们未被重新添加到包文件中时;因此不建议同时启用 loose-objectsgc 任务。

incremental-repack

incremental-repack 任务使用 multi-pack-index 功能重新打包对象目录。为了防止与并发 Git 命令的竞争条件,它遵循两步过程。首先,它调用 git multi-pack-index expire 删除未被 multi-pack-index 文件引用的包文件。其次,它调用 git multi-pack-index repack 选择几个小包文件并将它们重新打包为一个更大的包文件,然后更新引用小包文件的 multi-pack-index 条目以引用新包文件。这为这些小包文件在下次运行 git multi-pack-index expire 时被删除做准备。 小包文件的选择使得大包文件的预期大小至少为批次大小;有关 repack 子命令的 --batch-size 选项,请参阅 git-multi-pack-index(1)。默认批次大小为零,这是尝试将所有包文件重新打包为单个包文件的特殊情况。

pack-refs

pack-refs 任务收集松散引用文件并将它们收集到单个文件中。这加速了需要遍历许多引用的操作。有关更多信息,请参阅 git-pack-refs(1)

reflog-expire

reflog-expire 任务删除引用日志中超过过期阈值的任何条目。有关更多信息,请参阅 git-reflog(1)

rerere-gc

rerere-gc 任务对 rerere 缓存中的过时条目调用垃圾回收。有关更多信息,请参阅 git-rerere(1)

worktree-prune

worktree-prune 任务删除过时或损坏的工作树。有关更多信息,请参阅 git-worktree(1)

选项

--auto

:与 run 子命令组合时,仅在满足某些阈值时运行维护任务。例如,gc 任务在松散对象数量超过 gc.auto 配置设置中存储的数量或包文件数量超过 gc.autoPackLimit 配置设置时运行。与 --schedule 选项不兼容。 与 is-needed 子命令组合时,检查是否满足所需阈值而不实际运行维护。

--schedule

:与 run 子命令组合时,仅在满足某些时间条件时运行维护任务,如每个 <task>maintenance.<task>.schedule 配置值所指定。此配置值指定自上次运行该任务以来的秒数,根据 maintenance.<task>.lastRun 配置值。测试的任务是 --task=<task> 选项提供的任务或 maintenance.<task>.enabled 设置为 true 的任务。

--quiet

:不通过 stderr 报告进度或其他信息。

--task=<task>

:如果此选项指定一次或多次,则仅按指定顺序运行指定的任务。如果未指定 --task=<task> 参数,则仅考虑 maintenance.<task>.enabled 配置为 true 的任务。有关接受的 <task> 值列表,请参阅"任务"部分。

--scheduler=auto|crontab|systemd-timer|launchctl|schtasks

:与 start 子命令组合时,指定用于运行每小时、每日和每周执行 git maintenance run 的调度程序。 <scheduler> 的可能值为 autocrontab(POSIX)、systemd-timer(Linux)、launchctl(macOS)和 schtasks(Windows)。指定 auto 时,使用适当的平台特定调度程序;在 Linux 上,如果可用则使用 systemd-timer,否则使用 crontab。默认为 auto

故障排除

git maintenance 命令旨在简化仓库维护模式,同时最小化 Git 命令期间的用户等待时间。提供了各种配置选项以允许自定义此过程。默认维护选项侧重于即使在大型仓库上也能快速完成的操作。

用户可能会发现某些情况下计划维护任务没有按预期频率运行。每个 git maintenance run 命令都会在仓库的对象数据库上获取锁,这会阻止其他并发 git maintenance run 命令在同一仓库上运行。如果没有此保护,竞争进程可能会使仓库处于不可预测的状态。

后台维护计划每小时运行一次 git maintenance run 进程。每次运行执行"每小时"任务。在午夜,该进程还执行"每日"任务。在每周第一天的午夜,该进程还执行"每周"任务。单个进程遍历每个注册的仓库,执行该频率的计划任务。进程被安排在每小时的随机分钟,以分散多个客户端可能生成的负载(例如来自预取)。根据注册仓库的数量和大小,此过程可能需要超过一小时。在这种情况下,多个 git maintenance run 命令可能同时在同一仓库上运行,在对象数据库锁上冲突。这导致两个任务中的一个无法运行。

如果您发现某些维护窗口需要超过一小时才能完成,请考虑降低维护任务的复杂性。例如,gc 任务比 incremental-repack 任务慢得多。然而,这是以稍大的对象数据库为代价的。考虑将更耗时的任务移到更低频率运行。

专家用户可能考虑使用与 git maintenance start 和 Git 配置选项可用的不同计划来安排自己的维护任务。这些用户应该了解对象数据库锁以及并发 git maintenance run 命令的行为。此外,git gc 命令不应与 git maintenance run 命令组合使用。git gc 修改对象数据库但不像 git maintenance run 那样获取锁。如果可能,使用 git maintenance run --task=gc 代替 git gc

以下部分描述了 git maintenance start 为运行后台维护而设置的机制以及如何自定义它们。

POSIX 系统上的后台维护

在 POSIX 系统上调度后台任务的标准机制是 cron(8)。此工具根据给定计划执行命令。当前用户计划任务的列表可以通过运行 crontab -l 找到。git maintenance start 写入的计划类似于:

# BEGIN GIT MAINTENANCE SCHEDULE
# The following schedule was created by Git
# Any edits made in this region might be
# replaced in the future by a Git command.

0 1-23 * * * "/<path>/git" --exec-path="/<path>" for-each-repo --config=maintenance.repo maintenance run --schedule=hourly
0 0 * * 1-6 "/<path>/git" --exec-path="/<path>" for-each-repo --config=maintenance.repo maintenance run --schedule=daily
0 0 * * 0 "/<path>/git" --exec-path="/<path>" for-each-repo --config=maintenance.repo maintenance run --schedule=weekly

# END GIT MAINTENANCE SCHEDULE

注释用作标记 Git 写入的计划的区域。此区域内的任何修改将被 git maintenance stop 完全删除或被 git maintenance start 覆盖。

crontab 条目指定 git 可执行文件的完整路径,以确保执行的 git 命令与发出 git maintenance start 的命令相同,独立于 PATH。如果同一用户使用多个 Git 可执行文件运行 git maintenance start,则仅使用最新的可执行文件。

这些命令使用 git for-each-repo --config=maintenance.repo 对多值 maintenance.repo 配置选项中列出的每个仓库运行 git maintenance run --schedule=<frequency>。这些通常从用户特定的全局配置加载。然后 git maintenance 进程使用 maintenance.<task>.schedule 配置选项确定哪些维护任务配置为在每个仓库上以每个 <frequency> 运行。这些值从全局或仓库配置值加载。

如果配置值不足以实现您期望的后台维护计划,您可以创建自己的计划。如果运行 crontab -e,编辑器将加载您的用户特定 cron 计划。在该编辑器中,您可以添加自己的计划行。您可以从调整上面列出的默认计划开始,或者阅读 crontab(5) 文档了解高级调度技术。请使用默认计划中的完整路径和 --exec-path 技术,以确保在您的计划中执行正确的二进制文件。

Linux systemd 系统上的后台维护

虽然 Linux 支持 cron,但根据发行版,cron 可能是不一定安装的可选软件包。在现代 Linux 发行版上,systemd 计时器正在取代它。

如果用户 systemd 计时器可用,它们将用作 cron 的替代品。

在这种情况下,git maintenance start 将创建用户 systemd 计时器单元并启动计时器。当前用户计划任务的列表可以通过运行 systemctl --user list-timers 找到。git maintenance start 写入的计时器类似于:

$ systemctl --user list-timers
NEXT                         LEFT          LAST                         PASSED     UNIT                         ACTIVATES
Thu 2021-04-29 19:00:00 CEST 42min left    Thu 2021-04-29 18:00:11 CEST 17min ago  git-maintenance@hourly.timer git-maintenance@hourly.service
Fri 2021-04-30 00:00:00 CEST 5h 42min left Thu 2021-04-29 00:00:11 CEST 18h ago    git-maintenance@daily.timer  git-maintenance@daily.service
Mon 2021-05-03 00:00:00 CEST 3 days left   Mon 2021-04-26 00:00:11 CEST 3 days ago git-maintenance@weekly.timer git-maintenance@weekly.service

为每个 --schedule=<frequency> 选项注册一个计时器。

systemd 单元的定义可以在以下文件中检查:

~/.config/systemd/user/git-maintenance@.timer
~/.config/systemd/user/git-maintenance@.service
~/.config/systemd/user/timers.target.wants/git-maintenance@hourly.timer
~/.config/systemd/user/timers.target.wants/git-maintenance@daily.timer
~/.config/systemd/user/timers.target.wants/git-maintenance@weekly.timer

git maintenance start 将覆盖这些文件并再次使用 systemctl --user 启动计时器,因此任何自定义应通过创建插入文件(即 ~/.config/systemd/user/git-maintenance@.service.d 目录中以 .conf 为后缀的文件)来完成。

git maintenance stop 将停止用户 systemd 计时器并删除上述文件。

有关更多详细信息,请参阅 systemd.timer(5)

macOS 系统上的后台维护

虽然 macOS 技术上支持 cron,但使用 crontab -e 需要提升权限,且执行的进程没有完整的用户上下文。没有完整的用户上下文,Git 及其凭据助手无法访问存储的凭据,因此某些维护任务无法正常工作。

相反,git maintenance startlaunchctl 工具交互,这是在 macOS 中调度定时作业的推荐方式。通过 git maintenance (start|stop) 调度维护需要 macOS 10.11 或更高版本中可用的一些 launchctl 功能。

您的用户特定计划任务以 XML 格式的 .plist 文件存储在 ~/Library/LaunchAgents/ 中。您可以使用以下命令查看当前注册的任务:

$ ls ~/Library/LaunchAgents/org.git-scm.git*
org.git-scm.git.daily.plist
org.git-scm.git.hourly.plist
org.git-scm.git.weekly.plist

为每个 --schedule=<frequency> 选项注册一个任务。要检查 XML 格式如何描述每个计划,在编辑器中打开这些 .plist 文件之一并检查 <key>StartCalendarInterval</key> 元素后面的 <array> 元素。

git maintenance start 将覆盖这些文件并再次使用 launchctl 注册任务,因此任何自定义应通过创建具有不同名称的自己的 .plist 文件来完成。类似地,git maintenance stop 命令将使用 launchctl 注销任务并删除 .plist 文件。

要为后台任务创建更高级的自定义,请参阅 launchctl.plist(5) 了解更多信息。

Windows 系统上的后台维护

Windows 不支持 cron,而是有自己的后台任务调度系统。git maintenance start 命令使用 schtasks 命令将任务提交到此系统。您可以使用任务计划程序应用程序检查所有后台任务。Git 添加的任务名称格式为 Git Maintenance (<frequency>)。任务计划程序 GUI 有办法检查这些任务,但您也可以将任务导出为 XML 文件并在那里查看详细信息。

请注意,由于 Git 是控制台应用程序,这些后台任务会创建对当前用户可见的控制台窗口。可以通过在任务计划程序中选择"不管用户是否登录都要运行"选项来手动更改此更改。此更改需要输入密码,这就是为什么 git maintenance start 默认不选择它。

如果您想自定义后台任务,请重命名任务,以便将来调用 git maintenance (start|stop) 不会覆盖您的自定义任务。

配置

以下内容选自 git-config(1) 文档:

maintenance.auto

:此布尔配置选项控制某些命令在完成正常工作后是否运行 git maintenance run --auto。默认为 true。

maintenance.autoDetach

:许多 Git 命令在将数据写入仓库后触发自动维护。此布尔配置选项控制此自动维护是在前台发生还是维护进程应分离并继续在后台运行。 如果未设置,gc.autoDetach 的值用作回退。如果两者都未设置则默认为 true,这意味着维护进程将分离。

maintenance.strategy

:此字符串配置选项提供了一种方式来指定少数推荐的仓库维护策略之一。这影响在 git maintenance run 期间运行哪些任务,前提是未提供 --task=<task> 参数。此设置影响手动维护、自动维护以及计划维护。运行的任务可能因维护类型而异。 维护策略可以通过设置 maintenance.<task>.enabledmaintenance.<task>.schedule 进一步调整。如果设置了,这些值将代替 maintenance.strategy 提供的默认值使用。 可能的策略为:

  • none:此策略意味着根本不运行任何任务。这是计划维护的默认策略。
  • gc:此策略运行 gc 任务。
  • geometric:此策略执行包文件的几何重新打包并保持辅助数据结构最新。此策略过期引用日志中的数据并移除无法再定位的工作树。当几何重新打包策略决定执行全合一重新打包时,该策略为所有不可达对象生成 cruft 包。已经是 cruft 包一部分的对象将被过期。 此重新打包策略是 gc 策略的完全替代品,推荐用于大型仓库。这是手动维护的默认策略。
  • incremental:此设置优化为执行不删除任何数据的小型维护活动。此设置不定期安排 gc 任务,但每小时运行 prefetchcommit-graph 任务,每天运行 loose-objectsincremental-repack 任务,每周运行 pack-refs 任务。手动仓库维护使用 gc 任务。

maintenance.<task>.enabled

:此布尔配置选项控制当未指定 --task 选项时,名为 <task> 的维护任务是否在 git maintenance run 时运行。如果存在 --task 选项,则忽略这些配置值。默认情况下,只有 maintenance.gc.enabled 为 true。

maintenance.<task>.schedule

:此配置选项控制给定 <task> 是否在 git maintenance run --schedule=<frequency> 命令期间运行。值必须是 "hourly"、"daily" 或 "weekly" 之一。

maintenance.commit-graph.auto

:此整数配置选项控制 commit-graph 任务应作为 git maintenance run --auto 的一部分运行的频率。如果为零,则 commit-graph 任务不会使用 --auto 选项运行。负值将强制任务每次运行。否则,正值意味着当不在 commit-graph 文件中的可达提交数量至少为 maintenance.commit-graph.auto 的值时应运行该命令。默认值为 100。

maintenance.loose-objects.auto

:此整数配置选项控制 loose-objects 任务应作为 git maintenance run --auto 的一部分运行的频率。如果为零,则 loose-objects 任务不会使用 --auto 选项运行。负值将强制任务每次运行。否则,正值意味着当松散对象数量至少为 maintenance.loose-objects.auto 的值时应运行该命令。默认值为 100。

maintenance.loose-objects.batchSize

:此整数配置选项控制在 loose-objects 任务期间写入包文件的最大松散对象数量。默认为五万。使用值 0 表示无限制。

maintenance.incremental-repack.auto

:此整数配置选项控制 incremental-repack 任务应作为 git maintenance run --auto 的一部分运行的频率。如果为零,则 incremental-repack 任务不会使用 --auto 选项运行。负值将强制任务每次运行。否则,正值意味着当不在 multi-pack-index 中的包文件数量至少为 maintenance.incremental-repack.auto 的值时应运行该命令。默认值为 10。

maintenance.geometric-repack.auto

:此整数配置选项控制 geometric-repack 任务应作为 git maintenance run --auto 的一部分运行的频率。如果为零,则 geometric-repack 任务不会使用 --auto 选项运行。负值将强制任务每次运行。否则,正值意味着当需要合并包文件以保持几何级数,或至少有这么多松散对象将被写入新包文件时,该命令应运行。默认值为 100。

maintenance.geometric-repack.splitFactor

:此整数配置选项控制用于几何序列的因子。有关更多详细信息,请参阅 git-repack(1) 中的 --geometric= 选项。默认为 2

maintenance.reflog-expire.auto

:此整数配置选项控制 reflog-expire 任务应作为 git maintenance run --auto 的一部分运行的频率。如果为零,则 reflog-expire 任务不会使用 --auto 选项运行。负值将强制任务每次运行。否则,正值意味着当 "HEAD" 引用日志中的过期引用日志条目数量至少为 maintenance.loose-objects.auto 的值时应运行该命令。默认值为 100。

maintenance.rerere-gc.auto

:此整数配置选项控制 rerere-gc 任务应作为 git maintenance run --auto 的一部分运行的频率。如果为零,则 rerere-gc 任务不会使用 --auto 选项运行。负值将强制任务每次运行。否则,任何正值意味着当 "rr-cache" 目录存在且至少有一个条目时,无论是否过时,该命令都会运行。此启发式方法将来可能会改进。默认值为 1。

maintenance.worktree-prune.auto

:此整数配置选项控制 worktree-prune 任务应作为 git maintenance run --auto 的一部分运行的频率。如果为零,则 worktree-prune 任务不会使用 --auto 选项运行。负值将强制任务每次运行。否则,正值意味着当可修剪的工作树数量超过该值时应运行该命令。默认值为 1。

Git

git(1) 套件的一部分

基于 CC BY-NC-SA 3.0 许可发布