Merge branch 'ab/gc-reflog'
Fix various glitches in "git gc" around reflog handling. * ab/gc-reflog: gc: handle & check gc.reflogExpire config reflog tests: assert lack of early exit with expiry="never" reflog tests: test for the "points nowhere" warning reflog tests: make use of "test_config" idiom gc: refactor a "call me once" pattern gc: convert to using the_hash_algo gc: remove redundant check for gc_auto_threshold
This commit is contained in:
37
builtin/gc.c
37
builtin/gc.c
@ -116,6 +116,19 @@ static void process_log_file_on_signal(int signo)
|
|||||||
raise(signo);
|
raise(signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int gc_config_is_timestamp_never(const char *var)
|
||||||
|
{
|
||||||
|
const char *value;
|
||||||
|
timestamp_t expire;
|
||||||
|
|
||||||
|
if (!git_config_get_value(var, &value) && value) {
|
||||||
|
if (parse_expiry_date(value, &expire))
|
||||||
|
die(_("failed to parse '%s' value '%s'"), var, value);
|
||||||
|
return expire == 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void gc_config(void)
|
static void gc_config(void)
|
||||||
{
|
{
|
||||||
const char *value;
|
const char *value;
|
||||||
@ -127,6 +140,10 @@ static void gc_config(void)
|
|||||||
pack_refs = git_config_bool("gc.packrefs", value);
|
pack_refs = git_config_bool("gc.packrefs", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gc_config_is_timestamp_never("gc.reflogexpire") &&
|
||||||
|
gc_config_is_timestamp_never("gc.reflogexpireunreachable"))
|
||||||
|
prune_reflogs = 0;
|
||||||
|
|
||||||
git_config_get_int("gc.aggressivewindow", &aggressive_window);
|
git_config_get_int("gc.aggressivewindow", &aggressive_window);
|
||||||
git_config_get_int("gc.aggressivedepth", &aggressive_depth);
|
git_config_get_int("gc.aggressivedepth", &aggressive_depth);
|
||||||
git_config_get_int("gc.auto", &gc_auto_threshold);
|
git_config_get_int("gc.auto", &gc_auto_threshold);
|
||||||
@ -156,9 +173,7 @@ static int too_many_loose_objects(void)
|
|||||||
int auto_threshold;
|
int auto_threshold;
|
||||||
int num_loose = 0;
|
int num_loose = 0;
|
||||||
int needed = 0;
|
int needed = 0;
|
||||||
|
const unsigned hexsz_loose = the_hash_algo->hexsz - 2;
|
||||||
if (gc_auto_threshold <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dir = opendir(git_path("objects/17"));
|
dir = opendir(git_path("objects/17"));
|
||||||
if (!dir)
|
if (!dir)
|
||||||
@ -166,8 +181,8 @@ static int too_many_loose_objects(void)
|
|||||||
|
|
||||||
auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256);
|
auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256);
|
||||||
while ((ent = readdir(dir)) != NULL) {
|
while ((ent = readdir(dir)) != NULL) {
|
||||||
if (strspn(ent->d_name, "0123456789abcdef") != 38 ||
|
if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose ||
|
||||||
ent->d_name[38] != '\0')
|
ent->d_name[hexsz_loose] != '\0')
|
||||||
continue;
|
continue;
|
||||||
if (++num_loose > auto_threshold) {
|
if (++num_loose > auto_threshold) {
|
||||||
needed = 1;
|
needed = 1;
|
||||||
@ -491,14 +506,20 @@ done:
|
|||||||
|
|
||||||
static void gc_before_repack(void)
|
static void gc_before_repack(void)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* We may be called twice, as both the pre- and
|
||||||
|
* post-daemonized phases will call us, but running these
|
||||||
|
* commands more than once is pointless and wasteful.
|
||||||
|
*/
|
||||||
|
static int done = 0;
|
||||||
|
if (done++)
|
||||||
|
return;
|
||||||
|
|
||||||
if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
|
if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
|
||||||
die(FAILED_RUN, pack_refs_cmd.argv[0]);
|
die(FAILED_RUN, pack_refs_cmd.argv[0]);
|
||||||
|
|
||||||
if (prune_reflogs && run_command_v_opt(reflog.argv, RUN_GIT_CMD))
|
if (prune_reflogs && run_command_v_opt(reflog.argv, RUN_GIT_CMD))
|
||||||
die(FAILED_RUN, reflog.argv[0]);
|
die(FAILED_RUN, reflog.argv[0]);
|
||||||
|
|
||||||
pack_refs = 0;
|
|
||||||
prune_reflogs = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_gc(int argc, const char **argv, const char *prefix)
|
int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
|
@ -232,25 +232,34 @@ test_expect_success '--expire=never' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'gc.reflogexpire=never' '
|
test_expect_success 'gc.reflogexpire=never' '
|
||||||
|
test_config gc.reflogexpire never &&
|
||||||
|
test_config gc.reflogexpireunreachable never &&
|
||||||
|
|
||||||
|
git reflog expire --verbose --all >output &&
|
||||||
|
test_line_count = 9 output &&
|
||||||
|
|
||||||
git config gc.reflogexpire never &&
|
|
||||||
git config gc.reflogexpireunreachable never &&
|
|
||||||
git reflog expire --verbose --all &&
|
|
||||||
git reflog refs/heads/master >output &&
|
git reflog refs/heads/master >output &&
|
||||||
test_line_count = 4 output
|
test_line_count = 4 output
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'gc.reflogexpire=false' '
|
test_expect_success 'gc.reflogexpire=false' '
|
||||||
|
test_config gc.reflogexpire false &&
|
||||||
|
test_config gc.reflogexpireunreachable false &&
|
||||||
|
|
||||||
git config gc.reflogexpire false &&
|
|
||||||
git config gc.reflogexpireunreachable false &&
|
|
||||||
git reflog expire --verbose --all &&
|
git reflog expire --verbose --all &&
|
||||||
git reflog refs/heads/master >output &&
|
git reflog refs/heads/master >output &&
|
||||||
test_line_count = 4 output &&
|
test_line_count = 4 output
|
||||||
|
|
||||||
git config --unset gc.reflogexpire &&
|
'
|
||||||
git config --unset gc.reflogexpireunreachable
|
|
||||||
|
|
||||||
|
test_expect_success 'git reflog expire unknown reference' '
|
||||||
|
test_config gc.reflogexpire never &&
|
||||||
|
test_config gc.reflogexpireunreachable never &&
|
||||||
|
|
||||||
|
test_must_fail git reflog expire master@{123} 2>stderr &&
|
||||||
|
test_i18ngrep "points nowhere" stderr &&
|
||||||
|
test_must_fail git reflog expire does-not-exist 2>stderr &&
|
||||||
|
test_i18ngrep "points nowhere" stderr
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'checkout should not delete log for packed ref' '
|
test_expect_success 'checkout should not delete log for packed ref' '
|
||||||
|
@ -120,6 +120,25 @@ test_expect_success 'gc --quiet' '
|
|||||||
test_must_be_empty stderr
|
test_must_be_empty stderr
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'gc.reflogExpire{Unreachable,}=never skips "expire" via "gc"' '
|
||||||
|
test_config gc.reflogExpire never &&
|
||||||
|
test_config gc.reflogExpireUnreachable never &&
|
||||||
|
|
||||||
|
GIT_TRACE=$(pwd)/trace.out git gc &&
|
||||||
|
|
||||||
|
# Check that git-pack-refs is run as a sanity check (done via
|
||||||
|
# gc_before_repack()) but that git-expire is not.
|
||||||
|
grep -E "^trace: (built-in|exec|run_command): git pack-refs --" trace.out &&
|
||||||
|
! grep -E "^trace: (built-in|exec|run_command): git reflog expire --" trace.out
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'one of gc.reflogExpire{Unreachable,}=never does not skip "expire" via "gc"' '
|
||||||
|
>trace.out &&
|
||||||
|
test_config gc.reflogExpire never &&
|
||||||
|
GIT_TRACE=$(pwd)/trace.out git gc &&
|
||||||
|
grep -E "^trace: (built-in|exec|run_command): git reflog expire --" trace.out
|
||||||
|
'
|
||||||
|
|
||||||
run_and_wait_for_auto_gc () {
|
run_and_wait_for_auto_gc () {
|
||||||
# We read stdout from gc for the side effect of waiting until the
|
# We read stdout from gc for the side effect of waiting until the
|
||||||
# background gc process exits, closing its fd 9. Furthermore, the
|
# background gc process exits, closing its fd 9. Furthermore, the
|
||||||
|
Reference in New Issue
Block a user