Every change you’ve ever tracked in Git has a fingerprint. It’s called a commit hash, and if you’ve used version control for more than five minutes, you’ve seen one scroll past in your terminal without thinking twice about it.
But what is a commit hash, really? It’s more than a random string of characters. It’s how Git identifies every single snapshot of your code, verifies data integrity, and lets teams trace exactly which change broke production at 2 AM.
This article breaks down how Git generates these unique identifiers, the difference between SHA-1 and SHA-256, how developers use commit hashes in daily workflows, and what happens when history gets rewritten.
What Is a Commit Hash

A commit hash is a unique identifier that Git generates every time you save a snapshot of changes to a repository. It’s a 40-character hexadecimal string, and it acts as both a name and a fingerprint for that specific commit.
Git creates this string using a cryptographic hash function (SHA-1, by default) that takes in several pieces of data: the content of your files, the author information, the timestamp, the commit message, and a reference to the parent commit. All of that gets fed through the algorithm, and out comes something like e4a1f7c9b3d2a8e5f6c7d8b9a0e1f2c3d4b5a6c7.
Change even one character in any of those inputs, and you get a completely different hash. That’s the whole point.
You’ll sometimes hear people call it a “commit SHA” or “commit ID.” Same thing, different label. The terms get swapped around constantly in documentation, pull request comments, and Stack Overflow threads. Nobody’s going to correct you either way.
Git adoption has climbed from 87.1% in 2016 to 93.87% in 2025, according to Stack Overflow Developer Survey data. Over 150 million developers now use GitHub alone. Every single commit across those repositories gets identified by one of these hashes.
If you’re working in software development, you interact with commit hashes whether you realize it or not. They show up in your terminal, in your CI/CD logs, in code review links, and in deployment records. Understanding what they are (and how they work) saves you time when things go sideways.
How a Commit Hash Is Generated

Git doesn’t randomly assign identifiers. It computes them deterministically using the SHA-1 hash function. The same inputs always produce the same output. Different inputs always produce a different output.
The computation takes a blob of data, runs it through the algorithm, and returns a 160-bit value expressed as 40 hexadecimal characters. The process is fast enough that you never notice it happening, even on repositories with thousands of commits.
What Inputs Go Into the Hash Calculation
Four categories of data get hashed together:
- Tree object: a snapshot of every tracked file and directory at the moment of the commit
- Parent commit hash(es): the SHA of the previous commit (or commits, in the case of a merge)
- Author and committer info: name, email address, and precise timestamps for both
- Commit message: the text you type after
git commit -m
The tree object is where most of the weight sits. It captures the full state of your codebase at that point. But even something as trivial as changing a single letter in your commit message produces a completely new hash.
This is what makes Git a content-addressable storage system. The hash isn’t an arbitrary label assigned by a counter. It’s derived directly from the content itself.
Why Deterministic Hashing Matters
Because the hash is tied to content, it doubles as an integrity check. If any bit of data gets corrupted during transfer or storage, the recomputed hash won’t match the stored one. Git catches this immediately.
The Linux kernel repository, one of the largest Git repos in existence, recorded 75,314 commits in 2024 alone. Every one of those commits gets verified through this same hashing mechanism. When Linus Torvalds built Git in 2005, this was the core design decision: trust nothing, verify everything through cryptographic hashes.
Grand View Research valued the global version control systems market at $1.03 billion in 2024, with distributed systems like Git holding a 51.4% share. The hash function is the reason distributed version control works at all. Two developers on opposite sides of the planet can independently verify that their copies of a repository are identical, just by comparing hashes.
Full Commit Hash vs Short Commit Hash

