Skip to content

Commit e7bb3e3

Browse files
committed
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: always use absolute paths for reference stores 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()`
2 parents ba54818 + cca2df1 commit e7bb3e3

12 files changed

Lines changed: 83 additions & 119 deletions

chdir-notify.c

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,32 +43,6 @@ void chdir_notify_unregister(const char *name, chdir_notify_callback cb,
4343
}
4444
}
4545

46-
static void reparent_cb(const char *name,
47-
const char *old_cwd,
48-
const char *new_cwd,
49-
void *data)
50-
{
51-
char **path = data;
52-
char *tmp = *path;
53-
54-
if (!tmp)
55-
return;
56-
57-
*path = reparent_relative_path(old_cwd, new_cwd, tmp);
58-
free(tmp);
59-
60-
if (name) {
61-
trace_printf_key(&trace_setup_key,
62-
"setup: reparent %s to '%s'",
63-
name, *path);
64-
}
65-
}
66-
67-
void chdir_notify_reparent(const char *name, char **path)
68-
{
69-
chdir_notify_register(name, reparent_cb, path);
70-
}
71-
7246
int chdir_notify(const char *new_cwd)
7347
{
7448
struct strbuf old_cwd = STRBUF_INIT;

chdir-notify.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@
1919
* chdir_notify_register("description", foo, data);
2020
*
2121
* In practice most callers will want to move a relative path to the new root;
22-
* they can use the reparent_relative_path() helper for that. If that's all
23-
* you're doing, you can also use the convenience function:
24-
*
25-
* chdir_notify_reparent("description", &my_path);
22+
* they can use the reparent_relative_path() helper for that.
2623
*
2724
* Whenever a chdir event occurs, that will update my_path (if it's relative)
2825
* 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,
4340
void chdir_notify_register(const char *name, chdir_notify_callback cb, void *data);
4441
void chdir_notify_unregister(const char *name, chdir_notify_callback cb,
4542
void *data);
46-
void chdir_notify_reparent(const char *name, char **path);
4743

4844
/*
4945
*

refs.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2351,15 +2351,31 @@ void ref_store_release(struct ref_store *ref_store)
23512351

23522352
struct ref_store *get_main_ref_store(struct repository *r)
23532353
{
2354+
enum ref_storage_format format;
2355+
23542356
if (r->refs_private)
23552357
return r->refs_private;
23562358

23572359
if (!r->gitdir)
23582360
BUG("attempting to get main_ref_store outside of repository");
23592361

2360-
r->refs_private = ref_store_init(r, r->ref_storage_format,
2361-
r->gitdir, REF_STORE_ALL_CAPS);
2362+
/*
2363+
* When constructing the reference backend we'll end up reading the Git
2364+
* configuration. This means we'll also try to evaluate "onbranch"
2365+
* conditions.
2366+
*
2367+
* We cannot read branches when constructing the refdb, so it is not
2368+
* possible to evaluate those conditions in the first place. To gate
2369+
* their evaluation we check whether or not the reference storage
2370+
* format has been configured -- we thus have to temporarily set it to
2371+
* UNKNOWN here so that we don't end up recursing.
2372+
*/
2373+
format = r->ref_storage_format;
2374+
r->ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
2375+
r->refs_private = ref_store_init(r, format, r->gitdir, REF_STORE_ALL_CAPS);
23622376
r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private);
2377+
r->ref_storage_format = format;
2378+
23632379
return r->refs_private;
23642380
}
23652381

@@ -3555,8 +3571,6 @@ void refs_compute_filesystem_location(const char *gitdir, const char *payload,
35553571
bool *is_worktree, struct strbuf *refdir,
35563572
struct strbuf *ref_common_dir)
35573573
{
3558-
struct strbuf sb = STRBUF_INIT;
3559-
35603574
*is_worktree = get_common_dir_noenv(ref_common_dir, gitdir);
35613575

35623576
if (!payload) {
@@ -3565,15 +3579,16 @@ void refs_compute_filesystem_location(const char *gitdir, const char *payload,
35653579
* worktree path, as the 'gitdir' here is already the worktree
35663580
* path and is different from 'commondir' denoted by 'ref_common_dir'.
35673581
*/
3582+
strbuf_reset(refdir);
35683583
strbuf_addstr(refdir, gitdir);
3569-
return;
3584+
goto out;
35703585
}
35713586

35723587
if (!is_absolute_path(payload)) {
3573-
strbuf_addf(&sb, "%s/%s", ref_common_dir->buf, payload);
3574-
strbuf_realpath(ref_common_dir, sb.buf, 1);
3588+
strbuf_addf(ref_common_dir, "/%s", payload);
35753589
} else {
3576-
strbuf_realpath(ref_common_dir, payload, 1);
3590+
strbuf_reset(ref_common_dir);
3591+
strbuf_addstr(ref_common_dir, payload);
35773592
}
35783593

35793594
strbuf_addbuf(refdir, ref_common_dir);
@@ -3585,5 +3600,7 @@ void refs_compute_filesystem_location(const char *gitdir, const char *payload,
35853600
strbuf_addf(refdir, "/worktrees/%s", wt_id + 1);
35863601
}
35873602

3588-
strbuf_release(&sb);
3603+
out:
3604+
strbuf_realpath(ref_common_dir, ref_common_dir->buf, 1);
3605+
strbuf_realpath(refdir, refdir->buf, 1);
35893606
}

refs/files-backend.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
#include "../lockfile.h"
2222
#include "../path.h"
2323
#include "../dir.h"
24-
#include "../chdir-notify.h"
2524
#include "../setup.h"
2625
#include "../worktree.h"
2726
#include "../wrapper.h"
@@ -128,12 +127,7 @@ static struct ref_store *files_ref_store_init(struct repository *repo,
128127

129128
repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
130129

131-
chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
132-
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
133-
&refs->gitcommondir);
134-
135130
strbuf_release(&refdir);
136-
137131
return ref_store;
138132
}
139133

refs/packed-backend.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "packed-backend.h"
1414
#include "../iterator.h"
1515
#include "../lockfile.h"
16-
#include "../chdir-notify.h"
1716
#include "../statinfo.h"
1817
#include "../worktree.h"
1918
#include "../wrapper.h"
@@ -226,10 +225,9 @@ struct ref_store *packed_ref_store_init(struct repository *repo,
226225

227226
base_ref_store_init(ref_store, repo, gitdir, &refs_be_packed);
228227
refs->store_flags = opts->access_flags;
229-
230228
strbuf_addf(&sb, "%s/packed-refs", gitdir);
231229
refs->path = strbuf_detach(&sb, NULL);
232-
chdir_notify_reparent("packed-refs", &refs->path);
230+
233231
return ref_store;
234232
}
235233

refs/reftable-backend.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "../git-compat-util.h"
22
#include "../abspath.h"
3-
#include "../chdir-notify.h"
43
#include "../config.h"
54
#include "../dir.h"
65
#include "../environment.h"
@@ -445,8 +444,6 @@ static struct ref_store *reftable_be_init(struct repository *repo,
445444
goto done;
446445
}
447446

448-
chdir_notify_reparent("reftables-backend $GIT_DIR", &refs->base.gitdir);
449-
450447
done:
451448
assert(refs->err != REFTABLE_API_ERROR);
452449
strbuf_release(&ref_common_dir);

repository.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,11 @@ void repo_clear(struct repository *repo)
422422
FREE_AND_NULL(repo->remote_state);
423423
}
424424

425+
if (repo->refs_private) {
426+
ref_store_release(repo->refs_private);
427+
FREE_AND_NULL(repo->refs_private);
428+
}
429+
425430
strmap_for_each_entry(&repo->submodule_ref_stores, &iter, e)
426431
ref_store_release(e->value);
427432
strmap_clear(&repo->submodule_ref_stores, 1);

setup.c

Lines changed: 38 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,32 +1808,6 @@ int apply_repository_format(struct repository *repo,
18081808
return 0;
18091809
}
18101810

1811-
/*
1812-
* Check the repository format version in the path found in repo_get_git_dir(repo),
1813-
* and die if it is a version we don't understand. Generally one would
1814-
* set_git_dir() before calling this, and use it only for "are we in a valid
1815-
* repo?".
1816-
*
1817-
* If successful and fmt is not NULL, fill fmt with data.
1818-
*/
1819-
static void check_and_apply_repository_format(struct repository *repo,
1820-
struct repository_format *fmt,
1821-
enum apply_repository_format_flags flags)
1822-
{
1823-
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
1824-
struct strbuf err = STRBUF_INIT;
1825-
1826-
if (!fmt)
1827-
fmt = &repo_fmt;
1828-
1829-
check_repository_format_gently(repo_get_git_dir(repo), fmt, NULL);
1830-
if (apply_repository_format(repo, fmt, flags, &err) < 0)
1831-
die("%s", err.buf);
1832-
startup_info->have_repository = 1;
1833-
1834-
clear_repository_format(&repo_fmt);
1835-
}
1836-
18371811
const char *enter_repo(struct repository *repo, const char *path, unsigned flags)
18381812
{
18391813
static struct strbuf validated_path = STRBUF_INIT;
@@ -1907,9 +1881,17 @@ const char *enter_repo(struct repository *repo, const char *path, unsigned flags
19071881
}
19081882

19091883
if (is_git_directory(".")) {
1884+
struct repository_format fmt = REPOSITORY_FORMAT_INIT;
1885+
struct strbuf err = STRBUF_INIT;
1886+
19101887
set_git_dir(repo, ".", 0);
1911-
check_and_apply_repository_format(repo, NULL,
1912-
APPLY_REPOSITORY_FORMAT_HONOR_ENV);
1888+
check_repository_format_gently(".", &fmt, NULL);
1889+
if (apply_repository_format(repo, &fmt, APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
1890+
die("%s", err.buf);
1891+
startup_info->have_repository = 1;
1892+
1893+
clear_repository_format(&fmt);
1894+
strbuf_release(&err);
19131895
return path;
19141896
}
19151897

@@ -1944,7 +1926,6 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
19441926
static struct strbuf cwd = STRBUF_INIT;
19451927
struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT, report = STRBUF_INIT;
19461928
const char *prefix = NULL;
1947-
const char *ref_backend_uri;
19481929
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
19491930

19501931
/*
@@ -2061,13 +2042,33 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
20612042
startup_info->have_repository ||
20622043
/* GIT_DIR_EXPLICIT */
20632044
getenv(GIT_DIR_ENVIRONMENT)) {
2045+
const char *ref_backend_uri;
2046+
20642047
if (!repo->gitdir) {
20652048
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
20662049
if (!gitdir)
20672050
gitdir = DEFAULT_GIT_DIR_ENVIRONMENT;
20682051
setup_git_env_internal(repo, gitdir);
20692052
}
20702053

2054+
/*
2055+
* The env variable should override the repository config
2056+
* for 'extensions.refStorage'.
2057+
*/
2058+
ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
2059+
if (ref_backend_uri) {
2060+
char *format;
2061+
2062+
free(repo_fmt.ref_storage_payload);
2063+
2064+
parse_reference_uri(ref_backend_uri, &format, &repo_fmt.ref_storage_payload);
2065+
repo_fmt.ref_storage_format = ref_storage_format_by_name(format);
2066+
if (repo_fmt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
2067+
die(_("unknown ref storage format: '%s'"), format);
2068+
2069+
free(format);
2070+
}
2071+
20712072
if (startup_info->have_repository) {
20722073
struct strbuf err = STRBUF_INIT;
20732074

@@ -2095,25 +2096,6 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
20952096
setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
20962097
}
20972098

2098-
/*
2099-
* The env variable should override the repository config
2100-
* for 'extensions.refStorage'.
2101-
*/
2102-
ref_backend_uri = getenv(GIT_REFERENCE_BACKEND_ENVIRONMENT);
2103-
if (ref_backend_uri) {
2104-
char *backend, *payload;
2105-
enum ref_storage_format format;
2106-
2107-
parse_reference_uri(ref_backend_uri, &backend, &payload);
2108-
format = ref_storage_format_by_name(backend);
2109-
if (format == REF_STORAGE_FORMAT_UNKNOWN)
2110-
die(_("unknown ref storage format: '%s'"), backend);
2111-
repo_set_ref_storage_format(repo, format, payload);
2112-
2113-
free(backend);
2114-
free(payload);
2115-
}
2116-
21172099
setup_original_cwd(repo);
21182100

21192101
strbuf_release(&dir);
@@ -2748,8 +2730,7 @@ static int read_default_format_config(const char *key, const char *value,
27482730
return ret;
27492731
}
27502732

2751-
static void repository_format_configure(struct repository *repo,
2752-
struct repository_format *repo_fmt,
2733+
static void repository_format_configure(struct repository_format *repo_fmt,
27532734
int hash, enum ref_storage_format ref_format)
27542735
{
27552736
struct default_format_config cfg = {
@@ -2786,7 +2767,6 @@ static void repository_format_configure(struct repository *repo,
27862767
} else if (cfg.hash != GIT_HASH_UNKNOWN) {
27872768
repo_fmt->hash_algo = cfg.hash;
27882769
}
2789-
repo_set_hash_algo(repo, repo_fmt->hash_algo);
27902770

27912771
env = getenv("GIT_DEFAULT_REF_FORMAT");
27922772
if (repo_fmt->version >= 0 &&
@@ -2824,9 +2804,6 @@ static void repository_format_configure(struct repository *repo,
28242804

28252805
free(backend);
28262806
}
2827-
2828-
repo_set_ref_storage_format(repo, repo_fmt->ref_storage_format,
2829-
repo_fmt->ref_storage_payload);
28302807
}
28312808

28322809
int init_db(struct repository *repo,
@@ -2840,6 +2817,7 @@ int init_db(struct repository *repo,
28402817
int exist_ok = flags & INIT_DB_EXIST_OK;
28412818
char *original_git_dir = real_pathdup(git_dir, 1);
28422819
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
2820+
struct strbuf err = STRBUF_INIT;
28432821

28442822
if (real_git_dir) {
28452823
struct stat st;
@@ -2866,10 +2844,11 @@ int init_db(struct repository *repo,
28662844
* config file, so this will not fail. What we are catching
28672845
* is an attempt to reinitialize new repository with an old tool.
28682846
*/
2869-
check_and_apply_repository_format(repo, &repo_fmt,
2870-
APPLY_REPOSITORY_FORMAT_HONOR_ENV);
2871-
2872-
repository_format_configure(repo, &repo_fmt, hash, ref_storage_format);
2847+
check_repository_format_gently(repo_get_git_dir(repo), &repo_fmt, NULL);
2848+
repository_format_configure(&repo_fmt, hash, ref_storage_format);
2849+
if (apply_repository_format(repo, &repo_fmt, APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
2850+
die("%s", err.buf);
2851+
startup_info->have_repository = 1;
28732852

28742853
/*
28752854
* Ensure `core.hidedotfiles` is processed. This must happen after we
@@ -2924,6 +2903,7 @@ int init_db(struct repository *repo,
29242903
}
29252904

29262905
clear_repository_format(&repo_fmt);
2906+
strbuf_release(&err);
29272907
free(original_git_dir);
29282908
return 0;
29292909
}

0 commit comments

Comments
 (0)