{"thread":{"id":"61955","subject":"[PATCH 0/5] Introduce configs for default repo format","startedAt":"2024-08-15T07:59:59Z","lastAt":"2024-08-16T17:13:12Z","messageCount":24,"participants":["Patrick Steinhardt","shejialuo","Justin Tobler","brian m. carlson","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"500957","messageId":"cover.1723708417.git.ps@pks.im","threadId":"61955","inReplyTo":null,"subject":"[PATCH 0/5] Introduce configs for default repo format","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-15T07:59:54Z","receivedAt":"2024-08-15T07:59:59Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nto set up the default object and ref storage formats, users have to set\nup some environment variables. This is somewhat unwieldy and not really\nin line with how a user typically expects to configure Git, namely by\nusing the config system. It makes it harder than necessary to globally\ndefault to the different formats and requires the user to munge with\nfiles like `.profile` to persist that setting. Needless to say, this is\na bit of an awkward user experience.\n\nThis patch series thus introduces two new configs to set the default\nobject hash and ref storage format for newly created repositories. Like\nthis, folks can simply use the global- or system-level config to adapt\nto their needs. This also has the advantage of giving them the ability\nto adapt the default formats via guarded includes, such that e.g. repos\nin some filesystem hierarchy use format A, whereas others use format B.\n\nThis comes from a discussion with Sebastian (Cc'd) at the Git User Group\nin Berlin yesterday.\n\nThanks!\n\nPatrick\n\nPatrick Steinhardt (5):\n  t0001: exercise initialization with ref formats more thoroughly\n  t0001: delete repositories when object format tests finish\n  setup: merge configuration of repository formats\n  setup: make object format configurable via config\n  setup: make ref storage format configurable via config\n\n Documentation/config/init.txt |  10 +++\n setup.c                       | 101 ++++++++++++++++-------\n t/t0001-init.sh               | 145 +++++++++++++++++++++++++++++++---\n 3 files changed, 216 insertions(+), 40 deletions(-)\n\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"500958","messageId":"0d3844db32237983a1d85ced1a3b1b25fcd1d6eb.1723708417.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723708417.git.ps@pks.im","subject":"[PATCH 1/5] t0001: exercise initialization with ref formats more thoroughly","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-15T07:59:58Z","receivedAt":"2024-08-15T08:00:05Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"While our object format tests for git-init(1) exercise tests with all\nknown formats in t0001, the tests for the ref format don't. This leads\nto some missing test coverage for interesting cases, like whether or not\na non-default ref storage format causes us to bump the repository format\nversion. We also don't test for the precedence of the `--ref-format=`\nand the `GIT_DEFAULT_REF_FORMAT=` environment variable.\n\nExtend the test suite to cover more scenarios related to the ref format.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0001-init.sh | 48 +++++++++++++++++++++++++++++++++++-------------\n 1 file changed, 35 insertions(+), 13 deletions(-)\n\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 49e9bf77c6..2093f5c1ee 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -558,15 +558,6 @@ test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with unknown back\n \tgrep \"invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}\" err\n '\n \n-test_expect_success DEFAULT_REPO_FORMAT 'init with GIT_DEFAULT_REF_FORMAT=files' '\n-\ttest_when_finished \"rm -rf refformat\" &&\n-\tGIT_DEFAULT_REF_FORMAT=files git init refformat &&\n-\techo 0 >expect &&\n-\tgit -C refformat config core.repositoryformatversion >actual &&\n-\ttest_cmp expect actual &&\n-\ttest_must_fail git -C refformat config extensions.refstorage\n-'\n-\n test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '\n \ttest_when_finished \"rm -rf refformat\" &&\n \tcat >expect <<-EOF &&\n@@ -576,15 +567,46 @@ test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'init with --ref-format=files' '\n+backends=\"files reftable\"\n+for format in $backends\n+do\n+\ttest_expect_success DEFAULT_REPO_FORMAT \"init with GIT_DEFAULT_REF_FORMAT=$format\" '\n+\t\ttest_when_finished \"rm -rf refformat\" &&\n+\t\tGIT_DEFAULT_REF_FORMAT=$format git init refformat &&\n+\n+\t\tif test $format = files\n+\t\tthen\n+\t\t\ttest_must_fail git -C refformat config extensions.refstorage &&\n+\t\t\techo 0 >expect\n+\t\telse\n+\t\t\tgit -C refformat config extensions.refstorage &&\n+\t\t\techo 1 >expect\n+\t\tfi &&\n+\t\tgit -C refformat config core.repositoryformatversion >actual &&\n+\t\ttest_cmp expect actual &&\n+\n+\t\techo $format >expect &&\n+\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n+\n+\ttest_expect_success \"init with --ref-format=$format\" '\n+\t\ttest_when_finished \"rm -rf refformat\" &&\n+\t\tgit init --ref-format=$format refformat &&\n+\t\techo $format >expect &&\n+\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n+done\n+\n+test_expect_success \"--ref-format= overrides GIT_DEFAULT_REF_FORMAT\" '\n \ttest_when_finished \"rm -rf refformat\" &&\n-\tgit init --ref-format=files refformat &&\n-\techo files >expect &&\n+\tGIT_DEFAULT_REF_FORMAT=files git init --ref-format=reftable refformat &&\n+\techo reftable >expect &&\n \tgit -C refformat rev-parse --show-ref-format >actual &&\n \ttest_cmp expect actual\n '\n \n-backends=\"files reftable\"\n for from_format in $backends\n do\n \ttest_expect_success \"re-init with same format ($from_format)\" '\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"500959","messageId":"6b0cefef6af3a94cd3b650b2ab06de489dbdaf20.1723708417.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723708417.git.ps@pks.im","subject":"[PATCH 2/5] t0001: delete repositories when object format tests finish","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-15T08:00:00Z","receivedAt":"2024-08-15T08:00:06Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The object format tests create one-shot repositories that are only used\nby the respective test, but never delete them. This makes it hard to\npick a proper repository name in subsequent tests, as more and more\nnames are taken already.\n\nDelete these repositories via `test_when_finished`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0001-init.sh | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 2093f5c1ee..795408e16c 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -500,6 +500,7 @@ test_expect_success 're-init from a linked worktree' '\n '\n \n test_expect_success 'init honors GIT_DEFAULT_HASH' '\n+\ttest_when_finished \"rm -rf sha1 sha256\" &&\n \tGIT_DEFAULT_HASH=sha1 git init sha1 &&\n \tgit -C sha1 rev-parse --show-object-format >actual &&\n \techo sha1 >expected &&\n@@ -511,6 +512,7 @@ test_expect_success 'init honors GIT_DEFAULT_HASH' '\n '\n \n test_expect_success 'init honors --object-format' '\n+\ttest_when_finished \"rm -rf explicit-sha1 explicit-sha256\" &&\n \tgit init --object-format=sha1 explicit-sha1 &&\n \tgit -C explicit-sha1 rev-parse --show-object-format >actual &&\n \techo sha1 >expected &&\n@@ -522,6 +524,7 @@ test_expect_success 'init honors --object-format' '\n '\n \n test_expect_success 'extensions.objectFormat is not allowed with repo version 0' '\n+\ttest_when_finished \"rm -rf explicit-v0\" &&\n \tgit init --object-format=sha256 explicit-v0 &&\n \tgit -C explicit-v0 config core.repositoryformatversion 0 &&\n \ttest_must_fail git -C explicit-v0 rev-parse --show-object-format\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"500960","messageId":"16f52b75d8972343776adb269da305e7406ff385.1723708417.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723708417.git.ps@pks.im","subject":"[PATCH 3/5] setup: merge configuration of repository formats","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-15T08:00:03Z","receivedAt":"2024-08-15T08:00:06Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The configuration of repository formats is split up across two functions\n`validate_hash_algorithm()` and `validate_ref_storage_format()`. This is\nfine as-is, but we are about to extend the logic to also read default\nvalues from the config. With the logic split across two functions, we\nwould either have to pass in additional parameters read from the config,\nor read the config multiple times. Both of these options feel a bit\nunwieldy.\n\nMerge the code into a new a new function `repository_format_configure()`\nthat is responsible for configuring the whole repository's format. Like\nthis, we can easily read the config in a single place, only.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n setup.c | 47 ++++++++++++++++++++---------------------------\n 1 file changed, 20 insertions(+), 27 deletions(-)\n\ndiff --git a/setup.c b/setup.c\nindex d458edcc02..5dfcdc99dd 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -2284,14 +2284,17 @@ static void separate_git_dir(const char *git_dir, const char *git_link)\n \twrite_file(git_link, \"gitdir: %s\", git_dir);\n }\n \n-static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)\n+static void repository_format_configure(struct repository_format *repo_fmt,\n+\t\t\t\t\tint hash, enum ref_storage_format ref_format)\n {\n-\tconst char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);\n+\tconst char *env;\n+\n \t/*\n \t * If we already have an initialized repo, don't allow the user to\n \t * specify a different algorithm, as that could cause corruption.\n \t * Otherwise, if the user has specified one on the command line, use it.\n \t */\n+\tenv = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);\n \tif (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)\n \t\tdie(_(\"attempt to reinitialize repository with different hash\"));\n \telse if (hash != GIT_HASH_UNKNOWN)\n@@ -2302,25 +2305,22 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash\n \t\t\tdie(_(\"unknown hash algorithm '%s'\"), env);\n \t\trepo_fmt->hash_algo = env_algo;\n \t}\n-}\n-\n-static void validate_ref_storage_format(struct repository_format *repo_fmt,\n-\t\t\t\t\tenum ref_storage_format format)\n-{\n-\tconst char *name = getenv(\"GIT_DEFAULT_REF_FORMAT\");\n+\trepo_set_hash_algo(the_repository, repo_fmt->hash_algo);\n \n+\tenv = getenv(\"GIT_DEFAULT_REF_FORMAT\");\n \tif (repo_fmt->version >= 0 &&\n-\t    format != REF_STORAGE_FORMAT_UNKNOWN &&\n-\t    format != repo_fmt->ref_storage_format) {\n+\t    ref_format != REF_STORAGE_FORMAT_UNKNOWN &&\n+\t    ref_format != repo_fmt->ref_storage_format) {\n \t\tdie(_(\"attempt to reinitialize repository with different reference storage format\"));\n-\t} else if (format != REF_STORAGE_FORMAT_UNKNOWN) {\n-\t\trepo_fmt->ref_storage_format = format;\n-\t} else if (name) {\n-\t\tformat = ref_storage_format_by_name(name);\n-\t\tif (format == REF_STORAGE_FORMAT_UNKNOWN)\n-\t\t\tdie(_(\"unknown ref storage format '%s'\"), name);\n-\t\trepo_fmt->ref_storage_format = format;\n+\t} else if (ref_format != REF_STORAGE_FORMAT_UNKNOWN) {\n+\t\trepo_fmt->ref_storage_format = ref_format;\n+\t} else if (env) {\n+\t\tref_format = ref_storage_format_by_name(env);\n+\t\tif (ref_format == REF_STORAGE_FORMAT_UNKNOWN)\n+\t\t\tdie(_(\"unknown ref storage format '%s'\"), env);\n+\t\trepo_fmt->ref_storage_format = ref_format;\n \t}\n+\trepo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);\n }\n \n int init_db(const char *git_dir, const char *real_git_dir,\n@@ -2353,22 +2353,15 @@ int init_db(const char *git_dir, const char *real_git_dir,\n \t}\n \tstartup_info->have_repository = 1;\n \n-\t/* Check to see if the repository version is right.\n+\t/*\n+\t * Check to see if the repository version is right.\n \t * Note that a newly created repository does not have\n \t * config file, so this will not fail.  What we are catching\n \t * is an attempt to reinitialize new repository with an old tool.\n \t */\n \tcheck_repository_format(&repo_fmt);\n \n-\tvalidate_hash_algorithm(&repo_fmt, hash);\n-\tvalidate_ref_storage_format(&repo_fmt, ref_storage_format);\n-\n-\t/*\n-\t * Now that we have set up both the hash algorithm and the ref storage\n-\t * format we can update the repository's settings accordingly.\n-\t */\n-\trepo_set_hash_algo(the_repository, repo_fmt.hash_algo);\n-\trepo_set_ref_storage_format(the_repository, repo_fmt.ref_storage_format);\n+\trepository_format_configure(&repo_fmt, hash, ref_storage_format);\n \n \t/*\n \t * Ensure `core.hidedotfiles` is processed. This must happen after we\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"500961","messageId":"a0417b7d1a8e96f71399117f3f7333c5a2920dce.1723708417.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723708417.git.ps@pks.im","subject":"[PATCH 5/5] setup: make ref storage format configurable via config","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-15T08:00:09Z","receivedAt":"2024-08-15T08:00:17Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Similar as the preceding commit, introduce a new \"init.defaultRefFormat\"\nconfig that allows the user to globally set the ref storage format used\nby newly created repositories.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Documentation/config/init.txt |  5 ++++\n setup.c                       | 14 +++++++++++\n t/t0001-init.sh               | 44 +++++++++++++++++++++++++++++++++++\n 3 files changed, 63 insertions(+)\n\ndiff --git a/Documentation/config/init.txt b/Documentation/config/init.txt\nindex d6f8b6e61b..9be97bcac8 100644\n--- a/Documentation/config/init.txt\n+++ b/Documentation/config/init.txt\n@@ -13,3 +13,8 @@ endif::[]\n \t`--object-format=` in linkgit:git-init[1]. Both the command line option\n \tand the `GIT_DEFAULT_HASH` environment variable take precedence over\n \tthis config.\n+`init.defaultRefFormat`::\n+\tAllows overriding the default object format for new repositories. See\n+\t`--ref-format=` in linkgit:git-init[1]. Both the command line option\n+\tand the `GIT_DEFAULT_REF_FORMAT` environment variable take precedence\n+\tover this config.\ndiff --git a/setup.c b/setup.c\nindex 770ad1393f..dd2251f655 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -2286,6 +2286,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link)\n \n struct default_format_config {\n \tint hash;\n+\tenum ref_storage_format ref_format;\n };\n \n static int read_default_format_config(const char *key, const char *value,\n@@ -2306,6 +2307,16 @@ static int read_default_format_config(const char *key, const char *value,\n \t\tgoto out;\n \t}\n \n+\tif (!strcmp(key, \"init.defaultrefformat\")) {\n+\t\tret = git_config_string(&str, key, value);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t\tcfg->ref_format = ref_storage_format_by_name(str);\n+\t\tif (cfg->ref_format == REF_STORAGE_FORMAT_UNKNOWN)\n+\t\t\twarning(_(\"unknown ref storage format '%s'\"), str);\n+\t\tgoto out;\n+\t}\n+\n \tret = 0;\n out:\n \tfree(str);\n@@ -2317,6 +2328,7 @@ static void repository_format_configure(struct repository_format *repo_fmt,\n {\n \tstruct default_format_config cfg = {\n \t\t.hash = GIT_HASH_UNKNOWN,\n+\t\t.ref_format = REF_STORAGE_FORMAT_UNKNOWN,\n \t};\n \tstruct config_options opts = {\n \t\t.respect_includes = 1,\n@@ -2359,6 +2371,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,\n \t\tif (ref_format == REF_STORAGE_FORMAT_UNKNOWN)\n \t\t\tdie(_(\"unknown ref storage format '%s'\"), env);\n \t\trepo_fmt->ref_storage_format = ref_format;\n+\t} else if (cfg.ref_format != REF_STORAGE_FORMAT_UNKNOWN) {\n+\t\trepo_fmt->ref_storage_format = cfg.ref_format;\n \t}\n \trepo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);\n }\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex cd34710f32..0178aa62a4 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -620,6 +620,19 @@ test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '\n \ttest_cmp expect err\n '\n \n+test_expect_success 'init warns about invalid init.defaultRefFormat' '\n+\ttest_when_finished \"rm -rf repo\" &&\n+\ttest_config_global init.defaultRefFormat garbage &&\n+\n+\techo \"warning: unknown ref storage format ${SQ}garbage${SQ}\" >expect &&\n+\tgit init repo 2>err &&\n+\ttest_cmp expect err &&\n+\n+\tgit -C repo rev-parse --show-ref-format >actual &&\n+\techo $GIT_DEFAULT_REF_FORMAT >expected &&\n+\ttest_cmp expected actual\n+'\n+\n backends=\"files reftable\"\n for format in $backends\n do\n@@ -650,6 +663,27 @@ do\n \t\tgit -C refformat rev-parse --show-ref-format >actual &&\n \t\ttest_cmp expect actual\n \t'\n+\n+\ttest_expect_success \"init with init.defaultRefFormat=$format\" '\n+\t\ttest_when_finished \"rm -rf refformat\" &&\n+\t\ttest_config_global init.defaultRefFormat $format &&\n+\t\t(\n+\t\t\tsane_unset GIT_DEFAULT_REF_FORMAT &&\n+\t\t\tgit init refformat\n+\t\t) &&\n+\n+\t\techo $format >expect &&\n+\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n+\n+\ttest_expect_success \"--ref-format=$format overrides GIT_DEFAULT_REF_FORMAT\" '\n+\t\ttest_when_finished \"rm -rf refformat\" &&\n+\t\tGIT_DEFAULT_REF_FORMAT=garbage git init --ref-format=$format refformat &&\n+\t\techo $format >expect &&\n+\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n done\n \n test_expect_success \"--ref-format= overrides GIT_DEFAULT_REF_FORMAT\" '\n@@ -660,6 +694,16 @@ test_expect_success \"--ref-format= overrides GIT_DEFAULT_REF_FORMAT\" '\n \ttest_cmp expect actual\n '\n \n+test_expect_success \"GIT_DEFAULT_REF_FORMAT= overrides init.defaultRefFormat\" '\n+\ttest_when_finished \"rm -rf refformat\" &&\n+\ttest_config_global init.defaultRefFormat files &&\n+\n+\tGIT_DEFAULT_REF_FORMAT=reftable git init refformat &&\n+\techo reftable >expect &&\n+\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\ttest_cmp expect actual\n+'\n+\n for from_format in $backends\n do\n \ttest_expect_success \"re-init with same format ($from_format)\" '\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"500962","messageId":"e1cdaf0f0edec578d1cb9358fd4c6f6b39aaad3a.1723708417.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723708417.git.ps@pks.im","subject":"[PATCH 4/5] setup: make object format configurable via config","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-15T08:00:06Z","receivedAt":"2024-08-15T08:00:17Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The object format for repositories can either be configured explicitly\nby passing the `--object-format=` option to git-init(1) or git-clone(1),\nor globally by setting the `GIT_DEFAULT_HASH` environment variable.\nWhile the former makes sense, setting random environment variables is\nnot really a good user experience in case someone decides to only use\nSHA256 repositories.\n\nIt is only natural to expect for a user that things like this can also\nbe configured via their config. As such, introduce a new config\n\"init.defaultObjectFormat\", similar to \"init.defaultBranch\", that allows\nthe user to configure the default object format when creating new repos.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Documentation/config/init.txt |  5 ++++\n setup.c                       | 40 ++++++++++++++++++++++++++++\n t/t0001-init.sh               | 50 +++++++++++++++++++++++++++++++++++\n 3 files changed, 95 insertions(+)\n\ndiff --git a/Documentation/config/init.txt b/Documentation/config/init.txt\nindex af03acdbcb..d6f8b6e61b 100644\n--- a/Documentation/config/init.txt\n+++ b/Documentation/config/init.txt\n@@ -8,3 +8,8 @@ endif::[]\n `init.defaultBranch`::\n \tAllows overriding the default branch name e.g. when initializing\n \ta new repository.\n+`init.defaultObjectFormat`::\n+\tAllows overriding the default object format for new repositories. See\n+\t`--object-format=` in linkgit:git-init[1]. Both the command line option\n+\tand the `GIT_DEFAULT_HASH` environment variable take precedence over\n+\tthis config.\ndiff --git a/setup.c b/setup.c\nindex 5dfcdc99dd..770ad1393f 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -2284,11 +2284,49 @@ static void separate_git_dir(const char *git_dir, const char *git_link)\n \twrite_file(git_link, \"gitdir: %s\", git_dir);\n }\n \n+struct default_format_config {\n+\tint hash;\n+};\n+\n+static int read_default_format_config(const char *key, const char *value,\n+\t\t\t\t      const struct config_context *ctx UNUSED,\n+\t\t\t\t      void *payload)\n+{\n+\tstruct default_format_config *cfg = payload;\n+\tchar *str = NULL;\n+\tint ret;\n+\n+\tif (!strcmp(key, \"init.defaultobjectformat\")) {\n+\t\tret = git_config_string(&str, key, value);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t\tcfg->hash = hash_algo_by_name(str);\n+\t\tif (cfg->hash == GIT_HASH_UNKNOWN)\n+\t\t\twarning(_(\"unknown hash algorithm '%s'\"), str);\n+\t\tgoto out;\n+\t}\n+\n+\tret = 0;\n+out:\n+\tfree(str);\n+\treturn ret;\n+}\n+\n static void repository_format_configure(struct repository_format *repo_fmt,\n \t\t\t\t\tint hash, enum ref_storage_format ref_format)\n {\n+\tstruct default_format_config cfg = {\n+\t\t.hash = GIT_HASH_UNKNOWN,\n+\t};\n+\tstruct config_options opts = {\n+\t\t.respect_includes = 1,\n+\t\t.ignore_repo = 1,\n+\t\t.ignore_worktree = 1,\n+\t};\n \tconst char *env;\n \n+\tconfig_with_options(read_default_format_config, &cfg, NULL, NULL, &opts);\n+\n \t/*\n \t * If we already have an initialized repo, don't allow the user to\n \t * specify a different algorithm, as that could cause corruption.\n@@ -2304,6 +2342,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,\n \t\tif (env_algo == GIT_HASH_UNKNOWN)\n \t\t\tdie(_(\"unknown hash algorithm '%s'\"), env);\n \t\trepo_fmt->hash_algo = env_algo;\n+\t} else if (cfg.hash != GIT_HASH_UNKNOWN) {\n+\t\trepo_fmt->hash_algo = cfg.hash;\n \t}\n \trepo_set_hash_algo(the_repository, repo_fmt->hash_algo);\n \ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 795408e16c..cd34710f32 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -523,6 +523,56 @@ test_expect_success 'init honors --object-format' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'init honors init.defaultObjectFormat' '\n+\ttest_when_finished \"rm -rf sha1 sha256\" &&\n+\n+\ttest_config_global init.defaultObjectFormat sha1 &&\n+\t(\n+\t\tsane_unset GIT_DEFAULT_HASH &&\n+\t\tgit init sha1 &&\n+\t\tgit -C sha1 rev-parse --show-object-format >actual &&\n+\t\techo sha1 >expected &&\n+\t\ttest_cmp expected actual\n+\t) &&\n+\n+\ttest_config_global init.defaultObjectFormat sha256 &&\n+\t(\n+\t\tsane_unset GIT_DEFAULT_HASH &&\n+\t\tgit init sha256 &&\n+\t\tgit -C sha256 rev-parse --show-object-format >actual &&\n+\t\techo sha256 >expected &&\n+\t\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'init warns about invalid init.defaultObjectFormat' '\n+\ttest_when_finished \"rm -rf repo\" &&\n+\ttest_config_global init.defaultObjectFormat garbage &&\n+\n+\techo \"warning: unknown hash algorithm ${SQ}garbage${SQ}\" >expect &&\n+\tgit init repo 2>err &&\n+\ttest_cmp expect err &&\n+\n+\tgit -C repo rev-parse --show-object-format >actual &&\n+\techo $GIT_DEFAULT_HASH >expected &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success '--object-format overrides GIT_DEFAULT_HASH' '\n+\ttest_when_finished \"rm -rf repo\" &&\n+\tGIT_DEFAULT_HASH=sha1 git init --object-format=sha256 repo &&\n+\tgit -C repo rev-parse --show-object-format >actual &&\n+\techo sha256 >expected\n+'\n+\n+test_expect_success 'GIT_DEFAULT_HASH overrides init.defaultObjectFormat' '\n+\ttest_when_finished \"rm -rf repo\" &&\n+\ttest_config_global init.defaultObjectFormat sha1 &&\n+\tGIT_DEFAULT_HASH=sha256 git init repo &&\n+\tgit -C repo rev-parse --show-object-format >actual &&\n+\techo sha256 >expected\n+'\n+\n test_expect_success 'extensions.objectFormat is not allowed with repo version 0' '\n \ttest_when_finished \"rm -rf explicit-v0\" &&\n \tgit init --object-format=sha256 explicit-v0 &&\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"501014","messageId":"Zr4dvybR6j6Ifyya@ArchLinux","threadId":"61955","inReplyTo":"cover.1723708417.git.ps@pks.im","subject":"Re: [PATCH 0/5] Introduce configs for default repo format","fromName":"shejialuo","fromEmail":"shejialuo@gmail.com","sentAt":"2024-08-15T15:24:47Z","receivedAt":"2024-08-15T15:24:11Z","isPatch":true,"sender":{"key":"shejialuo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56911263?v=4"},"body":"On Thu, Aug 15, 2024 at 09:59:54AM +0200, Patrick Steinhardt wrote:\n> Hi,\n> \n> to set up the default object and ref storage formats, users have to set\n> up some environment variables. This is somewhat unwieldy and not really\n> in line with how a user typically expects to configure Git, namely by\n> using the config system. It makes it harder than necessary to globally\n> default to the different formats and requires the user to munge with\n> files like `.profile` to persist that setting. Needless to say, this is\n> a bit of an awkward user experience.\n> \n> This patch series thus introduces two new configs to set the default\n> object hash and ref storage format for newly created repositories. Like\n> this, folks can simply use the global- or system-level config to adapt\n> to their needs. This also has the advantage of giving them the ability\n> to adapt the default formats via guarded includes, such that e.g. repos\n> in some filesystem hierarchy use format A, whereas others use format B.\n> \n> This comes from a discussion with Sebastian (Cc'd) at the Git User Group\n> in Berlin yesterday.\n> \n> Thanks!\n> \n> Patrick\n> \n\nIt's a good idea to make the user could set up the default object and\nref storage formats by \"git-config(1)\". I have read all the patches,\nfrom my perspective, there is no major problems.\n\nBut I wanna ask a question here about the following code snippet:\n\n  if (repo_fmt->version >= 0 && hash !=  GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)\n          die(_(\"...\"));\n  else if (hash != GIT_HASH_UNKNOWN)\n          repo_fmt->hash_algo = hash;\n  else if (env) {\n          ...\n          repo_fmt->hash_algo = env_algo;\n  } else if (cfg.hash != GIT_HASH_UNKNOWN) {\n          repo_fmt->hash_algo = cfg.hash;\n  }\n\nIt's obvious that the precedence of \"hash\" is the top. We need to make\nsure when users execute \"git init --object-format=sha256\" command, this\nexplicit info should be considered at the top. However, in the current\ndesign, the precedence of the environment variable is higher than the\n\"git-config(1)\".\n\nIf the user uses the following command:\n\n  $ export GIT_DEFAULT_HASH_ENVIRONMENT=sha1\n  $ git -c init.defaultObjectFormat=sha256 repo\n\nThe repo would be initialized with the sha1 algorithm. I think we should\nthink carefully which precedence should be higher. I cannot give an\nanswer here. I am not familiar with the whole database and do not the\nconcern. But from my own perspective, I think the precedence of the\nconfig should be higher than the environment variable. This is a new\nfeature, the people who would like to use it, they will never use\nenvironment variable and we should ignore the functionality of the\nenvironment variable. But for people who do not know this feature, they\nwill continue to use the environment variable and they will never be\ninfluenced by the configs.\n\nThanks,\nJialuo\n"},{"id":"501044","messageId":"vivxxi4dylb74fmplbcizsslldsracntksmvw6m4m2yqgf3zp4@itwngidkrswy","threadId":"61955","inReplyTo":"0d3844db32237983a1d85ced1a3b1b25fcd1d6eb.1723708417.git.ps@pks.im","subject":"Re: [PATCH 1/5] t0001: exercise initialization with ref formats more thoroughly","fromName":"Justin Tobler","fromEmail":"jltobler@gmail.com","sentAt":"2024-08-15T20:35:38Z","receivedAt":"2024-08-15T20:36:29Z","isPatch":true,"sender":{"key":"jltobler@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53454972?v=4"},"body":"On 24/08/15 09:59AM, Patrick Steinhardt wrote:\n> While our object format tests for git-init(1) exercise tests with all\n> known formats in t0001, the tests for the ref format don't. This leads\n> to some missing test coverage for interesting cases, like whether or not\n> a non-default ref storage format causes us to bump the repository format\n> version. We also don't test for the precedence of the `--ref-format=`\n> and the `GIT_DEFAULT_REF_FORMAT=` environment variable.\n\nMakes sense to plug these test gaps.\n\n> Extend the test suite to cover more scenarios related to the ref format.\n> \n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  t/t0001-init.sh | 48 +++++++++++++++++++++++++++++++++++-------------\n>  1 file changed, 35 insertions(+), 13 deletions(-)\n> \n> diff --git a/t/t0001-init.sh b/t/t0001-init.sh\n> index 49e9bf77c6..2093f5c1ee 100755\n> --- a/t/t0001-init.sh\n> +++ b/t/t0001-init.sh\n> @@ -558,15 +558,6 @@ test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with unknown back\n>  \tgrep \"invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}\" err\n>  '\n>  \n> -test_expect_success DEFAULT_REPO_FORMAT 'init with GIT_DEFAULT_REF_FORMAT=files' '\n> -\ttest_when_finished \"rm -rf refformat\" &&\n> -\tGIT_DEFAULT_REF_FORMAT=files git init refformat &&\n> -\techo 0 >expect &&\n> -\tgit -C refformat config core.repositoryformatversion >actual &&\n> -\ttest_cmp expect actual &&\n> -\ttest_must_fail git -C refformat config extensions.refstorage\n> -'\n> -\n>  test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '\n>  \ttest_when_finished \"rm -rf refformat\" &&\n>  \tcat >expect <<-EOF &&\n> @@ -576,15 +567,46 @@ test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '\n>  \ttest_cmp expect err\n>  '\n>  \n> -test_expect_success 'init with --ref-format=files' '\n> +backends=\"files reftable\"\n> +for format in $backends\n> +do\n> +\ttest_expect_success DEFAULT_REPO_FORMAT \"init with GIT_DEFAULT_REF_FORMAT=$format\" '\n\nThe `DEFAULT_REPO_FORMAT` prereq is needed here because a non-default\nrepo format also changes the repository format version.\n\n> +\t\ttest_when_finished \"rm -rf refformat\" &&\n> +\t\tGIT_DEFAULT_REF_FORMAT=$format git init refformat &&\n> +\n> +\t\tif test $format = files\n> +\t\tthen\n> +\t\t\ttest_must_fail git -C refformat config extensions.refstorage &&\n> +\t\t\techo 0 >expect\n> +\t\telse\n> +\t\t\tgit -C refformat config extensions.refstorage &&\n> +\t\t\techo 1 >expect\n> +\t\tfi &&\n> +\t\tgit -C refformat config core.repositoryformatversion >actual &&\n> +\t\ttest_cmp expect actual &&\n> +\n> +\t\techo $format >expect &&\n> +\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n> +\t\ttest_cmp expect actual\n> +\t'\n> +\n> +\ttest_expect_success \"init with --ref-format=$format\" '\n> +\t\ttest_when_finished \"rm -rf refformat\" &&\n> +\t\tgit init --ref-format=$format refformat &&\n> +\t\techo $format >expect &&\n> +\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n> +\t\ttest_cmp expect actual\n> +\t'\n> +done\n> +\n> +test_expect_success \"--ref-format= overrides GIT_DEFAULT_REF_FORMAT\" '\n>  \ttest_when_finished \"rm -rf refformat\" &&\n> -\tgit init --ref-format=files refformat &&\n> -\techo files >expect &&\n> +\tGIT_DEFAULT_REF_FORMAT=files git init --ref-format=reftable refformat &&\n> +\techo reftable >expect &&\n>  \tgit -C refformat rev-parse --show-ref-format >actual &&\n>  \ttest_cmp expect actual\n>  '\n\nNice that we now validate that the `--ref-format` option takes\nprecedence over the `GIT_DEFAULT_REF_FORMAT` environment variable.\n\n-Justin\n"},{"id":"501059","messageId":"Zr5wODo8tgGtPEIM@tapette.crustytoothpaste.net","threadId":"61955","inReplyTo":"Zr4dvybR6j6Ifyya@ArchLinux","subject":"Re: [PATCH 0/5] Introduce configs for default repo format","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2024-08-15T21:16:40Z","receivedAt":"2024-08-15T21:16:48Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2024-08-15 at 15:24:47, shejialuo wrote:\n> If the user uses the following command:\n> \n>   $ export GIT_DEFAULT_HASH_ENVIRONMENT=sha1\n>   $ git -c init.defaultObjectFormat=sha256 repo\n> \n> The repo would be initialized with the sha1 algorithm. I think we should\n> think carefully which precedence should be higher. I cannot give an\n> answer here. I am not familiar with the whole database and do not the\n> concern. But from my own perspective, I think the precedence of the\n> config should be higher than the environment variable. This is a new\n> feature, the people who would like to use it, they will never use\n> environment variable and we should ignore the functionality of the\n> environment variable. But for people who do not know this feature, they\n> will continue to use the environment variable and they will never be\n> influenced by the configs.\n\nThe standard behaviour we have with other environment variables is that\nthey override the config, such as with `GIT_SSH_COMMAND` and\n`GIT_SSH_VARIANT`.  The reason is that the config in this case is\nusually per-user or per-system, but it's very common to override\nsettings on an ephemeral basis with the environment.\n\nThink of the case where you have a language package manager that's\ncreating a repository or fetching from one.  You can override on the\ncommand line with `GIT_DEFAULT_HASH` or `GIT_SSH_VARIANT`, but you can't\ncontrol the actual `git` invocation, since it's baked into the package\nmanager.  Or if you're writing a test and need all of the Git commands\nto use a particular setting, then it's easy to simply set the\nenvironment once and forget about it.  (This is what we do at $DAYJOB to\nimplement SHA-256 test modes for our repos: the test script sets\n`GIT_DEFAULT_HASH` and all of our test repos magically use the right\nsetting.)\n-- \nbrian m. carlson (they/them or he/him)\nToronto, Ontario, CA\n"},{"id":"501060","messageId":"Zr5xeURcnoqcZsEg@tapette.crustytoothpaste.net","threadId":"61955","inReplyTo":"cover.1723708417.git.ps@pks.im","subject":"Re: [PATCH 0/5] Introduce configs for default repo format","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2024-08-15T21:22:01Z","receivedAt":"2024-08-15T21:22:05Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2024-08-15 at 07:59:54, Patrick Steinhardt wrote:\n> Hi,\n> \n> to set up the default object and ref storage formats, users have to set\n> up some environment variables. This is somewhat unwieldy and not really\n> in line with how a user typically expects to configure Git, namely by\n> using the config system. It makes it harder than necessary to globally\n> default to the different formats and requires the user to munge with\n> files like `.profile` to persist that setting. Needless to say, this is\n> a bit of an awkward user experience.\n> \n> This patch series thus introduces two new configs to set the default\n> object hash and ref storage format for newly created repositories. Like\n> this, folks can simply use the global- or system-level config to adapt\n> to their needs. This also has the advantage of giving them the ability\n> to adapt the default formats via guarded includes, such that e.g. repos\n> in some filesystem hierarchy use format A, whereas others use format B.\n\nI like the idea of this series, which I think is a much nicer way to set\nthese defaults and can also correctly apply to existing terminal\nwindows.  As you mentioned, this also allows different configurations\nper directory, and it makes it easier if you need to have a system-wide\npolicy for whatever reason.\n\nI've taken a look at the patches and they seem fine to me.  Thanks for\nsending them.\n-- \nbrian m. carlson (they/them or he/him)\nToronto, Ontario, CA\n"},{"id":"501061","messageId":"hxnibmbakpvh72kfrycxnvo5a24f6atcqa73yys4zthbqpwikq@s7435n3nqmlz","threadId":"61955","inReplyTo":"16f52b75d8972343776adb269da305e7406ff385.1723708417.git.ps@pks.im","subject":"Re: [PATCH 3/5] setup: merge configuration of repository formats","fromName":"Justin Tobler","fromEmail":"jltobler@gmail.com","sentAt":"2024-08-15T21:37:26Z","receivedAt":"2024-08-15T21:38:21Z","isPatch":true,"sender":{"key":"jltobler@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53454972?v=4"},"body":"On 24/08/15 10:00AM, Patrick Steinhardt wrote:\n> The configuration of repository formats is split up across two functions\n> `validate_hash_algorithm()` and `validate_ref_storage_format()`. This is\n> fine as-is, but we are about to extend the logic to also read default\n> values from the config. With the logic split across two functions, we\n> would either have to pass in additional parameters read from the config,\n> or read the config multiple times. Both of these options feel a bit\n> unwieldy.\n\nCombining the repository format configuration logic into a single\nfunction seems like a good option. It looks like go we even further\nthough since we also include setting the hash and ref format for\n`the_repository`. Might be nice to also mention this.\n\n> Merge the code into a new a new function `repository_format_configure()`\n\ns/new a new/new/\n\n> that is responsible for configuring the whole repository's format. Like\n> this, we can easily read the config in a single place, only.\n> \n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n[snip]\n> -\t/*\n> -\t * Now that we have set up both the hash algorithm and the ref storage\n> -\t * format we can update the repository's settings accordingly.\n> -\t */\n\nThe above comment somewhat made it sound like the repository format had\nto be configured for both the hash algo and ref storage before updating\n`the_repository`, but that does not seem to be a requirement in\nactuality.\n\n> -\trepo_set_hash_algo(the_repository, repo_fmt.hash_algo);\n> -\trepo_set_ref_storage_format(the_repository, repo_fmt.ref_storage_format);\n> +\trepository_format_configure(&repo_fmt, hash, ref_storage_format);\n\nOverall, I like that this repostory format configuration is under\n`repository_format_configure()`. The `validate_*()` functions names\nconfused me slightly initially because I assumed they were only\nvalidating, but they also configure the repo format. Looking good :)\n\n-Justin\n"},{"id":"501062","messageId":"xmqq4j7lsbca.fsf@gitster.g","threadId":"61955","inReplyTo":"Zr5wODo8tgGtPEIM@tapette.crustytoothpaste.net","subject":"Re: [PATCH 0/5] Introduce configs for default repo format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-08-15T21:52:21Z","receivedAt":"2024-08-15T21:52:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"brian m. carlson\" <sandals@crustytoothpaste.net> writes:\n\n> On 2024-08-15 at 15:24:47, shejialuo wrote:\n>> If the user uses the following command:\n>> \n>>   $ export GIT_DEFAULT_HASH_ENVIRONMENT=sha1\n>>   $ git -c init.defaultObjectFormat=sha256 repo\n>> \n>> The repo would be initialized with the sha1 algorithm. I think we should\n>> think carefully which precedence should be higher. I cannot give an\n>> answer here. I am not familiar with the whole database and do not the\n>> concern. But from my own perspective, I think the precedence of the\n>> config should be higher than the environment variable. This is a new\n>> feature, the people who would like to use it, they will never use\n>> environment variable and we should ignore the functionality of the\n>> environment variable. But for people who do not know this feature, they\n>> will continue to use the environment variable and they will never be\n>> influenced by the configs.\n>\n> The standard behaviour we have with other environment variables is that\n> they override the config, such as with `GIT_SSH_COMMAND` and\n> `GIT_SSH_VARIANT`.  The reason is that the config in this case is\n> usually per-user or per-system, but it's very common to override\n> settings on an ephemeral basis with the environment.\n\nRight.  It is good that somebody can give a clear answer when a new\nperson says they cannot and then give an answer that contradicts\nwith an established practice ;-).\n\n\n"},{"id":"501063","messageId":"pvd6gvizns4wrwi6pq4gpouqfqxgycy7vkbdxhkgdcbcmcrw4n@7nlczody4vek","threadId":"61955","inReplyTo":"e1cdaf0f0edec578d1cb9358fd4c6f6b39aaad3a.1723708417.git.ps@pks.im","subject":"Re: [PATCH 4/5] setup: make object format configurable via config","fromName":"Justin Tobler","fromEmail":"jltobler@gmail.com","sentAt":"2024-08-15T22:17:36Z","receivedAt":"2024-08-15T22:18:28Z","isPatch":true,"sender":{"key":"jltobler@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53454972?v=4"},"body":"On 24/08/15 10:00AM, Patrick Steinhardt wrote:\n> The object format for repositories can either be configured explicitly\n> by passing the `--object-format=` option to git-init(1) or git-clone(1),\n> or globally by setting the `GIT_DEFAULT_HASH` environment variable.\n> While the former makes sense, setting random environment variables is\n> not really a good user experience in case someone decides to only use\n> SHA256 repositories.\n> \n> It is only natural to expect for a user that things like this can also\n> be configured via their config. As such, introduce a new config\n> \"init.defaultObjectFormat\", similar to \"init.defaultBranch\", that allows\n> the user to configure the default object format when creating new repos.\n\nAdding an option to the Git config to allow the default hash algorithm\nand reference format to be configured makes sense. In my opinion it is\nmuch more ergonomic.\n\n> \n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  Documentation/config/init.txt |  5 ++++\n>  setup.c                       | 40 ++++++++++++++++++++++++++++\n>  t/t0001-init.sh               | 50 +++++++++++++++++++++++++++++++++++\n>  3 files changed, 95 insertions(+)\n> \n> diff --git a/Documentation/config/init.txt b/Documentation/config/init.txt\n> index af03acdbcb..d6f8b6e61b 100644\n> --- a/Documentation/config/init.txt\n> +++ b/Documentation/config/init.txt\n> @@ -8,3 +8,8 @@ endif::[]\n>  `init.defaultBranch`::\n>  \tAllows overriding the default branch name e.g. when initializing\n>  \ta new repository.\n> +`init.defaultObjectFormat`::\n> +\tAllows overriding the default object format for new repositories. See\n> +\t`--object-format=` in linkgit:git-init[1]. Both the command line option\n> +\tand the `GIT_DEFAULT_HASH` environment variable take precedence over\n> +\tthis config.\n> diff --git a/setup.c b/setup.c\n> index 5dfcdc99dd..770ad1393f 100644\n> --- a/setup.c\n> +++ b/setup.c\n> @@ -2284,11 +2284,49 @@ static void separate_git_dir(const char *git_dir, const char *git_link)\n>  \twrite_file(git_link, \"gitdir: %s\", git_dir);\n>  }\n>  \n> +struct default_format_config {\n> +\tint hash;\n> +};\n> +\n> +static int read_default_format_config(const char *key, const char *value,\n> +\t\t\t\t      const struct config_context *ctx UNUSED,\n> +\t\t\t\t      void *payload)\n> +{\n> +\tstruct default_format_config *cfg = payload;\n> +\tchar *str = NULL;\n> +\tint ret;\n> +\n> +\tif (!strcmp(key, \"init.defaultobjectformat\")) {\n> +\t\tret = git_config_string(&str, key, value);\n> +\t\tif (ret)\n> +\t\t\tgoto out;\n> +\t\tcfg->hash = hash_algo_by_name(str);\n> +\t\tif (cfg->hash == GIT_HASH_UNKNOWN)\n> +\t\t\twarning(_(\"unknown hash algorithm '%s'\"), str);\n> +\t\tgoto out;\n> +\t}\n> +\n> +\tret = 0;\n> +out:\n> +\tfree(str);\n> +\treturn ret;\n> +}\n> +\n>  static void repository_format_configure(struct repository_format *repo_fmt,\n>  \t\t\t\t\tint hash, enum ref_storage_format ref_format)\n>  {\n> +\tstruct default_format_config cfg = {\n> +\t\t.hash = GIT_HASH_UNKNOWN,\n> +\t};\n> +\tstruct config_options opts = {\n> +\t\t.respect_includes = 1,\n> +\t\t.ignore_repo = 1,\n> +\t\t.ignore_worktree = 1,\n> +\t};\n\nAs these format configurations only make sense to be included in the\nglobal config, the search radius is limited accordingly. \n\n>  \tconst char *env;\n>  \n> +\tconfig_with_options(read_default_format_config, &cfg, NULL, NULL, &opts);\n> +\n>  \t/*\n>  \t * If we already have an initialized repo, don't allow the user to\n>  \t * specify a different algorithm, as that could cause corruption.\n> @@ -2304,6 +2342,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,\n>  \t\tif (env_algo == GIT_HASH_UNKNOWN)\n>  \t\t\tdie(_(\"unknown hash algorithm '%s'\"), env);\n>  \t\trepo_fmt->hash_algo = env_algo;\n> +\t} else if (cfg.hash != GIT_HASH_UNKNOWN) {\n> +\t\trepo_fmt->hash_algo = cfg.hash;\n\nThe environment variable takes higher precedence than the Git config.\nMakes sense to allow the env to override Git cofiguration.\n\nThe way this patch is setup should make it easy to extend for a default\nreference format config. Very nice.\n\n-Justin\n"},{"id":"501079","messageId":"c7ssb2tvukrbtftm2ifvz4aobp7hlunfkh3x25x4wysisvih62@utweuhfbcvjd","threadId":"61955","inReplyTo":"a0417b7d1a8e96f71399117f3f7333c5a2920dce.1723708417.git.ps@pks.im","subject":"Re: [PATCH 5/5] setup: make ref storage format configurable via config","fromName":"Justin Tobler","fromEmail":"jltobler@gmail.com","sentAt":"2024-08-15T22:29:36Z","receivedAt":"2024-08-15T22:30:25Z","isPatch":true,"sender":{"key":"jltobler@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53454972?v=4"},"body":"On 24/08/15 10:00AM, Patrick Steinhardt wrote:\n> Similar as the preceding commit, introduce a new \"init.defaultRefFormat\"\n\ns/as/to/\n\n> config that allows the user to globally set the ref storage format used\n> by newly created repositories.\n> \n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  Documentation/config/init.txt |  5 ++++\n>  setup.c                       | 14 +++++++++++\n>  t/t0001-init.sh               | 44 +++++++++++++++++++++++++++++++++++\n>  3 files changed, 63 insertions(+)\n> \n> diff --git a/Documentation/config/init.txt b/Documentation/config/init.txt\n> index d6f8b6e61b..9be97bcac8 100644\n> --- a/Documentation/config/init.txt\n> +++ b/Documentation/config/init.txt\n> @@ -13,3 +13,8 @@ endif::[]\n>  \t`--object-format=` in linkgit:git-init[1]. Both the command line option\n>  \tand the `GIT_DEFAULT_HASH` environment variable take precedence over\n>  \tthis config.\n> +`init.defaultRefFormat`::\n> +\tAllows overriding the default object format for new repositories. See\n\nI think you meant to say \"default reference format\" here. :)\n\n> +\t`--ref-format=` in linkgit:git-init[1]. Both the command line option\n> +\tand the `GIT_DEFAULT_REF_FORMAT` environment variable take precedence\n> +\tover this config.\n[snip]\n\nThe remainder of this patch extends from the previous patch to add\nsupport for a configurable default reference format set in a Git config.\nNicely done and looks good to me.\n\n-Justin\n"},{"id":"501102","messageId":"Zr8IoDy9dU2MNVB-@tanuki","threadId":"61955","inReplyTo":"hxnibmbakpvh72kfrycxnvo5a24f6atcqa73yys4zthbqpwikq@s7435n3nqmlz","subject":"Re: [PATCH 3/5] setup: merge configuration of repository formats","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-16T08:06:56Z","receivedAt":"2024-08-16T08:07:00Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Aug 15, 2024 at 04:37:26PM -0500, Justin Tobler wrote:\n> On 24/08/15 10:00AM, Patrick Steinhardt wrote:\n> > -\trepo_set_hash_algo(the_repository, repo_fmt.hash_algo);\n> > -\trepo_set_ref_storage_format(the_repository, repo_fmt.ref_storage_format);\n> > +\trepository_format_configure(&repo_fmt, hash, ref_storage_format);\n> \n> Overall, I like that this repostory format configuration is under\n> `repository_format_configure()`. The `validate_*()` functions names\n> confused me slightly initially because I assumed they were only\n> validating, but they also configure the repo format. Looking good :)\n\nYeah, agreed. We _did_ validate whether the new configuration makes\nsense, but that wasn't really the main thing those functions did.\n\nPatrick\n"},{"id":"501103","messageId":"Zr8IpMXjN94xnC0W@tanuki","threadId":"61955","inReplyTo":"xmqq4j7lsbca.fsf@gitster.g","subject":"Re: [PATCH 0/5] Introduce configs for default repo format","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-16T08:07:00Z","receivedAt":"2024-08-16T08:07:09Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Aug 15, 2024 at 02:52:21PM -0700, Junio C Hamano wrote:\n> \"brian m. carlson\" <sandals@crustytoothpaste.net> writes:\n> \n> > On 2024-08-15 at 15:24:47, shejialuo wrote:\n> >> If the user uses the following command:\n> >> \n> >>   $ export GIT_DEFAULT_HASH_ENVIRONMENT=sha1\n> >>   $ git -c init.defaultObjectFormat=sha256 repo\n> >> \n> >> The repo would be initialized with the sha1 algorithm. I think we should\n> >> think carefully which precedence should be higher. I cannot give an\n> >> answer here. I am not familiar with the whole database and do not the\n> >> concern. But from my own perspective, I think the precedence of the\n> >> config should be higher than the environment variable. This is a new\n> >> feature, the people who would like to use it, they will never use\n> >> environment variable and we should ignore the functionality of the\n> >> environment variable. But for people who do not know this feature, they\n> >> will continue to use the environment variable and they will never be\n> >> influenced by the configs.\n> >\n> > The standard behaviour we have with other environment variables is that\n> > they override the config, such as with `GIT_SSH_COMMAND` and\n> > `GIT_SSH_VARIANT`.  The reason is that the config in this case is\n> > usually per-user or per-system, but it's very common to override\n> > settings on an ephemeral basis with the environment.\n> \n> Right.  It is good that somebody can give a clear answer when a new\n> person says they cannot and then give an answer that contradicts\n> with an established practice ;-).\n\nYeah, thanks for putting it so clearly. I'll also put a variant of this\ninto the commit message to clarify.\n\nPatrick\n"},{"id":"501109","messageId":"6b0cefef6af3a94cd3b650b2ab06de489dbdaf20.1723798388.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723798388.git.ps@pks.im","subject":"[PATCH v2 2/5] t0001: delete repositories when object format tests finish","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-16T08:56:55Z","receivedAt":"2024-08-16T09:06:13Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The object format tests create one-shot repositories that are only used\nby the respective test, but never delete them. This makes it hard to\npick a proper repository name in subsequent tests, as more and more\nnames are taken already.\n\nDelete these repositories via `test_when_finished`.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0001-init.sh | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 2093f5c1ee..795408e16c 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -500,6 +500,7 @@ test_expect_success 're-init from a linked worktree' '\n '\n \n test_expect_success 'init honors GIT_DEFAULT_HASH' '\n+\ttest_when_finished \"rm -rf sha1 sha256\" &&\n \tGIT_DEFAULT_HASH=sha1 git init sha1 &&\n \tgit -C sha1 rev-parse --show-object-format >actual &&\n \techo sha1 >expected &&\n@@ -511,6 +512,7 @@ test_expect_success 'init honors GIT_DEFAULT_HASH' '\n '\n \n test_expect_success 'init honors --object-format' '\n+\ttest_when_finished \"rm -rf explicit-sha1 explicit-sha256\" &&\n \tgit init --object-format=sha1 explicit-sha1 &&\n \tgit -C explicit-sha1 rev-parse --show-object-format >actual &&\n \techo sha1 >expected &&\n@@ -522,6 +524,7 @@ test_expect_success 'init honors --object-format' '\n '\n \n test_expect_success 'extensions.objectFormat is not allowed with repo version 0' '\n+\ttest_when_finished \"rm -rf explicit-v0\" &&\n \tgit init --object-format=sha256 explicit-v0 &&\n \tgit -C explicit-v0 config core.repositoryformatversion 0 &&\n \ttest_must_fail git -C explicit-v0 rev-parse --show-object-format\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"501110","messageId":"b68a841450e8f2eeb73e59ddf6f38f4931589788.1723798388.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723798388.git.ps@pks.im","subject":"[PATCH v2 5/5] setup: make ref storage format configurable via config","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-16T08:57:12Z","receivedAt":"2024-08-16T09:06:13Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Similar to the preceding commit, introduce a new \"init.defaultRefFormat\"\nconfig that allows the user to globally set the ref storage format used\nby newly created repositories.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Documentation/config/init.txt |  5 ++++\n setup.c                       | 14 +++++++++++\n t/t0001-init.sh               | 44 +++++++++++++++++++++++++++++++++++\n 3 files changed, 63 insertions(+)\n\ndiff --git a/Documentation/config/init.txt b/Documentation/config/init.txt\nindex d6f8b6e61b..e45b2a8121 100644\n--- a/Documentation/config/init.txt\n+++ b/Documentation/config/init.txt\n@@ -13,3 +13,8 @@ endif::[]\n \t`--object-format=` in linkgit:git-init[1]. Both the command line option\n \tand the `GIT_DEFAULT_HASH` environment variable take precedence over\n \tthis config.\n+`init.defaultRefFormat`::\n+\tAllows overriding the default ref storage format for new repositories.\n+\tSee `--ref-format=` in linkgit:git-init[1]. Both the command line\n+\toption and the `GIT_DEFAULT_REF_FORMAT` environment variable take\n+\tprecedence over this config.\ndiff --git a/setup.c b/setup.c\nindex 770ad1393f..dd2251f655 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -2286,6 +2286,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link)\n \n struct default_format_config {\n \tint hash;\n+\tenum ref_storage_format ref_format;\n };\n \n static int read_default_format_config(const char *key, const char *value,\n@@ -2306,6 +2307,16 @@ static int read_default_format_config(const char *key, const char *value,\n \t\tgoto out;\n \t}\n \n+\tif (!strcmp(key, \"init.defaultrefformat\")) {\n+\t\tret = git_config_string(&str, key, value);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t\tcfg->ref_format = ref_storage_format_by_name(str);\n+\t\tif (cfg->ref_format == REF_STORAGE_FORMAT_UNKNOWN)\n+\t\t\twarning(_(\"unknown ref storage format '%s'\"), str);\n+\t\tgoto out;\n+\t}\n+\n \tret = 0;\n out:\n \tfree(str);\n@@ -2317,6 +2328,7 @@ static void repository_format_configure(struct repository_format *repo_fmt,\n {\n \tstruct default_format_config cfg = {\n \t\t.hash = GIT_HASH_UNKNOWN,\n+\t\t.ref_format = REF_STORAGE_FORMAT_UNKNOWN,\n \t};\n \tstruct config_options opts = {\n \t\t.respect_includes = 1,\n@@ -2359,6 +2371,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,\n \t\tif (ref_format == REF_STORAGE_FORMAT_UNKNOWN)\n \t\t\tdie(_(\"unknown ref storage format '%s'\"), env);\n \t\trepo_fmt->ref_storage_format = ref_format;\n+\t} else if (cfg.ref_format != REF_STORAGE_FORMAT_UNKNOWN) {\n+\t\trepo_fmt->ref_storage_format = cfg.ref_format;\n \t}\n \trepo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);\n }\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex cd34710f32..0178aa62a4 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -620,6 +620,19 @@ test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '\n \ttest_cmp expect err\n '\n \n+test_expect_success 'init warns about invalid init.defaultRefFormat' '\n+\ttest_when_finished \"rm -rf repo\" &&\n+\ttest_config_global init.defaultRefFormat garbage &&\n+\n+\techo \"warning: unknown ref storage format ${SQ}garbage${SQ}\" >expect &&\n+\tgit init repo 2>err &&\n+\ttest_cmp expect err &&\n+\n+\tgit -C repo rev-parse --show-ref-format >actual &&\n+\techo $GIT_DEFAULT_REF_FORMAT >expected &&\n+\ttest_cmp expected actual\n+'\n+\n backends=\"files reftable\"\n for format in $backends\n do\n@@ -650,6 +663,27 @@ do\n \t\tgit -C refformat rev-parse --show-ref-format >actual &&\n \t\ttest_cmp expect actual\n \t'\n+\n+\ttest_expect_success \"init with init.defaultRefFormat=$format\" '\n+\t\ttest_when_finished \"rm -rf refformat\" &&\n+\t\ttest_config_global init.defaultRefFormat $format &&\n+\t\t(\n+\t\t\tsane_unset GIT_DEFAULT_REF_FORMAT &&\n+\t\t\tgit init refformat\n+\t\t) &&\n+\n+\t\techo $format >expect &&\n+\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n+\n+\ttest_expect_success \"--ref-format=$format overrides GIT_DEFAULT_REF_FORMAT\" '\n+\t\ttest_when_finished \"rm -rf refformat\" &&\n+\t\tGIT_DEFAULT_REF_FORMAT=garbage git init --ref-format=$format refformat &&\n+\t\techo $format >expect &&\n+\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n done\n \n test_expect_success \"--ref-format= overrides GIT_DEFAULT_REF_FORMAT\" '\n@@ -660,6 +694,16 @@ test_expect_success \"--ref-format= overrides GIT_DEFAULT_REF_FORMAT\" '\n \ttest_cmp expect actual\n '\n \n+test_expect_success \"GIT_DEFAULT_REF_FORMAT= overrides init.defaultRefFormat\" '\n+\ttest_when_finished \"rm -rf refformat\" &&\n+\ttest_config_global init.defaultRefFormat files &&\n+\n+\tGIT_DEFAULT_REF_FORMAT=reftable git init refformat &&\n+\techo reftable >expect &&\n+\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\ttest_cmp expect actual\n+'\n+\n for from_format in $backends\n do\n \ttest_expect_success \"re-init with same format ($from_format)\" '\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"501111","messageId":"cover.1723798388.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723708417.git.ps@pks.im","subject":"[PATCH v2 0/5] Introduce configs for default repo format","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-16T08:56:50Z","receivedAt":"2024-08-16T09:06:13Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nthis is the second version of my patch series that introduces two new\nconfig settings `init.defaultRefFormat` and `init.defaultObjectFormat`\nto make the default formats configurable without environment variables.\n\nChanges compared to v1:\n\n  - Extend commit message to mention that we also move\n    `repo_set_ref_storage_format()` and `repo_set_hash_algo()` into\n    `repository_format_configure()`.\n\n  - Extend commit message to explain precedence.\n\n  - Fix a grammar issue.\n\n  - Fix a copy/paste error in the documentation of\n    `init.defaultRefFormat`.\n\nThanks!\n\nPatrick\n\nPatrick Steinhardt (5):\n  t0001: exercise initialization with ref formats more thoroughly\n  t0001: delete repositories when object format tests finish\n  setup: merge configuration of repository formats\n  setup: make object format configurable via config\n  setup: make ref storage format configurable via config\n\n Documentation/config/init.txt |  10 +++\n setup.c                       | 101 ++++++++++++++++-------\n t/t0001-init.sh               | 145 +++++++++++++++++++++++++++++++---\n 3 files changed, 216 insertions(+), 40 deletions(-)\n\nRange-diff against v1:\n1:  0d3844db32 = 1:  0d3844db32 t0001: exercise initialization with ref formats more thoroughly\n2:  6b0cefef6a = 2:  6b0cefef6a t0001: delete repositories when object format tests finish\n3:  16f52b75d8 ! 3:  ce0fad88bb setup: merge configuration of repository formats\n    @@ Commit message\n         or read the config multiple times. Both of these options feel a bit\n         unwieldy.\n     \n    -    Merge the code into a new a new function `repository_format_configure()`\n    -    that is responsible for configuring the whole repository's format. Like\n    -    this, we can easily read the config in a single place, only.\n    +    Merge the code into a new function `repository_format_configure()` that\n    +    is responsible for configuring the whole repository's format. Like this,\n    +    we can easily read the config in a single place, only.\n    +\n    +    Furthermore, move the calls to `repo_set_ref_storage_format()` and\n    +    `repo_set_hash_algo()` into this new function as well, such that all the\n    +    logic to configure the repository format is self-contained here.\n     \n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n4:  e1cdaf0f0e ! 4:  8508662062 setup: make object format configurable via config\n    @@ Commit message\n         \"init.defaultObjectFormat\", similar to \"init.defaultBranch\", that allows\n         the user to configure the default object format when creating new repos.\n     \n    +    The precedence order now is the following, where the first one wins:\n    +\n    +      1. The `--object-format=` switch.\n    +\n    +      2. The `GIT_DEFAULT_HASH` environment variable.\n    +\n    +      3. The `init.defaultObjectFormat` config variable.\n    +\n    +    This matches the typical precedence order we use in Git. We typically\n    +    let the environment override the config such that the latter can easily\n    +    be overridden on an ephemeral basis, for example by scripts.\n    +\n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n      ## Documentation/config/init.txt ##\n5:  a0417b7d1a ! 5:  b68a841450 setup: make ref storage format configurable via config\n    @@ Metadata\n      ## Commit message ##\n         setup: make ref storage format configurable via config\n     \n    -    Similar as the preceding commit, introduce a new \"init.defaultRefFormat\"\n    +    Similar to the preceding commit, introduce a new \"init.defaultRefFormat\"\n         config that allows the user to globally set the ref storage format used\n         by newly created repositories.\n     \n    @@ Documentation/config/init.txt: endif::[]\n      \tand the `GIT_DEFAULT_HASH` environment variable take precedence over\n      \tthis config.\n     +`init.defaultRefFormat`::\n    -+\tAllows overriding the default object format for new repositories. See\n    -+\t`--ref-format=` in linkgit:git-init[1]. Both the command line option\n    -+\tand the `GIT_DEFAULT_REF_FORMAT` environment variable take precedence\n    -+\tover this config.\n    ++\tAllows overriding the default ref storage format for new repositories.\n    ++\tSee `--ref-format=` in linkgit:git-init[1]. Both the command line\n    ++\toption and the `GIT_DEFAULT_REF_FORMAT` environment variable take\n    ++\tprecedence over this config.\n     \n      ## setup.c ##\n     @@ setup.c: static void separate_git_dir(const char *git_dir, const char *git_link)\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"501112","messageId":"ce0fad88bb819c1dfa206e7327522ce625c32e65.1723798388.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723798388.git.ps@pks.im","subject":"[PATCH v2 3/5] setup: merge configuration of repository formats","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-16T08:56:58Z","receivedAt":"2024-08-16T09:06:13Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The configuration of repository formats is split up across two functions\n`validate_hash_algorithm()` and `validate_ref_storage_format()`. This is\nfine as-is, but we are about to extend the logic to also read default\nvalues from the config. With the logic split across two functions, we\nwould either have to pass in additional parameters read from the config,\nor read the config multiple times. Both of these options feel a bit\nunwieldy.\n\nMerge the code into a new function `repository_format_configure()` that\nis responsible for configuring the whole repository's format. Like this,\nwe can easily read the config in a single place, only.\n\nFurthermore, move the calls to `repo_set_ref_storage_format()` and\n`repo_set_hash_algo()` into this new function as well, such that all the\nlogic to configure the repository format is self-contained here.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n setup.c | 47 ++++++++++++++++++++---------------------------\n 1 file changed, 20 insertions(+), 27 deletions(-)\n\ndiff --git a/setup.c b/setup.c\nindex d458edcc02..5dfcdc99dd 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -2284,14 +2284,17 @@ static void separate_git_dir(const char *git_dir, const char *git_link)\n \twrite_file(git_link, \"gitdir: %s\", git_dir);\n }\n \n-static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)\n+static void repository_format_configure(struct repository_format *repo_fmt,\n+\t\t\t\t\tint hash, enum ref_storage_format ref_format)\n {\n-\tconst char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);\n+\tconst char *env;\n+\n \t/*\n \t * If we already have an initialized repo, don't allow the user to\n \t * specify a different algorithm, as that could cause corruption.\n \t * Otherwise, if the user has specified one on the command line, use it.\n \t */\n+\tenv = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);\n \tif (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)\n \t\tdie(_(\"attempt to reinitialize repository with different hash\"));\n \telse if (hash != GIT_HASH_UNKNOWN)\n@@ -2302,25 +2305,22 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash\n \t\t\tdie(_(\"unknown hash algorithm '%s'\"), env);\n \t\trepo_fmt->hash_algo = env_algo;\n \t}\n-}\n-\n-static void validate_ref_storage_format(struct repository_format *repo_fmt,\n-\t\t\t\t\tenum ref_storage_format format)\n-{\n-\tconst char *name = getenv(\"GIT_DEFAULT_REF_FORMAT\");\n+\trepo_set_hash_algo(the_repository, repo_fmt->hash_algo);\n \n+\tenv = getenv(\"GIT_DEFAULT_REF_FORMAT\");\n \tif (repo_fmt->version >= 0 &&\n-\t    format != REF_STORAGE_FORMAT_UNKNOWN &&\n-\t    format != repo_fmt->ref_storage_format) {\n+\t    ref_format != REF_STORAGE_FORMAT_UNKNOWN &&\n+\t    ref_format != repo_fmt->ref_storage_format) {\n \t\tdie(_(\"attempt to reinitialize repository with different reference storage format\"));\n-\t} else if (format != REF_STORAGE_FORMAT_UNKNOWN) {\n-\t\trepo_fmt->ref_storage_format = format;\n-\t} else if (name) {\n-\t\tformat = ref_storage_format_by_name(name);\n-\t\tif (format == REF_STORAGE_FORMAT_UNKNOWN)\n-\t\t\tdie(_(\"unknown ref storage format '%s'\"), name);\n-\t\trepo_fmt->ref_storage_format = format;\n+\t} else if (ref_format != REF_STORAGE_FORMAT_UNKNOWN) {\n+\t\trepo_fmt->ref_storage_format = ref_format;\n+\t} else if (env) {\n+\t\tref_format = ref_storage_format_by_name(env);\n+\t\tif (ref_format == REF_STORAGE_FORMAT_UNKNOWN)\n+\t\t\tdie(_(\"unknown ref storage format '%s'\"), env);\n+\t\trepo_fmt->ref_storage_format = ref_format;\n \t}\n+\trepo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);\n }\n \n int init_db(const char *git_dir, const char *real_git_dir,\n@@ -2353,22 +2353,15 @@ int init_db(const char *git_dir, const char *real_git_dir,\n \t}\n \tstartup_info->have_repository = 1;\n \n-\t/* Check to see if the repository version is right.\n+\t/*\n+\t * Check to see if the repository version is right.\n \t * Note that a newly created repository does not have\n \t * config file, so this will not fail.  What we are catching\n \t * is an attempt to reinitialize new repository with an old tool.\n \t */\n \tcheck_repository_format(&repo_fmt);\n \n-\tvalidate_hash_algorithm(&repo_fmt, hash);\n-\tvalidate_ref_storage_format(&repo_fmt, ref_storage_format);\n-\n-\t/*\n-\t * Now that we have set up both the hash algorithm and the ref storage\n-\t * format we can update the repository's settings accordingly.\n-\t */\n-\trepo_set_hash_algo(the_repository, repo_fmt.hash_algo);\n-\trepo_set_ref_storage_format(the_repository, repo_fmt.ref_storage_format);\n+\trepository_format_configure(&repo_fmt, hash, ref_storage_format);\n \n \t/*\n \t * Ensure `core.hidedotfiles` is processed. This must happen after we\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"501113","messageId":"0d3844db32237983a1d85ced1a3b1b25fcd1d6eb.1723798388.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723798388.git.ps@pks.im","subject":"[PATCH v2 1/5] t0001: exercise initialization with ref formats more thoroughly","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-16T08:56:53Z","receivedAt":"2024-08-16T09:06:13Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"While our object format tests for git-init(1) exercise tests with all\nknown formats in t0001, the tests for the ref format don't. This leads\nto some missing test coverage for interesting cases, like whether or not\na non-default ref storage format causes us to bump the repository format\nversion. We also don't test for the precedence of the `--ref-format=`\nand the `GIT_DEFAULT_REF_FORMAT=` environment variable.\n\nExtend the test suite to cover more scenarios related to the ref format.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n t/t0001-init.sh | 48 +++++++++++++++++++++++++++++++++++-------------\n 1 file changed, 35 insertions(+), 13 deletions(-)\n\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 49e9bf77c6..2093f5c1ee 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -558,15 +558,6 @@ test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with unknown back\n \tgrep \"invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}\" err\n '\n \n-test_expect_success DEFAULT_REPO_FORMAT 'init with GIT_DEFAULT_REF_FORMAT=files' '\n-\ttest_when_finished \"rm -rf refformat\" &&\n-\tGIT_DEFAULT_REF_FORMAT=files git init refformat &&\n-\techo 0 >expect &&\n-\tgit -C refformat config core.repositoryformatversion >actual &&\n-\ttest_cmp expect actual &&\n-\ttest_must_fail git -C refformat config extensions.refstorage\n-'\n-\n test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '\n \ttest_when_finished \"rm -rf refformat\" &&\n \tcat >expect <<-EOF &&\n@@ -576,15 +567,46 @@ test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '\n \ttest_cmp expect err\n '\n \n-test_expect_success 'init with --ref-format=files' '\n+backends=\"files reftable\"\n+for format in $backends\n+do\n+\ttest_expect_success DEFAULT_REPO_FORMAT \"init with GIT_DEFAULT_REF_FORMAT=$format\" '\n+\t\ttest_when_finished \"rm -rf refformat\" &&\n+\t\tGIT_DEFAULT_REF_FORMAT=$format git init refformat &&\n+\n+\t\tif test $format = files\n+\t\tthen\n+\t\t\ttest_must_fail git -C refformat config extensions.refstorage &&\n+\t\t\techo 0 >expect\n+\t\telse\n+\t\t\tgit -C refformat config extensions.refstorage &&\n+\t\t\techo 1 >expect\n+\t\tfi &&\n+\t\tgit -C refformat config core.repositoryformatversion >actual &&\n+\t\ttest_cmp expect actual &&\n+\n+\t\techo $format >expect &&\n+\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n+\n+\ttest_expect_success \"init with --ref-format=$format\" '\n+\t\ttest_when_finished \"rm -rf refformat\" &&\n+\t\tgit init --ref-format=$format refformat &&\n+\t\techo $format >expect &&\n+\t\tgit -C refformat rev-parse --show-ref-format >actual &&\n+\t\ttest_cmp expect actual\n+\t'\n+done\n+\n+test_expect_success \"--ref-format= overrides GIT_DEFAULT_REF_FORMAT\" '\n \ttest_when_finished \"rm -rf refformat\" &&\n-\tgit init --ref-format=files refformat &&\n-\techo files >expect &&\n+\tGIT_DEFAULT_REF_FORMAT=files git init --ref-format=reftable refformat &&\n+\techo reftable >expect &&\n \tgit -C refformat rev-parse --show-ref-format >actual &&\n \ttest_cmp expect actual\n '\n \n-backends=\"files reftable\"\n for from_format in $backends\n do\n \ttest_expect_success \"re-init with same format ($from_format)\" '\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"501114","messageId":"85086620628b1fa136ebf7a1c9e2f64ebdbc7b92.1723798388.git.ps@pks.im","threadId":"61955","inReplyTo":"cover.1723798388.git.ps@pks.im","subject":"[PATCH v2 4/5] setup: make object format configurable via config","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2024-08-16T08:57:03Z","receivedAt":"2024-08-16T09:06:13Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The object format for repositories can either be configured explicitly\nby passing the `--object-format=` option to git-init(1) or git-clone(1),\nor globally by setting the `GIT_DEFAULT_HASH` environment variable.\nWhile the former makes sense, setting random environment variables is\nnot really a good user experience in case someone decides to only use\nSHA256 repositories.\n\nIt is only natural to expect for a user that things like this can also\nbe configured via their config. As such, introduce a new config\n\"init.defaultObjectFormat\", similar to \"init.defaultBranch\", that allows\nthe user to configure the default object format when creating new repos.\n\nThe precedence order now is the following, where the first one wins:\n\n  1. The `--object-format=` switch.\n\n  2. The `GIT_DEFAULT_HASH` environment variable.\n\n  3. The `init.defaultObjectFormat` config variable.\n\nThis matches the typical precedence order we use in Git. We typically\nlet the environment override the config such that the latter can easily\nbe overridden on an ephemeral basis, for example by scripts.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n Documentation/config/init.txt |  5 ++++\n setup.c                       | 40 ++++++++++++++++++++++++++++\n t/t0001-init.sh               | 50 +++++++++++++++++++++++++++++++++++\n 3 files changed, 95 insertions(+)\n\ndiff --git a/Documentation/config/init.txt b/Documentation/config/init.txt\nindex af03acdbcb..d6f8b6e61b 100644\n--- a/Documentation/config/init.txt\n+++ b/Documentation/config/init.txt\n@@ -8,3 +8,8 @@ endif::[]\n `init.defaultBranch`::\n \tAllows overriding the default branch name e.g. when initializing\n \ta new repository.\n+`init.defaultObjectFormat`::\n+\tAllows overriding the default object format for new repositories. See\n+\t`--object-format=` in linkgit:git-init[1]. Both the command line option\n+\tand the `GIT_DEFAULT_HASH` environment variable take precedence over\n+\tthis config.\ndiff --git a/setup.c b/setup.c\nindex 5dfcdc99dd..770ad1393f 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -2284,11 +2284,49 @@ static void separate_git_dir(const char *git_dir, const char *git_link)\n \twrite_file(git_link, \"gitdir: %s\", git_dir);\n }\n \n+struct default_format_config {\n+\tint hash;\n+};\n+\n+static int read_default_format_config(const char *key, const char *value,\n+\t\t\t\t      const struct config_context *ctx UNUSED,\n+\t\t\t\t      void *payload)\n+{\n+\tstruct default_format_config *cfg = payload;\n+\tchar *str = NULL;\n+\tint ret;\n+\n+\tif (!strcmp(key, \"init.defaultobjectformat\")) {\n+\t\tret = git_config_string(&str, key, value);\n+\t\tif (ret)\n+\t\t\tgoto out;\n+\t\tcfg->hash = hash_algo_by_name(str);\n+\t\tif (cfg->hash == GIT_HASH_UNKNOWN)\n+\t\t\twarning(_(\"unknown hash algorithm '%s'\"), str);\n+\t\tgoto out;\n+\t}\n+\n+\tret = 0;\n+out:\n+\tfree(str);\n+\treturn ret;\n+}\n+\n static void repository_format_configure(struct repository_format *repo_fmt,\n \t\t\t\t\tint hash, enum ref_storage_format ref_format)\n {\n+\tstruct default_format_config cfg = {\n+\t\t.hash = GIT_HASH_UNKNOWN,\n+\t};\n+\tstruct config_options opts = {\n+\t\t.respect_includes = 1,\n+\t\t.ignore_repo = 1,\n+\t\t.ignore_worktree = 1,\n+\t};\n \tconst char *env;\n \n+\tconfig_with_options(read_default_format_config, &cfg, NULL, NULL, &opts);\n+\n \t/*\n \t * If we already have an initialized repo, don't allow the user to\n \t * specify a different algorithm, as that could cause corruption.\n@@ -2304,6 +2342,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,\n \t\tif (env_algo == GIT_HASH_UNKNOWN)\n \t\t\tdie(_(\"unknown hash algorithm '%s'\"), env);\n \t\trepo_fmt->hash_algo = env_algo;\n+\t} else if (cfg.hash != GIT_HASH_UNKNOWN) {\n+\t\trepo_fmt->hash_algo = cfg.hash;\n \t}\n \trepo_set_hash_algo(the_repository, repo_fmt->hash_algo);\n \ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 795408e16c..cd34710f32 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -523,6 +523,56 @@ test_expect_success 'init honors --object-format' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'init honors init.defaultObjectFormat' '\n+\ttest_when_finished \"rm -rf sha1 sha256\" &&\n+\n+\ttest_config_global init.defaultObjectFormat sha1 &&\n+\t(\n+\t\tsane_unset GIT_DEFAULT_HASH &&\n+\t\tgit init sha1 &&\n+\t\tgit -C sha1 rev-parse --show-object-format >actual &&\n+\t\techo sha1 >expected &&\n+\t\ttest_cmp expected actual\n+\t) &&\n+\n+\ttest_config_global init.defaultObjectFormat sha256 &&\n+\t(\n+\t\tsane_unset GIT_DEFAULT_HASH &&\n+\t\tgit init sha256 &&\n+\t\tgit -C sha256 rev-parse --show-object-format >actual &&\n+\t\techo sha256 >expected &&\n+\t\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'init warns about invalid init.defaultObjectFormat' '\n+\ttest_when_finished \"rm -rf repo\" &&\n+\ttest_config_global init.defaultObjectFormat garbage &&\n+\n+\techo \"warning: unknown hash algorithm ${SQ}garbage${SQ}\" >expect &&\n+\tgit init repo 2>err &&\n+\ttest_cmp expect err &&\n+\n+\tgit -C repo rev-parse --show-object-format >actual &&\n+\techo $GIT_DEFAULT_HASH >expected &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success '--object-format overrides GIT_DEFAULT_HASH' '\n+\ttest_when_finished \"rm -rf repo\" &&\n+\tGIT_DEFAULT_HASH=sha1 git init --object-format=sha256 repo &&\n+\tgit -C repo rev-parse --show-object-format >actual &&\n+\techo sha256 >expected\n+'\n+\n+test_expect_success 'GIT_DEFAULT_HASH overrides init.defaultObjectFormat' '\n+\ttest_when_finished \"rm -rf repo\" &&\n+\ttest_config_global init.defaultObjectFormat sha1 &&\n+\tGIT_DEFAULT_HASH=sha256 git init repo &&\n+\tgit -C repo rev-parse --show-object-format >actual &&\n+\techo sha256 >expected\n+'\n+\n test_expect_success 'extensions.objectFormat is not allowed with repo version 0' '\n \ttest_when_finished \"rm -rf explicit-v0\" &&\n \tgit init --object-format=sha256 explicit-v0 &&\n-- \n2.46.0.46.g406f326d27.dirty\n\n"},{"id":"501141","messageId":"ay6lkuxsmdlqbjcrhk2qooh2ewuaumfzjpyhgowbsh4mycwwyv@pzsttqqgqvsp","threadId":"61955","inReplyTo":"cover.1723798388.git.ps@pks.im","subject":"Re: [PATCH v2 0/5] Introduce configs for default repo format","fromName":"Justin Tobler","fromEmail":"jltobler@gmail.com","sentAt":"2024-08-16T14:46:35Z","receivedAt":"2024-08-16T14:47:27Z","isPatch":true,"sender":{"key":"jltobler@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53454972?v=4"},"body":"On 24/08/16 10:56AM, Patrick Steinhardt wrote:\n> Hi,\n> \n> this is the second version of my patch series that introduces two new\n> config settings `init.defaultRefFormat` and `init.defaultObjectFormat`\n> to make the default formats configurable without environment variables.\n> \n> Changes compared to v1:\n> \n>   - Extend commit message to mention that we also move\n>     `repo_set_ref_storage_format()` and `repo_set_hash_algo()` into\n>     `repository_format_configure()`.\n> \n>   - Extend commit message to explain precedence.\n> \n>   - Fix a grammar issue.\n> \n>   - Fix a copy/paste error in the documentation of\n>     `init.defaultRefFormat`.\n> \n> Thanks!\n> \n> Patrick\n\nAll of my comments have been addressed with this version of the patch\nseries. This version looks good to me. Thanks\n\n-Justin\n"},{"id":"501145","messageId":"xmqqed6ol7bw.fsf@gitster.g","threadId":"61955","inReplyTo":"85086620628b1fa136ebf7a1c9e2f64ebdbc7b92.1723798388.git.ps@pks.im","subject":"Re: [PATCH v2 4/5] setup: make object format configurable via config","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-08-16T17:13:07Z","receivedAt":"2024-08-16T17:13:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The precedence order now is the following, where the first one wins:\n>\n>   1. The `--object-format=` switch.\n>\n>   2. The `GIT_DEFAULT_HASH` environment variable.\n>\n>   3. The `init.defaultObjectFormat` config variable.\n>\n> This matches the typical precedence order we use in Git. We typically\n> let the environment override the config such that the latter can easily\n> be overridden on an ephemeral basis, for example by scripts.\n\nThanks for documenting this, as the reason for deciding the\nprecedence between environment and configuration is no longer as\nstrong as it used to be.\n\nBefore the \"git -c var=val\" happened, the only sensible preference\norder was to allow environment to override a configured default by\ndoing \"VAR=val git cmd ...\".  In other words, the order used to be\nsomething you could safely forget and still infer the right order\nwith logic alone.\n\nBut with \"git -c var=val\", even if a hypothetical Git allowed\nconfiguration to override environment, a user could still override\nthem with \"-c var=val\", so \"environment trumps configuration\" is no\nlonger \"because there is no sensible workaround if it were the other\nway around\", but merely \"because that used to be the only logical\nway\".\n\n"}]}