Browse Source

gc: call "prune --expire 2.weeks.ago" by default

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>
maint
Johannes Schindelin 17 years ago committed by Junio C Hamano
parent
commit
25ee9731c1
  1. 4
      Documentation/config.txt
  2. 17
      Documentation/git-gc.txt
  3. 17
      builtin-gc.c
  4. 18
      t/t1410-reflog.sh
  5. 49
      t/t5304-prune.sh

4
Documentation/config.txt

@ -590,6 +590,10 @@ gc.packrefs:: @@ -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.

17
Documentation/git-gc.txt

@ -8,7 +8,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository @@ -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
-----------
@ -25,17 +25,6 @@ operating performance. Some git commands may automatically run @@ -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
@ -104,6 +93,10 @@ the value, the more time is spent optimizing the delta compression. See @@ -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]

17
builtin-gc.c

@ -26,12 +26,13 @@ static int pack_refs = 1; @@ -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)
@ -55,6 +56,17 @@ static int gc_config(const char *var, const char *value) @@ -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);
}

@ -234,7 +246,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix) @@ -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))

18
t/t1410-reflog.sh

@ -202,22 +202,4 @@ test_expect_success 'delete' ' @@ -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
t/t5304-prune.sh

@ -29,4 +29,53 @@ test_expect_success 'prune stale packs' ' @@ -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

Loading…
Cancel
Save