⏱️ Reading time: 14 min
As of 2026, Git still uses SHA-1 by default to identify every commit, blob, and tree, even though that algorithm has been flagged as cryptographically broken since 2017. Scott Chacon, cofounder of GitButler, published a sharp critique of the Git 3.0 plan. According to his argument, adopting SHA-256 in Git as the default hash format would produce repositories that GitHub and GitLab still can’t host, with no practical benefit for most projects.
📑 En este artículo
- TL;DR
- What Is SHA-256 in Git?
- Why SHA-1 Stopped Being Enough
- How the Hash Change Works in Git
- Practical Examples: Testing SHA-256 on Your Machine
- Getting Started: Testing a SHA-256 Repository Step by Step
- Real Use Cases for the SHA-256 Format
- Common Mistakes When Testing the SHA-256 Format
- Comparison: SHA-1 vs. SHA-256
- Deep Dive: The Official Hash Transition Plan
- Frequently Asked Questions
- Can I migrate an existing SHA-1 repository to SHA-256 in Git without losing history?
- Do GitHub or GitLab accept repositories with the SHA-256 algorithm?
- What happens to a Git submodule if its hash format differs from the superproject’s?
- When will SHA-256 become Git’s default hash format?
- How do I check if a local repository uses SHA-1 or SHA-256?
- Does the SHA-256 algorithm make verifying signed commits slower?
- References
The controversy makes for a good hook, but the underlying issue is technical: what that algorithm actually changes, how compatible it is with the current ecosystem, and how to test it today on your own machine.
TL;DR
- Git has supported SHA-256 experimentally since version 2.29 via
git init --object-format=sha256. - GitHub and GitLab still don’t host SHA-256 repositories: there’s no direct
git pushto those services today. - The hash goes from 40 to 64 hexadecimal characters, which slightly increases the size of trees and commits with many references.
- There’s no official conversion that preserves hashes when migrating an existing SHA-1 repository to SHA-256.
git rev-parse --show-object-formatconfirms in seconds which algorithm any local repository uses.
What Is SHA-256 in Git?
SHA-256 in Git is the alternative hash algorithm to SHA-1 that the project’s official documentation defines as the new 256-bit object format, capable of identifying every commit, tree, and blob with a wider cryptographic margin, and that any repository can adopt today experimentally at the moment of initialization.
The project documents this in its technical transition plan, hash-function-transition, published within the Git repository itself. That document explains why SHA-1 no longer suffices as an integrity guarantee and what steps the project plans to take to migrate without breaking the history of millions of existing repositories.
Why SHA-1 Stopped Being Enough
Git is what’s called a content-addressable database: every file, every directory tree, and every commit is identified by the hash of its content, not by an arbitrary number. That property is what gives it integrity. Changing a single byte in an old commit changes its hash, and that change propagates to every subsequent commit because each one includes the hash of its parent.
Since Linus Torvalds chose SHA-1 in 2005, that design has worked without any known accidental collision incidents. The problem isn’t chance, it’s deliberate attack. In 2017, the Google and CWI Amsterdam team published SHAttered, the first practical SHA-1 collision: two different PDF files with the same hash. In 2020, the paper SHA-1 is a Shambles made the attack even cheaper, to the point of making it viable with GPUs rented in the cloud instead of dedicated supercomputers.
That doesn’t mean a Git commit could easily be forged tomorrow: a practical attack against a real repository still requires specific conditions in the manipulated content. But it does mean SHA-1 no longer meets the standard that modern cryptography demands for an integrity hash, and that Git needs a replacement before the attack window gets any cheaper.
How the Hash Change Works in Git
Git doesn’t swap one algorithm for another within the same repository. Instead, it defines a new repository format. When you run git init --object-format=sha256, Git creates a .git folder whose config file includes the [extensions] objectFormat = sha256 section. That flag tells any version of Git that opens that repository to use SHA-256 for everything: computing blob hashes, building trees, signing commits, and writing the object pack.
What Changes in Object Size
The most visible difference is hash length. SHA-1 produces 160 bits, represented as 40 hexadecimal characters; SHA-256 produces 256 bits, represented as 64 characters. A commit or a tree that references other objects stores those references as text, so every internal reference grows from 40 to 64 bytes.
The effect is more noticeable in trees with many files and in long histories. A monorepo with tens of thousands of files per commit sees the size of each tree object grow in direct proportion to that 24-byte difference per entry. For an individual blob, on the other hand, the change is negligible, because the file’s content doesn’t change, only its identifier.
Compatibility and Interoperability Today
This is the technical core of GitButler’s critique. A SHA-1 repository and a SHA-256 one aren’t interchangeable: you can’t run git push or git pull between them without going through a conversion, and Git still doesn’t include a tool in its stable branch that preserves the original hashes when migrating.
The official hash-function-transition document describes the design meant to solve this: a translation table that maps every SHA-1 identifier to its SHA-256 equivalent and vice versa, so a repository can speak both formats during the transition. That mechanism remains, for the most part, a documented plan rather than a production-ready feature across all workflows.
flowchart TD
A["SHA-1 Repository"] -->|"git push / git pull"| B["SHA-1 Remote, GitHub or GitLab"]
C["SHA-256 Repository"] -.->|"no native support today"| B
C -->|"git push / git pull"| D["SHA-256 Remote, self-hosted"]
subgraph Hosting available in 2026
B
end
subgraph Experimental hosting
D
end
Why SHA-256 and Not Another Algorithm
The transition document itself explains the selection criteria. SHA-256 is an already-validated NIST standard, with mature implementations across every cryptographic library and hardware acceleration available on modern processors through Intel and ARM’s SHA extensions. Alternatives like BLAKE2 or SHA-3 also met the required security level, but prioritizing an already-ubiquitous algorithm reduced adoption friction across the entire ecosystem of tools surrounding Git.
Practical Examples: Testing SHA-256 on Your Machine
You don’t have to wait for Git 3.0 to experiment. Support for --object-format=sha256 has existed since Git 2.29, released in 2020, so any recent installation already includes it. The only thing that changes with Git 3.0 is that it would stop being an explicit option and become the default value.
Creating a New Repository with SHA-256
git init --object-format=sha256 repo-sha256
cd repo-sha256
Git responds with the standard initialization confirmation:
Initialized empty Git repository in /home/dev/repo-sha256/.git/
To confirm which algorithm is active, without relying on memory, Git exposes a dedicated command:
git rev-parse --show-object-format
The output is a single word with the algorithm’s name:
sha256
If you run the same command on a repository created without the --object-format flag, the output is sha1: that’s today’s default value in any standard Git installation, the same one GitButler doesn’t want to see replaced without a resolved interoperability path.
Computing a SHA-256 Hash of a File
Within that same repository, any normal operation uses SHA-256 transparently. git hash-object makes it explicit:
echo "hello world" | git hash-object --stdin
In a SHA-1 repository that line returns a 40-character hexadecimal identifier. In a SHA-256 one, like the one you just created, the result has 64 characters: double the length, even though the hashed content is exactly the same.
sequenceDiagram
participant U as User
participant G as Git
participant O as Object Database
U->>G: git hash-object --stdin -w
G->>G: computes the hash according to the repository's object-format
G->>O: stores the blob object
O-->>G: confirms the write
G-->>U: returns the hash, 40 or 64 hex characters
⚠️ Heads up: a SHA-256 repository works perfectly on your machine, but today it’s an island: you can’t clone it or push it to GitHub, GitLab, or most of the forges you use in your daily work.
Getting Started: Testing a SHA-256 Repository Step by Step
You’ll need Git 2.29 or newer; any maintained Linux distribution in 2026 already meets this. Check your version before continuing:
git --version
If the result is lower than 2.29, update the git package with your Linux distribution’s package manager before continuing (on macOS, brew upgrade git; on Windows, download the installer from git-scm.com).
- Create the repository with the new format:
git init --object-format=sha256 demo-sha256. - Go into the folder and confirm the active algorithm:
cd demo-sha256 && git rev-parse --show-object-format. It should printsha256. - Add a file and make the first commit like in any repository:
echo "demo" > file.txt && git add file.txt && git commit -m "first SHA-256 commit". - Inspect the hash of the commit you just created with
git log --format=%H -1: it will show 64 hexadecimal characters instead of the usual 40.
What you won’t be able to do yet, at least with most hosting services available in 2026, is push that repository to a remote on GitHub or GitLab: neither currently accepts the SHA-256 object format in its hosted repositories.
💡 Tip: if you need extra precision, git rev-parse --show-object-format=storage indicates the format objects are stored in on disk, which is different from the input or output format a specific command might use.
Real Use Cases for the SHA-256 Format
For now, the SHA-256 format makes sense in specific scenarios, not as a general replacement for everyday workflow.
- Security teams that need to assess, before any corporate migration, how their internal tooling (hooks, CI, automation scripts) behaves with 64-character hashes.
- Contributors to the Git project itself who test and report bugs on the translation table and the protocol support documented in hash-function-transition.
- Environments with strict regulatory compliance, where internal policy requires avoiding SHA-1 in any system, including version control, regardless of whether a practical attack has been demonstrated against Git specifically.
- Maintainers of self-hosted forges (Gitea, Forgejo, plain Git servers over SSH) who can host SHA-256 repositories without depending on GitHub or GitLab adding support first.
Common Mistakes When Testing the SHA-256 Format
The most common mistake is assuming it’s enough to run git init --object-format=sha256 on a repository that already exists. That command only works for new, empty repositories: it doesn’t convert an existing SHA-1 history, because changing the hash algorithm changes every object’s identifier, which breaks the integrity chain Git built commit by commit.
The second mistake is assuming a hosting provider will accept the push without any warning. In practice, the attempt fails immediately, or the service doesn’t even offer the option to create a remote repository in that format.
The third mistake is mixing submodules with different formats without checking first. A SHA-256 superproject that references a SHA-1 submodule, or vice versa, doesn’t currently have an officially supported end-to-end path. It’s best to keep the entire submodule tree in the same format while the ecosystem finishes maturing.
As a best practice, evaluate the technical impact on a disposable test repository, never on a copy of a production project, and document which tools in your pipeline (linters, pre-commit hooks, CI integrations) assume 40-character hashes somewhere in their code.
Comparison: SHA-1 vs. SHA-256
| Aspect | SHA-1 (today’s default) | SHA-256 (experimental) |
|---|---|---|
| Hash length | 160 bits, 40 hex characters | 256 bits, 64 hex characters |
| Cryptographic status | Practical collision demonstrated (SHAttered, 2017) | No known practical collision |
| Creation command | git init (no flags) | git init --object-format=sha256 |
| GitHub/GitLab support | Full | Not available in 2026 |
| Interoperability between formats | Not applicable | No official conversion that preserves hashes |
| Relative size of objects with many references | Baseline | Slightly larger due to the longer hash |
Deep Dive: The Official Hash Transition Plan
The hash-function-transition document doesn’t describe a simple algorithm swap: it describes a coexistence period. The underlying idea is that a repository can store objects with their native hash (SHA-1 or SHA-256) while also maintaining a table that translates each identifier into the other format, so tools and protocols that still expect SHA-1 keep working while the ecosystem migrates.
That translation table is different from a simple history rewrite. Rewriting history with something like git filter-repo generates new commits, with new parents and new hashes, which changes every commit’s identity. The translation table, instead, aims for the same logical commit to have two valid, equivalent identifiers, one per format, without changing its content or its position in the history.
flowchart LR
A["Commit, 40-hex SHA-1 hash"] --> T["Translation table"]
B["Commit, 64-hex SHA-256 hash"] --> T
T --> C["Bidirectional per-object mapping"]
subgraph Interoperability design
T
C
end
The repository also uses the extensions.objectFormat field to mark the repository’s format version as 1 instead of 0, a deliberate decision. This way, older Git versions that don’t understand SHA-256 reject the repository instead of silently corrupting it. In this design, backward compatibility is resolved by failing fast with a clear message instead of silently corrupting data.
Another detail the project itself documents is that GPG-signing commits and tags requires format consistency: a signed SHA-256 commit includes that 64-character hash inside the signed object, so external tools that parse signatures, for instance to verify them in a CI pipeline, need to be updated to accept the new length before they can validate that type of commit.
The impact isn’t limited to Git itself. Any tool that has assumed, directly or indirectly, that a Git hash always has 40 characters (CI scripts, log parsers, third-party integrations, custom hooks) needs a review before SHA-256 stops being a marginal option. That is, at bottom, the real technical concern behind GitButler’s critique. The cost of adaptation falls on thousands of projects that never asked for the change, even though SHA-256 itself is a solid cryptographic choice.
Your next step: clone an empty test repository, run git init --object-format=sha256, and compare with your own eyes the length of a commit’s hash against that of any SHA-1 repository.
Frequently Asked Questions
Can I migrate an existing SHA-1 repository to SHA-256 in Git without losing history?
Not directly. Git still doesn’t include a stable tool that converts a SHA-1 repository to SHA-256 while preserving each commit’s original hashes. The official plan to achieve this, based on a translation table, remains documented as a design rather than a production-ready feature across all workflows.
Do GitHub or GitLab accept repositories with the SHA-256 algorithm?
No, at least not in 2026. Neither service currently offers the option to host a repository with extensions.objectFormat = sha256, which limits this format’s practical use to local repositories or those hosted on self-hosted forges.
What happens to a Git submodule if its hash format differs from the superproject’s?
There’s no officially supported path for mixing formats between a superproject and its submodules. The practical recommendation is to keep the entire submodule tree on the same algorithm while interoperability support remains incomplete.
When will SHA-256 become Git’s default hash format?
The Git community itself is debating the timeline. The GitButler post that prompted this piece claims the change is planned for a future 3.0 version, but that date depends on interoperability with the major hosting services advancing first.
How do I check if a local repository uses SHA-1 or SHA-256?
Run git rev-parse --show-object-format inside the repository. The output is a single word, sha1 or sha256, unambiguously.
Does the SHA-256 algorithm make verifying signed commits slower?
Not in any noticeable way for an individual developer. The extra cost of computing and verifying a SHA-256 hash instead of SHA-1 is minimal on modern hardware. The real bottleneck today is the lack of support in external tools, not the algorithm’s performance.
References
- Git 3.0’s upcoming SHA-256 default will be a costly mistake: Scott Chacon’s (GitButler) critique that prompted this piece.
- hash-function-transition, Git’s official technical documentation: the SHA-1 to SHA-256 transition plan, with the translation table and interoperability design.
- git-init, official documentation: details the
--object-formatoption for creating repositories with a specific hash algorithm. - git-hash-object, official documentation: describes how Git computes each object’s identifier based on the repository’s active format.
- SHAttered: the research by Google and CWI Amsterdam that published the first practical SHA-1 collision in 2017.
📱 Do you like this content? Follow @programacion on Telegram for daily tech content in Spanish: quick summaries, fresh content every day.
Featured image: Foto de Rahul Mishra en Unsplash
Did it work for you? Got a different error? Say so below: questions get answered and help the next reader.
Leave a comment
0 Comments