Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger `git prune` automatically on `git pull`?

Tags:

git

On my local copy of a company-wide repository (where I make lots of short-lived branches and git rebase very very often, and where many other people are also pushing short-lived branches to the origin I'm pulling from), I regularly have the following conversation with git.

(env)$ git pull
remote: Counting objects: 382, done.
remote: Compressing objects: 100% (247/247), done.
remote: Total 382 (delta 182), reused 62 (delta 62), pack-reused 73
Receiving objects: 100% (382/382), 228.63 KiB | 0 bytes/s, done.
Resolving deltas: 100% (232/232), completed with 15 local objects.
From github.com:anon/anony2
   aee962f..055a717  master     -> origin/master
   [...]
Auto packing the repository in background for optimum performance.
See "git help gc" for manual housekeeping.
error: The last gc run reported the following. Please correct the root cause
and remove .git/gc.log.
Automatic cleanup will not be performed until the file is removed.

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

Updating aee962f..055a717
Fast-forward
Auto packing the repository in background for optimum performance.
See "git help gc" for manual housekeeping.
error: The last gc run reported the following. Please correct the root cause
and remove .git/gc.log.
Automatic cleanup will not be performed until the file is removed.

warning: There are too many unreachable loose objects; run 'git prune' to remove them.
 [...]
 9 files changed, 128 insertions(+), 95 deletions(-)
(env)$ git prune
Checking connectivity: 772524, done.
(env)$ rm .git/gc.log
(env)$

```

That is: I say git pull; git spews a bunch of stuff at me, helpfully including two commands I need to run; I run those commands; then I can continue with my work.

It would be awesome if git would just run those commands for me, instead of forcing me to cut-and-paste them. I get that this wouldn't be the default behavior of git pull, but it seems like the sort of thing that probably exists as an option I could add to my .gitconfig. Does such a thing exist?

like image 414
Quuxplusone Avatar asked Jan 20 '17 19:01

Quuxplusone


1 Answers

The problem is most likely that you generate loose objects fast enough to, in effect, overrun the default git gc protection time of 2.weeks.ago:

--prune=<date>
       Prune loose objects older than date (default is 2 weeks ago, overridable by the config variable gc.pruneExpire). --prune=all prunes loose objects regardless of their age (do not use --prune=all unless you know exactly what you are doing. Unless the repository is quiescent, you will lose newly created objects that haven't been anchored with the refs and end up corrupting your repository). --prune is on by default.

What's happening here is that git gc is automatically, in the background, pruning loose objects with its default mechanism, which is to run git prune --expire=2.weeks.ago (or whatever you have configured for gc.pruneExpire). But this leaves behind enough loose objects that git gc thinks it has done a poor job of pruning.

Running git prune with no expire time (as in manual git prune), or with --prune=all in git gc, removes all loose objects. This is only safe if no other Git command is running. Since git gc --auto runs in the background, it needs a safety margin—but two weeks is too much for your usage.

If you're confident that your various Git commands will complete in just one week, or even perhaps a day, :-) you can configure gc.pruneExpire to 1.week.ago or 1.day.ago to make it prune more aggressively. Unless you're generating a really huge number of loose objects, that will probably do the trick:

$ git config gc.pruneExpire 3.days.ago

Note that when set this way, you change only the setting for this repository, and override any more global setting. Or:

$ git config --global gc.pruneExpire 1.week.ago

This sets your personal (user-global) default to one week, instead of two (but this will be overridden by the repo-specific "three days" setting, if that's set).


I noticed while checking all this that extensions.preciousObjects is not documented. (As with all config variables, this may be spelled with arbitrary upper and lower case mixtures.) It was added in Git 2.7.0 and lets you prevent all automatic pruning of objects, which you might want if you set up a shared repository. (It's tricky to use and probably not something any casual user should ever set.)

like image 87
torek Avatar answered Sep 27 '22 19:09

torek