How to Prevent Garbage Collection in GIT?

Another approach, recently documented in:
Documentation/config: mention "now" and "never" for 'expire' settings

In addition to approxidate-style values ("2.months.ago", "yesterday"), consumers of 'gc.*expire*' configuration variables also accept and respect 'now' ("do it immediately") and 'never' ("suppress entirely").

See commit 8cc8816 (28 Jul 2015) by Eric Sunshine (sunshineco).
Suggested-by: Michael Haggerty (mhagger).
(Merged by Junio C Hamano -- gitster -- in commit 8cc8816, 28 Jul 2015)

That means this would also prevent any gc:

git config --global gc.pruneExpire never
git config --global gc.reflogExpire never

However, you may encounter (if you use configuration value never):

warning: There are too many unreachable loose objects; run 'git prune' to remove them. 

In that case, you probably want to set gc.auto to some high value (e.g. 100000) if you really do not want to expire anything. That will silence the warning but may cause garbage collection to be less effective overall so this should be considered as a workaround, not a real fix. See Is it possible to get `git gc` to pack reflog objects? for additional details.


To avoid git gc only in background, set, as in nornagon's answer:

git config --global gc.autodetach false

That comes from Git v2.14.0-rc1 commit c45af94 (11 Jul 2017) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 764046f, 18 Jul 2017)

We run an early part of "git gc" that deals with refs before daemonising (and not under lock) even when running a background auto-gc, which caused multiple gc processes attempting to run the early part at the same time.
This is now prevented by running the early part also under the GC lock.

gc: run pre-detach operations under lock

We normally try to avoid having two auto-gc operations run at the same time, because it wastes resources.
This was done long ago in 64a99eb (gc: reject if another gc is running, unless --force is given, 2013-08-08, v1.8.5-rc0).

When we do a detached auto-gc, we run the ref-related commands before detaching, to avoid confusing lock contention.
This was done by 62aad18 (gc --auto: do not lock refs in the background, 2014-05-25, Git v2.0.1).

These two features do not interact well.
The pre-detach operations are run before we check the gc.pid lock, meaning that on a busy repository we may run many of them concurrently.
Ideally we'd take the lock before spawning any operations, and hold it for the duration of the program.

This is tricky, though, with the way the pid-file interacts with the daemonize() process.
Other processes will check that the pid recorded in the pid-file still exists. But detaching causes us to fork and continue running under a new pid.
So if we take the lock before detaching, the pid-file will have a bogus pid in it. We'd have to go back and update it with the new pid after detaching.
We'd also have to play some tricks with the tempfile subsystem to tweak the "owner" field, so that the parent process does not clean it up on exit, but the child process does.

Instead, we can do something a bit simpler: take the lock only for the duration of the pre-detach work, then detach, then take it again for the post-detach work.

Technically, this means that the post-detach lock could lose to another process doing pre-detach work.
But in the long run this works out.

That second process would then follow-up by doing post-detach work. Unless it was in turn blocked by a third process doing pre-detach work, and so on.

This could in theory go on indefinitely, as the pre-detach work does not repack, and so need_to_gc() will continue to trigger.
But in each round we are racing between the pre- and post-detach locks.
Eventually, one of the post-detach locks will win the race and complete the full gc.

So in the worst case, we may racily repeat the pre-detach work, but we would never do so simultaneously (it would happen via a sequence of serialized race-wins).


From the very same page you just linked to:

Some git commands may automatically run git gc; see the --auto flag below for details. If you know what you’re doing and all you want is to disable this behavior permanently without further considerations, just do:

$ git config --global gc.auto 0