setup: start tracking ref storage format

In order to discern which ref storage format a repository is supposed to use we need to start setting up and/or discovering the format. This needs to happen in two separate code paths. - The first path is when we create a repository via `init_db()`. When we are re-initializing a preexisting repository we need to retain the previously used ref storage format -- if the user asked for a different format then this indicates an error and we error out. Otherwise we either initialize the repository with the format asked for by the user or the default format, which currently is the "files" backend. - The second path is when discovering repositories, where we need to read the config of that repository. There is not yet any way to configure something other than the "files" backend, so we can just blindly set the ref storage format to this backend. Wire up this logic so that we have the ref storage format always readily available when needed. As there is only a single backend and because it is not configurable we cannot yet verify that this tracking works as expected via tests, but tests will be added in subsequent commits. To countermand this ommission now though, raise a BUG() in case the ref storage format is not set up properly in `ref_store_init()`. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Dec 29, 2023 at 08:26 UTC 173761e21b2978fe7c0f7af7276e8b14511fed23
7 files changed +48 -9
builtin/clone.c
+3 -2
@@ -1107,7 +1107,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1107 * repository, and reference backends may persist that information into
1108 * their on-disk data structures.
1109 */
1110 - init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
1110 + init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN,
1111 + REF_STORAGE_FORMAT_UNKNOWN, NULL,
1112 do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
1113
1114 if (real_git_dir) {
@@ -1292,7 +1293,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1293 hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
1294 initialize_repository_version(hash_algo, 1);
1295 repo_set_hash_algo(the_repository, hash_algo);
1295 - create_reference_database(NULL, 1);
1296 + create_reference_database(the_repository->ref_storage_format, NULL, 1);
1297
1298 /*
1299 * Before fetching from the remote, download and install bundle
builtin/init-db.c
+3 -1
@@ -11,6 +11,7 @@
11 #include "object-file.h"
12 #include "parse-options.h"
13 #include "path.h"
14 +#include "refs.h"
15 #include "setup.h"
16 #include "strbuf.h"
17
@@ -236,5 +237,6 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
237
238 flags |= INIT_DB_EXIST_OK;
239 return init_db(git_dir, real_git_dir, template_dir, hash_algo,
239 - initial_branch, init_shared_repository, flags);
240 + REF_STORAGE_FORMAT_UNKNOWN, initial_branch,
241 + init_shared_repository, flags);
242 }
refs.c
+2 -2
@@ -2045,10 +2045,10 @@ static struct ref_store *ref_store_init(struct repository *repo,
2045 const char *gitdir,
2046 unsigned int flags)
2047 {
2048 - unsigned int format = REF_STORAGE_FORMAT_FILES;
2049 - const struct ref_storage_be *be = find_ref_storage_backend(format);
2048 + const struct ref_storage_be *be;
2049 struct ref_store *refs;
2050
2051 + be = find_ref_storage_backend(repo->ref_storage_format);
2052 if (!be)
2053 BUG("reference backend is unknown");
2054
repository.c
+6
@@ -104,6 +104,11 @@ void repo_set_hash_algo(struct repository *repo, int hash_algo)
104 repo->hash_algo = &hash_algos[hash_algo];
105 }
106
107 +void repo_set_ref_storage_format(struct repository *repo, unsigned int format)
108 +{
109 + repo->ref_storage_format = format;
110 +}
111 +
112 /*
113 * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
114 * Return 0 upon success and a non-zero value upon failure.
@@ -184,6 +189,7 @@ int repo_init(struct repository *repo,
189 goto error;
190
191 repo_set_hash_algo(repo, format.hash_algo);
192 + repo_set_ref_storage_format(repo, format.ref_storage_format);
193 repo->repository_format_worktree_config = format.worktree_config;
194
195 /* take ownership of format.partial_clone */
repository.h
+4
@@ -163,6 +163,9 @@ struct repository {
163 /* Repository's current hash algorithm, as serialized on disk. */
164 const struct git_hash_algo *hash_algo;
165
166 + /* Repository's reference storage format, as serialized on disk. */
167 + unsigned int ref_storage_format;
168 +
169 /* A unique-id for tracing purposes. */
170 int trace2_repo_id;
171
@@ -202,6 +205,7 @@ void repo_set_gitdir(struct repository *repo, const char *root,
205 const struct set_gitdir_args *extra_args);
206 void repo_set_worktree(struct repository *repo, const char *path);
207 void repo_set_hash_algo(struct repository *repo, int algo);
208 +void repo_set_ref_storage_format(struct repository *repo, unsigned int format);
209 void initialize_the_repository(void);
210 RESULT_MUST_BE_USED
211 int repo_init(struct repository *r, const char *gitdir, const char *worktree);
setup.c
+25 -3
@@ -1566,6 +1566,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
1566 }
1567 if (startup_info->have_repository) {
1568 repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
1569 + repo_set_ref_storage_format(the_repository,
1570 + repo_fmt.ref_storage_format);
1571 the_repository->repository_format_worktree_config =
1572 repo_fmt.worktree_config;
1573 /* take ownership of repo_fmt.partial_clone */
@@ -1659,6 +1661,8 @@ void check_repository_format(struct repository_format *fmt)
1661 check_repository_format_gently(get_git_dir(), fmt, NULL);
1662 startup_info->have_repository = 1;
1663 repo_set_hash_algo(the_repository, fmt->hash_algo);
1664 + repo_set_ref_storage_format(the_repository,
1665 + fmt->ref_storage_format);
1666 the_repository->repository_format_worktree_config =
1667 fmt->worktree_config;
1668 the_repository->repository_format_partial_clone =
@@ -1899,7 +1903,8 @@ static int is_reinit(void)
1903 return ret;
1904 }
1905
1902 -void create_reference_database(const char *initial_branch, int quiet)
1906 +void create_reference_database(unsigned int ref_storage_format,
1907 + const char *initial_branch, int quiet)
1908 {
1909 struct strbuf err = STRBUF_INIT;
1910 int reinit = is_reinit();
@@ -1919,6 +1924,7 @@ void create_reference_database(const char *initial_branch, int quiet)
1924 safe_create_dir(git_path("refs"), 1);
1925 adjust_shared_perm(git_path("refs"));
1926
1927 + repo_set_ref_storage_format(the_repository, ref_storage_format);
1928 if (refs_init_db(&err))
1929 die("failed to set up refs db: %s", err.buf);
1930
@@ -2137,8 +2143,22 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
2143 }
2144 }
2145
2146 +static void validate_ref_storage_format(struct repository_format *repo_fmt,
2147 + unsigned int format)
2148 +{
2149 + if (repo_fmt->version >= 0 &&
2150 + format != REF_STORAGE_FORMAT_UNKNOWN &&
2151 + format != repo_fmt->ref_storage_format) {
2152 + die(_("attempt to reinitialize repository with different reference storage format"));
2153 + } else if (format != REF_STORAGE_FORMAT_UNKNOWN) {
2154 + repo_fmt->ref_storage_format = format;
2155 + }
2156 +}
2157 +
2158 int init_db(const char *git_dir, const char *real_git_dir,
2141 - const char *template_dir, int hash, const char *initial_branch,
2159 + const char *template_dir, int hash,
2160 + unsigned int ref_storage_format,
2161 + const char *initial_branch,
2162 int init_shared_repository, unsigned int flags)
2163 {
2164 int reinit;
@@ -2181,13 +2201,15 @@ int init_db(const char *git_dir, const char *real_git_dir,
2201 check_repository_format(&repo_fmt);
2202
2203 validate_hash_algorithm(&repo_fmt, hash);
2204 + validate_ref_storage_format(&repo_fmt, ref_storage_format);
2205
2206 reinit = create_default_files(template_dir, original_git_dir,
2207 &repo_fmt, prev_bare_repository,
2208 init_shared_repository);
2209
2210 if (!(flags & INIT_DB_SKIP_REFDB))
2190 - create_reference_database(initial_branch, flags & INIT_DB_QUIET);
2211 + create_reference_database(repo_fmt.ref_storage_format,
2212 + initial_branch, flags & INIT_DB_QUIET);
2213 create_object_directory();
2214
2215 if (get_shared_repository()) {
setup.h
+5 -1
@@ -115,6 +115,7 @@ struct repository_format {
115 int worktree_config;
116 int is_bare;
117 int hash_algo;
118 + unsigned int ref_storage_format;
119 int sparse_index;
120 char *work_tree;
121 struct string_list unknown_extensions;
@@ -131,6 +132,7 @@ struct repository_format {
132 .version = -1, \
133 .is_bare = -1, \
134 .hash_algo = GIT_HASH_SHA1, \
135 + .ref_storage_format = REF_STORAGE_FORMAT_FILES, \
136 .unknown_extensions = STRING_LIST_INIT_DUP, \
137 .v1_only_extensions = STRING_LIST_INIT_DUP, \
138 }
@@ -175,10 +177,12 @@ void check_repository_format(struct repository_format *fmt);
177
178 int init_db(const char *git_dir, const char *real_git_dir,
179 const char *template_dir, int hash_algo,
180 + unsigned int ref_storage_format,
181 const char *initial_branch, int init_shared_repository,
182 unsigned int flags);
183 void initialize_repository_version(int hash_algo, int reinit);
181 -void create_reference_database(const char *initial_branch, int quiet);
184 +void create_reference_database(unsigned int ref_storage_format,
185 + const char *initial_branch, int quiet);
186
187 /*
188 * NOTE NOTE NOTE!!