The full SHA-1 commit hash is always 40 characters long. Something like a3f5b7c9d1e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0. Nobody types that out in conversation.
Git lets you abbreviate it. By default, git log with the --oneline flag shows 7 characters. That’s usually enough.
| Hash Type | Length | Example | Where You See It |
|---|---|---|---|
| Full SHA-1 | 40 characters | a3f5b7c9d1… | git log, API responses |
| Short hash | 7–12 characters | a3f5b7c | GitHub UI, git log –oneline |
| Full SHA-256 | 64 characters | a3f5b7c9d1e2… | SHA-256 repos (experimental) |
The short hash works as long as it’s unambiguous within your repository. Git checks whether the abbreviated string matches exactly one commit. If the repo grows large enough that two commits share the same first 7 characters (unlikely but possible), Git automatically asks for more characters to tell them apart.
GitHub and GitLab both display 7-character abbreviations in their web interfaces. Bitbucket does the same. When you’re linking to a specific commit in a pull request or in technical documentation, the short hash is fine for human-readable references. For scripts and automation, always use the full 40-character hash.
Took me a while to learn that lesson. I once had a deployment script that used short hashes, and it broke silently when the repo hit around 200,000 commits. The fix was trivial (use the full hash), but tracking down the problem wasn’t.
How to Find a Commit Hash

Several Git commands give you commit hashes. The right one depends on what you’re looking for.
Basic Lookup Commands
git log is where most people start. It shows the full commit history of the current branch with hashes, author info, dates, and messages. Add --oneline for a compact view.
git rev-parse HEAD returns the full 40-character hash of the current commit. This is the one you want in shell scripts and build pipelines.
git reflog shows your local history of HEAD movements, including commits that aren’t reachable from any branch. If you accidentally deleted a branch or did a hard reset, reflog is how you recover it. The hashes are right there.
Finding the Hash of a Specific Commit
Need to locate a particular commit? A few approaches:
git log --grep="fix login bug"searches commit messagesgit log --author="Jane"filters by who wrote itgit log --since="2024-01-01" --until="2024-02-01"narrows by date rangegit show v2.1.0reveals the commit hash behind a tag
On GitHub and GitLab, you can also browse commit history through the web interface. Click any commit to see its full hash in the URL. Easy enough if you’re not in the terminal.
According to GitHub’s Octoverse data, developers made over 5 billion contributions across public and private projects in 2024. Every one of those contributions is traceable through a commit hash. That’s the kind of audit trail that makes source control management actually useful.
How Developers Use Commit Hashes in Practice
Hashes aren’t just internal plumbing. They’re part of daily workflows.
Checking Out and Cherry-Picking
Running git checkout a3f5b7c puts your working directory into a detached HEAD state at that exact commit. Useful when you need to inspect old code or run tests against a previous version without touching your current branch.
Cherry-picking (git cherry-pick a3f5b7c) grabs a single commit from one branch and applies it to another. You reference the commit by its hash. This comes up constantly when hotfixing production bugs. You don’t want the whole feature branch, just that one specific fix.
Referencing Commits in Code Reviews and Bug Reports
Pasting a commit hash into a GitHub issue or pull request comment automatically creates a clickable link. It’s the fastest way to point someone at exactly the right change.
During the code review process, reviewers often reference specific commits by hash to discuss individual changes within a larger pull request. “The logic change in f4c2a1b looks good, but d7e8f9a introduces a regression.” That kind of precision matters when a PR has 15 commits in it.
Pinning Deployments and Container Images
Deployment pinning is probably the most practical use of commit hashes outside of Git itself.
Teams tag Docker images with commit hashes instead of (or alongside) semantic versioning tags. A tag like myapp:latest is mutable. Someone can push a new image to that tag tomorrow. But myapp:a3f5b7c points to one exact build. It can’t drift.
The same principle applies in continuous integration and continuous deployment pipelines. GitHub Actions, Jenkins, and GitLab CI all expose the current commit hash as an environment variable. Your pipeline can stamp that hash onto build artifacts, log entries, and deployment records.
GitHub Actions Marketplace has exceeded 20,000 available actions, and continuous deployment through Actions increased by 50% in 2024. Almost all of those workflows reference commit hashes to track exactly which code got deployed and when. If something breaks in production, you can trace it back to the precise commit that caused the issue. That’s the difference between a 5-minute rollback and a 5-hour investigation.
Commit Hash vs Branch Name vs Tag
This is where people get confused. Branches, tags, and hashes all point to commits, but they’re not the same kind of reference.
| Reference Type | Mutable? | Points To | Typical Use |
|---|---|---|---|
| Commit hash | No | One exact commit | Permanent identification |
| Branch name | Yes (moves with new commits) | Latest commit on that branch | Active development |
| Tag | Technically yes, but shouldn’t be | One specific commit | Releases, milestones |
| HEAD | Yes | Current checked-out commit | Working state |
A branch is a moving pointer. Every time you make a new commit on main, the branch pointer advances forward. Yesterday, main pointed to commit a3f5b7c. Today it points to d7e8f9a. The hash didn’t change, but the branch reference did.
Tags are meant to be fixed. When you tag a release as v2.0.0, that tag should always resolve to the same commit hash. You can overwrite a tag (with git tag -f), but doing that to a shared tag is asking for trouble.
HEAD is a symbolic reference that resolves to whatever commit you currently have checked out. When you’re on a branch, HEAD points to the branch, which points to the latest commit. When you checkout a specific commit hash directly, HEAD points to that commit (detached HEAD state).
The takeaway: commit hashes are the only truly immutable reference in Git. Branches move. Tags can be overwritten. HEAD changes constantly. If you need a reference that will still be valid six months from now, use the hash.
This matters for things like software configuration management and auditing. When you’re tracking which version of code was running in production during a specific incident, “it was on main” tells you nothing useful. The commit hash a3f5b7c9d1e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0 tells you everything.
SHA-1 vs SHA-256 in Git
Git has used SHA-1 since Linus Torvalds wrote the first version in 2005. That’s changing, but slowly.
SHA-1 produces a 160-bit hash (40 hex characters). SHA-256 produces a 256-bit hash (64 hex characters). The longer output means a much larger space of possible values, which makes collisions harder to produce by orders of magnitude.
| Property | SHA-1 | SHA-256 |
|---|---|---|
| Output length | 160 bits (40 chars) | 256 bits (64 chars) |
| Collision resistance | Broken (< 80 bits) | 128 bits (strong) |
| Git default | Yes (current) | Planned for Git 3.0 |
| GitHub support | Full | Not yet |
The SHAttered Attack and What It Means for Git
In February 2017, researchers from CWI Amsterdam and Google demonstrated the first practical SHA-1 collision. They created two different PDF files that produced the same SHA-1 hash value. NIST had already deprecated SHA-1 in 2011, but this was the first real-world proof.
The attack required roughly 2^63 SHA-1 computations, which Google described as one of the largest computations ever completed. Expensive, but achievable for a well-funded attacker.
Git responded quickly. Version 2.13.0 added collision detection code developed by Marc Stevens (one of the SHAttered researchers) that catches known cryptanalytic collision techniques. But this is a patch, not a fix. The underlying weakness in SHA-1 remains.
Where the SHA-256 Transition Stands

