Contents/ Part XXV Β· Tools & Workflow/ Chapter 156

Reproducibility & Version Control

An analysis nobody can rerun is a story, not a result. This closing chapter of the toolkit is about making your work trustworthy: fixing randomness, pinning environments, versioning data, and above all tracking code with Git, so that you, or a stranger, can run it again and get the same answer. Five runnable notebooks, real Git included.

⏱️ ~38 min read
🐍 5 Notebooks included
πŸ“Š Chapter 156

Somewhere in your future is a moment of quiet panic: a result you produced months ago, a stakeholder asking how, and no way to rerun it. Reproducibility is the discipline that prevents that moment. It means anyone with your project can run it and get the same answer, and it rests on four things being captured: the code, the data, the randomness, and the environment. Get those under control and your analysis stops being a personal artifact and becomes something the world can check, which is what turns a claim into evidence.

πŸ”
Reproducibility is the ability to obtain the same result from the same inputs. Version control (chiefly Git) records the full history of your code as commits you can inspect, revert, and share, and it is the backbone of a reproducible, collaborative workflow.
🧰
Five runnable notebooks, real Git

This is a doing skill, so the chapter is a five-notebook mini-course: reproducibility (seeds, environments, data hashes), project structure, Git basics, Git branching and merging, and end-to-end experiment tracking. The Git notebooks run real git commands against a throwaway repository created just for the demo, so you watch an actual commit history and a real merge conflict form and resolve, with nothing installed and nothing of yours touched.

1

The Four Pillars of a Reproducible Result

“It works on my machine” is the enemy. A result reproduces only when four separate things are the same as when it was first produced. Miss any one and the answer can quietly change.

Four things must match for a result to reproduce CODEthe codeversion control (Git) DATAthe inputsa content hash RANDOMNESSthe chancea fixed seed ENVIRONMENTthe librariespinned deps the same answer every run, every machine the test of reproducibility: would a stranger, given only your project, get this exact result?
Code, data, randomness, and environment. Version control handles the first, a hash pins the second, a seed pins the third, and a pinned requirements file pins the fourth. This chapter covers all four, and the notebooks make each one concrete.

Three of the four are quick habits. Set a seed (np.random.default_rng(42)) and random operations repeat exactly. Pin the environment by listing every package at an exact version in a requirements.txt, ideally inside a per-project virtual environment. And hash the data, a short fingerprint of its exact contents, so you can prove later whether it changed. The fourth pillar, versioning the code, is big enough to be the rest of this chapter.

2

Git: A History You Can Trust

Git is a version control system: it records your project as a sequence of snapshots called commits, each with a message, an author, and a timestamp. It answers what changed, when, why, and by whom, lets you return to any past state, and makes experimentation safe because nothing is ever truly lost.

The everyday loop is three steps. You edit files in your working folder. You stage the changes you want to record with git add, choosing what goes in. And you commit them with git commit, saving a snapshot with a message. That is 90 percent of Git.

Edit, add, commit: the everyday loop working directoryyour edited files staging areachanges you chose to record repositorythe permanent history git add git commit history: InitialAdd meanRound itHEAD every dot is a full, recoverable snapshot you can inspect, compare, or return to
Staging is Git's superpower: you decide exactly what each commit contains, so history reads as a series of deliberate, meaningful changes. git status, git diff, and git log let you see it all.

A companion habit lives here too: the .gitignore file, a list of things Git should never track. Large data files, generated outputs, and above all secrets like API keys and passwords belong out of version control. Notebook 3 shows a .gitignore making a committed secret and a data folder vanish from Git's view, which is a mistake you very much want to prevent, not fix.

3

Branching, Merging, and Working Together

A branch is a parallel line of work. You branch off main to try an idea, commit freely without risking the stable version, and when it is ready you merge it back. This is how one person experiments safely and how a whole team builds in parallel without overwriting each other.

a branch, merged back into main
git switch -c add-feature     # branch off and move onto it
git commit -am "Add region feature"
git switch main
git merge --no-ff add-feature   # bring the finished work back
Branch off, work safely, merge back main add-feature baseline main work merge feature commit the feature branch never disturbs main until it is finished and merged back in
The stable main line keeps working while an idea grows on its own branch. When the branch is ready it rejoins main at a merge commit, and the graph permanently records that the branch happened.

