Skip to content

Commit

Permalink
gc: call "prune --expire 2.weeks.ago" by default
Browse files Browse the repository at this point in the history
The only reason we did not call "prune" in git-gc was that it is an
inherently dangerous operation: if there is a commit going on, you will
prune loose objects that were just created, and are, in fact, needed by the
commit object just about to be created.

Since it is dangerous, we told users so.  That led to many users not even
daring to run it when it was actually safe. Besides, they are users, and
should not have to remember such details as when to call git-gc with
--prune, or to call git-prune directly.

Of course, the consequence was that "git gc --auto" gets triggered much
more often than we would like, since unreferenced loose objects (such as
left-overs from a rebase or a reset --hard) were never pruned.

Alas, git-prune recently learnt the option --expire <minimum-age>, which
makes it a much safer operation.  This allows us to call prune from git-gc,
with a grace period of 2 weeks for the unreferenced loose objects (this
value was determined in a discussion on the git list as a safe one).

If you want to override this grace period, just set the config variable
gc.pruneExpire to a different value; an example would be

	[gc]
		pruneExpire = 6.months.ago

or even "never", if you feel really paranoid.

Note that this new behaviour makes "--prune" be a no-op.

While adding a test to t5304-prune.sh (since it really tests the implicit
call to "prune"), also the original test for "prune --expire" was moved
there from t1410-reflog.sh, where it did not belong.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
  • Loading branch information
Johannes Schindelin authored and Junio C Hamano committed Mar 13, 2008
1 parent dbdbfec commit 25ee973
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 32 deletions.
4 changes: 4 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,10 @@ gc.packrefs::
at some stage, and setting this to `false` will continue to
prevent `git pack-refs` from being run from `git gc`.

gc.pruneexpire::
When `git gc` is run, it will call `prune --expire 2.weeks.ago`.
Override the grace period with this config variable.

gc.reflogexpire::
`git reflog expire` removes reflog entries older than
this time; defaults to 90 days.
Expand Down
17 changes: 5 additions & 12 deletions Documentation/git-gc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository

SYNOPSIS
--------
'git-gc' [--prune] [--aggressive] [--auto] [--quiet]
'git-gc' [--aggressive] [--auto] [--quiet]

DESCRIPTION
-----------
Expand All @@ -25,17 +25,6 @@ operating performance. Some git commands may automatically run
OPTIONS
-------

--prune::
Usually `git-gc` packs refs, expires old reflog entries,
packs loose objects,
and removes old 'rerere' records. Removal
of unreferenced loose objects is an unsafe operation
while other git operations are in progress, so it is not
done by default. Pass this option if you want it, and only
when you know nobody else is creating new objects in the
repository at the same time (e.g. never use this option
in a cron script).

--aggressive::
Usually 'git-gc' runs very quickly while providing good disk
space utilization and performance. This option will cause
Expand Down Expand Up @@ -104,6 +93,10 @@ the value, the more time is spent optimizing the delta compression. See
the documentation for the --window' option in linkgit:git-repack[1] for
more details. This defaults to 10.

The optional configuration variable 'gc.pruneExpire' controls how old
the unreferenced loose objects have to be before they are pruned. The
default is "2 weeks ago".

See Also
--------
linkgit:git-prune[1]
Expand Down
17 changes: 15 additions & 2 deletions builtin-gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ static int pack_refs = 1;
static int aggressive_window = -1;
static int gc_auto_threshold = 6700;
static int gc_auto_pack_limit = 20;
static char *prune_expire = "2.weeks.ago";

#define MAX_ADD 10
static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL};
static const char *argv_prune[] = {"prune", NULL};
static const char *argv_prune[] = {"prune", "--expire", NULL, NULL};
static const char *argv_rerere[] = {"rerere", "gc", NULL};

static int gc_config(const char *var, const char *value)
Expand All @@ -55,6 +56,17 @@ static int gc_config(const char *var, const char *value)
gc_auto_pack_limit = git_config_int(var, value);
return 0;
}
if (!strcmp(var, "gc.pruneexpire")) {
if (!value)
return config_error_nonbool(var);
if (strcmp(value, "now")) {
unsigned long now = approxidate("now");
if (approxidate(value) >= now)
return error("Invalid %s: '%s'", var, value);
}
prune_expire = xstrdup(value);
return 0;
}
return git_default_config(var, value);
}

Expand Down Expand Up @@ -234,7 +246,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
return error(FAILED_RUN, argv_repack[0]);

if (prune && run_command_v_opt(argv_prune, RUN_GIT_CMD))
argv_prune[2] = prune_expire;
if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
return error(FAILED_RUN, argv_prune[0]);

if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
Expand Down
18 changes: 0 additions & 18 deletions t/t1410-reflog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -202,22 +202,4 @@ test_expect_success 'delete' '
'

test_expect_success 'prune --expire' '
before=$(git count-objects | sed "s/ .*//") &&
BLOB=$(echo aleph | git hash-object -w --stdin) &&
BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") &&
test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test -f $BLOB_FILE &&
git reset --hard &&
git prune --expire=1.hour.ago &&
test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test -f $BLOB_FILE &&
test-chmtime -86500 $BLOB_FILE &&
git prune --expire 1.day &&
test $before = $(git count-objects | sed "s/ .*//") &&
! test -f $BLOB_FILE
'

test_done
49 changes: 49 additions & 0 deletions t/t5304-prune.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,53 @@ test_expect_success 'prune stale packs' '
'

test_expect_success 'prune --expire' '
before=$(git count-objects | sed "s/ .*//") &&
BLOB=$(echo aleph | git hash-object -w --stdin) &&
BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") &&
test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test -f $BLOB_FILE &&
git prune --expire=1.hour.ago &&
test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test -f $BLOB_FILE &&
test-chmtime -86500 $BLOB_FILE &&
git prune --expire 1.day &&
test $before = $(git count-objects | sed "s/ .*//") &&
! test -f $BLOB_FILE
'

test_expect_success 'gc: implicit prune --expire' '
before=$(git count-objects | sed "s/ .*//") &&
BLOB=$(echo aleph_0 | git hash-object -w --stdin) &&
BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") &&
test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test -f $BLOB_FILE &&
test-chmtime -$((86400*14-30)) $BLOB_FILE &&
git gc &&
test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test -f $BLOB_FILE &&
test-chmtime -$((86400*14+1)) $BLOB_FILE &&
git gc &&
test $before = $(git count-objects | sed "s/ .*//") &&
! test -f $BLOB_FILE
'

test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' '
git config gc.pruneExpire invalid &&
test_must_fail git gc
'

test_expect_success 'gc: start with ok gc.pruneExpire' '
git config gc.pruneExpire 2.days.ago &&
git gc
'

test_done

0 comments on commit 25ee973

Please sign in to comment.