Git 2.29 (October 2020) introduced experimental SHA-256 support. You can create a SHA-256 repository right now with git init --object-format=sha256.
The practical problem? You can’t push it to GitHub. As of early 2026, GitHub still doesn’t support SHA-256 repositories. GitLab has experimental support. Forgejo and Codeberg have full support.
Git 3.0, targeted for late 2026, will make SHA-256 the default for new repositories. Patrick Steinhardt from GitLab’s Git team noted at FOSDEM 2026 that the transition required an estimated 200 to 400 patches to Git’s core. Brian M. Carlson, who wrote most of that code, has called SHA-1 “obsolete” and noted that SHA-256 can be “substantially faster.”
Federal regulations including NIST and CISA guidelines have set a 2030 deadline for organizations to stop using SHA-1. Some organizations have already banned SHA-1 entirely, regardless of context, which has pushed a few teams away from Git altogether.
Can Two Commits Have the Same Hash

Short answer: theoretically yes, practically no.
SHA-1 has a domain of 2^160 possible hash values. That’s roughly 1.46 x 10^48 unique outputs. To hit a 50% chance of a random collision, you’d need approximately 1.2 x 10^24 objects in a single repository, according to birthday attack math. No repository on earth comes close.
Accidental Collisions vs Deliberate Attacks
Accidental collision: has never happened in any Git repository, ever. The probability is so small that even Facebook and Twitter processing every post through SHA-1 would need over 3,400 years of data before reaching a 50% collision chance (per Grayson Kent’s calculations).
Deliberate collision: demonstrated by Google’s SHAttered attack in 2017. A follow-up chosen-prefix attack in 2020 (“SHA-1 is a Shambles”) reduced the cost further. But these attacks require producing two files simultaneously. They don’t let you forge a collision with an existing commit.
Git’s built-in collision detection (since version 2.13) catches known attack patterns with a false positive probability below 2^-90. That’s the kind of margin where you’re more likely to get hit by a meteorite. Twice.
Should You Worry About It
For personal projects and most commercial software development processes, no. The risk is negligible right now.
For regulated industries where SHA-1 is banned (banking, defense, government contractors), the hash algorithm matters regardless of actual collision risk. Those teams need to watch the SHA-256 transition closely and plan migration once their hosting platform supports it.
What Happens When a Commit Hash Changes
Commit hashes don’t change. They get replaced.
When you alter anything about a commit, Git doesn’t edit the existing object. It creates a brand new commit with a brand new hash. The old commit still exists in the object store (for a while), but all references now point to the new one.
Operations That Create New Hashes
git commit --amend: rewrites the most recent commit. Even changing just the commit message produces a new hash. The original commit becomes “orphaned” but is still recoverable through git reflog for a limited time.
Git rebase: replays commits onto a new base, generating fresh hashes for every single affected commit. A rebase of 10 commits produces 10 new hashes.
Git squash: combines multiple commits into one. The resulting commit has a hash that’s different from any of the originals.
Hutte research data shows 45% of developers have been negatively affected by a colleague’s force push, and roughly 55% find rebase to be error-prone at times. These numbers make sense. Once hashes change on a shared branch, every collaborator’s local copy falls out of sync.
Why Force Pushing Breaks Things
After a rebase, your local branch and the remote branch have completely different commit histories. A regular git push gets rejected. The only way to update the remote is git push --force (or the safer --force-with-lease).
Force pushing to a shared branch overwrites the remote history. Anyone who pulled the old commits now has orphaned references that don’t match the remote. Their next git pull creates a mess of merge conflicts, or worse, silently duplicates work.
Most teams protect their main branch from force pushes entirely. GitHub and GitLab both offer branch protection rules that block this. Resolving merge conflicts is hard enough without someone rewriting the history underneath you.
The LLVM project’s guidelines capture it well: avoid rebasing a pull request and force pushing to the branch that’s the root of the pull request during review.
Commit Hashes in GitHub and GitLab URLs

