Skip to content

Commit 2cf9c22

Browse files
committed
Merge branch 'ps/hash-and-ref-format-from-config'
The default object hash and ref backend format used to be settable only with explicit command line option to "git init" and environment variables, but now they can be configured in the user's global and system wide configuration. * ps/hash-and-ref-format-from-config: setup: make ref storage format configurable via config setup: make object format configurable via config setup: merge configuration of repository formats t0001: delete repositories when object format tests finish t0001: exercise initialization with ref formats more thoroughly
2 parents 668843e + d2511ee commit 2cf9c22

File tree

3 files changed

+216
-40
lines changed

3 files changed

+216
-40
lines changed

Documentation/config/init.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,13 @@ endif::[]
88
`init.defaultBranch`::
99
Allows overriding the default branch name e.g. when initializing
1010
a new repository.
11+
`init.defaultObjectFormat`::
12+
Allows overriding the default object format for new repositories. See
13+
`--object-format=` in linkgit:git-init[1]. Both the command line option
14+
and the `GIT_DEFAULT_HASH` environment variable take precedence over
15+
this config.
16+
`init.defaultRefFormat`::
17+
Allows overriding the default ref storage format for new repositories.
18+
See `--ref-format=` in linkgit:git-init[1]. Both the command line
19+
option and the `GIT_DEFAULT_REF_FORMAT` environment variable take
20+
precedence over this config.

setup.c

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2320,14 +2320,67 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
23202320
write_file(git_link, "gitdir: %s", git_dir);
23212321
}
23222322

2323-
static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
2323+
struct default_format_config {
2324+
int hash;
2325+
enum ref_storage_format ref_format;
2326+
};
2327+
2328+
static int read_default_format_config(const char *key, const char *value,
2329+
const struct config_context *ctx UNUSED,
2330+
void *payload)
23242331
{
2325-
const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
2332+
struct default_format_config *cfg = payload;
2333+
char *str = NULL;
2334+
int ret;
2335+
2336+
if (!strcmp(key, "init.defaultobjectformat")) {
2337+
ret = git_config_string(&str, key, value);
2338+
if (ret)
2339+
goto out;
2340+
cfg->hash = hash_algo_by_name(str);
2341+
if (cfg->hash == GIT_HASH_UNKNOWN)
2342+
warning(_("unknown hash algorithm '%s'"), str);
2343+
goto out;
2344+
}
2345+
2346+
if (!strcmp(key, "init.defaultrefformat")) {
2347+
ret = git_config_string(&str, key, value);
2348+
if (ret)
2349+
goto out;
2350+
cfg->ref_format = ref_storage_format_by_name(str);
2351+
if (cfg->ref_format == REF_STORAGE_FORMAT_UNKNOWN)
2352+
warning(_("unknown ref storage format '%s'"), str);
2353+
goto out;
2354+
}
2355+
2356+
ret = 0;
2357+
out:
2358+
free(str);
2359+
return ret;
2360+
}
2361+
2362+
static void repository_format_configure(struct repository_format *repo_fmt,
2363+
int hash, enum ref_storage_format ref_format)
2364+
{
2365+
struct default_format_config cfg = {
2366+
.hash = GIT_HASH_UNKNOWN,
2367+
.ref_format = REF_STORAGE_FORMAT_UNKNOWN,
2368+
};
2369+
struct config_options opts = {
2370+
.respect_includes = 1,
2371+
.ignore_repo = 1,
2372+
.ignore_worktree = 1,
2373+
};
2374+
const char *env;
2375+
2376+
config_with_options(read_default_format_config, &cfg, NULL, NULL, &opts);
2377+
23262378
/*
23272379
* If we already have an initialized repo, don't allow the user to
23282380
* specify a different algorithm, as that could cause corruption.
23292381
* Otherwise, if the user has specified one on the command line, use it.
23302382
*/
2383+
env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
23312384
if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
23322385
die(_("attempt to reinitialize repository with different hash"));
23332386
else if (hash != GIT_HASH_UNKNOWN)
@@ -2337,26 +2390,27 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
23372390
if (env_algo == GIT_HASH_UNKNOWN)
23382391
die(_("unknown hash algorithm '%s'"), env);
23392392
repo_fmt->hash_algo = env_algo;
2393+
} else if (cfg.hash != GIT_HASH_UNKNOWN) {
2394+
repo_fmt->hash_algo = cfg.hash;
23402395
}
2341-
}
2342-
2343-
static void validate_ref_storage_format(struct repository_format *repo_fmt,
2344-
enum ref_storage_format format)
2345-
{
2346-
const char *name = getenv("GIT_DEFAULT_REF_FORMAT");
2396+
repo_set_hash_algo(the_repository, repo_fmt->hash_algo);
23472397

2398+
env = getenv("GIT_DEFAULT_REF_FORMAT");
23482399
if (repo_fmt->version >= 0 &&
2349-
format != REF_STORAGE_FORMAT_UNKNOWN &&
2350-
format != repo_fmt->ref_storage_format) {
2400+
ref_format != REF_STORAGE_FORMAT_UNKNOWN &&
2401+
ref_format != repo_fmt->ref_storage_format) {
23512402
die(_("attempt to reinitialize repository with different reference storage format"));
2352-
} else if (format != REF_STORAGE_FORMAT_UNKNOWN) {
2353-
repo_fmt->ref_storage_format = format;
2354-
} else if (name) {
2355-
format = ref_storage_format_by_name(name);
2356-
if (format == REF_STORAGE_FORMAT_UNKNOWN)
2357-
die(_("unknown ref storage format '%s'"), name);
2358-
repo_fmt->ref_storage_format = format;
2403+
} else if (ref_format != REF_STORAGE_FORMAT_UNKNOWN) {
2404+
repo_fmt->ref_storage_format = ref_format;
2405+
} else if (env) {
2406+
ref_format = ref_storage_format_by_name(env);
2407+
if (ref_format == REF_STORAGE_FORMAT_UNKNOWN)
2408+
die(_("unknown ref storage format '%s'"), env);
2409+
repo_fmt->ref_storage_format = ref_format;
2410+
} else if (cfg.ref_format != REF_STORAGE_FORMAT_UNKNOWN) {
2411+
repo_fmt->ref_storage_format = cfg.ref_format;
23592412
}
2413+
repo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);
23602414
}
23612415

