Merge branch 'ab/gc-reflog'
authorJunio C Hamano <gitster@pobox.com>
Thu, 25 Apr 2019 07:41:14 +0000 (16:41 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 25 Apr 2019 07:41:14 +0000 (16:41 +0900)
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

builtin/gc.c
t/t1410-reflog.sh
t/t6500-gc.sh
index 020f725acc40f413c49f812ea0e6aac0153d097c..8943bcc300d4a2ce6786857908e189c374373906 100644 (file)
@@ -116,6 +116,19 @@ static void process_log_file_on_signal(int 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)
 {
        const char *value;
@@ -127,6 +140,10 @@ static void gc_config(void)
                        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.aggressivedepth", &aggressive_depth);
        git_config_get_int("gc.auto", &gc_auto_threshold);
@@ -156,9 +173,7 @@ static int too_many_loose_objects(void)
        int auto_threshold;
        int num_loose = 0;
        int needed = 0;
-
-       if (gc_auto_threshold <= 0)
-               return 0;
+       const unsigned hexsz_loose = the_hash_algo->hexsz - 2;
 
        dir = opendir(git_path("objects/17"));
        if (!dir)
@@ -166,8 +181,8 @@ static int too_many_loose_objects(void)
 
        auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256);
        while ((ent = readdir(dir)) != NULL) {
-               if (strspn(ent->d_name, "0123456789abcdef") != 38 ||
-                   ent->d_name[38] != '\0')
+               if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose ||
+                   ent->d_name[hexsz_loose] != '\0')
                        continue;
                if (++num_loose > auto_threshold) {
                        needed = 1;
@@ -491,14 +506,20 @@ static int report_last_gc_error(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))
                die(FAILED_RUN, pack_refs_cmd.argv[0]);
 
        if (prune_reflogs && run_command_v_opt(reflog.argv, RUN_GIT_CMD))
                die(FAILED_RUN, reflog.argv[0]);
-
-       pack_refs = 0;
-       prune_reflogs = 0;
 }
 
 int cmd_gc(int argc, const char **argv, const char *prefix)
index ae8a448e34356034a88fcf0799ef2f53e55f73b8..79f731db37cfa1a9e44fe4b966cbe6a72706ee94 100755 (executable)
@@ -232,25 +232,34 @@ test_expect_success '--expire=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 &&
        test_line_count = 4 output
 '
 
 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 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' '
index 4684d06552ac2eeafff19cfd696fd36d20cef5d4..7411bf7fecd89984c7256668863c9f96bb75efbf 100755 (executable)
@@ -120,6 +120,25 @@ test_expect_success 'gc --quiet' '
        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 () {
        # We read stdout from gc for the side effect of waiting until the
        # background gc process exits, closing its fd 9.  Furthermore, the