Skip to content

Hash Algorithm

Since its creation, Git has used SHA-1 (Secure Hash Algorithm 1) to identify all objects. Every Blob, tree, commit, and tag is named by the 40-character hexadecimal representation of its SHA-1 Hash, producing a 21602^{160} address space.

PropertyValue
Output size160 bits (20 bytes, 40 hex characters)
Collision resistance2802^{80} (theoretical) — broken in practice
Preimage resistance21602^{160} (unbroken)
SpeedFast (hardware-accelerated on modern CPUs)

In 2017, researchers at Google and CWI Amsterdam demonstrated the first SHA-1 collision (the “SHAttered” attack). They produced two different PDF files with the same SHA-1 hash, requiring Approximately 263.12^{63.1} computations (far below the theoretical 2802^{80}).

Does this affect Git? Directly, not much. The attack required significant computational Resources (\sim6,500 CPU-years) and was specifically crafted for PDF files. However, it proved That SHA-1”s collision resistance is weaker than assumed, and future advances could make attacks Cheaper.

Git’s Defenses Against Collision Attacks

Section titled “Git’s Defenses Against Collision Attacks”

Git has several properties that make collision attacks harder than generic SHA-1 collisions:

  1. Object headers: Git hashes "<type> <size>\0<content>"Not raw content. An attacker must collide the full header+content.
  2. Detect checks: git fsck detects objects whose hash does not match their content.
  3. Collision detection: Git includes collision detection code that detects SHAttered-style attacks.

Git 2.29 (September 2020) added experimental support for SHA-256 as an alternative hash Algorithm.

Terminal window
## Initialize a new repository with SHA-256
$ git init --object-format=sha256
## Configure globally for new repositories
$ git config --global init.defaultObjectFormat sha256
# Check the hash algorithm of an existing repository (0=SHA-1, 1=SHA-256)
$ git config core.repositoryFormatVersion
PropertySHA-1SHA-256
Output size160 bits256 bits
Collision resistance2802^{80} (broken)21282^{128} (secure)
Preimage resistance21602^{160} (secure)22562^{256} (secure)
Hash length40 hex chars64 hex chars
SpeedFaster\sim20% slower (software)

Migrating an existing repository from SHA-1 to SHA-256 is not currently supported by Git. This Is because:

  1. Every object hash changes: All blobs, trees, commits, and tags get new hashes.
  2. All references break: Branches, tags, remotes. Everything must be updated.
  3. All packfiles must be regenerated: The entire object store is invalidated.
  4. Interoperability: SHA-256 repositories cannot interoperate with SHA-1 tools or servers.

The Git community is working on a migration path, but it is not yet production-ready. For new Repositories, enabling SHA-256 from the start is recommended.

Git allows abbreviating hashes to the shortest unambiguous prefix:

Terminal window
# Full SHA-1 (40 chars)
a3f2b1c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6
# Abbreviated (minimum unambiguous length)
a3f2b1c
# Configure minimum abbreviation length
$ git config core.abbrev 12 # Require at least 12 chars

With SHA-256, the minimum abbreviation length is longer (more objects can share a prefix before Diverging). Git handles this automatically.

Terminal window
# Start new projects with SHA-256
$ git init --object-format=sha256

This provides future-proofing at essentially zero cost (the slight speed difference is negligible For most workflows).

No migration path exists yet. Monitor the Git mailing list for updates. In the meantime:

  • Run git fsck periodically to detect corruption.
  • Keep your gc.pruneExpire settings generous to avoid accidental data loss.
  • Back up your .git directory regularly.

If you are concerned about collision attacks:

  1. Enable fsck: Run git fsck in CI to detect corrupted objects.
  2. Sign commits: Use GPG or SSH to sign commits and tags.
  3. Use SHA-256 for new repositories.

Content-Addressable Storage: Design Rationale

Section titled “Content-Addressable Storage: Design Rationale”

Git’s choice of content-addressable storage (CAS) is fundamental to its design. The implications are Far-reaching:

PropertyBenefit
DeduplicationIdentical files across commits produce one blob object
IntegrityAny modification of an object changes its hash, breaking references
Distributed consensusTwo developers can independently verify they have the same object
Deterministic buildsA commit hash uniquely identifies a project state
Garbage collectionUnreachable objects can be safely deleted without affecting reachable objects

The trade-off is that Git cannot efficiently store files that change slightly and frequently (e.g., Large binary files, databases). This is why Git LFS exists — it stores the large file content Outside the object store and tracks only a pointer.

  1. Writing vague answers without specific biological terminology. Use precise terms (e.g., ‘phospholipid bilayer’ not ‘membrane’).

  2. Using anecdotal evidence or small sample sizes as though they constitute robust scientific data.

  3. Failing to link structure to function when describing biological molecules, cells, or organs.

  4. Misinterpreting graphs by confusing the independent and dependent variables or reading scales incorrectly.

The key principles covered in this topic are linked in the sub-pages above. Focus on understanding the definitions, applying the formulas or frameworks, and evaluating strengths and limitations of each approach.

Worked examples demonstrating the application of key concepts are covered in the detailed sub-pages linked above.

Hashing is like a fingerprint for data. Just as a fingerprint uniquely identifies a person, a hash uniquely identifies a piece of content. Content-addressable storage is like a library where books are shelved by their ISBN number instead of by title or author - if two books have the same ISBN, they must be the same book. SHA-1 produces a 40-character hex string that acts as this ISBN. The key insight is that hashing provides integrity verification - if even one bit of a file changes, its hash changes completely. This is like a tamper-evident seal on a package - any attempt to open it leaves evidence. Git uses this to ensure that every object in the repository is exactly what it claims to be.