setup: correctly reinitialize repository version

When reinitializing a repository, Git does not account for extensions other than `objectformat` and `refstorage` when determining the repository version. This can lead to a repository being downgraded to version 0 if extensions are set, causing Git future operations to fail. This patch teaches Git to check if other extensions are defined in the config to ensure that the repository version is set correctly. Signed-off-by: Caleb White <cdwhite3@pm.me> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Caleb White committed Nov 29, 2024 at 22:22 UTC d897f2c16da9ab9588d2015121449d5bc54c9736
2 files changed +26 -12
setup.c
+23 -9
@@ -2204,8 +2204,8 @@ void initialize_repository_version(int hash_algo,
2204 enum ref_storage_format ref_storage_format,
2205 int reinit)
2206 {
2207 - char repo_version_string[10];
2208 - int repo_version = GIT_REPO_VERSION;
2207 + struct strbuf repo_version = STRBUF_INIT;
2208 + int target_version = GIT_REPO_VERSION;
2209
2210 /*
2211 * Note that we initialize the repository version to 1 when the ref
@@ -2216,12 +2216,7 @@ void initialize_repository_version(int hash_algo,
2216 */
2217 if (hash_algo != GIT_HASH_SHA1 ||
2218 ref_storage_format != REF_STORAGE_FORMAT_FILES)
2219 - repo_version = GIT_REPO_VERSION_READ;
2220 -
2221 - /* This forces creation of new config file */
2222 - xsnprintf(repo_version_string, sizeof(repo_version_string),
2223 - "%d", repo_version);
2224 - git_config_set("core.repositoryformatversion", repo_version_string);
2219 + target_version = GIT_REPO_VERSION_READ;
2220
2221 if (hash_algo != GIT_HASH_SHA1 && hash_algo != GIT_HASH_UNKNOWN)
2222 git_config_set("extensions.objectformat",
@@ -2234,6 +2229,25 @@ void initialize_repository_version(int hash_algo,
2229 ref_storage_format_to_name(ref_storage_format));
2230 else if (reinit)
2231 git_config_set_gently("extensions.refstorage", NULL);
2232 +
2233 + if (reinit) {
2234 + struct strbuf config = STRBUF_INIT;
2235 + struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
2236 +
2237 + strbuf_git_common_path(&config, the_repository, "config");
2238 + read_repository_format(&repo_fmt, config.buf);
2239 +
2240 + if (repo_fmt.v1_only_extensions.nr)
2241 + target_version = GIT_REPO_VERSION_READ;
2242 +
2243 + strbuf_release(&config);
2244 + clear_repository_format(&repo_fmt);
2245 + }
2246 +
2247 + strbuf_addf(&repo_version, "%d", target_version);
2248 + git_config_set("core.repositoryformatversion", repo_version.buf);
2249 +
2250 + strbuf_release(&repo_version);
2251 }
2252
2253 static int is_reinit(void)
@@ -2333,7 +2347,7 @@ static int create_default_files(const char *template_path,
2347 adjust_shared_perm(repo_get_git_dir(the_repository));
2348 }
2349
2336 - initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, 0);
2350 + initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, reinit);
2351
2352 /* Check filemode trustability */
2353 path = git_path_buf(&buf, "config");
t/t5504-fetch-receive-strict.sh
+3 -3
@@ -171,7 +171,7 @@ test_expect_success 'fsck with invalid or bogus skipList input' '
171 test_must_fail git -c fsck.skipList=does-not-exist -c fsck.missingEmail=ignore fsck 2>err &&
172 test_grep "could not open.*: does-not-exist" err &&
173 test_must_fail git -c fsck.skipList=.git/config -c fsck.missingEmail=ignore fsck 2>err &&
174 - test_grep "invalid object name: \[core\]" err
174 + test_grep "invalid object name: " err
175 '
176
177 test_expect_success 'fsck with other accepted skipList input (comments & empty lines)' '
@@ -234,7 +234,7 @@ test_expect_success 'push with receive.fsck.skipList' '
234 test_grep "could not open.*: does-not-exist" err &&
235 git --git-dir=dst/.git config receive.fsck.skipList config &&
236 test_must_fail git push --porcelain dst bogus 2>err &&
237 - test_grep "invalid object name: \[core\]" err &&
237 + test_grep "invalid object name: " err &&
238
239 git --git-dir=dst/.git config receive.fsck.skipList SKIP &&
240 git push --porcelain dst bogus
@@ -263,7 +263,7 @@ test_expect_success 'fetch with fetch.fsck.skipList' '
263 test_grep "could not open.*: does-not-exist" err &&
264 git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/config &&
265 test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec 2>err &&
266 - test_grep "invalid object name: \[core\]" err &&
266 + test_grep "invalid object name: " err &&
267
268 git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/SKIP &&
269 git --git-dir=dst/.git fetch "file://$(pwd)" $refspec