Northeastern University
.ipynb files clean, diffable, and reviewableA short tour of the options: strip outputs, strip metadata, or pair with a text file.
An .ipynb file is JSON that stores code, results, and metadata all together — and Git sees all of it. That causes four recurring problems.
Embedded plots and images are base64 blobs. Every rerun rewrites them, so the repository grows fast — and Git keeps every version forever.
Two people run the same notebook, and execution counts, outputs, and metadata all collide. Nothing about the code conflicted, but Git can’t tell.
Reviewers wade through thousands of lines of output JSON to find the few lines of code that actually changed.
A one-line code edit can show up as a 500-line diff once outputs and counters are regenerated.
Commit the parts that matter; drop or separate the parts that don’t. An .ipynb mixes three layers:
The options below differ only in how they separate these layers, and in what ends up in the commit.
Trade-off: rendered results no longer live in the repository, so you lose the at-a-glance view on GitHub.
In .pre-commit-config.yaml:
Or install it as a Git filter directly, with no pre-commit involved:
Tutorials and shared analyses are more useful when the rendered figures show up on GitHub. In that case, strip only the volatile bits.
What’s noisy: execution counts, kernelspec, language_version, widget state, signature, and editor metadata — all of which change constantly even when the code doesn’t.
Use nbstripout flags to keep outputs but drop counts and metadata, or set a Git filter via .gitattributes so it is transparent and repository-wide:
See the --keep-output and --keep-metadata-keys flags in the nbstripout docs.
.py (or .md) script, paired and kept in sync with the .ipynb..py file: clean line-by-line diffs, easy review, trivial merges..py reads as normal code with # %% cell markers, so black, ruff, and isort all work on it.Trade-off: outputs aren’t stored at all; collaborators regenerate them by running the notebook.
As a pre-commit hook:
| Approach | Outputs in repo? | Diff quality | Best when… |
|---|---|---|---|
| nbstripout (strip outputs) | No | Good | Code-focused projects; you just want the bloat gone |
| Strip metadata only | Yes | Better | Tutorials and shared analyses where rendered results matter |
| Jupytext pairing | No (commit .py) |
Best | Real code review, heavy collaboration, linting and CI |
They combine. A common setup is Jupytext to pair and sync, with nbstripout also in pre-commit. Pick per repository, not per career.
Pick one repository with notebooks and set up a pre-commit hook this week.
.pre-commit-config.yaml.nbstripout — instant relief from bloat and most merge conflicts, at near-zero effort.