mirror of
https://github.com/git/git.git
synced 2026-06-19 15:39:47 +02:00
Merge branch 'ps/refs-avoid-chdir-notify-reparent' into seen
The reference backends have been converted to always use absolute paths internally. This allows dropping the calls to `chdir_notify_reparent()` and fixes a memory leak in how the reference database is constructed with an "onbranch" condition. * ps/refs-avoid-chdir-notify-reparent: refs: drop local buffer in `refs_compute_filesystem_location()` refs: fix recursing `get_main_ref_store()` with "onbranch" config repository: free main reference database chdir-notify: drop unused `chdir_notify_reparent()` refs: unregister reference stores from "chdir_notify" setup: don't apply "GIT_REFERENCE_BACKEND" without a repository setup: stop applying repository format twice setup: inline `check_and_apply_repository_format()`
This commit is contained in:
@@ -43,32 +43,6 @@ void chdir_notify_unregister(const char *name, chdir_notify_callback cb,
|
||||
}
|
||||
}
|
||||
|
||||
static void reparent_cb(const char *name,
|
||||
const char *old_cwd,
|
||||
const char *new_cwd,
|
||||
void *data)
|
||||
{
|
||||
char **path = data;
|
||||
char *tmp = *path;
|
||||
|
||||
if (!tmp)
|
||||
return;
|
||||
|
||||
*path = reparent_relative_path(old_cwd, new_cwd, tmp);
|
||||
free(tmp);
|
||||
|
||||
if (name) {
|
||||
trace_printf_key(&trace_setup_key,
|
||||
"setup: reparent %s to '%s'",
|
||||
name, *path);
|
||||
}
|
||||
}
|
||||
|
||||
void chdir_notify_reparent(const char *name, char **path)
|
||||
{
|
||||
chdir_notify_register(name, reparent_cb, path);
|
||||
}
|
||||
|
||||
int chdir_notify(const char *new_cwd)
|
||||
{
|
||||
struct strbuf old_cwd = STRBUF_INIT;
|
||||
|
||||
+1
-5
@@ -19,10 +19,7 @@
|
||||
* chdir_notify_register("description", foo, data);
|
||||
*
|
||||
* In practice most callers will want to move a relative path to the new root;
|
||||
* they can use the reparent_relative_path() helper for that. If that's all
|
||||
* you're doing, you can also use the convenience function:
|
||||
*
|
||||
* chdir_notify_reparent("description", &my_path);
|
||||
* they can use the reparent_relative_path() helper for that.
|
||||
*
|
||||
* Whenever a chdir event occurs, that will update my_path (if it's relative)
|
||||
* to adjust for the new cwd by freeing any existing string and allocating a
|
||||
@@ -43,7 +40,6 @@ typedef void (*chdir_notify_callback)(const char *name,
|
||||
void chdir_notify_register(const char *name, chdir_notify_callback cb, void *data);
|
||||
void chdir_notify_unregister(const char *name, chdir_notify_callback cb,
|
||||
void *data);
|
||||
void chdir_notify_reparent(const char *name, char **path);
|
||||
|
||||
/*
|
||||
*
|
||||
|
||||
@@ -2351,15 +2351,31 @@ void ref_store_release(struct ref_store *ref_store)
|
||||
|
||||
struct ref_store *get_main_ref_store(struct repository *r)
|
||||
{
|
||||
enum ref_storage_format format;
|
||||
|
||||
if (r->refs_private)
|
||||
return r->refs_private;
|
||||
|
||||
if (!r->gitdir)
|
||||
BUG("attempting to get main_ref_store outside of repository");
|
||||
|
||||
r->refs_private = ref_store_init(r, r->ref_storage_format,
|
||||
r->gitdir, REF_STORE_ALL_CAPS);
|
||||
/*
|
||||
* When constructing the reference backend we'll end up reading the Git
|
||||
* configuration. This means we'll also try to evaluate "onbranch"
|
||||
* conditions.
|
||||
*
|
||||
* We cannot read branches when constructing the refdb, so it is not
|
||||
* possible to evaluate those conditions in the first place. To gate
|
||||
* their evaluation we check whether or not the reference storage
|
||||
* format has been configured -- we thus have to temporarily set it to
|
||||
* UNKNOWN here so that we don't end up recursing.
|
||||
*/
|
||||
format = r->ref_storage_format;
|
||||
r->ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
|
||||
r->refs_private = ref_store_init(r, format, r->gitdir, REF_STORE_ALL_CAPS);
|
||||
r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private);
|
||||
r->ref_storage_format = format;
|
||||
|
||||
return r->refs_private;
|
||||
}
|
||||
|
||||
@@ -3555,8 +3571,6 @@ void refs_compute_filesystem_location(const char *gitdir, const char *payload,
|
||||
bool *is_worktree, struct strbuf *refdir,
|
||||
struct strbuf *ref_common_dir)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
*is_worktree = get_common_dir_noenv(ref_common_dir, gitdir);
|
||||
|
||||
if (!payload) {
|
||||
@@ -3570,8 +3584,8 @@ void refs_compute_filesystem_location(const char *gitdir, const char *payload,
|
||||
}
|
||||
|
||||
if (!is_absolute_path(payload)) {
|
||||
strbuf_addf(&sb, "%s/%s", ref_common_dir->buf, payload);
|
||||
strbuf_realpath(ref_common_dir, sb.buf, 1);
|
||||
strbuf_addf(ref_common_dir, "/%s", payload);
|
||||
strbuf_realpath(ref_common_dir, ref_common_dir->buf, 1);
|
||||
} else {
|
||||
strbuf_realpath(ref_common_dir, payload, 1);
|
||||
}
|
||||
@@ -3584,6 +3598,4 @@ void refs_compute_filesystem_location(const char *gitdir, const char *payload,
|
||||
BUG("worktree path does not contain slash");
|
||||
strbuf_addf(refdir, "/worktrees/%s", wt_id + 1);
|
||||
}
|
||||
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
+19
-3
@@ -100,6 +100,23 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)
|
||||
}
|
||||
}
|
||||
|
||||
static void files_ref_store_reparent(const char *name UNUSED,
|
||||
const char *old_cwd,
|
||||
const char *new_cwd,
|
||||
void *payload)
|
||||
{
|
||||
struct files_ref_store *refs = payload;
|
||||
char *tmp;
|
||||
|
||||
tmp = reparent_relative_path(old_cwd, new_cwd, refs->base.gitdir);
|
||||
free(refs->base.gitdir);
|
||||
refs->base.gitdir = tmp;
|
||||
|
||||
tmp = reparent_relative_path(old_cwd, new_cwd, refs->gitcommondir);
|
||||
free(refs->gitcommondir);
|
||||
refs->gitcommondir = tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new submodule ref cache and add it to the internal
|
||||
* set of caches.
|
||||
@@ -128,9 +145,7 @@ static struct ref_store *files_ref_store_init(struct repository *repo,
|
||||
|
||||
repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
|
||||
|
||||
chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
|
||||
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
|
||||
&refs->gitcommondir);
|
||||
chdir_notify_register(NULL, files_ref_store_reparent, refs);
|
||||
|
||||
strbuf_release(&refdir);
|
||||
|
||||
@@ -182,6 +197,7 @@ static void files_ref_store_release(struct ref_store *ref_store)
|
||||
free(refs->gitcommondir);
|
||||
ref_store_release(refs->packed_ref_store);
|
||||
free(refs->packed_ref_store);
|
||||
chdir_notify_unregister(NULL, files_ref_store_reparent, refs);
|
||||
}
|
||||
|
||||
static void files_reflog_path(struct files_ref_store *refs,
|
||||
|
||||
+15
-1
@@ -211,6 +211,19 @@ static size_t snapshot_hexsz(const struct snapshot *snapshot)
|
||||
return snapshot->refs->base.repo->hash_algo->hexsz;
|
||||
}
|
||||
|
||||
static void packed_ref_store_reparent(const char *name UNUSED,
|
||||
const char *old_cwd,
|
||||
const char *new_cwd,
|
||||
void *payload)
|
||||
{
|
||||
struct packed_ref_store *refs = payload;
|
||||
char *tmp;
|
||||
|
||||
tmp = reparent_relative_path(old_cwd, new_cwd, refs->path);
|
||||
free(refs->path);
|
||||
refs->path = tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since packed-refs is only stored in the common dir, don't parse the
|
||||
* payload and rely on the files-backend to set 'gitdir' correctly.
|
||||
@@ -229,7 +242,7 @@ struct ref_store *packed_ref_store_init(struct repository *repo,
|
||||
|
||||
strbuf_addf(&sb, "%s/packed-refs", gitdir);
|
||||
refs->path = strbuf_detach(&sb, NULL);
|
||||
chdir_notify_reparent("packed-refs", &refs->path);
|
||||
chdir_notify_register(NULL, packed_ref_store_reparent, refs);
|
||||
return ref_store;
|
||||
}
|
||||
|
||||
@@ -274,6 +287,7 @@ static void packed_ref_store_release(struct ref_store *ref_store)
|
||||
clear_snapshot(refs);
|
||||
rollback_lock_file(&refs->lock);
|
||||
delete_tempfile(&refs->tempfile);
|
||||
chdir_notify_unregister(NULL, packed_ref_store_reparent, refs);
|
||||
free(refs->path);
|
||||
}
|
||||
|
||||
|
||||
+15
-1
@@ -363,6 +363,19 @@ static int reftable_be_config(const char *var, const char *value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reftable_be_reparent(const char *name UNUSED,
|
||||
const char *old_cwd,
|
||||
const char *new_cwd,
|
||||
void *payload)
|
||||
{
|
||||
struct reftable_ref_store *refs = payload;
|
||||
char *tmp;
|
||||
|
||||
tmp = reparent_relative_path(old_cwd, new_cwd, refs->base.gitdir);
|
||||
free(refs->base.gitdir);
|
||||
refs->base.gitdir = tmp;
|
||||
}
|
||||
|
||||
static struct ref_store *reftable_be_init(struct repository *repo,
|
||||
const char *payload,
|
||||
const char *gitdir,
|
||||
@@ -445,7 +458,7 @@ static struct ref_store *reftable_be_init(struct repository *repo,
|
||||
goto done;
|
||||
}
|
||||
|
||||
chdir_notify_reparent("reftables-backend $GIT_DIR", &refs->base.gitdir);
|
||||
chdir_notify_register(NULL, reftable_be_reparent, refs);
|
||||
|
||||
done:
|
||||
assert(refs->err != REFTABLE_API_ERROR);
|
||||
@@ -472,6 +485,7 @@ static void reftable_be_release(struct ref_store *ref_store)
|
||||
free(be);
|
||||
}
|
||||
strmap_clear(&refs->worktree_backends, 0);
|
||||
chdir_notify_unregister(NULL, reftable_be_reparent, refs);
|
||||
}
|
||||
|
||||
static int reftable_be_create_on_disk(struct ref_store *ref_store,
|
||||
|
||||
@@ -422,6 +422,11 @@ void repo_clear(struct repository *repo)
|
||||
FREE_AND_NULL(repo->remote_state);
|
||||
}
|
||||
|
||||
if (repo->refs_private) {
|
||||
ref_store_release(repo->refs_private);
|
||||
FREE_AND_NULL(repo->refs_private);
|
||||
}
|
||||
|
||||
strmap_for_each_entry(&repo->submodule_ref_stores, &iter, e)
|
||||
ref_store_release(e->value);
|
||||
strmap_clear(&repo->submodule_ref_stores, 1);
|
||||
|
||||
@@ -1798,32 +1798,6 @@ int apply_repository_format(struct repository *repo,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the repository format version in the path found in repo_get_git_dir(repo),
|
||||
* and die if it is a version we don't understand. Generally one would
|
||||
* set_git_dir() before calling this, and use it only for "are we in a valid
|
||||
* repo?".
|
||||
*
|
||||
* If successful and fmt is not NULL, fill fmt with data.
|
||||
*/
|
||||
static void check_and_apply_repository_format(struct repository *repo,
|
||||
struct repository_format *fmt,
|
||||
enum apply_repository_format_flags flags)
|
||||
{
|
||||
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
||||
if (!fmt)
|
||||
fmt = &repo_fmt;
|
||||
|
||||
check_repository_format_gently(repo_get_git_dir(repo), fmt, NULL);
|
||||
if (apply_repository_format(repo, fmt, flags, &err) < 0)
|
||||
die("%s", err.buf);
|
||||
startup_info->have_repository = 1;
|
||||
|
||||
clear_repository_format(&repo_fmt);
|
||||
}
|
||||
|
||||
const char *enter_repo(struct repository *repo, const char *path, unsigned flags)
|
||||
{
|
||||
static struct strbuf validated_path = STRBUF_INIT;
|
||||
@@ -1897,9 +1871,17 @@ const char *enter_repo(struct repository *repo, const char *path, unsigned flags
|
||||
}
|
||||
|
||||
if (is_git_directory(".")) {
|
||||
struct repository_format fmt = REPOSITORY_FORMAT_INIT;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
||||
set_git_dir(repo, ".", 0);
|
||||
check_and_apply_repository_format(repo, NULL,
|
||||
APPLY_REPOSITORY_FORMAT_HONOR_ENV);
|
||||
check_repository_format_gently(".", &fmt, NULL);
|
||||
if (apply_repository_format(repo, &fmt, APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
|
||||
die("%s", err.buf);
|
||||
startup_info->have_repository = 1;
|
||||
|
||||
clear_repository_format(&fmt);
|
||||
strbuf_release(&err);
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -1934,7 +1916,6 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
|
||||
static struct strbuf cwd = STRBUF_INIT;
|
||||
struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT, report = STRBUF_INIT;
|
||||
const char *prefix = NULL;
|
||||
const char *ref_backend_uri;
|
||||
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
|
||||
|
||||
/*
|
||||
@@ -2060,6 +2041,25 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
|
||||
|
||||
if (startup_info->have_repository) {
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
const char *ref_backend_uri;
|
||||
|
||||
/*
|
||||
* The env variable should override the repository config
|
||||
* for 'extensions.refStorage'.
|
||||
*/
|
||||
ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
|
||||
if (ref_backend_uri) {
|
||||
char *format;
|
||||
|
||||
free(repo_fmt.ref_storage_payload);
|
||||
|
||||
parse_reference_uri(ref_backend_uri, &format, &repo_fmt.ref_storage_payload);
|
||||
repo_fmt.ref_storage_format = ref_storage_format_by_name(format);
|
||||
if (repo_fmt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
|
||||
die(_("unknown ref storage format: '%s'"), format);
|
||||
|
||||
free(format);
|
||||
}
|
||||
|
||||
if (apply_repository_format(repo, &repo_fmt,
|
||||
APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
|
||||
@@ -2085,25 +2085,6 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
|
||||
setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The env variable should override the repository config
|
||||
* for 'extensions.refStorage'.
|
||||
*/
|
||||
ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
|
||||
if (ref_backend_uri) {
|
||||
char *backend, *payload;
|
||||
enum ref_storage_format format;
|
||||
|
||||
parse_reference_uri(ref_backend_uri, &backend, &payload);
|
||||
format = ref_storage_format_by_name(backend);
|
||||
if (format == REF_STORAGE_FORMAT_UNKNOWN)
|
||||
die(_("unknown ref storage format: '%s'"), backend);
|
||||
repo_set_ref_storage_format(repo, format, payload);
|
||||
|
||||
free(backend);
|
||||
free(payload);
|
||||
}
|
||||
|
||||
setup_original_cwd(repo);
|
||||
|
||||
strbuf_release(&dir);
|
||||
@@ -2738,8 +2719,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void repository_format_configure(struct repository *repo,
|
||||
struct repository_format *repo_fmt,
|
||||
static void repository_format_configure(struct repository_format *repo_fmt,
|
||||
int hash, enum ref_storage_format ref_format)
|
||||
{
|
||||
struct default_format_config cfg = {
|
||||
@@ -2776,7 +2756,6 @@ static void repository_format_configure(struct repository *repo,
|
||||
} else if (cfg.hash != GIT_HASH_UNKNOWN) {
|
||||
repo_fmt->hash_algo = cfg.hash;
|
||||
}
|
||||
repo_set_hash_algo(repo, repo_fmt->hash_algo);
|
||||
|
||||
env = getenv("GIT_DEFAULT_REF_FORMAT");
|
||||
if (repo_fmt->version >= 0 &&
|
||||
@@ -2814,9 +2793,6 @@ static void repository_format_configure(struct repository *repo,
|
||||
|
||||
free(backend);
|
||||
}
|
||||
|
||||
repo_set_ref_storage_format(repo, repo_fmt->ref_storage_format,
|
||||
repo_fmt->ref_storage_payload);
|
||||
}
|
||||
|
||||
int init_db(struct repository *repo,
|
||||
@@ -2830,6 +2806,7 @@ int init_db(struct repository *repo,
|
||||
int exist_ok = flags & INIT_DB_EXIST_OK;
|
||||
char *original_git_dir = real_pathdup(git_dir, 1);
|
||||
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
|
||||
if (real_git_dir) {
|
||||
struct stat st;
|
||||
@@ -2856,10 +2833,11 @@ int init_db(struct repository *repo,
|
||||
* config file, so this will not fail. What we are catching
|
||||
* is an attempt to reinitialize new repository with an old tool.
|
||||
*/
|
||||
check_and_apply_repository_format(repo, &repo_fmt,
|
||||
APPLY_REPOSITORY_FORMAT_HONOR_ENV);
|
||||
|
||||
repository_format_configure(repo, &repo_fmt, hash, ref_storage_format);
|
||||
check_repository_format_gently(repo_get_git_dir(repo), &repo_fmt, NULL);
|
||||
repository_format_configure(&repo_fmt, hash, ref_storage_format);
|
||||
if (apply_repository_format(repo, &repo_fmt, APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
|
||||
die("%s", err.buf);
|
||||
startup_info->have_repository = 1;
|
||||
|
||||
/*
|
||||
* Ensure `core.hidedotfiles` is processed. This must happen after we
|
||||
@@ -2914,6 +2892,7 @@ int init_db(struct repository *repo,
|
||||
}
|
||||
|
||||
clear_repository_format(&repo_fmt);
|
||||
strbuf_release(&err);
|
||||
free(original_git_dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user