refs: move parsing of "core.logAllRefUpdates" back into ref stores

In cc42c88945 (refs: extract out reflog config to generic layer, 2026-05-04) we have refactored how we parse "core.logAllRefUpdates" so that it happens in the generic layer. Unfortunately, this has worsened a preexisting issue where we may recurse when creating the reference store because of a chicken-and-egg problem between parsing the configuration and evaluating "onbranch" conditions. Prepare for a fix by essentially reverting that change so that we handle this setting in the respective backends again. The backends are already parsing other configuration anyway, so by moving the logic back in there we can ensure that all backend configuration is parsed the same way. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jun 25, 2026 at 11:20 UTC a9e4ce0aec738ca3047d77f3781159424703a2a3
9 files changed +56 -47
builtin/checkout.c
+5 -2
@@ -952,10 +952,13 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
952 const char *old_desc, *reflog_msg;
953 if (opts->new_branch) {
954 if (opts->new_orphan_branch) {
955 - enum log_refs_config log_all_ref_updates =
956 - repo_settings_get_log_all_ref_updates(the_repository);
955 + enum log_refs_config log_all_ref_updates = LOG_REFS_UNSET;
956 + const char *value;
957 char *refname;
958
959 + if (!repo_config_get_string_tmp(the_repository, "core.logallrefupdates", &value))
960 + log_all_ref_updates = refs_parse_log_all_ref_updates_config(value);
961 +
962 refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
963 if (opts->new_branch_log &&
964 !should_autocreate_reflog(log_all_ref_updates, refname)) {
refs.c
+9 -1
@@ -1053,6 +1053,15 @@ static char *normalize_reflog_message(const char *msg)
1053 return strbuf_detach(&sb, NULL);
1054 }
1055
1056 +enum log_refs_config refs_parse_log_all_ref_updates_config(const char *value)
1057 +{
1058 + if (value && !strcasecmp(value, "always"))
1059 + return LOG_REFS_ALWAYS;
1060 + else if (git_config_bool("core.logallrefupdates", value))
1061 + return LOG_REFS_NORMAL;
1062 + return LOG_REFS_NONE;
1063 +}
1064 +
1065 int should_autocreate_reflog(enum log_refs_config log_all_ref_updates,
1066 const char *refname)
1067 {
@@ -2327,7 +2336,6 @@ static struct ref_store *ref_store_init(struct repository *repo,
2336 struct ref_store *refs;
2337 struct ref_store_init_options opts = {
2338 .access_flags = flags,
2330 - .log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo),
2339 };
2340
2341 be = find_ref_storage_backend(format);
refs.h
+9
@@ -146,6 +146,15 @@ enum ref_transaction_error refs_verify_refname_available(struct ref_store *refs,
146
147 int refs_ref_exists(struct ref_store *refs, const char *refname);
148
149 +enum log_refs_config {
150 + LOG_REFS_UNSET = -1,
151 + LOG_REFS_NONE = 0,
152 + LOG_REFS_NORMAL,
153 + LOG_REFS_ALWAYS
154 +};
155 +
156 +enum log_refs_config refs_parse_log_all_ref_updates_config(const char *value);
157 +
158 int should_autocreate_reflog(enum log_refs_config log_all_ref_updates,
159 const char *refname);
160
refs/files-backend.c
+17 -3
@@ -117,6 +117,21 @@ static void files_ref_store_reparent(const char *name UNUSED,
117 refs->gitcommondir = tmp;
118 }
119
120 +static int files_ref_store_config(const char *var, const char *value,
121 + const struct config_context *ctx UNUSED,
122 + void *payload)
123 +{
124 + struct files_ref_store *refs = payload;
125 +
126 + if (!strcmp(var, "core.prefersymlinkrefs")) {
127 + refs->prefer_symlink_refs = git_config_bool(var, value);
128 + } else if (!strcmp(var, "core.logallrefupdates")) {
129 + refs->log_all_ref_updates = refs_parse_log_all_ref_updates_config(value);
130 + }
131 +
132 + return 0;
133 +}
134 +
135 /*
136 * Create a new submodule ref cache and add it to the internal
137 * set of caches.
@@ -141,10 +156,9 @@ static struct ref_store *files_ref_store_init(struct repository *repo,
156 refs->packed_ref_store =
157 packed_ref_store_init(repo, NULL, refs->gitcommondir, opts);
158 refs->store_flags = opts->access_flags;
144 - refs->log_all_ref_updates = opts->log_all_ref_updates;
145 -
146 - repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
159 + refs->log_all_ref_updates = LOG_REFS_UNSET;
160
161 + repo_config(repo, files_ref_store_config, refs);
162 chdir_notify_register(NULL, files_ref_store_reparent, refs);
163
164 strbuf_release(&refdir);
refs/refs-internal.h
-6
@@ -406,12 +406,6 @@ struct ref_store;
406 struct ref_store_init_options {
407 /* The kind of operations that the ref_store is allowed to perform. */
408 unsigned int access_flags;
409 -
410 - /*
411 - * Denotes under what conditions reflogs should be created when updating
412 - * references.
413 - */
414 - enum log_refs_config log_all_ref_updates;
409 };
410
411 /*
refs/reftable-backend.c
+11 -9
@@ -332,34 +332,36 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru
332
333 static int reftable_be_config(const char *var, const char *value,
334 const struct config_context *ctx,
335 - void *_opts)
335 + void *payload)
336 {
337 - struct reftable_write_options *opts = _opts;
337 + struct reftable_ref_store *refs = payload;
338
339 if (!strcmp(var, "reftable.blocksize")) {
340 unsigned long block_size = git_config_ulong(var, value, ctx->kvi);
341 if (block_size > 16777215)
342 die("reftable block size cannot exceed 16MB");
343 - opts->block_size = block_size;
343 + refs->write_options.block_size = block_size;
344 } else if (!strcmp(var, "reftable.restartinterval")) {
345 unsigned long restart_interval = git_config_ulong(var, value, ctx->kvi);
346 if (restart_interval > UINT16_MAX)
347 die("reftable block size cannot exceed %u", (unsigned)UINT16_MAX);
348 - opts->restart_interval = restart_interval;
348 + refs->write_options.restart_interval = restart_interval;
349 } else if (!strcmp(var, "reftable.indexobjects")) {
350 - opts->skip_index_objects = !git_config_bool(var, value);
350 + refs->write_options.skip_index_objects = !git_config_bool(var, value);
351 } else if (!strcmp(var, "reftable.geometricfactor")) {
352 unsigned long factor = git_config_ulong(var, value, ctx->kvi);
353 if (factor > UINT8_MAX)
354 die("reftable geometric factor cannot exceed %u", (unsigned)UINT8_MAX);
355 - opts->auto_compaction_factor = factor;
355 + refs->write_options.auto_compaction_factor = factor;
356 } else if (!strcmp(var, "reftable.locktimeout")) {
357 int64_t lock_timeout = git_config_int64(var, value, ctx->kvi);
358 if (lock_timeout > LONG_MAX)
359 die("reftable lock timeout cannot exceed %"PRIdMAX, (intmax_t)LONG_MAX);
360 if (lock_timeout < 0 && lock_timeout != -1)
361 die("reftable lock timeout does not support negative values other than -1");
362 - opts->lock_timeout_ms = lock_timeout;
362 + refs->write_options.lock_timeout_ms = lock_timeout;
363 + } else if (!strcmp(var, "core.logallrefupdates")) {
364 + refs->log_all_ref_updates = refs_parse_log_all_ref_updates_config(value);
365 }
366
367 return 0;
@@ -398,7 +400,6 @@ static struct ref_store *reftable_be_init(struct repository *repo,
400
401 base_ref_store_init(&refs->base, repo, refdir.buf, &refs_be_reftable);
402 strmap_init(&refs->worktree_backends);
401 - refs->log_all_ref_updates = opts->log_all_ref_updates;
403 refs->store_flags = opts->access_flags;
404
405 switch (repo->hash_algo->format_id) {
@@ -415,8 +416,9 @@ static struct ref_store *reftable_be_init(struct repository *repo,
416 refs->write_options.disable_auto_compact =
417 !git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
418 refs->write_options.lock_timeout_ms = 100;
419 + refs->log_all_ref_updates = LOG_REFS_UNSET;
420
419 - repo_config(repo, reftable_be_config, &refs->write_options);
421 + repo_config(repo, reftable_be_config, refs);
422
423 /*
424 * It is somewhat unfortunate that we have to mirror the default block
repo-settings.c
-16
@@ -177,22 +177,6 @@ void repo_settings_set_big_file_threshold(struct repository *repo, unsigned long
177 repo->settings.big_file_threshold = value;
178 }
179
180 -enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo)
181 -{
182 - const char *value;
183 -
184 - if (!repo_config_get_string_tmp(repo, "core.logallrefupdates", &value)) {
185 - if (value && !strcasecmp(value, "always"))
186 - return LOG_REFS_ALWAYS;
187 - else if (git_config_bool("core.logallrefupdates", value))
188 - return LOG_REFS_NORMAL;
189 - else
190 - return LOG_REFS_NONE;
191 - }
192 -
193 - return LOG_REFS_UNSET;
194 -}
195 -
180 int repo_settings_get_warn_ambiguous_refs(struct repository *repo)
181 {
182 prepare_repo_settings(repo);
repo-settings.h
-9
@@ -16,13 +16,6 @@ enum fetch_negotiation_setting {
16 FETCH_NEGOTIATION_NOOP,
17 };
18
19 -enum log_refs_config {
20 - LOG_REFS_UNSET = -1,
21 - LOG_REFS_NONE = 0,
22 - LOG_REFS_NORMAL,
23 - LOG_REFS_ALWAYS
24 -};
25 -
19 struct repo_settings {
20 int initialized;
21
@@ -86,8 +79,6 @@ struct repo_settings {
79 void prepare_repo_settings(struct repository *r);
80 void repo_settings_clear(struct repository *r);
81
89 -/* Read the value for "core.logAllRefUpdates". */
90 -enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo);
82 /* Read the value for "core.warnAmbiguousRefs". */
83 int repo_settings_get_warn_ambiguous_refs(struct repository *repo);
84 /* Read the value for "core.hooksPath". */
setup.c
+5 -1
@@ -2584,10 +2584,14 @@ static int create_default_files(struct repository *repo,
2584 if (is_bare_repository())
2585 repo_config_set(repo, "core.bare", "true");
2586 else {
2587 + const char *value;
2588 +
2589 repo_config_set(repo, "core.bare", "false");
2590 +
2591 /* allow template config file to override the default */
2589 - if (repo_settings_get_log_all_ref_updates(repo) == LOG_REFS_UNSET)
2592 + if (repo_config_get_string_tmp(repo, "core.logallrefupdates", &value))
2593 repo_config_set(repo, "core.logallrefupdates", "true");
2594 +
2595 if (needs_work_tree_config(original_git_dir, work_tree))
2596 repo_config_set(repo, "core.worktree", work_tree);
2597 }