23622416
int init_db(const char *git_dir, const char *real_git_dir,
@@ -2389,22 +2443,15 @@ int init_db(const char *git_dir, const char *real_git_dir,
23892443
}
23902444
startup_info->have_repository = 1;
23912445

2392-
/* Check to see if the repository version is right.
2446+
/*
2447+
* Check to see if the repository version is right.
23932448
* Note that a newly created repository does not have
23942449
* config file, so this will not fail. What we are catching
23952450
* is an attempt to reinitialize new repository with an old tool.
23962451
*/
23972452
check_repository_format(&repo_fmt);
23982453

2399-
validate_hash_algorithm(&repo_fmt, hash);
2400-
validate_ref_storage_format(&repo_fmt, ref_storage_format);
2401-
2402-
/*
2403-
* Now that we have set up both the hash algorithm and the ref storage
2404-
* format we can update the repository's settings accordingly.
2405-
*/
2406-
repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
2407-
repo_set_ref_storage_format(the_repository, repo_fmt.ref_storage_format);
2454+
repository_format_configure(&repo_fmt, hash, ref_storage_format);
24082455

24092456
/*
24102457
* Ensure `core.hidedotfiles` is processed. This must happen after we

t/t0001-init.sh

Lines changed: 132 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ test_expect_success 're-init from a linked worktree' '
500500
'
501501

502502
test_expect_success 'init honors GIT_DEFAULT_HASH' '
503+
test_when_finished "rm -rf sha1 sha256" &&
503504
GIT_DEFAULT_HASH=sha1 git init sha1 &&
504505
git -C sha1 rev-parse --show-object-format >actual &&
505506
echo sha1 >expected &&
@@ -511,6 +512,7 @@ test_expect_success 'init honors GIT_DEFAULT_HASH' '
511512
'
512513

513514
test_expect_success 'init honors --object-format' '
515+
test_when_finished "rm -rf explicit-sha1 explicit-sha256" &&
514516
git init --object-format=sha1 explicit-sha1 &&
515517
git -C explicit-sha1 rev-parse --show-object-format >actual &&
516518
echo sha1 >expected &&
@@ -521,7 +523,58 @@ test_expect_success 'init honors --object-format' '
521523
test_cmp expected actual
522524
'
523525

526+
test_expect_success 'init honors init.defaultObjectFormat' '
527+
test_when_finished "rm -rf sha1 sha256" &&
528+
529+
test_config_global init.defaultObjectFormat sha1 &&
530+
(
531+
sane_unset GIT_DEFAULT_HASH &&
532+
git init sha1 &&
533+
git -C sha1 rev-parse --show-object-format >actual &&
534+
echo sha1 >expected &&
535+
test_cmp expected actual
536+
) &&
537+
538+
test_config_global init.defaultObjectFormat sha256 &&
539+
(
540+
sane_unset GIT_DEFAULT_HASH &&
541+
git init sha256 &&
542+
git -C sha256 rev-parse --show-object-format >actual &&
543+
echo sha256 >expected &&
544+
test_cmp expected actual
545+
)
546+
'
547+
548+
test_expect_success 'init warns about invalid init.defaultObjectFormat' '
549+
test_when_finished "rm -rf repo" &&
550+
test_config_global init.defaultObjectFormat garbage &&
551+
552+
echo "warning: unknown hash algorithm ${SQ}garbage${SQ}" >expect &&
553+
git init repo 2>err &&
554+
test_cmp expect err &&
555+
556+
git -C repo rev-parse --show-object-format >actual &&
557+
echo $GIT_DEFAULT_HASH >expected &&
558+
test_cmp expected actual
559+
'
560+
561+
test_expect_success '--object-format overrides GIT_DEFAULT_HASH' '
562+
test_when_finished "rm -rf repo" &&
563+
GIT_DEFAULT_HASH=sha1 git init --object-format=sha256 repo &&
564+
git -C repo rev-parse --show-object-format >actual &&
565+
echo sha256 >expected
566+
'
567+
568+
test_expect_success 'GIT_DEFAULT_HASH overrides init.defaultObjectFormat' '
569+
test_when_finished "rm -rf repo" &&
570+
test_config_global init.defaultObjectFormat sha1 &&
571+
GIT_DEFAULT_HASH=sha256 git init repo &&
572+
git -C repo rev-parse --show-object-format >actual &&
573+
echo sha256 >expected
574+
'
575+
524576
test_expect_success 'extensions.objectFormat is not allowed with repo version 0' '
577+
test_when_finished "rm -rf explicit-v0" &&
525578
git init --object-format=sha256 explicit-v0 &&
526579
git -C explicit-v0 config core.repositoryformatversion 0 &&
527580
test_must_fail git -C explicit-v0 rev-parse --show-object-format
@@ -558,15 +611,6 @@ test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with unknown back
558611
grep "invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}" err
559612
'
560613

561-
test_expect_success DEFAULT_REPO_FORMAT 'init with GIT_DEFAULT_REF_FORMAT=files' '
562-
test_when_finished "rm -rf refformat" &&
563-
GIT_DEFAULT_REF_FORMAT=files git init refformat &&
564-
echo 0 >expect &&
565-
git -C refformat config core.repositoryformatversion >actual &&
566-
test_cmp expect actual &&
567-
test_must_fail git -C refformat config extensions.refstorage
568-
'
569-
570614
test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '
571615
test_when_finished "rm -rf refformat" &&
572616
cat >expect <<-EOF &&
@@ -576,15 +620,90 @@ test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '
576620
test_cmp expect err
577621
'
578622

579-
test_expect_success 'init with --ref-format=files' '
623+
test_expect_success 'init warns about invalid init.defaultRefFormat' '
624+
test_when_finished "rm -rf repo" &&
625+
test_config_global init.defaultRefFormat garbage &&
626+
627+
echo "warning: unknown ref storage format ${SQ}garbage${SQ}" >expect &&
628+
git init repo 2>err &&
629+
test_cmp expect err &&
630+
631+
git -C repo rev-parse --show-ref-format >actual &&
632+
echo $GIT_DEFAULT_REF_FORMAT >expected &&
633+
test_cmp expected actual
634+
'
635+
636+
backends="files reftable"
637+
for format in $backends
638+
do
639+
test_expect_success DEFAULT_REPO_FORMAT "init with GIT_DEFAULT_REF_FORMAT=$format" '
640+
test_when_finished "rm -rf refformat" &&
641+
GIT_DEFAULT_REF_FORMAT=$format git init refformat &&
642+
643+
if test $format = files
644+
then
645+
test_must_fail git -C refformat config extensions.refstorage &&
646+
echo 0 >expect
647+
else
648+
git -C refformat config extensions.refstorage &&
649+
echo 1 >expect
650+
fi &&
651+
git -C refformat config core.repositoryformatversion >actual &&
652+
test_cmp expect actual &&
653+
654+
echo $format >expect &&
655+
git -C refformat rev-parse --show-ref-format >actual &&
656+
test_cmp expect actual
657+
'
658+
659+
test_expect_success "init with --ref-format=$format" '
660+
test_when_finished "rm -rf refformat" &&
661+
git init --ref-format=$format refformat &&
662+
echo $format >expect &&
663+
git -C refformat rev-parse --show-ref-format >actual &&
664+
test_cmp expect actual
665+
'
666+
667+
test_expect_success "init with init.defaultRefFormat=$format" '
668+
test_when_finished "rm -rf refformat" &&
669+
test_config_global init.defaultRefFormat $format &&
670+
(
671+
sane_unset GIT_DEFAULT_REF_FORMAT &&
672+
git init refformat
673+
) &&
674+
675+
echo $format >expect &&
676+
git -C refformat rev-parse --show-ref-format >actual &&
677+
test_cmp expect actual
678+
'
679+
680+
test_expect_success "--ref-format=$format overrides GIT_DEFAULT_REF_FORMAT" '
681+
test_when_finished "rm -rf refformat" &&
682+
GIT_DEFAULT_REF_FORMAT=garbage git init --ref-format=$format refformat &&
683+
echo $format >expect &&
684+
git -C refformat rev-parse --show-ref-format >actual &&
685+
test_cmp expect actual
686+
'
687+
done
688+
689+
test_expect_success "--ref-format= overrides GIT_DEFAULT_REF_FORMAT" '
580690
test_when_finished "rm -rf refformat" &&
581-
git init --ref-format=files refformat &&
582-
echo files >expect &&
691+
GIT_DEFAULT_REF_FORMAT=files git init --ref-format=reftable refformat &&
692+
echo reftable >expect &&
693+
git -C refformat rev-parse --show-ref-format >actual &&
694+
test_cmp expect actual
695+
'
696+
697+
test_expect_success "GIT_DEFAULT_REF_FORMAT= overrides init.defaultRefFormat" '
698+
test_when_finished "rm -rf refformat" &&
699+
test_config_global init.defaultRefFormat files &&
700+
701+
GIT_DEFAULT_REF_FORMAT=reftable git init refformat &&
702+
echo reftable >expect &&
583703
git -C refformat rev-parse --show-ref-format >actual &&
584704
test_cmp expect actual
585705
'
586706

587-
backends="files reftable"
588707
for from_format in $backends
589708
do
590709
test_expect_success "re-init with same format ($from_format)" '

0 commit comments

Comments
 (0)