Tie it together: a DVC pipeline defines stages with their data, code, and outputs, so a single command reproduces everything — and only re-runs what actually changed.
Why: full reproducibility needs three things pinned together — the data version (DVC), the code version (Git), and the parameters (logged to MLflow) — so anyone can recreate a result exactly. When: capture all three on every run; missing any one breaks reproducibility. Where: a DVC pipeline wires data and code into named stages, while MLflow records the run.
REPRODUCIBLE RUN = pinned DATA + pinned CODE + pinned PARAMS
DVC -> data version (dataset hash) + pipeline stages
Git -> code version (commit SHA)
MLflow -> params, metrics, and the resulting model
Record all three and any run recreates exactly. Miss one and it won't.Why: a DVC pipeline (dvc.yaml) declares each stage’s command, its dependencies (data + code), and its outputs — turning an ad-hoc script into a tracked DAG. When: define stages for prepare → train → evaluate so the whole flow is one reproducible unit. Where: DVC hashes the dependencies, so it knows exactly what changed.
# Add a stage: name, dependencies (-d), outputs (-o), and the command.
dvc stage add -n prepare \
-d src/prepare.py -d data/raw.csv \
-o data/prepared.csv \
python src/prepare.py
dvc stage add -n train \
-d src/train.py -d data/prepared.csv \
-o models/model.pkl \
python src/train.py
# This writes dvc.yaml — commit it to git.Why: dvc repro runs the pipeline but only re-executes stages whose data or code actually changed — so re-running is cheap and deterministic, the same idea as build caching. When: run it after any change; unchanged upstream stages are skipped. Where: this is what makes iterating on a large pipeline fast and reproducible at once.
dvc repro # runs only the stages whose deps changed; skips the rest
# Changed only train.py? prepare is skipped, train + downstream re-run.
git add dvc.yaml dvc.lock && git commit -m "Update training stage"
dvc push # push the new data/model outputs to the remote
# dvc.lock records the exact hashes -> the run is fully reproducible.