Sometimes two branches change the same line differently, and Git cannot know which is right. It stops and marks the spot, a merge conflict. This is not an error but a request for a human decision: Git kept both versions safe and is asking you to choose. You edit the file to the version you want, remove Git's marker lines, and commit the resolution. Notebook 4 creates a real conflict over a threshold value and walks the resolution end to end, finishing with the branching commit graph.

CommandWhat it does
git switch -c nameCreate a branch and move onto it, to work without touching main.
git merge nameBring a branch's finished commits into the current branch.
git log --graphDraw the history, branches and merges included, as a graph.
git clone / push / pullCopy, upload, and download a repository shared on a host like GitHub.

Scale this branch-commit-merge cycle across a team on a shared host, GitHub, GitLab, or Bitbucket, and you have how essentially all modern software and data science is built. A pull request proposes a branch's changes for review before they merge, adding a human check to the version history.

4

Everyday Version Control at the Command Line

Editors and desktop apps put a friendly face on Git, but underneath, and for most developers and statisticians day to day, version control lives in the command line. The terminal is universal (the same commands work on every machine and every host), scriptable (you can automate it), and it is where every tutorial, error message, and teammate's instructions are written. A handful of commands cover almost everything you will ever do.

Here is the whole everyday rhythm of working with a shared repository, from getting a copy to sending your work back, as it actually looks in a terminal.

a normal day with a shared repository
# get your own copy of a project that lives on GitHub
$ git clone https://github.com/acme/sales-analysis.git
$ cd sales-analysis

# before starting work, pull the latest changes teammates have pushed
$ git pull

# make a branch for your task, so main stays stable
$ git switch -c add-region-breakdown

# ...edit analysis.py, add a chart... then see what changed
$ git status
  modified:   analysis.py
$ git diff                          # review the exact line changes

# stage, commit with a clear message, and push the branch to GitHub
$ git add -A
$ git commit -m "Add revenue breakdown by region"
$ git push -u origin add-region-breakdown

# open a pull request on GitHub, get review, then it merges into main

That is the loop nearly everyone repeats many times a day: pull, branch, edit, add, commit, push, open a pull request. The one golden habit inside it is pull before you push, so you build on your teammates' latest work and avoid surprise conflicts. When a conflict does happen, it is the same event from the branching section, resolved the same way.

CommandWhat it does
git clone <url>Copy a remote repository to your machine, ready to work on.
git initStart version control in a new, local folder (then add a remote to share it).
git status / git diffSee what has changed since the last commit, by file and by line.
git add / git commitStage changes, then save them as a snapshot with a message.
git pull / git pushDownload teammates' commits; upload yours to the shared host.
git switch / git mergeMove between branches; bring a finished branch's work back in.
git remote -v / git logList the shared hosts this repo talks to; read its history.

A developer runs these dozens of times a day almost without thinking. A statistician or data scientist uses the very same commands to version analysis scripts, notebooks, and reports, and to sync a project with collaborators through a shared remote. Learn these ten and you are fluent in the language every team, tool, and tutorial speaks.

5

Automating the Flow: CI/CD

Once your code lives in a shared repository, you can make a robot watch it. Continuous Integration (CI) means that every push automatically triggers a fresh build and a run of your tests, in a clean environment, so a broken change is caught in minutes rather than discovered in production. Continuous Delivery / Deployment (CD) goes one step further: when the tests pass, the result is automatically packaged and released, or even deployed live.

For this book the connection is direct. CI is reproducibility enforced by machine. The pipeline checks out your exact commit, rebuilds the pinned environment, reruns the analysis from scratch, and fails loudly if a number moves or a test breaks. If it cannot reproduce your result on a clean server, neither can anyone else.

Push once; the pipeline does the rest git pusha new commit buildpin the environment testrerun the analysis pass?the gate deploy / releaseship it automatically stop & alertnothing ships yes no every push is rebuilt and retested from scratch, so a result that cannot be reproduced never ships
A CI/CD pipeline is a script that runs on every push. It rebuilds the environment, reruns the tests, and only releases when they pass. The same idea powers the automated retraining pipelines of the MLOps chapter.

The pipeline itself is just a file in your repository, so it is versioned like everything else. Here is a minimal GitHub Actions workflow that, on every push, sets up Python, installs the pinned dependencies, and runs the test suite.

.github/workflows/ci.yml
name: tests
on: [push]                       # run on every push
jobs:
  test:
    runs-on: ubuntu-latest          # a fresh, clean machine each time
    steps:
      - uses: actions/checkout@v4    # get the exact commit
      - run: pip install -r requirements.txt   # rebuild the pinned environment
      - run: pytest                   # rerun the tests; fail loudly if anything broke
