What Is Data Versioning and How Content Hashing Tracks Dataset Changes Like Git

ELI5
Data versioning records every change to a dataset by fingerprinting its contents with a hash, the way Git tracks code. The data itself stays in cheap storage; only a tiny pointer to that fingerprint lives in your repository.
Two engineers run the same training script on the same dataset and get models that disagree. Nobody touched the code. The dataset is the suspect: a few hundred rows were relabeled last Tuesday, and the folder name never changed to announce it.
Filenames lie. Contents don’t.
That single asymmetry is the entire foundation of data versioning, and it is borrowed almost wholesale from the tool sitting in every developer’s terminal.
The Address Is the Content
Git never trusted filenames. When you commit, Git computes a hash of the bytes themselves and uses that hash as the object’s address. Rename the file, move it to another directory, copy it three times — the address is unchanged, because the content is unchanged. This is Content Addressable Storage, and it is the mechanism every data versioning tool quietly imports.
What is data versioning in machine learning?
Data versioning is the practice of recording the exact state of a dataset every time it is used, so any model can be traced back to the precise bytes that produced it. It is an MLOps discipline built for Reproducibility and Data Provenance: not “which folder did the training read,” but “which exact arrangement of rows, labels, and pixels existed at that moment.”
Not a backup. An identity system.
A backup answers “can I restore yesterday’s file.” Versioning answers a sharper question: “are these two datasets the same, and if not, where exactly do they differ.” The mechanism that answers it is the hash. Under the hood, Git stores four object types — a blob holding raw file bytes, a tree describing a directory listing, a commit wrapping a snapshot with metadata, and a tag naming a pointer, according to Git Docs. Each one is addressed by a hash of its own content. Git’s default algorithm is SHA-1, with SHA-256 added in Git 2.29 back in 2020, a transition that is still rolling out gradually across the ecosystem (Git Docs). The algorithm matters less than the rule it enforces: the content is the address.
Is data versioning the same as git for datasets?
Almost — and the gap is the whole story.
Git was built to store everything inside the repository. Every byte of every version of every file lives in .git. That is a gift when your files are source code measured in kilobytes, because the full history fits comfortably and diffs are cheap. Point the same machinery at a 50 GB image corpus and it inverts into a liability: cloning drags the entire binary history across the network, line-based diffs are meaningless on compressed blobs, and the repository swells past the point of usefulness.
So data versioning tools keep the Git idea and discard the Git storage model. They keep content addressing — fingerprint the bytes, identify by hash. They throw out the assumption that the bytes must live inside the repo. The data moves elsewhere; only its fingerprint travels with your code.
Like Git, with one clause of the contract rewritten.
The Pointer That Stands In for a Terabyte
Once you accept that the data lives outside the repository, you need something to stand in its place — a stub that says “the real thing is over there, and here is its fingerprint so you know exactly which version ’there’ refers to.” Every tool in this space implements that stub differently, but the shape is identical.
How does data versioning work?
The shared trick is substitution: replace the heavy data with a light pointer. The pointer is a small text file recording three things — the content hash, the byte size, and where the real data lives. That pointer is what Git commits, so your repository stays small and diffable while still pinning an exact dataset version.
The round trip is the elegant part. When you check out an old commit, the tool reads the pointer, looks the hash up in a local cache or a remote store, and materializes the exact bytes that hash describes. Change one row and the content hash changes; a new pointer is written; the old version remains addressable forever, because nothing was overwritten — a new object was simply added. This is the same immutability that makes Git history trustworthy, applied to data.
The table formats live here too. Delta Lake, currently on version 4.1.0, and Apache Iceberg, at 1.10.1, apply the same content-addressed, immutable-snapshot logic at the table level: every write produces new data files plus a new manifest, and the previous snapshot stays queryable. You version a billion-row table the way you version a commit — by pointing at an immutable snapshot, not by copying it.
Where the Bytes Actually Live
Three tools mark three points on a spectrum, from “lightweight pointer for one dataset” to “version control over an entire object store.” They share the principle and disagree on almost everything else, including the hash algorithm each one uses.
How does DVC version large datasets without storing them in git?
DVC’s answer is the pointer file taken to its logical conclusion. Run dvc add on a dataset and DVC writes a small text file — <file>.dvc — holding the path, the size, and an MD5 hash of the content (DVC Docs). The dataset itself is moved into a local cache, content-addressed by that MD5 at .dvc/cache/files/md5/<first-two-hex>/<remaining-thirty-hex>, and pushed to a remote you control. Only the tiny .dvc pointer is committed to Git. Your repository now references a precise dataset version without ever holding its bytes.
As of mid-2026 DVC sits at version 3.67.1 (DVC on PyPI), and its stewardship recently changed hands: lakeFS, the data-versioning platform built by Treeverse, acquired the project from Iterative in November 2025, and DVC stays fully open source under the same license, with the canonical repository now living under the Treeverse organization (DVC Blog). The mechanism did not change — the maintainer did.
One detail worth holding onto: DVC fingerprints with MD5 while Git uses SHA-1. Different algorithm, identical principle — the hash is the identity.
The other two tools widen the lens. lakeFS operates over object storage directly — S3, Azure Blob, or GCS — and versions the entire bucket rather than individual files. Its branches are zero-copy: creating one writes a metadata pointer instead of duplicating the data, so branching a petabyte costs roughly the same as branching a megabyte (lakeFS Docs). Commits are immutable snapshots, merges are atomic, and the version metadata is stored as sorted structures rather than inside Git at all. It is Apache 2.0 licensed, with the core server on the v1.82.x line.
Git LFS sits at the naive end. It swaps each large file for a text pointer carrying a SHA-256 object id and a byte size, parks the real bytes on an LFS server, and swaps them back in transparently through Git’s clean and smudge filters during checkout (Git LFS). It solves the “Git chokes on big binaries” problem, but it still chains every dataset version to Git history rather than treating data as its own first-class timeline.
Three tools, three hash algorithms — SHA-1, MD5, SHA-256 — one shared idea.

