keeping repository health in check automatically
As a repository grows, loose objects, expanding pack files, and an increasingly costly commit graph pile up over time. The git maintenance command replaces the blunt, occasional git gc with several granular, schedulable maintenance tasks that run in the background without getting in the way of daily work.
Table of Contents
- 1. Why repositories get slower over time
- 2. The old approach: git gc --auto and its weaknesses
- 3. git maintenance as a structured successor
- 4. An overview of the individual maintenance tasks
- 5. Automatic scheduling with git maintenance start
- 6. Configuring maintenance per repository
- 7. Benefits for large monorepos and many contributors
- 8. Running tasks manually and deliberately
- 9. Checking status and spotting problems
- 10. Summary
- 11. FAQ
1. Why repositories get slower over time
Every new commit, every fetch, and every merge creates new Git objects that initially get stored loose, meaning as individual files inside the object directory. Without regular consolidation, the number of these loose objects keeps growing, which increases both disk usage and the time needed for operations that have to iterate over the entire object database.
At the same time, the commit graph itself gets more expensive to traverse over time: commands like git log or git blame, which need to evaluate ancestry relationships between commits, get noticeably slower on a large repository with many thousands of commits once Git has to reconstruct those relationships from raw commit objects on every single request.
2. The old approach: git gc --auto and its weaknesses
Before git maintenance was introduced, git gc --auto was the usual mechanism, triggered automatically once certain thresholds for loose objects or pack files were reached, running in the background of an otherwise ordinary Git operation. The problem: it ran blocking in the foreground of whatever operation triggered it, which on a large repository could cause noticeable, unpredictable delays right in the middle of a workday.
On top of that, git gc only knew a single, coarse task that handled everything at once, from object compaction to pruning old references. There was no way to control which sub-task should run how often, nor any clean scheduling outside of actual Git usage.
3. git maintenance as a structured successor
Since Git 2.31, the git maintenance command has split maintenance work explicitly into individual, independently schedulable tasks. Instead of a single coarse operation, every sub-task can be configured with its own frequency, from hourly to weekly, depending on how actively a repository is actually being used.
The git maintenance run command runs either every configured task or, via --task, a single specific task, which fits both interactive, manual use and integration into automated maintenance windows.
# Run every configured maintenance task once
git maintenance run
# Trigger only a single specific task
git maintenance run --task=gc
4. An overview of the individual maintenance tasks
The gc task corresponds at its core to classic garbage collection, compacting loose objects into pack files and removing unreachable objects once their retention window has expired. The commit-graph task updates a special file that pre-computes ancestry relationships between commits, considerably speeding up git log and similar commands.
The prefetch task downloads new objects from configured remotes in the background without touching local branches, so a later git fetch or git pull completes noticeably faster. loose-objects continuously consolidates newly created loose objects into smaller pack files, while incremental-repack merges existing pack files step by step, without repacking the entire repository from scratch on every run.
5. Automatic scheduling with git maintenance start
The git maintenance start command registers the configured maintenance tasks as recurring background jobs in the scheduler of the underlying operating system, typically via systemd timers or cron on Linux, launchd on macOS, and the built-in Task Scheduler on Windows.
Every task gets a sensible default frequency: the prefetch task usually runs hourly, the commit-graph task also runs frequently, while the more resource-intensive gc task only runs daily, keeping system load low during active working hours.
# Set up recurring maintenance in the background
git maintenance start
# Remove the registered maintenance again
git maintenance stop
6. Configuring maintenance per repository
Individual tasks can be turned on or off deliberately through configuration values such as maintenance.gc.enabled, in case a particular task is not wanted in a specific repository. Via maintenance.strategy, a predefined profile called incremental is also available, enabling a sensible combination of several tasks with staggered frequencies without having to configure each setting one by one.
Since git maintenance start only registers the current repository by default, every additional repository that should be maintained automatically needs to either be activated individually with the same command inside its own directory, or added explicitly to the global list via git config --global --add maintenance.repo
# Enable the predefined, staggered maintenance profile
git config maintenance.strategy incremental
# Add another repository to the global maintenance list
git config --global --add maintenance.repo /path/to/other-repo
7. Benefits for large monorepos and many contributors
In a large monorepo with many active contributors, frequent small commits and regular fetches quickly add up to a substantial number of loose objects, making the effect of continuous consolidation especially noticeable. An up to date commit graph there measurably speeds up commands like git log --graph and git blame on files with a long change history in particular.
The prefetch task also pays off especially well in that kind of environment, since new objects are already available in the background before a developer runs the first git pull of the day, noticeably reducing the perceived wait time at the start of the workday.
8. Running tasks manually and deliberately
For server repositories where no interactive scheduler should or may run, a single task can also be called deliberately from an external cron job or a CI maintenance window, without git maintenance start ever being run at all.
That fits particularly well for central bare repositories on a Git server, where maintenance should deliberately be placed into a fixed, predictable time window outside of peak usage hours rather than relying on the operating system's automatic scheduler integration.
# Deliberate invocation from an external cron job
0 3 * * * git -C /srv/git/project.git maintenance run --task=gc
9. Checking status and spotting problems
A simple before and after comparison with git count-objects -v shows both the number of loose objects and the size and count of existing pack files, making the effect of maintenance directly visible. If the number of loose objects stays persistently high despite maintenance being enabled, it is worth checking the logs of the underlying operating system scheduler to confirm the registered jobs are actually running.
Once automatic maintenance is no longer needed, for instance because a repository gets archived, git maintenance stop cleanly removes all registered background jobs from the operating system's scheduler again.
# Check the number of loose objects and pack files
git count-objects -v
| Criterion | git gc --auto | git maintenance |
|---|---|---|
| Execution | Blocking, in the foreground of an operation | In the background, independent of any command |
| Granularity | One single coarse task | Several independent tasks with their own frequency |
| Scheduling | No built-in scheduling | Native integration with systemd, launchd, cron, Task Scheduler |
| Commit graph maintenance | Not included | Dedicated commit-graph task |
| Fit for server repositories | Limited, no fine control | Good, callable deliberately via --task |
Mironsoft
Git workflows, branching strategies, and CI hooks
Chaotic Git history and unclear branching rules across the team?
We set up clean Git workflows, clarify branching strategies for the team, and automate quality checks via Git hooks and CI pipelines so the history stays traceable.
Workflow Audit
Review the existing branching strategy and merge practice for weak spots.
Hook Automation
Set up pre-commit and pre-push hooks for linting, tests, and commit conventions.
Team Training
Teach rebase, cherry-pick, and conflict resolution hands-on across the team.
10. Summary
Git Maintenance
Core idea
git maintenance splits maintenance into independent, schedulable tasks instead of one coarse, blocking git gc run.
Activation
git maintenance start registers recurring background jobs in the operating system's scheduler.
Key tasks
gc, commit-graph, prefetch, loose-objects, and incremental-repack each run independently with their own frequency.
Biggest benefit
Large monorepos with many contributors benefit the most from continuous, unobtrusive consolidation.