Every commit on GitHub lives at a predictable URL: github.com/user/repo/commit/<hash>. Paste a full or short hash into that pattern and you get the commit’s diff, message, and metadata.
But that’s just the start. The real value is in file permalinks.
Creating Permanent Links to Code
When you view a file on GitHub, the URL contains the branch name by default (like /blob/main/README.md). That URL is mutable. Someone pushes a new commit to main, the file content changes, and your link now shows different code than what you intended.
Press “y” on any GitHub file view. The URL updates to include the full commit hash instead of the branch name. Now it’s a permalink. The content at that URL will never change, because it’s tied to a specific commit hash.
GitHub Docs confirms this: you can use any identifier that resolves to a commit in the URL, including branch names, specific commit SHAs, or tags. The commit hash version is the only one guaranteed to be stable.
How GitLab and Bitbucket Handle It
GitLab: same pattern. Files at /-/blob/<hash>/path/to/file are permalinks. GitLab’s merge request comments automatically convert commit SHA references into clickable links.
Bitbucket: uses /src/<hash>/path/to/file for file views. Commit pages live at /commits/<hash>.
All three platforms display 7-character abbreviated hashes in their UIs but store and resolve the full 40-character value. When you’re writing software documentation or filing bug reports, always link to the hash-based URL. Branch-based links break. Hash-based links don’t.
GitHub hosts over 400 million repositories and receives roughly 14 million daily visitors, according to GitHub Innovation Graph data. Every file, every commit, every diff across those repositories is addressable by hash. That’s the kind of addressability that makes distributed source control actually work at scale.
By the way, if you’re looking at a file and want to link to specific lines, click the line number (or shift-click for a range) and then press “y” to lock it to that commit. The resulting URL points to those exact lines in that exact version of the file. Perfect for defect tracking and post-incident reviews.
FAQ on What Is A Commit Hash
What is a commit hash in Git?
A commit hash is a unique 40-character hexadecimal string that Git generates using the SHA-1 algorithm. It identifies a specific snapshot of changes in a repository, acting as both a name and an integrity check for that commit.
How is a commit hash generated?
Git feeds the tree object, parent commit reference, author information, timestamp, and commit message through a cryptographic hash function. The output is a deterministic 160-bit value. Change any input, even one character, and the hash is completely different.
What is the difference between a full hash and a short hash?
A full hash is 40 characters. A short hash is typically 7 to 12 characters. Git accepts abbreviated hashes as long as they’re unambiguous within the repository. Platforms like GitHub display the short version in their UI by default.
Can two commits have the same hash?
Theoretically possible, practically negligible. SHA-1 has 2^160 possible outputs. No accidental collision has ever occurred in any Git repository. The 2017 SHAttered attack demonstrated a deliberate collision, but it required massive computational resources.
How do I find a commit hash?
Run git log to see your commit history with hashes. Use git rev-parse HEAD for the current commit’s full hash. You can also browse commit history on GitHub, GitLab, or Bitbucket through their web interfaces.
What happens to a commit hash after a rebase?
Rebasing replays commits onto a new base, which generates entirely new hashes for every affected commit. The old commits become orphaned. This is why force pushing after a rebase can disrupt collaborators who pulled the original history.
Is a commit hash the same as a commit ID?
Yes. “Commit hash,” “commit SHA,” and “commit ID” all refer to the same thing. Different documentation and tools use different terms, but they all point to the same unique identifier that Git assigns to each commit.
Why is Git moving from SHA-1 to SHA-256?
SHA-1 has known cryptographic weaknesses. Researchers demonstrated practical collision attacks in 2017 and 2020. Git 3.0, expected in late 2026, will default to SHA-256, which produces 64-character hashes with much stronger collision resistance.
Can I use a commit hash to check out old code?
Yes. Running git checkout <hash> puts your working directory into a detached HEAD state at that exact commit. This lets you inspect, test, or build against any previous version without affecting your current branch.
Why do developers pin deployments to commit hashes?
Branch names and tags can move or be overwritten. A commit hash is immutable. Pinning Docker images, CI/CD builds, and deployment records to a specific hash guarantees you can always trace and reproduce exactly what was deployed.
Conclusion
A commit hash is more than a long string of characters in your terminal. It’s the mechanism that holds Git’s entire distributed version control model together, from data integrity verification to deployment traceability across CI/CD pipelines.
Whether you’re cherry-picking a fix across branches, pinning a Docker container to a specific build, or creating permanent links in GitHub, the hash is what makes it reliable. Branch names shift. Tags can be overwritten. The commit hash stays.
With the SHA-256 transition approaching in Git 3.0, those 40-character identifiers will eventually become 64. The concept stays the same. Your scripts and workflows might need updating, so start planning now.
Understanding how commit hashes work gives you better control over your repository history, cleaner collaboration with your team, and faster debugging when something goes wrong in production.
- How to Set Up Subscriptions on Google Play (Developer Guide) - July 12, 2026
- Why Work With a CMS Development Company for a Secure and Scalable Website? - July 12, 2026
- ADB Commands Cheat Sheet - July 11, 2026



