[PATCH v2 0/2] builtin/maintenance: improve heuristic for "rerere gc"
- From
Patrick Steinhardt <ps@pks.im>
- Date
- Sep 4, 2026, 07:03 UTC
- Message-ID
- <20260904-b4-pks-maintenance-rerere-gc-heuristic-v2-0-b1691121fe1c@pks.im>
- In-Reply-To
- <20260903-b4-pks-maintenance-rerere-gc-heuristic-v1-0-9929c45a9788@pks.im>
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]: <pull.2214.git.1788337897490.gitgitgadget@gmail.com>
---
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