From 2e573d61ffe3d1e7ea94673757fb69477c1499bc Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 8 Jan 2024 11:05:26 +0100 Subject: refs: prepare `refs_init_db()` for initializing worktree refs The purpose of `refs_init_db()` is to initialize the on-disk files of a new ref database. The function is quite inflexible right now though, as callers can neither specify the `struct ref_store` nor can they pass any flags. Refactor the interface to accept both of these. This will be required so that we can start initializing per-worktree ref databases via the ref backend instead of open-coding the initialization in "worktree.c". Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/files-backend.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'refs/files-backend.c') diff --git a/refs/files-backend.c b/refs/files-backend.c index 43fd0ac760..153efe6662 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -3220,7 +3220,9 @@ static int files_reflog_expire(struct ref_store *ref_store, return -1; } -static int files_init_db(struct ref_store *ref_store, struct strbuf *err UNUSED) +static int files_init_db(struct ref_store *ref_store, + int flags UNUSED, + struct strbuf *err UNUSED) { struct files_ref_store *refs = files_downcast(ref_store, REF_STORE_WRITE, "init_db"); -- cgit v1.2.3 From c358d165f2a4b3176b527e18c207105f6821335e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 8 Jan 2024 11:05:30 +0100 Subject: setup: move creation of "refs/" into the files backend When creating the ref database we unconditionally create the "refs/" directory in "setup.c". This is a mandatory prerequisite for all Git repositories regardless of the ref backend in use, because Git will be unable to detect the directory as a repository if "refs/" doesn't exist. We are about to add another new caller that will want to create a ref database when creating worktrees. We would require the same logic to create the "refs/" directory even though the caller really should not care about such low-level details. Ideally, the ref database should be fully initialized after calling `refs_init_db()`. Move the code to create the directory into the files backend itself to make it so. This means that future ref backends will also need to have equivalent logic around to ensure that the directory exists, but it seems a lot more sensible to have it this way round than to require callers to create the directory themselves. An alternative to this would be to create "refs/" in `refs_init_db()` directly. This feels conceptually unclean though as the creation of the refdb is now cluttered across different callsites. Furthermore, both the "files" and the upcoming "reftable" backend write backend-specific data into the "refs/" directory anyway, so splitting up this logic would only make it harder to reason about. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/files-backend.c | 17 +++++++++++++++++ setup.c | 15 --------------- 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'refs/files-backend.c') diff --git a/refs/files-backend.c b/refs/files-backend.c index 153efe6662..054ecdbca3 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -3228,9 +3228,26 @@ static int files_init_db(struct ref_store *ref_store, files_downcast(ref_store, REF_STORE_WRITE, "init_db"); struct strbuf sb = STRBUF_INIT; + /* + * We need to create a "refs" dir in any case so that older versions of + * Git can tell that this is a repository. This serves two main purposes: + * + * - Clients will know to stop walking the parent-directory chain when + * detecting the Git repository. Otherwise they may end up detecting + * a Git repository in a parent directory instead. + * + * - Instead of failing to detect a repository with unknown reference + * format altogether, old clients will print an error saying that + * they do not understand the reference format extension. + */ + strbuf_addf(&sb, "%s/refs", ref_store->gitdir); + safe_create_dir(sb.buf, 1); + adjust_shared_perm(sb.buf); + /* * Create .git/refs/{heads,tags} */ + strbuf_reset(&sb); files_ref_path(refs, &sb, "refs/heads"); safe_create_dir(sb.buf, 1); diff --git a/setup.c b/setup.c index 6c8f656f7c..abb271e017 100644 --- a/setup.c +++ b/setup.c @@ -1927,21 +1927,6 @@ void create_reference_database(unsigned int ref_storage_format, struct strbuf err = STRBUF_INIT; int reinit = is_reinit(); - /* - * We need to create a "refs" dir in any case so that older versions of - * Git can tell that this is a repository. This serves two main purposes: - * - * - Clients will know to stop walking the parent-directory chain when - * detecting the Git repository. Otherwise they may end up detecting - * a Git repository in a parent directory instead. - * - * - Instead of failing to detect a repository with unknown reference - * format altogether, old clients will print an error saying that - * they do not understand the reference format extension. - */ - safe_create_dir(git_path("refs"), 1); - adjust_shared_perm(git_path("refs")); - repo_set_ref_storage_format(the_repository, ref_storage_format); if (refs_init_db(get_main_ref_store(the_repository), 0, &err)) die("failed to set up refs db: %s", err.buf); -- cgit v1.2.3 From 2eb1d0c45271faf149a13b61bb74af52abd7b3aa Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 8 Jan 2024 11:05:35 +0100 Subject: refs/files: skip creation of "refs/{heads,tags}" for worktrees The files ref backend will create both "refs/heads" and "refs/tags" in the Git directory. While this logic makes sense for normal repositories, it does not for worktrees because those refs are "common" refs that would always be contained in the main repository's ref database. Introduce a new flag telling the backend that it is expected to create a per-worktree ref database and skip creation of these dirs in the files backend when the flag is set. No other backends (currently) need worktree-specific logic, so this is the only required change to start creating per-worktree ref databases via `refs_init_db()`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs.h | 2 ++ refs/files-backend.c | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'refs/files-backend.c') diff --git a/refs.h b/refs.h index 114caa272a..c2dfe451a1 100644 --- a/refs.h +++ b/refs.h @@ -126,6 +126,8 @@ int should_autocreate_reflog(const char *refname); int is_branch(const char *refname); +#define REFS_INIT_DB_IS_WORKTREE (1 << 0) + int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err); /* diff --git a/refs/files-backend.c b/refs/files-backend.c index 054ecdbca3..6dae37e351 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -3221,7 +3221,7 @@ static int files_reflog_expire(struct ref_store *ref_store, } static int files_init_db(struct ref_store *ref_store, - int flags UNUSED, + int flags, struct strbuf *err UNUSED) { struct files_ref_store *refs = @@ -3245,15 +3245,21 @@ static int files_init_db(struct ref_store *ref_store, adjust_shared_perm(sb.buf); /* - * Create .git/refs/{heads,tags} + * There is no need to create directories for common refs when creating + * a worktree ref store. */ - strbuf_reset(&sb); - files_ref_path(refs, &sb, "refs/heads"); - safe_create_dir(sb.buf, 1); + if (!(flags & REFS_INIT_DB_IS_WORKTREE)) { + /* + * Create .git/refs/{heads,tags} + */ + strbuf_reset(&sb); + files_ref_path(refs, &sb, "refs/heads"); + safe_create_dir(sb.buf, 1); - strbuf_reset(&sb); - files_ref_path(refs, &sb, "refs/tags"); - safe_create_dir(sb.buf, 1); + strbuf_reset(&sb); + files_ref_path(refs, &sb, "refs/tags"); + safe_create_dir(sb.buf, 1); + } strbuf_release(&sb); return 0; -- cgit v1.2.3