
Git 3.0 Defaults to SHA-256. Nothing Can Talk To It.
Quick answer: Git 3.0 will initialise new repositories with SHA-256 instead of SHA-1. Git's own git init manual page says, flatly, that "At present, there is no interoperability between SHA-256 repositories and SHA-1 repositories" — and GitHub still cannot host one, years after Git shipped the format. The default is changing before the thing that makes the default survivable exists.
Git's BreakingChanges document lists what the project intends to change at the next major version boundary. One line in it is the whole story: "The default hash function for new repositories will be changed from sha1 to sha256."
The cryptographic case is not in dispute. The same document cites four published attacks on SHA-1 — the SHAppening (2015, 2^57 operations), SHAttered (2017, 2^63, two colliding PDFs), Birthday-Near-Collision (2019, 2^68, chosen-prefix) and Shambles (2020, 2^63, chosen-prefix) — and notes that NIST deprecated SHA-1 in 2011. What is in dispute is whether flipping the default is the right move while the migration path is a design document rather than code.
The sentence that undercuts the plan
Git has had a SHA-256 object format for years. You can use it today: git init --object-format=sha256. Read the manual page for that flag and you hit this, verbatim:
"Note: At present, there is no interoperability between SHA-256 repositories and SHA-1 repositories." — git-init(1)
Now read Git's hash-function-transition design document, which states as an explicit goal: "A SHA-256 repository can communicate with SHA-1 Git servers (push/fetch)." It describes the mechanism in detail — a translation table, an index-pack pass that computes SHA-1 for each object, a topological sort, a conversion step, a re-sort to match the server's pack order.
That is a design. It is not a shipped feature. The two documents sit on the same site and say opposite things about the same capability, and the one describing reality is the terser of the two. This is the same docs-versus-intent gap we keep finding when we read a vendor's reference page against its own announcement — see what Git 2.56 actually changed for the near-term version of the same exercise.
The forge gap is the real blocker
BreakingChanges states the precondition in one sentence: "An important requirement for this change is that the ecosystem is ready to support the sha256 object format. This includes popular Git libraries, applications and forges."
Measure that against where the forges actually are.
| Host | SHA-256 repositories | Evidence |
|---|---|---|
| GitHub | Not supported | Feature request open since 2020, still marked unanswered |
| GitLab | Experimental | Announced 19 Aug 2024; "should only be used to create test projects" |
| Gitea / Forgejo | Supported | Gitea PR #23894; Forgejo tracked at issue #124 |
GitLab's own August 2024 announcement puts the feature behind "Experimental settings" on the project creation page and says it "is experimental and should only be used to create test projects." That is two years old and still the current framing. The GitHub community request for SHA-256 support has no staff timeline attached to it at all.
The precondition Git wrote for itself is not met by the two largest hosts. Git can ship the default anyway, but a default most developers cannot push anywhere is a default in name only.
What breaks in your own code
A SHA-1 object ID is 40 hex characters. A SHA-256 object ID is 64. If you have written anything that touches commit hashes, that is the audit.
Fixed-width assumptions
Regular expressions written as [0-9a-f]{40}, database columns declared CHAR(40), log redaction patterns, deploy scripts that slice a fixed number of characters off a ref. Same class of failure as the credential-format changes moving through package registries: the breakage is never in the vendor's client, it is in your glue code.
Submodules and vendored repos
A SHA-256 superproject cannot reference a SHA-1 submodule, because the gitlink stores an object ID in the parent's format. Mixed-format dependency trees are not a thing. Any shared library consumed as a submodule has to pick a side, or exist twice.
Every link you ever wrote down
Because conversion rewrites every object, every commit ID changes. Issue references, changelogs, incident writeups, signed tags — all of it points at hashes that no longer resolve, with no forge-served mapping to redirect them. A text diff across before-and-after exports shows you the scale faster than reasoning about it will.
Reimplementations
Most of the Git ecosystem is not Git. It is libgit2 bindings, pure-Go and pure-Rust implementations, CI providers parsing porcelain output, and the long tail of developer tools and cloud and DevOps listings. Each needs a second hash format before a SHA-256 default is usable rather than survivable.
Chacon's objection
Scott Chacon — a GitHub co-founder, now at GitButler — published an argument that the SHA-256 default is a costly mistake. His case is not that SHA-1 is fine. It is that the threat model is wrong: Git hashes are content addresses, not trust anchors, and real attacks on repositories come through distribution and social engineering, not collision construction. He quotes Torvalds' original position — "The real security is in distribution" — and calls the collision premise "just honestly a ridiculous premise" as a primary threat vector.
His counter-proposal deserves more attention than the polemic around it. Rather than replacing the storage hash, add independent SHA-256 tree-content hashes as signed commit headers: collision resistance where it matters, in what a signature attests to, without bifurcating the object format for everyone else. He reports generating those checksums across Chromium (35GB, 2.1 million files) in about five seconds and across the Linux kernel tree in 257 milliseconds — his numbers, not independently reproduced, but the right order of magnitude to make the idea cheap.
Whether or not you buy the argument, it clarifies the actual decision: SHA-256-as-default buys cryptographic hygiene for the object store, and costs an ecosystem split. A signed-header approach buys verification without the split. Git has chosen the first. Nobody has committed a date to it.
There is no Git 3.0 date
This matters for how urgently you should care. BreakingChanges does not carry a release date for 3.0. The changes are gated behind a compile-time switch: "The breaking changes MUST be guarded with the a compile-time switch, WITH_BREAKING_CHANGES, to help this process. When built with it, the resulting Git binary together with its documentation would behave as if these breaking changes slated for the next big version boundary are already in effect." There is a CI job that exercises that build.
So you can test against the future today by building Git with that switch, and that is the correct amount of effort to spend right now. SHA-256 is not the only thing in the 3.0 list, either: the reference backend default moves from files to reftable, the default branch name becomes main, safe.bareRepository defaults to explicit instead of all, Rust becomes mandatory to build Git, and a batch of long-deprecated features go — graft commits, git-pack-redundant, .git/branches/ and .git/remotes/, git-whatchanged, --stdin on name-rev, core.commentString=auto and core.preferSymlinkRefs=true.
The reftable default and the mandatory Rust dependency will break more build pipelines in practice than the hash change will, precisely because the hash change cannot reach most people's hosts yet.
What to do this quarter
Grep for 40. Specifically: hash-shaped regexes, fixed-width schema columns, and anything that substrings a ref. A regex tester makes the first pass quick — widen {40} to {7,64} and confirm nothing downstream depends on the length. Do not convert production repositories. Do not enable the experimental path on a hosted forge and call it migrated. If you want to see the failure modes, create a throwaway SHA-256 repository locally and try to push it anywhere; the error you get is the honest status report.
And watch the forges rather than the mailing list. The realistic ordering is forge support, then conversion tooling, then the default. Anyone selling you a migration plan before step one lands is selling a plan for something that cannot be done.
FAQ
When does Git 3.0 ship?
No date has been published. Git's BreakingChanges document describes 3.0 as the next major version boundary and lists what will change, but does not attach a release date. The changes are already testable behind the WITH_BREAKING_CHANGES compile-time switch, which has its own CI job.
Can I push a SHA-256 repository to GitHub?
No. GitHub does not support SHA-256 repositories, and the community feature request for it — open since 2020 — carries no official timeline. GitLab offers SHA-256 projects behind an experimental setting that its own announcement says should only be used for test projects. Gitea and Forgejo support the format.
Is SHA-1 being removed from Git?
No. BreakingChanges says explicitly: "There is no plan to deprecate the sha1 object format at this point in time." Only the default for newly initialised repositories changes. Existing SHA-1 repositories keep working.
Can I convert an existing repository from SHA-1 to SHA-256?
Not with a supported in-place command, and not without changing every object ID in your history. The hash-function-transition design document describes conversion and interoperability mechanisms, but the git-init manual page states that at present there is no interoperability between SHA-256 and SHA-1 repositories. Treat conversion as unavailable rather than difficult.
What else changes in Git 3.0 besides the hash?
The reference storage default moves from files to reftable, the default branch name becomes main, safe.bareRepository defaults to explicit, Rust becomes a mandatory build dependency, and several deprecated features are removed including graft commits, git-pack-redundant, git-whatchanged, and support for the .git/branches/ and .git/remotes/ directories.
Does SHA-1 collision risk actually affect my repository?
Git already ships collision detection for the known SHAttered-class attacks, and accidental collisions are not a practical concern. The published attacks are real but require constructing both sides of a collision, which is an attack on content you accept, not on content you already have. That is the basis of Scott Chacon's argument that the migration solves a theoretical problem at a practical cost.
A default nobody can push is a roadmap item, not a migration. Audit your 40-character assumptions now; wait for the forges before anything else.

