* Default object format for new repositories in Git v3
@ 2026-11-06 16:50 Adam Dinwoodie
2026-11-06 20:46 ` brian m. carlson
2026-11-08 1:16 ` [PATCH] setup: default hash algo to GIT_HASH_DEFAULT brian m. carlson
0 siblings, 2 replies; 7+ messages in thread
From: Adam Dinwoodie @ 2026-11-06 16:50 UTC (permalink / raw)
To: Git Mailing List
[-- Attachment #1: Type: text/plain, Size: 795 bytes --]
Hi folks,
As part of preparing for Git v3, in particular for Nixpkgs, I've been
running a bunch of tests using Git built with
`WITH_BREAKING_CHANGES=1`. Somewhat to my surprise, `git init` seems
to still be creating new repositories using sha1 rather than sha256.
Is this expected?
For reference, I've attached the test script I've produced as a repro
that can be run from the root of a Git checkout, although it does
require Nix. I've confirmed the behaviour at v2.56.0, next
(972d6e3ab651d838b30a8d5d70d8ef6ced05a986) and main
(0ffa3e35c7c82ab8d0de226149fb03b3f7674d05).
For a simpler repro that doesn't require Nix, build Git with
`WITH_BREAKING_CHANGES=1`, then run:
```
git init tmpdir
git -C tmpdir rev-parse --show-object-format
```
This will print "sha1", when I'd expect "sha256".
[-- Attachment #2: test.sh --]
[-- Type: text/x-sh, Size: 1832 bytes --]
#!/usr/bin/env nix
#!nix shell
#!nix --override-flake nixpkgs https://releases.nixos.org/nixos/unstable/nixos-26.11pre1105037.1c89083e451e/nixexprs.tar.zst
#!nix --ignore-env
#!nix nixpkgs#bash nixpkgs#coreutils nixpkgs#nix nixpkgs#findutils nixpkgs#gnused nixpkgs#autoconf nixpkgs#gnumake nixpkgs#gcc nixpkgs#cargo
#!nix --command bash
set -euo pipefail
tmpdir="$(mktemp --dir)"
trap 'rm -rf -- "$tmpdir"' EXIT
# Get the paths we need for zlib-ng
export NIX_PATH=nixpkgs=https://releases.nixos.org/nixos/unstable/nixos-26.11pre1105037.1c89083e451e/nixexprs.tar.zst
nix-build '<nixpkgs>' -A zlib-ng -A zlib-ng.dev -o "$tmpdir"/zlib-ng
zlib_lib="$(realpath "$tmpdir"/zlib-ng)"
zlib_dev="$(realpath "$tmpdir"/zlib-ng-dev)"
# Work out how much to parallelise the builds
jobs="$(nproc)"
# Make sure the build process can find zlib-ng
export CPPFLAGS="-isystem $zlib_dev/include" LDFLAGS="-L$zlib_lib/lib -Wl,-rpath,$zlib_lib"
# Set options: disable features we don't need for speed of building, use
# zlib-ng, enable breaking changes.
export ZLIB_NG=1 WITH_BREAKING_CHANGES=1 NO_TCLTK=1 NO_GETTEXT=1
# Build git
make -j"$jobs" configure
./configure
make -j"$jobs"
# Make sure Git config doesn't have anything unexpected
export GIT_CONFIG_GLOBAL=/dev/null
export GIT_CONFIG_SYSTEM=/dev/null
export GIT_CONFIG=/dev/null
export GIT_CONFIG_COUNT=2
export GIT_CONFIG_KEY_0=user.name GIT_CONFIG_VALUE_0=Adam
export GIT_CONFIG_KEY_1=user.email GIT_CONFIG_VALUE_1=adam@localhost
export GIT_PAGER=cat
# Make sure calling `git` gets the right executable
export PATH="$PWD":"$PATH"
# Set up a simple repository with a single commit
git init "$tmpdir"/repo
cd "$tmpdir"/repo
touch test-file
git add test-file
git commit -m 'demo commit'
# Show everything's sha1 rather than sha256
git log --format=raw
git rev-parse --show-object-format
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Default object format for new repositories in Git v3
2026-11-06 16:50 Default object format for new repositories in Git v3 Adam Dinwoodie
@ 2026-11-06 20:46 ` brian m. carlson
2026-11-08 1:16 ` [PATCH] setup: default hash algo to GIT_HASH_DEFAULT brian m. carlson
1 sibling, 0 replies; 7+ messages in thread
From: brian m. carlson @ 2026-11-06 20:46 UTC (permalink / raw)
To: Adam Dinwoodie; +Cc: Git Mailing List
[-- Attachment #1: Type: text/plain, Size: 1170 bytes --]
On 2026-11-06 at 16:50:03, Adam Dinwoodie wrote:
> Hi folks,
>
> As part of preparing for Git v3, in particular for Nixpkgs, I've been
> running a bunch of tests using Git built with
> `WITH_BREAKING_CHANGES=1`. Somewhat to my surprise, `git init` seems
> to still be creating new repositories using sha1 rather than sha256.
> Is this expected?
>
> For reference, I've attached the test script I've produced as a repro
> that can be run from the root of a Git checkout, although it does
> require Nix. I've confirmed the behaviour at v2.56.0, next
> (972d6e3ab651d838b30a8d5d70d8ef6ced05a986) and main
> (0ffa3e35c7c82ab8d0de226149fb03b3f7674d05).
>
> For a simpler repro that doesn't require Nix, build Git with
> `WITH_BREAKING_CHANGES=1`, then run:
>
> ```
> git init tmpdir
> git -C tmpdir rev-parse --show-object-format
> ```
>
> This will print "sha1", when I'd expect "sha256".
This does appear to be broken. I have a patch that should fix it that's
running through CI right now. I'll send it once it's green, either
later tonight or tomorrow.
--
brian m. carlson (they/them)
Toronto, Ontario, CA
Speaking for myself only
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 325 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] setup: default hash algo to GIT_HASH_DEFAULT
2026-11-06 16:50 Default object format for new repositories in Git v3 Adam Dinwoodie
2026-11-06 20:46 ` brian m. carlson
@ 2026-11-08 1:16 ` brian m. carlson
2026-11-08 4:42 ` Junio C Hamano
2026-11-08 18:22 ` Junio C Hamano
1 sibling, 2 replies; 7+ messages in thread
From: brian m. carlson @ 2026-11-08 1:16 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Adam Dinwoodie
When we have no other hash algorithm to choose, we set no hash
algorithm, which ends up with us defaulting to SHA-1. Instead, default
to GIT_HASH_DEFAULT. This means that we will choose SHA-256 in breaking
changes mode and in Git 3.0, which is what we want.
Reported-by: Adam Dinwoodie <adam@dinwoodie.org>
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
setup.c | 2 ++
t/t0001-init.sh | 16 ++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/setup.c b/setup.c
index 61bcdafe82..4a0dfc8908 100644
--- a/setup.c
+++ b/setup.c
@@ -2830,6 +2830,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,
repo_fmt->hash_algo = env_algo;
} else if (cfg.hash != GIT_HASH_UNKNOWN) {
repo_fmt->hash_algo = cfg.hash;
+ } else {
+ repo_fmt->hash_algo = GIT_HASH_DEFAULT;
}
/*
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index f1d227f271..98c7562f32 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -516,6 +516,22 @@ test_expect_success 're-init from a linked worktree' '
)
'
+test_expect_success 'git init uses default object format' '
+ test_when_finished "rm -rf repo" &&
+ (
+ sane_unset GIT_DEFAULT_HASH &&
+ git init repo &&
+ if test_have_prereq WITH_BREAKING_CHANGES
+ then
+ echo sha256
+ else
+ echo sha1
+ fi >expect &&
+ git -C repo rev-parse --show-object-format >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'init honors GIT_DEFAULT_HASH' '
test_when_finished "rm -rf sha1 sha256" &&
GIT_DEFAULT_HASH=sha1 git init sha1 &&
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH] setup: default hash algo to GIT_HASH_DEFAULT
2026-11-08 1:16 ` [PATCH] setup: default hash algo to GIT_HASH_DEFAULT brian m. carlson
@ 2026-11-08 4:42 ` Junio C Hamano
2026-11-08 14:38 ` brian m. carlson
2026-11-08 18:22 ` Junio C Hamano
1 sibling, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2026-11-08 4:42 UTC (permalink / raw)
To: brian m. carlson; +Cc: git, Adam Dinwoodie
"brian m. carlson" <sandals@crustytoothpaste.net> writes:
> When we have no other hash algorithm to choose, we set no hash
> algorithm, which ends up with us defaulting to SHA-1. Instead, default
> to GIT_HASH_DEFAULT. This means that we will choose SHA-256 in breaking
> changes mode and in Git 3.0, which is what we want.
>
> Reported-by: Adam Dinwoodie <adam@dinwoodie.org>
> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
> ---
> setup.c | 2 ++
> t/t0001-init.sh | 16 ++++++++++++++++
> 2 files changed, 18 insertions(+)
With Git 3.0, we promised that SHA-1/SHA-256 interop will not have
to be ready, and that SHA-256 would become the default. And this
patch would be a good thing to have for the second promise.
But didn't we also discuss "empty/initial repository whose hash
algorithm is undecided can take a push of either SHA-1 or SHA-256
payload and that first push can decide and freeze the hash algorithm
used in the repository" or something along that line?
I am wondering if we want to reserve 'HASH_UNKNOWN' for such a "was
just created, not quite finished initializing yet" state.
The patch looks good for the goal stated in the log message.
Thanks.
> diff --git a/setup.c b/setup.c
> index 61bcdafe82..4a0dfc8908 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -2830,6 +2830,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,
> repo_fmt->hash_algo = env_algo;
> } else if (cfg.hash != GIT_HASH_UNKNOWN) {
> repo_fmt->hash_algo = cfg.hash;
> + } else {
> + repo_fmt->hash_algo = GIT_HASH_DEFAULT;
> }
>
> /*
> diff --git a/t/t0001-init.sh b/t/t0001-init.sh
> index f1d227f271..98c7562f32 100755
> --- a/t/t0001-init.sh
> +++ b/t/t0001-init.sh
> @@ -516,6 +516,22 @@ test_expect_success 're-init from a linked worktree' '
> )
> '
>
> +test_expect_success 'git init uses default object format' '
> + test_when_finished "rm -rf repo" &&
> + (
> + sane_unset GIT_DEFAULT_HASH &&
> + git init repo &&
> + if test_have_prereq WITH_BREAKING_CHANGES
> + then
> + echo sha256
> + else
> + echo sha1
> + fi >expect &&
> + git -C repo rev-parse --show-object-format >actual &&
> + test_cmp expect actual
> + )
> +'
> +
> test_expect_success 'init honors GIT_DEFAULT_HASH' '
> test_when_finished "rm -rf sha1 sha256" &&
> GIT_DEFAULT_HASH=sha1 git init sha1 &&
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] setup: default hash algo to GIT_HASH_DEFAULT
2026-11-08 4:42 ` Junio C Hamano
@ 2026-11-08 14:38 ` brian m. carlson
0 siblings, 0 replies; 7+ messages in thread
From: brian m. carlson @ 2026-11-08 14:38 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Adam Dinwoodie, Jeff King
[-- Attachment #1: Type: text/plain, Size: 2037 bytes --]
On 2026-11-08 at 04:42:56, Junio C Hamano wrote:
> "brian m. carlson" <sandals@crustytoothpaste.net> writes:
>
> > When we have no other hash algorithm to choose, we set no hash
> > algorithm, which ends up with us defaulting to SHA-1. Instead, default
> > to GIT_HASH_DEFAULT. This means that we will choose SHA-256 in breaking
> > changes mode and in Git 3.0, which is what we want.
> >
> > Reported-by: Adam Dinwoodie <adam@dinwoodie.org>
> > Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
> > ---
> > setup.c | 2 ++
> > t/t0001-init.sh | 16 ++++++++++++++++
> > 2 files changed, 18 insertions(+)
>
> With Git 3.0, we promised that SHA-1/SHA-256 interop will not have
> to be ready, and that SHA-256 would become the default. And this
> patch would be a good thing to have for the second promise.
>
> But didn't we also discuss "empty/initial repository whose hash
> algorithm is undecided can take a push of either SHA-1 or SHA-256
> payload and that first push can decide and freeze the hash algorithm
> used in the repository" or something along that line?
We discussed that as a possibility, but it requires protocol changes and
nobody has stepped up to implement that. I think Peff was thinking
about maybe implementing that, but I don't think anyone came to a
decision.
> I am wondering if we want to reserve 'HASH_UNKNOWN' for such a "was
> just created, not quite finished initializing yet" state.
I think we concluded that we'd need to initialize a repository to _some_
hash algorithm even if we had the limbo state because otherwise people
could `git init` and then work locally and we need to have some existing
hash algorithm for that case. That would be true even with bare
repositories.
So I think the limbo functionality, if we implemented it, would be a
separate option (maybe `extensions.potentialObjectFormat`?) and this
patch should go in either way.
--
brian m. carlson (they/them)
Toronto, Ontario, CA
Speaking for myself only
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 325 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] setup: default hash algo to GIT_HASH_DEFAULT
2026-11-08 1:16 ` [PATCH] setup: default hash algo to GIT_HASH_DEFAULT brian m. carlson
2026-11-08 4:42 ` Junio C Hamano
@ 2026-11-08 18:22 ` Junio C Hamano
2026-11-09 2:21 ` Junio C Hamano
1 sibling, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2026-11-08 18:22 UTC (permalink / raw)
To: brian m. carlson; +Cc: git, Adam Dinwoodie, Patrick Steinhardt
"brian m. carlson" <sandals@crustytoothpaste.net> writes:
> When we have no other hash algorithm to choose, we set no hash
> algorithm, which ends up with us defaulting to SHA-1. Instead, default
> to GIT_HASH_DEFAULT. This means that we will choose SHA-256 in breaking
> changes mode and in Git 3.0, which is what we want.
>
> Reported-by: Adam Dinwoodie <adam@dinwoodie.org>
> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
> ---
> setup.c | 2 ++
> t/t0001-init.sh | 16 ++++++++++++++++
> 2 files changed, 18 insertions(+)
>
> diff --git a/setup.c b/setup.c
> index 61bcdafe82..4a0dfc8908 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -2830,6 +2830,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,
> repo_fmt->hash_algo = env_algo;
> } else if (cfg.hash != GIT_HASH_UNKNOWN) {
> repo_fmt->hash_algo = cfg.hash;
> + } else {
> + repo_fmt->hash_algo = GIT_HASH_DEFAULT;
> }
Hmph, maybe I am not reading the code flow correctly, but does this
not break running "git init" to reinitialize an already initialized
repository? I mimicked the new test in your patch and wrote the
following just immediately after it, which
* figures out our hash and the other hash
* create a new repository with the "other" hash
* run "git init" without specifying any hash
It is debatable what should happen when you run "git init" from Git
3.0 without any specialization in an existing SHA-1 repository.
Possibilities include:
1. turn an existing SHA-1 repository into SHA-256 including format
conversion.
2. notice that the repository is already set up to use the SHA-1
format, and that the user did not explicitly say what format to
use, and behave as if --object-format=sha1 were given with a
notice or warning.
3. notice that the repository is already set up to use the SHA-1
format, but our default format is SHA-256. Because the user did
not countermand via an explicit --object-format=sha1 on the
command line, we should fail loudly, "cannot convert this SHA-1
repository to SHA-256".
I think #1 is impractical, #2 is probably the best, and #3 would
also be reasonable.
But the behaviour I am seeing with
$ make WITH_BREAKING_CHANGES=YesPlease
$ cd t && WITH_BREAKING_CHANGES=YesPlease sh t0001-init.sh -i -v
with the additional patch is different from any of the three (well,
technically, because the repository is empty, we _could_ argue that
we did #1, but ...).
I wonder what the "git init" command does wrt the reference storage
format (Patrick CC'ed for this)? I am sure we do not convert from
reffiles to reftable on the fly at "git init" time.
diff --git i/t/t0001-init.sh w/t/t0001-init.sh
index bc30cf853b..1d48a712ae 100755
--- i/t/t0001-init.sh
+++ w/t/t0001-init.sh
@@ -532,6 +532,31 @@ test_expect_success 'git init uses default object format' '
)
'
+test_expect_success 'git (re)init does not clobber object format' '
+ test_when_finished "rm -rf repo" &&
+ (
+ sane_unset GIT_DEFAULT_HASH &&
+ if test_have_prereq WITH_BREAKING_CHANGES
+ then
+ ours=sha256 opposite=sha1
+ else
+ ours=sha1 opposite=sha256
+ fi &&
+
+ # initialize to non-default format
+ git init --object-format=$opposite repo &&
+ git -C repo rev-parse --show-object-format >actual &&
+ echo "$opposite" >expect &&
+ test_cmp expect actual &&
+
+ # reinitialize without configuration
+ git init repo &&
+ git -C repo rev-parse --show-object-format >actual &&
+ echo "$opposite" >expect &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'init honors GIT_DEFAULT_HASH' '
test_when_finished "rm -rf sha1 sha256" &&
GIT_DEFAULT_HASH=sha1 git init sha1 &&
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH] setup: default hash algo to GIT_HASH_DEFAULT
2026-11-08 18:22 ` Junio C Hamano
@ 2026-11-09 2:21 ` Junio C Hamano
0 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2026-11-09 2:21 UTC (permalink / raw)
To: brian m. carlson; +Cc: git, Adam Dinwoodie, Patrick Steinhardt
Junio C Hamano <gitster@pobox.com> writes:
> I wonder what the "git init" command does wrt the reference storage
> format (Patrick CC'ed for this)? I am sure we do not convert from
> reffiles to reftable on the fly at "git init" time.
I looked at setup.c:repository_format_configure() and found why
your patch regresses, as well as a latent bug in the existing code.
First, REPOSITORY_FORMAT_INIT sets .hash_algo = GIT_HASH_DEFAULT,
but read_repository_format() forces it to GIT_HASH_SHA1_LEGACY
when version == -1 (no config yet), which is why new repositories
kept getting SHA-1.
Second, unlike the ref-storage block right below it, which checks
"else if (repo_fmt->version >= 0)" once between the explicit
overrides and all default sources, the hash-algo block guards only
the GIT_DEFAULT_HASH branch (repo_fmt->version < 0), leaving "else
if (cfg.hash != GIT_HASH_UNKNOWN)" unguarded.
So init.defaultObjectFormat in ~/.gitconfig already corrupts an
existing repository on re-init, and an unguarded "else" for
GIT_HASH_DEFAULT falls into the same trap even without config.
Instead of starting the if/else if cascade like this:
if (repo_fmt->version >= 0 &&
hash != GIT_HASH_UNKNOWN &&
hash != repo_fmt->hash_algo)
die(_("attempt to reinitialize repository with different hash"));
we should have started it like so:
if (repo_fmt->version >= 0) {
if (hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
die(_("attempt to reinitialize repository with different hash"));
/* otherwise happy */
} else if ...
so that all the "set a new value from different sources like command
line, environment, ~/.gitconfig, or the built-in default" would
happen only when (repo_fmt->version < 0), probably?
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-11-09 2:21 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-06 16:50 Default object format for new repositories in Git v3 Adam Dinwoodie
2026-11-06 20:46 ` brian m. carlson
2026-11-08 1:16 ` [PATCH] setup: default hash algo to GIT_HASH_DEFAULT brian m. carlson
2026-11-08 4:42 ` Junio C Hamano
2026-11-08 14:38 ` brian m. carlson
2026-11-08 18:22 ` Junio C Hamano
2026-11-09 2:21 ` Junio C Hamano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox