5.3.4 · D5MLOps & Deployment
Question bank — Data versioning (DVC)
Every idea here rests on three plain-language pillars from the parent note, so let's re-anchor them in one breath before the traps:
True or false — justify
Content hashing means two identical files are stored twice if they have different names
False. The hash comes from the content, not the name — identical bytes give the same hash, so DVC stores them once and both pointers resolve to it (deduplication). This is Content-addressable storage at work.
dvc add uploads your data to the remote
False.
dvc add only moves the file into the local cache and writes a pointer. Nothing leaves your machine until dvc push.After git commit, a teammate who does git pull immediately has your 2 GB dataset
False.
git pull gives them the ~100-byte pointer only. They still need dvc pull to fetch the actual bytes from the remote.Changing one byte in a 2 GB file makes DVC store roughly one byte of new data
False. Default hashing is whole-file, so any change flips the hash and a full new 2 GB copy lands in cache. Version snapshots, not micro-edits.
git checkout <old-commit> alone restores both the old code and the old data
False. It restores code and the old pointer, but the working data file only changes after
dvc checkout reads that pointer and swaps in the matching cached bytes.DVC replaces Git
False. DVC layers on top of Git version control — Git still versions the code and the tiny pointers; DVC handles only the heavy bytes.
A .dvc pointer file is binary and should be git-ignored
False. The pointer is small human-readable YAML (hash + size + path). You want Git to track it; the
.gitignore ignores the real data file, not the pointer.If two commits reference the same data hash, the data is duplicated in cache
False. Same hash → same single cache entry. The cache is keyed by content, so shared data across commits costs storage once.
dvc repro re-runs every stage whenever you type it
False. It hashes each stage's
deps; if nothing changed it skips that stage, like make. Only stages with changed inputs re-run.Committing the .dvc/cache/ folder to Git is a good backup practice
False. That defeats the whole point — the cache holds the heavy bytes Git can't handle. The remote (
dvc push) is the backup; .dvc/cache/ is git-ignored.Spot the error
"I edited data.csv in place, committed, so the new version is versioned."
The error: DVC only re-hashes when told. Editing the file changed bytes but not the pointer, so the old hash is still recorded. Fix: run
dvc add data.csv (or dvc commit) to record the new hash before the git commit."Fresh clone: I ran dvc checkout but no data appeared — DVC is broken."
The error: a fresh clone has an empty cache, so
dvc checkout has nothing to copy from. Fix: dvc pull first to download bytes from the remote, then the pointer resolves."I git-added the real data.csv because it was 'only' 200 MB, plus its .dvc pointer."
The error: you've now committed the heavy file into
.git/ (defeating DVC) and kept a pointer. Every future edit stores another full copy in Git history. Fix: only git-add the pointer + .gitignore; let DVC hold the bytes."I deleted data.csv.dvc to clean up, the data is still in cache so I'm fine."
The error: the pointer is the only record of which hash belongs to this file in this commit. Without it, nothing knows to restore that cache entry — the data is orphaned. Never delete a committed pointer.
"I set up a remote, so dvc add now syncs to it automatically."
The error: adding a remote just registers a destination. Upload is still explicit via
dvc push. dvc add is a local operation only."My dvc.yaml stage lists outs: [model.pkl], so I should also git add model.pkl."
The error: DVC-tracked outputs are auto-git-ignored and versioned by their hash inside
dvc.lock. Git-adding the binary re-introduces the bloat problem. Track dvc.lock in Git, not the artifact.Why questions
Why hash the file's content instead of tracking a version number like v1, v2?
A version number is a promise a human must keep; a content hash is self-verifying. Any byte change flips the hash automatically, so tampered or edited data can never silently reuse an old version tag.
Why is restoring an old dataset two steps (git checkout then dvc checkout) instead of one?
Separation of concerns: Git moves the light pointer, DVC moves the heavy data. Keeping them separate lets Git stay tiny while the bytes live anywhere (S3, SSH, local), decoupling storage from hosting.
Why can DVC use "any" storage backend while Git LFS is tied to hosting quotas?
DVC treats the remote as a plain content-addressed key–value store — put bytes at their hash, get them back by hash. It needs nothing Git-specific, so any Object storage (S3/GCS) or SSH target works.
Why does reproducibility need both the code hash and the data hash in one commit?
A model is a function of code + data. Pin only code and the data may have drifted; pin only data and the script may differ. Binding both hashes in a single Git commit makes the pair restorable together. See Reproducibility in ML.
Why does DVC skip a pipeline stage whose deps are unchanged?
Because the output is a deterministic function of its inputs — if the input hashes match a previous run, the output would be identical. Re-running wastes compute; skipping is safe and make-like, powering MLOps pipelines.
Why pair DVC with something like MLflow rather than expecting DVC to log metrics?
DVC pins the inputs and artifacts (data, model files); MLflow records the results (metrics, params). Different jobs — one answers "what produced this?", the other "how good was it?".
Why is the .dvc pointer safe to commit even for a 2 GB dataset?
The pointer holds only the hash, size, and path — a fixed ~100 bytes regardless of file size. Git never sees the payload, so a 2 GB file and a 2 KB file produce equally tiny commits.
Edge cases
You run dvc add on a folder that is already tracked, unchanged. What happens?
DVC re-hashes, finds the same hash, and does nothing new — no cache growth, pointer unchanged. Idempotent by design because the content is identical.
Two teammates independently dvc add the exact same dataset file. Do you get two copies on the remote?
No. Both produce the same content hash, so after
dvc push the remote holds one object. Content addressing deduplicates across people automatically.You dvc push, then git commit the pointer fails/aborts. Is the remote now inconsistent?
The remote just gained a content-addressed object keyed by hash — harmless orphaned bytes, not corruption. Nothing points to it yet, and a future commit with that hash will reuse it. Push-before-commit is not dangerous, just slightly out of order.
A dataset file is empty (0 bytes). Can DVC still version it?
Yes. An empty file still has a well-defined content hash (the hash of "no bytes"). DVC stores a zero-byte cache entry and a normal pointer — degenerate but perfectly valid.
You clone the repo but the remote is offline. What can and can't you do?
You have all pointers and pipeline definitions (they're in Git), so you can inspect history and stages. But
dvc checkout/dvc pull fail for any data not already in your local cache — bytes are unreachable until the remote returns.A file's content changes but its size stays identical. Does DVC still detect a new version?
Yes. Detection is by hash, not size — size is stored only as metadata. Even a same-length edit produces a completely different hash, so the new version is recorded.
You delete an old commit's data from cache to save space. Is the old version lost?
Only locally. If you'd pushed it,
dvc pull from the remote restores it via the pointer's hash. If it was never pushed and you deleted it, that version is genuinely gone — pointer resolves to nothing.Recall One-line survival summary
Git moves the pointer; DVC moves the bytes. Every "it's broken" trap is really one of these two moving without the other. Commit binds a code hash to a data hash; push/pull ship the cargo the pointer names.
Connections
- Data versioning (DVC) — parent note; full derivation of the pointer/cache/remote model.
- Git version control — where the pointers live and the hashing idea is borrowed.
- Content-addressable storage — why identical content dedupes across people and commits.
- Object storage (S3/GCS) — the remote that holds pushed bytes.
- Reproducibility in ML — the code-hash + data-hash binding these traps protect.
- MLOps pipelines — where
dvc reproskip-logic matters. - Experiment tracking (MLflow) — the results-logging partner to DVC's input-pinning.