[PATCH v2 0/2] builtin/maintenance: improve heuristic for "rerere gc"
From: Patrick Steinhardt <hidden>
Date: 2026-09-04 07:03:28
Hi, as reported and discussed in [1]. Thanks! Changes in v2: - Restore `prune_one()`. - Handle "maintenance.rerere-gc.auto" values explicitly. - Rename `rerere_gc_estimate()` to `rerere_gc_needed()`. - Link to v1: https://patch.msgid.link/20260903-b4-pks-maintenance-rerere-gc-heuristic-v1-0-9929c45a9788@pks.im Patrick [1]: [ref] --- Patrick Steinhardt (2): rerere: extract logic to determine whether entries are stale builtin/maintenance: improve heuristic for "rerere gc" Documentation/config/maintenance.adoc | 8 +-- builtin/gc.c | 28 +++-------- rerere.c | 94 ++++++++++++++++++++++++++++++----- rerere.h | 6 +++ t/t7900-maintenance.sh | 61 +++++++++++++++++------ 5 files changed, 144 insertions(+), 53 deletions(-) Range-diff versus v1: 1: 343dbf1c0c ! 1: 1b0b7a7b9a rerere: extract logic to determine whether entries are stale @@ rerere.c: static void unlink_rr_item(struct rerere_id *id) cutoff = cutoff_noresolve; } - if (then < cutoff) -- unlink_rr_item(id); + + return then < cutoff; ++} ++ ++static void prune_one(struct rerere_id *id, ++ timestamp_t cutoff_resolve, timestamp_t cutoff_noresolve) ++{ ++ if (rerere_id_is_stale(id, cutoff_resolve, cutoff_noresolve)) + unlink_rr_item(id); } - /* Does the basename in "path" look plausibly like an rr-cache entry? */ @@ rerere.c: void rerere_gc(struct repository *r, struct string_list *rr) DIR *dir; struct dirent *e; @@ rerere.c: void rerere_gc(struct repository *r, struct string_list *rr) repo_config(the_repository, git_default_config, NULL); dir = opendir(repo_git_path_replace(the_repository, &buf, "rr-cache")); if (!dir) -@@ rerere.c: void rerere_gc(struct repository *r, struct string_list *rr) - for (id.variant = 0, id.collection = rr_dir; - id.variant < id.collection->status_nr; - id.variant++) { -- prune_one(&id, cutoff_resolve, cutoff_noresolve); -+ if (rerere_id_is_stale(&id, cutoff_resolve, cutoff_noresolve)) -+ unlink_rr_item(&id); - if (id.collection->status[id.variant]) - now_empty = 0; - } 2: c8a52f0663 ! 2: 1ceb798cdf builtin/maintenance: improve heuristic for "rerere gc" @@ builtin/gc.c: static int maintenance_task_rerere_gc(struct maintenance_run_opts - if (!dir) - goto out; - should_gc = !!readdir_skip_dot_and_dotdot(dir); -+ if (limit <= 0) -+ return limit < 0; ++ if (!limit) ++ return 0; /* never prune */ ++ if (limit < 0) ++ return 1; /* always prune */ -out: - strbuf_release(&path); - if (dir) - closedir(dir); - return should_gc; -+ return rerere_gc_estimate(the_repository, limit) >= (size_t)limit; ++ return rerere_gc_needed(the_repository, (size_t)limit); } #define OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, aggressive) \ @@ rerere.c: static int is_rr_cache_dirname(const char *path) return !parse_oid_hex(path, &oid, &end) && !*end; } -+size_t rerere_gc_estimate(struct repository *r, size_t limit) ++bool rerere_gc_needed(struct repository *r, size_t limit) +{ + timestamp_t cutoff_resolve, cutoff_noresolve; + struct strbuf buf = STRBUF_INIT; ++ bool needed = false; + struct dirent *e; + size_t count = 0; + DIR *dir; @@ rerere.c: static int is_rr_cache_dirname(const char *path) + if (rerere_id_is_stale(&id, cutoff_resolve, + cutoff_noresolve)) { + count += 256; -+ if (count >= limit) ++ if (count >= limit) { ++ needed = true; + goto out; ++ } + } + } + } @@ rerere.c: static int is_rr_cache_dirname(const char *path) + closedir(dir); + free_rerere_dirs(); + strbuf_release(&buf); -+ return count; ++ return needed; +} + void rerere_gc(struct repository *r, struct string_list *rr) @@ rerere.h: int rerere_remaining(struct repository *, struct string_list *); void rerere_gc(struct repository *, struct string_list *); +/* -+ * Estimate the number of stale entries that a run of "git rerere gc" -+ * would prune. ++ * Check whether garbage collection for rerere entries is needed, which is ++ * the case when there's at least `limit` stale entries that would be pruned. + */ -+size_t rerere_gc_estimate(struct repository *r, size_t limit); ++bool rerere_gc_needed(struct repository *r, size_t limit); + #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \ N_("update the index with reused conflict resolution if possible")) --- base-commit: 3cb9185f65410273787f74333cc027d2ea5daada change-id: 20260903-b4-pks-maintenance-rerere-gc-heuristic-763b0a9a50d2