ToolWhat it is, and where you meet it
JenkinsThe long-established, self-hosted automation server; highly customizable through plugins, common in enterprises.
GitHub ActionsCI/CD built into GitHub, configured with a YAML file in the repo. The most common choice for open-source and new projects.
GitLab CI/CDThe same, native to GitLab, driven by a .gitlab-ci.yml file.
CircleCI / Travis CIPopular hosted CI services that connect to your repository.
Azure PipelinesMicrosoft's CI/CD in Azure DevOps, widely used in enterprise and .NET shops.

Data scientists lean on the same machinery: a pipeline can rerun a notebook end to end, validate that a model still clears an accuracy bar, regenerate a report, or trigger a retraining job. It is the automated backbone of the reproducible, monitored workflow the MLOps chapter describes.

6

Git Everywhere: Version Control in Your Tools

You rarely have to leave your editor to use Git, because version control is now built into nearly every serious development and analysis tool. The commands underneath are identical; the difference is a graphical front door, staging changes with a checkbox, seeing a colored diff in the margin, committing from a panel, and resolving a conflict in a visual three-way view.

Tool or platformHow Git shows up in it
VS CodeA built-in Source Control panel for staging, committing, branching, and pushing; the popular GitLens extension adds inline blame and rich history.
Visual StudioFull Git integration in the IDE: clone, branch, commit, and manage pull requests to GitHub or Azure DevOps without a terminal.
RStudio / PositA Git pane for staging and committing, and project-level integration with GitHub, the standard way R users version their analyses.
JupyterLabThe jupyterlab-git extension adds a Git panel and diff viewer for notebooks right in the browser.
SASSAS Studio, Enterprise Guide, and SAS Viya include built-in Git integration, so even a menu-driven analyst can clone, commit, and push program versions.
JetBrains (PyCharm, etc.)Deep, first-class version control with a visual merge tool and change lists across the whole IDE.
Desktop clientsGitHub Desktop, GitKraken, Sourcetree: standalone graphical apps for people who prefer buttons to the terminal.

The lesson is that Git is the shared plumbing beneath a dozen different front doors. A developer might commit from the VS Code sidebar, a statistician from the RStudio or SAS Studio Git pane, and a data engineer from the terminal, and they all push to the same GitHub repository and see the same history. That commercial statistical platforms like SAS now build in Git is the clearest sign of how universal version control has become: it is no longer a programmer's tool, but everyone's.

🐍

The Five-Notebook Mini-Course

Work through these in order. The Git notebooks run real commands against a disposable repository, so you see an actual history, branch, and conflict, not a description of one.

Notebook 1

Reproducibility

The other three pillars: seeds for repeatable randomness, an environment report and requirements.txt, and a data hash that detects a single changed value.

Notebook 2

Project Structure

Scaffold a standard project (data / src / notebooks / outputs), separate config from code, use relative paths, and run a pipeline that reproduces its output byte for byte.

Notebook 3

Git Basics

Real git: init, add, commit, then status, diff, and log on a growing history, plus a .gitignore that hides a secret and a data folder from version control.

Notebook 4

Branching & Merging

Branch off, commit, and merge back with a real merge commit, then create a genuine merge conflict over a threshold and resolve it, ending on the commit graph.

Notebook 5

Experiment Tracking

Read a run log, prove which runs are reproducible by grouping on code, data, and seed, catch the unseeded run that is not, and chart accuracy across runs.

Solutions

Challenge Solutions

Worked answers to the five practice challenges below, from proving determinism through auditing a run for reproducibility.

Real dataset

An experiment-tracking log, 20 model runs. Each row records what a reproducible result needs: the code version (git_commit), the input fingerprint (data_hash), the random seed, the environment (python_version, sklearn_version), and the accuracy produced. Notebook 5 uses it to prove the point: runs that share code, data, and seed give identical accuracy (runs 1 and 2 both score 0.8793), while the single run that set no seed drifts off on its own, the classic reproducibility bug, found in one line.

Notebooks run on pandas, numpy, matplotlib, and the built-in subprocess plus a real git (preinstalled on Colab).

7

Reproducibility in Data Science, ML & AI

In machine learning the stakes are higher, because a model has more moving parts to pin: not just code and data but the exact split, the hyperparameters, the framework versions, and every seed. The field has built dedicated tools for it, and they are all doing, at scale, what the notebooks here do by hand.

