Schedule and Run Git Repository Maintenance Safely
You will finish with a repeatable way to run Git maintenance on one repository, register it for background work, check the resulting schedule, and remove that registration without touching the repository's commits or working tree. The examples match Git 2.43.0 from the Ubuntu git-man package installed here.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need Git 2.43 or later and a repository you can inspect. The normal commands are unprivileged. Do not use sudo: git maintenance register changes your user's global Git configuration, and start changes your user's scheduler. Make a note of the repository path before registering it.
1. Check the Git version and repository
Move into the repository that needs maintenance and confirm that Git recognises it:
$ cd /path/to/repository
$ git --version
git version 2.43.0
$ git rev-parse --show-toplevel
/path/to/repository
The version line is useful when comparing behaviour with other machines. The git-maintenance(1) page used for this guide documents Git 2.43.0. If your version differs, check its local manual before copying a schedule or task list.
Checkpoint: the second command must print the repository root. If it reports that this is not a Git repository, stop and correct the path rather than registering a parent directory by accident.
2. Run one low-risk task manually
git maintenance run runs configured tasks. With --task, it runs only the named task, in the order supplied. Start with the commit graph task:
$ git maintenance run --task=commit-graph
$ printf 'exit status: %s\n' "$?"
exit status: 0
A successful run normally prints nothing. The task incrementally updates commit-graph files and verifies the data it writes. It is designed to run alongside other Git processes. Check the repository afterwards:
$ git status --short
$ git log -1 --oneline
<recent commit remains unchanged>
Maintenance changes data under .git, not tracked files. There is no ordinary undo for an optimisation pass, so keep a backup of a valuable repository before experimenting with aggressive maintenance.
3. Understand automatic and scheduled runs
These two options answer different questions:
--autoruns tasks only when thresholds such as the loose-object or pack-file limits are met.--schedule=hourly,dailyorweeklyruns tasks whose configured schedule is due, based on Git's maintenance timestamps.
They cannot be combined. A safe read-and-run check is:
$ git maintenance run --auto
$ git maintenance run --schedule=hourly
The second command may do nothing if no task is due. Without --task, run uses the enabled task configuration. In a fresh configuration, only maintenance.gc.enabled is true. That default matters: manually invoking run can select garbage collection, which may be expensive for a large repository.
4. Register the repository for background maintenance
Registering records the current repository in the multi-valued global maintenance.repo setting and enables recommended schedules. If maintenance.strategy is unset, Git sets it to incremental:
$ git maintenance register
$ git config --global --get-all maintenance.repo
/path/to/repository
$ git config --global --get maintenance.strategy
incremental
With the incremental strategy, commit-graph and prefetch work is hourly, loose-object cleanup and incremental repacking are daily, and packing references is weekly. Garbage collection is disabled by this strategy. The register command also sets maintenance.auto=false in the current repository, so foreground automatic maintenance is not duplicated by the background plan.
Checkpoint: inspect the effective settings before starting a scheduler:
$ git config --show-origin --get-regexp '^maintenance\.'
file:/home/you/.gitconfig maintenance.repo /path/to/repository
file:/home/you/.gitconfig maintenance.strategy incremental
file:.git/config maintenance.auto false
Paths and the exact ordering vary. The useful checks are that this repository is listed, the strategy is what you expect, and an existing per-repository choice has not been overwritten unexpectedly.
5. Start and verify the scheduler
Start the background schedule only after checking the configuration:
$ git maintenance start
$ systemctl --user list-timers 'git-maintenance@*'
NEXT ... UNIT ACTIVATES
... [email protected] [email protected]
... [email protected] [email protected]
... [email protected] [email protected]
On Linux, Git's default auto scheduler uses a user systemd timer when available, otherwise it uses the user's crontab. If systemd user timers are unavailable, inspect the generated entries with crontab -l. Git writes a marked schedule region. Edits inside that region can be overwritten by a later start, and stop removes it.
Do not run both a hand-written job and Git's generated schedule for the same repository unless you understand the object database lock. Concurrent maintenance runs on one repository cannot both proceed; one may be skipped. Do not run standalone git gc at the same time as scheduled maintenance. The manual recommends git maintenance run --task=gc instead, because the maintenance command uses the relevant lock.
6. Stop or unregister without guessing
stop halts the scheduler but keeps the repository registered, ready for a later start. Use it when you want a temporary pause:
$ git maintenance stop
$ systemctl --user list-timers 'git-maintenance@*'
# no active Git maintenance timers should be listed
To remove this repository from the background list as well:
$ git maintenance unregister
$ git config --global --get-all maintenance.repo
# the repository path is absent
Unregister does not stop already-running maintenance processes. It only removes the repository from the configured list. If the repository is not registered, the command reports an error; use git maintenance unregister --force when an idempotent cleanup script must succeed either way.
7. Diagnose a slow or missing run
First check whether another maintenance process holds the repository's object database lock. A second run may be skipped rather than corrupting the repository. If jobs regularly take longer than an hour, reduce the work: the full gc task is slower than incremental repacking, although the smaller tasks can leave a somewhat larger object database.
Check the scheduler and Git's effective configuration as the same user who registered the repository. A root shell has a different global configuration and a different user systemd instance. If a repository is missing from maintenance.repo, register it again from the repository directory. If the schedule is present but a task does not run, inspect its maintenance.<task>.schedule and maintenance.<task>.enabled values, and remember that an explicit --task overrides the enabled-task selection.
Done means
- You confirmed the Git version and repository root.
- You ran a named task and checked that tracked files were unchanged.
- You distinguished threshold-based
--autoruns from schedule-based runs. - You inspected the incremental strategy before enabling background work.
- You verified the user systemd timers or user crontab entry.
- You know that
stoppauses scheduling, whileunregisterremoves the repository from the list. - You have not overlapped Git maintenance with standalone
git gc.