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>
This commit is contained in:
Patrick Steinhardt
2026-06-25 11:20:05 +02:00
committed by Junio C Hamano
parent 432b2e4f9e
commit a9e4ce0aec
9 changed files with 56 additions and 47 deletions

View File

@@ -952,10 +952,13 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
const char *old_desc, *reflog_msg;
if (opts->new_branch) {
if (opts->new_orphan_branch) {
enum log_refs_config log_all_ref_updates =
repo_settings_get_log_all_ref_updates(the_repository);
enum log_refs_config log_all_ref_updates = LOG_REFS_UNSET;
const char *value;
char *refname;
if (!repo_config_get_string_tmp(the_repository, "core.logallrefupdates", &value))
log_all_ref_updates = refs_parse_log_all_ref_updates_config(value);
refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
if (opts->new_branch_log &&
!should_autocreate_reflog(log_all_ref_updates, refname)) {

10
refs.c
View File

@@ -1053,6 +1053,15 @@ static char *normalize_reflog_message(const char *msg)
return strbuf_detach(&sb, NULL);
}
enum log_refs_config refs_parse_log_all_ref_updates_config(const char *value)
{
if (value && !strcasecmp(value, "always"))
return LOG_REFS_ALWAYS;
else if (git_config_bool("core.logallrefupdates", value))
return LOG_REFS_NORMAL;
return LOG_REFS_NONE;
}
int should_autocreate_reflog(enum log_refs_config log_all_ref_updates,
const char *refname)
{
@@ -2327,7 +2336,6 @@ static struct ref_store *ref_store_init(struct repository *repo,
struct ref_store *refs;
struct ref_store_init_options opts = {
.access_flags = flags,
.log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo),
};
be = find_ref_storage_backend(format);

9
refs.h
View File

@@ -146,6 +146,15 @@ enum ref_transaction_error refs_verify_refname_available(struct ref_store *refs,
int refs_ref_exists(struct ref_store *refs, const char *refname);
enum log_refs_config {
LOG_REFS_UNSET = -1,
LOG_REFS_NONE = 0,
LOG_REFS_NORMAL,
LOG_REFS_ALWAYS
};
enum log_refs_config refs_parse_log_all_ref_updates_config(const char *value);
int should_autocreate_reflog(enum log_refs_config log_all_ref_updates,
const char *refname);

View File

@@ -117,6 +117,21 @@ static void files_ref_store_reparent(const char *name UNUSED,
refs->gitcommondir = tmp;
}
static int files_ref_store_config(const char *var, const char *value,
const struct config_context *ctx UNUSED,
void *payload)
{
struct files_ref_store *refs = payload;
if (!strcmp(var, "core.prefersymlinkrefs")) {
refs->prefer_symlink_refs = git_config_bool(var, value);
} else if (!strcmp(var, "core.logallrefupdates")) {
refs->log_all_ref_updates = refs_parse_log_all_ref_updates_config(value);
}
return 0;
}
/*
* Create a new submodule ref cache and add it to the internal
* set of caches.
@@ -141,10 +156,9 @@ static struct ref_store *files_ref_store_init(struct repository *repo,
refs->packed_ref_store =
packed_ref_store_init(repo, NULL, refs->gitcommondir, opts);
refs->store_flags = opts->access_flags;
refs->log_all_ref_updates = opts->log_all_ref_updates;
repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
refs->log_all_ref_updates = LOG_REFS_UNSET;
repo_config(repo, files_ref_store_config, refs);
chdir_notify_register(NULL, files_ref_store_reparent, refs);
strbuf_release(&refdir);

View File

@@ -406,12 +406,6 @@ struct ref_store;
struct ref_store_init_options {
/* The kind of operations that the ref_store is allowed to perform. */
unsigned int access_flags;
/*
* Denotes under what conditions reflogs should be created when updating
* references.
*/
enum log_refs_config log_all_ref_updates;
};
/*

View File

@@ -332,34 +332,36 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru
static int reftable_be_config(const char *var, const char *value,
const struct config_context *ctx,
void *_opts)
void *payload)
{
struct reftable_write_options *opts = _opts;
struct reftable_ref_store *refs = payload;
if (!strcmp(var, "reftable.blocksize")) {
unsigned long block_size = git_config_ulong(var, value, ctx->kvi);
if (block_size > 16777215)
die("reftable block size cannot exceed 16MB");
opts->block_size = block_size;
refs->write_options.block_size = block_size;
} else if (!strcmp(var, "reftable.restartinterval")) {
unsigned long restart_interval = git_config_ulong(var, value, ctx->kvi);
if (restart_interval > UINT16_MAX)
die("reftable block size cannot exceed %u", (unsigned)UINT16_MAX);
opts->restart_interval = restart_interval;
refs->write_options.restart_interval = restart_interval;
} else if (!strcmp(var, "reftable.indexobjects")) {
opts->skip_index_objects = !git_config_bool(var, value);
refs->write_options.skip_index_objects = !git_config_bool(var, value);
} else if (!strcmp(var, "reftable.geometricfactor")) {
unsigned long factor = git_config_ulong(var, value, ctx->kvi);
if (factor > UINT8_MAX)
die("reftable geometric factor cannot exceed %u", (unsigned)UINT8_MAX);
opts->auto_compaction_factor = factor;
refs->write_options.auto_compaction_factor = factor;
} else if (!strcmp(var, "reftable.locktimeout")) {
int64_t lock_timeout = git_config_int64(var, value, ctx->kvi);
if (lock_timeout > LONG_MAX)
die("reftable lock timeout cannot exceed %"PRIdMAX, (intmax_t)LONG_MAX);
if (lock_timeout < 0 && lock_timeout != -1)
die("reftable lock timeout does not support negative values other than -1");
opts->lock_timeout_ms = lock_timeout;
refs->write_options.lock_timeout_ms = lock_timeout;
} else if (!strcmp(var, "core.logallrefupdates")) {
refs->log_all_ref_updates = refs_parse_log_all_ref_updates_config(value);
}
return 0;
@@ -398,7 +400,6 @@ static struct ref_store *reftable_be_init(struct repository *repo,
base_ref_store_init(&refs->base, repo, refdir.buf, &refs_be_reftable);
strmap_init(&refs->worktree_backends);
refs->log_all_ref_updates = opts->log_all_ref_updates;
refs->store_flags = opts->access_flags;
switch (repo->hash_algo->format_id) {
@@ -415,8 +416,9 @@ static struct ref_store *reftable_be_init(struct repository *repo,
refs->write_options.disable_auto_compact =
!git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
refs->write_options.lock_timeout_ms = 100;
refs->log_all_ref_updates = LOG_REFS_UNSET;
repo_config(repo, reftable_be_config, &refs->write_options);
repo_config(repo, reftable_be_config, refs);
/*
* It is somewhat unfortunate that we have to mirror the default block

View File

@@ -177,22 +177,6 @@ void repo_settings_set_big_file_threshold(struct repository *repo, unsigned long
repo->settings.big_file_threshold = value;
}
enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo)
{
const char *value;
if (!repo_config_get_string_tmp(repo, "core.logallrefupdates", &value)) {
if (value && !strcasecmp(value, "always"))
return LOG_REFS_ALWAYS;
else if (git_config_bool("core.logallrefupdates", value))
return LOG_REFS_NORMAL;
else
return LOG_REFS_NONE;
}
return LOG_REFS_UNSET;
}
int repo_settings_get_warn_ambiguous_refs(struct repository *repo)
{
prepare_repo_settings(repo);

View File

@@ -16,13 +16,6 @@ enum fetch_negotiation_setting {
FETCH_NEGOTIATION_NOOP,
};
enum log_refs_config {
LOG_REFS_UNSET = -1,
LOG_REFS_NONE = 0,
LOG_REFS_NORMAL,
LOG_REFS_ALWAYS
};
struct repo_settings {
int initialized;
@@ -86,8 +79,6 @@ struct repo_settings {
void prepare_repo_settings(struct repository *r);
void repo_settings_clear(struct repository *r);
/* Read the value for "core.logAllRefUpdates". */
enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo);
/* Read the value for "core.warnAmbiguousRefs". */
int repo_settings_get_warn_ambiguous_refs(struct repository *repo);
/* Read the value for "core.hooksPath". */

View File

@@ -2584,10 +2584,14 @@ static int create_default_files(struct repository *repo,
if (is_bare_repository())
repo_config_set(repo, "core.bare", "true");
else {
const char *value;
repo_config_set(repo, "core.bare", "false");
/* allow template config file to override the default */
if (repo_settings_get_log_all_ref_updates(repo) == LOG_REFS_UNSET)
if (repo_config_get_string_tmp(repo, "core.logallrefupdates", &value))
repo_config_set(repo, "core.logallrefupdates", "true");
if (needs_work_tree_config(original_git_dir, work_tree))
repo_config_set(repo, "core.worktree", work_tree);
}