Tool or practiceWhat it versions, and where you meet it
Git + GitHubThe code and its history, plus collaboration through branches and pull requests. The universal base layer.
Experiment trackersMLflow, Weights & Biases: log every run's parameters, metrics, and artifacts automatically, the run log of Notebook 5, industrialized.
Data & model versioningDVC, model registries: version large datasets and trained models alongside the code that made them.
Environment capturerequirements.txt, conda, and Docker containers that freeze the entire software stack, not just Python packages.
Pipelines & CIAutomated, version-controlled pipelines (the MLOps chapter) that rerun the whole analysis on a trigger and fail loudly if a result changes.
Research note

This is not housekeeping; it is a scientific crisis. A widely discussed 2016 Nature survey found that most researchers had failed to reproduce someone else's results, and many had failed to reproduce their own. In computational fields the fix is unusually tractable, because a result is its code, data, seed, and environment, and all four can be captured and shared. That is why version control and reproducible pipelines have moved from nice-to-have to the baseline of credible quantitative work. A result no one can rerun is, increasingly, not accepted as a result at all.

πŸŽ“ Key Takeaways

  • βœ“Reproducibility rests on four pillars: versioned code, versioned data, a fixed random seed, and a pinned environment. Miss one and the answer can silently change.
  • βœ“Three are quick habits: seed your randomness, pin dependencies in a requirements.txt inside a virtual environment, and hash your data to detect changes.
  • βœ“Git versions the code: the loop is edit, add, commit, building a trustworthy history you inspect with status, diff, and log.
  • βœ“A .gitignore keeps the wrong things out: big data, generated outputs, and secrets like API keys must never be committed.
  • βœ“Branches make work safe: experiment on a branch, merge it back, and treat a merge conflict as a request for your decision, not an error.
  • βœ“The everyday loop lives at the command line: pull, branch, edit, add, commit, push, open a pull request; and always pull before you push to avoid surprise conflicts.
  • βœ“CI/CD automates reproducibility: every push triggers a fresh build, rerun, and test (Jenkins, GitHub Actions, GitLab CI), and only releases when it passes, so a result that cannot be reproduced never ships.
  • βœ“Git is built into your tools: VS Code, RStudio, JupyterLab, JetBrains, and even SAS Studio put a graphical front door on the same commands, all pushing to the same shared history.
  • βœ“An experiment log makes reproducibility checkable: record code, data, seed, and environment per run, and identical inputs provably give identical results.
  • βœ“ML scales this up with MLflow, DVC, and Docker, but they only automate the same four pillars. A result no one can rerun is not really a result.
8

Practice Challenges

Five exercises, one per notebook area. Full solutions are in the companion solutions notebook.

1

Prove determinism

Write a seeded random summary and show two calls with the same seed match, while two unseeded calls differ.

Hint: np.random.default_rng(seed), then compare the results.
2

Detect a changed dataset

Hash a dataframe, change one value, and confirm the hash changes.

Hint: hashlib.sha256(df.to_csv(index=False).encode()).
3

Scaffold a project

Create the standard folders and a .gitignore that excludes data and outputs.

Hint: Path.mkdir for folders, then write the ignore patterns.
4

Build a commit history

Initialize a repository and make three commits, then print the one-line log.

Hint: loop over three messages, doing add then commit each time.
5

Audit a run

Given a run record, report whether all four pillars (code, data, seed, environment) are present.

Hint: check each field is not missing, and list any that are.
πŸ““

Solutions notebook

All five challenges worked in code: a determinism proof, a data-hash change detector, a project scaffold with a .gitignore, a real three-commit git history, and a four-pillar reproducibility audit.

πŸ““ View Solutions β–Ά Open in Colab ⬇ GitHub
9

Quiz: Test Yourself

Eight questions on the four pillars, Git basics, branching, and experiment tracking. Answer them, hit Check Answers, and keep refining until you score 100%. Your progress is saved.

🧰
That completes Tools & Workflow

This part turned the statistics of the book into a working practice. Python for Data Analysis and R for Statistics gave you the two great open-source languages; Statistical Software read the output of the commercial packages; SQL & Databases got the data out at the source; Excel & BI Tools covered the spreadsheet and the dashboard; and this chapter made the whole workflow reproducible and version-controlled. Next, the Communicating Results & Data Ethics part turns from producing analysis to sharing it responsibly. Browse the full Contents for what is published and what is on the way.