setup: construct object database in `apply_repository_format()`

With the preceding changes we now always construct the repository's object database before applying the repository format. Remove this duplication by constructing it in `apply_repository_format()` instead. Note that we create the object database _after_ having set up the repository's hash algorithm, but _before_ setting the compat hash algorithm. This is intentional: - Constructing the object database may require knowledge of its intended object format. - Setting up the compatibility hash requires the object database to be initialized already, because we immediately read the loose object map. The first point is sensible, the second maybe a little less so. Ideally, it should be the responsibility of the object database itself to initialize any data structures required for the compatibility hash. But this would require further changes, so this is kept as-is for now. Further note that this requires us to move handling of the environment variables GIT_OBJECT_DIRECTORY and GIT_ALTERNATE_OBJECT_DIRECTORIES into the repository format, as well. This allows the caller more flexibility around whether or not those environment variables are being honored, as we want to respect them in "setup.c", but not in "repository.c". Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jun 4, 2026 at 09:46 UTC 42b9d3dc9dfa9e733cbd6402e665ac35fce0c216
3 files changed +32 -27
repository.c
+1 -3
@@ -291,13 +291,11 @@ int repo_init(struct repository *repo,
291 if (read_repository_format_from_commondir(&format, repo->commondir))
292 goto error;
293
294 - if (apply_repository_format(repo, &format, &err) < 0) {
294 + if (apply_repository_format(repo, &format, 0, &err) < 0) {
295 warning("%s", err.buf);
296 goto error;
297 }
298
299 - repo->objects = odb_new(repo, NULL, NULL);
300 -
299 if (worktree)
300 repo_set_worktree(repo, worktree);
301
setup.c
+21 -24
@@ -1752,12 +1752,22 @@ enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
1752
1753 int apply_repository_format(struct repository *repo,
1754 const struct repository_format *format,
1755 + enum apply_repository_format_flags flags,
1756 struct strbuf *err)
1757 {
1758 + char *object_directory = NULL, *alternate_object_directories = NULL;
1759 +
1760 if (verify_repository_format(format, err) < 0)
1761 return -1;
1762
1763 + if (flags & APPLY_REPOSITORY_FORMAT_HONOR_ENV) {
1764 + object_directory = xstrdup_or_null(getenv(DB_ENVIRONMENT));
1765 + alternate_object_directories = xstrdup_or_null(getenv(ALTERNATE_DB_ENVIRONMENT));
1766 + }
1767 +
1768 repo_set_hash_algo(repo, format->hash_algo);
1769 + repo->objects = odb_new(repo, object_directory,
1770 + alternate_object_directories);
1771 repo_set_compat_hash_algo(repo, format->compat_hash_algo);
1772 repo_set_ref_storage_format(repo,
1773 format->ref_storage_format,
@@ -1773,6 +1783,8 @@ int apply_repository_format(struct repository *repo,
1783 repo->repository_format_precious_objects =
1784 format->precious_objects;
1785
1786 + free(alternate_object_directories);
1787 + free(object_directory);
1788 return 0;
1789 }
1790
@@ -1785,7 +1797,8 @@ int apply_repository_format(struct repository *repo,
1797 * If successful and fmt is not NULL, fill fmt with data.
1798 */
1799 static void check_and_apply_repository_format(struct repository *repo,
1788 - struct repository_format *fmt)
1800 + struct repository_format *fmt,
1801 + enum apply_repository_format_flags flags)
1802 {
1803 struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
1804 struct strbuf err = STRBUF_INIT;
@@ -1794,7 +1807,7 @@ static void check_and_apply_repository_format(struct repository *repo,
1807 fmt = &repo_fmt;
1808
1809 check_repository_format_gently(repo_get_git_dir(repo), fmt, NULL);
1797 - if (apply_repository_format(repo, fmt, &err) < 0)
1810 + if (apply_repository_format(repo, fmt, flags, &err) < 0)
1811 die("%s", err.buf);
1812 startup_info->have_repository = 1;
1813
@@ -1874,15 +1887,9 @@ const char *enter_repo(struct repository *repo, const char *path, unsigned flags
1887 }
1888
1889 if (is_git_directory(".")) {
1877 - struct strvec to_free = STRVEC_INIT;
1878 -
1890 set_git_dir(repo, ".", 0);
1880 - repo->objects = odb_new(repo,
1881 - getenv_safe(&to_free, DB_ENVIRONMENT),
1882 - getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT));
1883 - check_and_apply_repository_format(repo, NULL);
1884 -
1885 - strvec_clear(&to_free);
1891 + check_and_apply_repository_format(repo, NULL,
1892 + APPLY_REPOSITORY_FORMAT_HONOR_ENV);
1893 return path;
1894 }
1895
@@ -2034,8 +2041,6 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
2041 startup_info->have_repository ||
2042 /* GIT_DIR_EXPLICIT */
2043 getenv(GIT_DIR_ENVIRONMENT)) {
2037 - struct strvec to_free = STRVEC_INIT;
2038 -
2044 if (!repo->gitdir) {
2045 const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
2046 if (!gitdir)
@@ -2046,17 +2051,13 @@ const char *setup_git_directory_gently(struct repository *repo, int *nongit_ok)
2051 if (startup_info->have_repository) {
2052 struct strbuf err = STRBUF_INIT;
2053
2049 - repo->objects = odb_new(repo,
2050 - getenv_safe(&to_free, DB_ENVIRONMENT),
2051 - getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT));
2052 - if (apply_repository_format(repo, &repo_fmt, &err) < 0)
2054 + if (apply_repository_format(repo, &repo_fmt,
2055 + APPLY_REPOSITORY_FORMAT_HONOR_ENV, &err) < 0)
2056 die("%s", err.buf);
2057
2058 clear_repository_format(&repo_fmt);
2059 strbuf_release(&err);
2060 }
2058 -
2059 - strvec_clear(&to_free);
2061 }
2062 /*
2063 * Since precompose_string_if_needed() needs to look at
@@ -2805,7 +2806,6 @@ int init_db(struct repository *repo,
2806 int exist_ok = flags & INIT_DB_EXIST_OK;
2807 char *original_git_dir = real_pathdup(git_dir, 1);
2808 struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
2808 - struct strvec to_free = STRVEC_INIT;
2809
2810 if (real_git_dir) {
2811 struct stat st;
@@ -2826,16 +2826,14 @@ int init_db(struct repository *repo,
2826 }
2827 startup_info->have_repository = 1;
2828
2829 - repo->objects = odb_new(repo, getenv_safe(&to_free, DB_ENVIRONMENT),
2830 - getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT));
2831 -
2829 /*
2830 * Check to see if the repository version is right.
2831 * Note that a newly created repository does not have
2832 * config file, so this will not fail. What we are catching
2833 * is an attempt to reinitialize new repository with an old tool.
2834 */
2838 - check_and_apply_repository_format(repo, &repo_fmt);
2835 + check_and_apply_repository_format(repo, &repo_fmt,
2836 + APPLY_REPOSITORY_FORMAT_HONOR_ENV);
2837
2838 repository_format_configure(repo, &repo_fmt, hash, ref_storage_format);
2839
@@ -2892,7 +2890,6 @@ int init_db(struct repository *repo,
2890 }
2891
2892 clear_repository_format(&repo_fmt);
2895 - strvec_clear(&to_free);
2893 free(original_git_dir);
2894 return 0;
2895 }
setup.h
+10
@@ -221,6 +221,15 @@ void clear_repository_format(struct repository_format *format);
221 int verify_repository_format(const struct repository_format *format,
222 struct strbuf *err);
223
224 +enum apply_repository_format_flags {
225 + /*
226 + * Honor environment variables when applying the repository format to
227 + * the repository. For now, this only covers environment variables that
228 + * relate to the object database.
229 + */
230 + APPLY_REPOSITORY_FORMAT_HONOR_ENV = (1 << 0),
231 +};
232 +
233 /*
234 * Apply the given repository format to the repo. This initializes extensions
235 * and basic data structures required for normal operation. Returns 0 on
@@ -229,6 +238,7 @@ int verify_repository_format(const struct repository_format *format,
238 */
239 int apply_repository_format(struct repository *repo,
240 const struct repository_format *format,
241 + enum apply_repository_format_flags flags,
242 struct strbuf *err);
243
244 const char *get_template_dir(const char *option_template);