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

[PATCH 6/7] rerere: bundle global state into a struct

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

The state of the rerere subsystem is tracked across several global variables. Move them into a struct so that we can easily de-globalize the state.

Note that the lock timeout is only ever used in `setup_rerere()`. So instead of moving it into the new struct, we just keep it as a local variable.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 rerere.c | 44 +++++++++++++++++++-------------------------
 rerere.h | 11 +++++++++++
 2 files changed, 30 insertions(+), 25 deletions(-)
diff --git a/rerere.c b/rerere.c
index 366797ab7e..23bcb8bc31 100644
--- a/rerere.c
+++ b/rerere.c
@@ -21,17 +21,15 @@
 #include "odb.h"
 #include "strmap.h"
 
+static struct rerere_cache cache = {
+	.dirs = STRMAP_INIT,
+};
+
 #define RESOLVED 0
 #define PUNTED 1
 #define THREE_STAGED 2
 void *RERERE_RESOLVED = &RERERE_RESOLVED;
 
-/* automatically update cleanly resolved paths to the index */
-static int rerere_autoupdate;
-
-/* how long to wait for MERGE_RR.lock, in milliseconds */
-static int rerere_lock_timeout_ms = 1000;
-
 #define RR_HAS_POSTIMAGE 1
 #define RR_HAS_PREIMAGE 2
 struct rerere_dir {
@@ -40,19 +38,17 @@ struct rerere_dir {
 	char name[FLEX_ARRAY];
 };
 
-static struct strmap rerere_dirs = STRMAP_INIT;
-
 static void free_rerere_dirs(void)
 {
 	struct hashmap_iter iter;
 	struct strmap_entry *ent;
 
-	strmap_for_each_entry(&rerere_dirs, &iter, ent) {
+	strmap_for_each_entry(&cache.dirs, &iter, ent) {
 		struct rerere_dir *rr_dir = ent->value;
 		free(rr_dir->status);
 		free(rr_dir);
 	}
-	strmap_clear(&rerere_dirs, 0);
+	strmap_clear(&cache.dirs, 0);
 }
 
 static void free_rerere_id(struct string_list_item *item)
@@ -154,13 +150,13 @@ static struct rerere_dir *find_rerere_dir(struct repository *r, const char *hex)
 {
 	struct rerere_dir *rr_dir;
 
-	rr_dir = strmap_get(&rerere_dirs, hex);
+	rr_dir = strmap_get(&cache.dirs, hex);
 	if (!rr_dir) {
 		FLEX_ALLOC_STR(rr_dir, name, hex);
 		rr_dir->status = NULL;
 		rr_dir->status_nr = 0;
 		rr_dir->status_alloc = 0;
-		strmap_put(&rerere_dirs, hex, rr_dir);
+		strmap_put(&cache.dirs, hex, rr_dir);
 
 		scan_rerere_dir(r, rr_dir);
 	}
@@ -241,8 +237,6 @@ static void read_rr(struct repository *r, struct string_list *rr)
 	fclose(in);
 }
 
-static struct lock_file write_lock;
-
 static int write_rr(struct string_list *rr, int out_fd)
 {
 	int i;
@@ -270,7 +264,7 @@ static int write_rr(struct string_list *rr, int out_fd)
 
 		strbuf_release(&buf);
 	}
-	if (commit_lock_file(&write_lock) != 0)
+	if (commit_lock_file(&cache.write_lock) != 0)
 		die(_("unable to write rerere record"));
 	return 0;
 }
@@ -785,7 +779,7 @@ static void do_rerere_one_path(struct index_state *istate,
 		if (0 <= id->variant && id->variant != variant)
 			remove_variant(istate->repo, id);
 
-		if (rerere_autoupdate)
+		if (cache.autoupdate)
 			string_list_insert(update, path);
 		else
 			fprintf_ln(stderr,
@@ -902,27 +896,27 @@ static int is_rerere_enabled(struct repository *r)
 
 int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
 {
+	int lock_timeout_ms = 1000;
 	int fd;
 
 	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);
+	repo_config_get_bool(r, "rerere.autoupdate", &cache.autoupdate);
+	repo_config_get_int(r, "rerere.locktimeout", &lock_timeout_ms);
 
 	if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE))
-		rerere_autoupdate = !!(flags & RERERE_AUTOUPDATE);
+		cache.autoupdate = !!(flags & RERERE_AUTOUPDATE);
 	if ((flags & RERERE_READONLY) && (flags & RERERE_NOWAIT))
 		BUG("RERERE_NOWAIT does not apply with RERERE_READONLY");
 	if (flags & RERERE_READONLY) {
 		fd = 0;
 	} else {
 		int lock_flags = LOCK_DIE_ON_ERROR;
-		int timeout_ms = rerere_lock_timeout_ms;
 
 		if (flags & RERERE_NOWAIT) {
 			lock_flags = 0;
-			timeout_ms = 0;
+			lock_timeout_ms = 0;
 		}
 
 		/*
@@ -930,9 +924,9 @@ int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
 		 * "git rerere gc" while it prunes rr-cache, so by default
 		 * wait for it instead of dying right away.
 		 */
-		fd = repo_hold_lock_file_for_update_timeout(r, &write_lock,
+		fd = repo_hold_lock_file_for_update_timeout(r, &cache.write_lock,
 							    git_path_merge_rr(r),
-							    lock_flags, timeout_ms);
+							    lock_flags, lock_timeout_ms);
 		if (fd < 0)
 			return -1;
 	}
@@ -1369,7 +1363,7 @@ void rerere_gc(struct repository *r, struct string_list *rr, int flags)
 					    "rr-cache/%s", to_remove.items[i].string));
 
 	string_list_clear(&to_remove, 0);
-	rollback_lock_file(&write_lock);
+	rollback_lock_file(&cache.write_lock);
 	strbuf_release(&buf);
 }
 
@@ -1399,5 +1393,5 @@ void rerere_clear(struct repository *r, struct string_list *merge_rr)
 		strbuf_release(&buf);
 	}
 	unlink_or_warn(git_path_merge_rr(r));
-	rollback_lock_file(&write_lock);
+	rollback_lock_file(&cache.write_lock);
 }
diff --git a/rerere.h b/rerere.h
index ee8d97917d..570667d866 100644
--- a/rerere.h
+++ b/rerere.h
@@ -2,7 +2,9 @@
 #define RERERE_H
 
 #include "gettext.h"
+#include "lockfile.h"
 #include "string-list.h"
+#include "strmap.h"
 
 struct pathspec;
 struct repository;
@@ -20,6 +22,15 @@ struct repository;
  */
 extern void *RERERE_RESOLVED;
 
+struct rerere_cache {
+	/* Automatically update cleanly resolved paths to the index. */
+	int autoupdate;
+
+	struct strmap dirs;
+
+	struct lock_file write_lock;
+};
+
 struct rerere_dir;
 struct rerere_id {
 	struct rerere_dir *collection;
-- 
2.56.0.307.g5fe7bd680c.dirty
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 7 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.