git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 4/7] rerere: cache result of `is_rerere_enabled()`

From
Patrick Steinhardt <ps@pks.im>
Date
Oct 23, 2026, 12:50 UTC
Message-ID
<20261023-pks-rerere-wo-the-repository-v1-4-b6ac0c2e4b81@pks.im>
In-Reply-To
<20261023-pks-rerere-wo-the-repository-v1-0-b6ac0c2e4b81@pks.im>

The function `setup_rerere()` reads the rerere configuration and then figures out whether the rerere cache is enabled after all, either because it has been explicitly enabled or because it's implicitly enabled and ".git/rr-cache" exists. Whether the cache is enabled will not change in a single process though, so it does not make sense to reevaluate these conditions every single time `setup_rerere()` is called.

Adapt the function to instead cache the status of the rerere cache via a new `struct repository::rerere_cache_enabled` member. This allows us to get rid of the `GIT_PATH_FUNC()`, which caches the path to the rerere cache directory. But now that we already cache the enabled state in the first place it becomes moot to cache the path, as well.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 repository.c |  1 +
 repository.h |  6 ++++++
 rerere.c     | 43 +++++++++++++++++++++++--------------------
 3 files changed, 30 insertions(+), 20 deletions(-)
diff --git a/repository.c b/repository.c
index e584d6c405..f51699a6dd 100644
--- a/repository.c
+++ b/repository.c
@@ -76,6 +76,7 @@ void initialize_repository(struct repository *repo)
 	repo->bare_cfg = -1;
 	repo->fetch_if_missing = 1;
 	repo_config_values_init(&repo->config_values_private_);
+	repo->rerere_cache_enabled = -1;
 
 	/*
 	 * When a command runs inside a repository, it learns what
diff --git a/repository.h b/repository.h
index 91b1f57db7..86795b6946 100644
--- a/repository.h
+++ b/repository.h
@@ -185,6 +185,12 @@ struct repository {
 	/* True if commit-graph has been disabled within this process. */
 	int commit_graph_disabled;
 
+	/*
+	 * Indicates whether the rerere-cache has been enabled. -1 (the default
+	 * value) causes us to perform auto-detection via ".git/rr-cache".
+	 */
+	int rerere_cache_enabled;
+
 	/*
 	 * Controls whether the repository should lazily fetch missing
 	 * objects from promisor remotes. Defaults to 1.
diff --git a/rerere.c b/rerere.c
index 56b6ef547b..8fa921fc8f 100644
--- a/rerere.c
+++ b/rerere.c
@@ -27,9 +27,6 @@
 #define THREE_STAGED 2
 void *RERERE_RESOLVED = &RERERE_RESOLVED;
 
-/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
-static int rerere_enabled = -1;
-
 /* automatically update cleanly resolved paths to the index */
 static int rerere_autoupdate;
 
@@ -873,40 +870,46 @@ static int do_plain_rerere(struct repository *r,
 	return write_rr(rr, fd);
 }
 
-static void git_rerere_config(struct repository *r)
-{
-	repo_config_get_bool(r, "rerere.enabled", &rerere_enabled);
-	repo_config_get_bool(r, "rerere.autoupdate", &rerere_autoupdate);
-	repo_config_get_int(r, "rerere.locktimeout", &rerere_lock_timeout_ms);
-}
-
-static GIT_PATH_FUNC(git_path_rr_cache, "rr-cache")
-
 static int is_rerere_enabled(struct repository *r)
 {
 	int rr_cache_exists;
+	char *dir;
 
-	if (!rerere_enabled)
+	if (r->rerere_cache_enabled != -1)
+		return r->rerere_cache_enabled;
+
+	repo_config_get_bool(r, "rerere.enabled", &r->rerere_cache_enabled);
+	if (!r->rerere_cache_enabled)
 		return 0;
 
-	rr_cache_exists = is_directory(git_path_rr_cache());
-	if (rerere_enabled < 0)
-		return rr_cache_exists;
+	dir = repo_git_path(r, "rr-cache");
+
+	rr_cache_exists = is_directory(dir);
+	if (r->rerere_cache_enabled < 0) {
+		r->rerere_cache_enabled = rr_cache_exists;
+		goto out;
+	}
 
 	if (!rr_cache_exists &&
-	    safe_create_dir_in_gitdir(r, git_path_rr_cache()))
-		die(_("could not create directory '%s'"), git_path_rr_cache());
-	return 1;
+	    safe_create_dir_in_gitdir(r, dir))
+		die(_("could not create directory '%s'"), dir);
+	r->rerere_cache_enabled = 1;
+
+out:
+	free(dir);
+	return r->rerere_cache_enabled;
 }
 
 int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
 {
 	int fd;
 
-	git_rerere_config(r);
 	if (!is_rerere_enabled(r))
 		return -1;
 
+	repo_config_get_bool(r, "rerere.autoupdate", &rerere_autoupdate);
+	repo_config_get_int(r, "rerere.locktimeout", &rerere_lock_timeout_ms);
+
 	if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE))
 		rerere_autoupdate = !!(flags & RERERE_AUTOUPDATE);
 	if ((flags & RERERE_READONLY) && (flags & RERERE_NOWAIT))
-- 
2.56.0.307.g5fe7bd680c.dirty
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 5 of 10 in “rerere: remove global state”
  1. 0/7 rerere: remove global statePatrick Steinhardt, Oct 23, 2026
  2. 1/7 rerere: stop using `the_repository` in `rerere_path()`Patrick Steinhardt, Oct 23, 2026
  3. 2/7 rerere: stop using `the_repository` in internal helpersPatrick Steinhardt, Oct 23, 2026
  4. 3/7 rerere: remove redundant calls to `repo_config()`Patrick Steinhardt, Oct 23, 2026
  5. 4/7 rerere: cache result of `is_rerere_enabled()`Patrick Steinhardt, Oct 23, 2026
  6. 5/7 rerere: stop using `the_repository`Patrick Steinhardt, Oct 23, 2026
  7. 6/7 rerere: bundle global state into a structPatrick Steinhardt, Oct 23, 2026
  8. 7/7 rerere: get rid of global rerere cache statePatrick Steinhardt, Oct 23, 2026
  9. Junio C HamanoOct 23, 2026
  10. Patrick SteinhardtOct 26, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.