Git Maintenance: Keeping Repository Health in Check Automatically
AI generated
git
HEAD
Git
Git Maintenance
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.

9 min read Git Performance

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.

11. FAQ: Git Maintenance

1From which Git version is git maintenance available?
Since Git 2.31, on older versions only the classic mechanism via git gc --auto remains available without the granular task split.
2Does git maintenance start fully replace running git gc manually?
For most repositories yes, the gc task inside git maintenance handles the same job, just embedded in a schedulable, less disruptive process.
3Do I have to register every repository individually for automatic maintenance?
Yes, either with git maintenance start inside each individual repository, or by adding its path to the global list via maintenance.repo.
4Does background maintenance run even when no terminal is open?
Yes, since the jobs are registered directly in the operating system's scheduler, they run independently of whether a Git session or terminal happens to be open.
5What exactly does the commit-graph task do?
It computes and updates a special file with pre-computed ancestry relationships between commits, making commands like git log and git blame noticeably faster on large repositories.
6Does git maintenance fit a central server repository too?
Yes, individual tasks can be run deliberately from an external cron job with git maintenance run --task, without needing the operating system's interactive scheduler at all.
7How do I know whether automatic maintenance is actually doing anything?
Comparing the output of git count-objects -v before and after a maintenance run directly shows whether the number of loose objects and pack files goes down.
8Can I disable individual tasks deliberately?
Yes, configuration values such as maintenance.gc.enabled false let every task be turned on or off independently of the others.
9What exactly does the prefetch task do?
It downloads new objects from the configured remotes in the background without touching local branches, so a later git fetch or git pull completes noticeably faster.
10How do I remove automatic maintenance again completely?
git maintenance stop cleanly removes every background job registered for the current repository from the operating system's scheduler.