Home / Alt manpages / git-maintenance(1)

  • git-maintenance(1)
  • User command
  • linux

Schedule Git Maintenance Without Breaking Anything

git maintenance keeps a repository's object database tidy in the background, and getting it wrong can leave a scheduled gc fighting your own commits. By the end you will have a repeatable way to run maintenance on one repository, register it for background work, check the resulting schedule, and remove that registration again without touching a single commit or working-tree file. The examples match Git 2.43.0 from the Ubuntu git-man package installed here.

Allow about fifteen minutes. You need Git 2.43 or later and a repository you can inspect. The normal commands are unprivileged. Skip sudo: git maintenance register changes your user's global Git configuration, and start changes your user's scheduler, not the system's. Note the repository path before you register it.

1. Check the Git version and repository

Move into the repository that needs maintenance and confirm 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 matters when comparing behaviour across machines: the git-maintenance(1) page used here documents Git 2.43.0, so check your own local manual first if yours differs before copying a schedule or task list.

Checkpoint

The second command must print the repository root. If it says this is not a Git repository, correct the path rather than accidentally registering a parent directory.

2. Run one low-risk task manually

git maintenance run runs configured tasks, and with --task it runs only the one you name, 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, and 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 your tracked files. There is no ordinary undo for an optimisation pass, so back up a valuable repository before you experiment with the more aggressive tasks.

3. Understand automatic and scheduled runs

  • --auto runs tasks only when a threshold, such as the loose-object or pack-file limit, is actually met.
  • --schedule=hourly, daily or weekly runs tasks whose configured schedule is due, based on Git's own maintenance timestamps.

The two cannot be combined. A safe read-and-run check is:

$ git maintenance run --auto
$ git maintenance run --schedule=hourly

The second may do nothing at all if no task is due. Without --task, run uses the enabled task configuration, and in a fresh setup only maintenance.gc.enabled is true. That default matters: calling run by hand can trigger garbage collection, which can get expensive fast on a large repository.

4. Register the repository for background maintenance

Registering records the current repository in the multi-valued global maintenance.repo setting and switches on the 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

Under the incremental strategy, commit-graph and prefetch work run hourly, loose-object cleanup and incremental repacking run daily, and packing references runs weekly. Garbage collection is switched off by this strategy entirely. Registering also sets maintenance.auto=false in the current repository, so foreground automatic maintenance does not double up with the background plan.

Checkpoint

Inspect the effective settings before you start 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 ordering vary by machine. What matters is that this repository is listed, the strategy is the one you expect, and an existing per-repository choice has not been quietly overwritten.

5. Start and verify the scheduler

Start the background schedule only after checking the configuration above:

$ 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 auto scheduler uses a user systemd timer when one is available, and falls back to the user's crontab otherwise. No systemd user timers? Check the generated entries with crontab -l instead. Git writes a marked region for its schedule: edits inside that region can be overwritten by a later start, and stop removes it entirely.

Do not run a hand-written job alongside Git's generated schedule for the same repository unless you understand the object database lock involved. Two concurrent maintenance runs on one repository cannot both proceed; one gets skipped. Do not run standalone git gc at the same time as scheduled maintenance either. The manual recommends git maintenance run --task=gc instead, because it takes the relevant lock properly.

6. Stop or unregister without guessing

stop halts the scheduler but keeps the repository registered, ready for a later start. Reach for 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 drop this repository from the background list too:

$ git maintenance unregister
$ git config --global --get-all maintenance.repo
  # the repository path is absent

Unregistering does not stop a maintenance process that is already running; it only removes the repository from the configured list. If the repository was never registered, the command errors out, so use git maintenance unregister --force when an idempotent cleanup script needs to succeed either way.

7. Diagnose a slow or missing run

First check whether another maintenance process is holding the repository's object database lock. A second run is meant to be skipped rather than corrupt anything. If jobs regularly run past an hour, cut the work down: the full gc task is slower than incremental repacking, though the smaller tasks can leave a somewhat larger object database behind.

Check the scheduler and Git's effective configuration as the same user who registered the repository. A root shell has an entirely different global configuration and systemd instance. If a repository has gone missing from maintenance.repo, register it again from that repository's own directory. If the schedule is present but a task never runs, inspect its maintenance.<task>.schedule and maintenance.<task>.enabled values, and remember an explicit --task overrides the enabled-task selection anyway.

Done means

  • Version and repo confirmed: you checked the Git version and repository root.
  • Task tested: you ran a named task and confirmed tracked files were unchanged.
  • Auto vs scheduled clear: you can tell threshold-based --auto runs from schedule-based runs.
  • Strategy inspected: you checked the incremental strategy before enabling background work.
  • Scheduler verified: you confirmed the user systemd timers or crontab entry.
  • Stop vs unregister understood: you know stop pauses scheduling while unregister removes the repository from the list.
  • No overlap: you have not run standalone git gc alongside scheduled maintenance.