Stewardship & integrity notes:
- DVC ownership: DVC is now maintained by lakeFS/Treeverse, not Iterative (acquired November 2025). The canonical repository moved under the Treeverse organization; older
iterative/dvcreferences are stale. Still Apache-2.0, no paywall.- Git LFS: the latest 3.7.1 release ships a security update and is recommended for all users.
- Hashing is not tamper-proofing: Git’s SHA-1 and DVC’s MD5 both have published collision attacks. Treat content hashes as change-detection and addressing, not a cryptographic guarantee that data was not maliciously altered.
What the Fingerprint Buys You, and What It Doesn’t
Content addressing is not a feature you switch on; it is a set of consequences you inherit. Once a dataset’s identity is its hash, certain things become free and certain things become impossible.
- If you change a single label in a million-row dataset, expect an entirely new hash and a new version. Content addressing has no notion of “a small edit” — every change is total, which is precisely why it is trustworthy.
- If two datasets share a hash, they are byte-identical. You can skip recomputation, deduplicate storage, and prove that a benchmark ran on the same data as last quarter without comparing a single row by hand.
- If a model’s accuracy slips in production, a versioned dataset lets you diff the training snapshot against current data and locate the Data Drift instead of guessing which input shifted.
- If a Data Leakage or Target Leakage bug surfaces, you can walk the commit history to the exact version where contaminated rows entered, rather than auditing the entire pipeline. The same trace exposes Dataset Bias introduced during a relabeling pass that nobody documented.
Rule of thumb: commit the pointer to Git, store the bytes in a content-addressed cache or remote, and never let a dataset’s identity depend on its filename.
When it breaks: content hashes detect that data changed, not why or whether the change was intentional — a one-row correction and a malicious swap both register as nothing more than “a new version.” Because MD5 and SHA-1 carry known collision attacks, the hash is a change-detector, not a tamper-proof seal. And if your remote storage is mutable, the bytes behind a pointer can drift while the recorded hash stays the same, silently voiding the guarantee the whole system depends on.
The Data Says
Data versioning is content addressing applied to datasets: identify by the hash of the bytes, version the pointer, leave the bytes in cheap storage. It borrows Git’s immutability and discards Git’s habit of swallowing every byte, which is exactly why DVC, lakeFS, and Git LFS can version terabytes that Git alone would choke on. The fingerprint tells you that two datasets differ; closing the loop from “differ” to “trustworthy and explained” is still the engineer’s job.
AI-assisted content, human-reviewed. Images AI-generated. Editorial Standards · Our Editors