Honglin Li
  • Research
  • Projects
  • Publications
  • Software
  • Teaching
  • Learn
  • Notes
  • CV
  • Journeys

Git and reproducible notebooks

Commit, compare and rewind a small model project, then make its notebook rerun cleanly

Math toolbox K8 of Energy Systems, Step by Step: in a simulated model project built on Prairie Town’s real day, run git status, diff, add and commit, try a what-if on a branch, find the commit that broke a result by halving the history, catch a notebook’s hidden state, and rerun the project from a clean clone.
  1. Learn
  2. K8
  • Math toolbox
  • 20 min guided · about 30 min practice
  • No prerequisites
  • Completed
  1. 1Step by step
  2. 2Explain
  3. 3Check
  4. 4Sources

A small model project's history, in nine steps

The project computes the electricity Prairie Town's gas plants make in one day, 1,965 MWh: what demand leaves after wind, solar and a 100 MW plant that runs flat. At $40/MWh it costs $78,600; a balance check asserts that supply equals demand.

A commit records the staged versions of the project's tracked files, with a message and a link to the commit before it.

Step Command What it shows
1 git log --oneline Three commits, newest first: 7a83e3d Read the gas cost and flat output from params.yml; 7ab11e0 Add a README: how to run, expected numbers; 10f1f7e Add Prairie Town's day and the gas model.
2 git status, git diff After gas_cost 40 → 55 in params.yml: one modified file, the line “−gas_cost: 40” and “+gas_cost: 55”; the day's cost goes from $78,600 to $108,075.
3 git switch -c high-gas, git add params.yml, git commit -m A new branch, the change staged, then recorded as a commit on high-gas only.
4 git switch main params.yml says 40 again and the result is $78,600; git switch high-gas brings back 55.
5 git pull, then git switch --detach <id> and python check.py A teammate's three commits arrive; the balance check fails by 2,822 MWh. Halving the history (once a commit fails, every later one fails too): commit 3 passes, commit 4 fails, so commit 4 (2b77767) is the first bad one, found in 2 checks.
6 git diff 7a83e3d 2b77767, git revert 2b77767 The line became −(wind − solar): solar is added, not subtracted, so gas is 4,787 MWh instead of 1,965 (2 × 1,411 MWh too much). The revert commit brings back 1,965 MWh.
7 a notebook: edit cell 2, run only cell 4 Cell 4 still shows 78600 (memory holds gas_cost = 40) under a cell that says 55; Restart and run all gives 108075.
8 five fixes Before sharing: exact versions (pandas==2.2.3, an illustrative version); a path inside the project; the raw data's source, download date and checksum; a fixed random seed; .env, data/raw/ and charts in .gitignore before anything is staged.
9 git clone, pip install -r requirements.txt, jupyter nbconvert --to notebook --execute day.ipynb The fresh copy has no .env and no raw data. Its notebook runs top to bottom: cell 3 gives 1,965 MWh, cell 4 shows 78600 (dollars), and cell 6's balance assert prints “balance OK”, as the README says.
Commit Message Gas, MWh Balance check
1 · 10f1f7e Add Prairie Town's day and the gas model 1,965 passes
2 · 7ab11e0 Add a README: how to run, expected numbers 1,965 passes
3 · 7a83e3d Read the gas cost and flat output from params.yml 1,965 passes
4 · 2b77767 Tidy the model: net demand in one line 4,787 fails by 2,822 MWh
5 · 10aa115 Add a chart of the gas hours 4,787 fails by 2,822 MWh
6 · f304d5b README: how to make the chart 4,787 fails by 2,822 MWh

With JavaScript on, you run each command yourself in a simulated project.

  • Source: demand, wind and solar follow the real hourly shapes of 3 September 2025 on the Southwest Power Pool grid (EIA-930), scaled as in lesson 0.
  • Illustrative: the 100 MW plant that runs flat all day and the $40/MWh gas cost, as in K7.
  • The project, its files, its messages and the teammate are illustrative. Nothing on this page creates or touches a real repository; commands are shown as text.
  • Commit ids here are 7-character fingerprints this page computes. Git's own ids are 40-character SHA-1 hashes. The version numbers in requirements.txt (pandas==2.2.3 and the others) are illustrative: they show what an exact pin looks like and are not a recommendation.

What you just did, as diagrams

Commit
The unit of version control: the staged versions of the tracked files, with a message, a parent and an id; git add picks what goes in, git commit records it.
Three places
A change sits in the working folder, then the staging area, then the history.
Branch
A movable label on a line of commits: a what-if lives on its own branch while main stays as it was.
Halving the history
With one good and one bad commit, check the middle each time: 1,000 commits need at most 10 checks, if every commit after the first bad one also fails.
Hidden state
A notebook's memory can be older than its code; only Restart and run all shows the outputs come from the cells as written.
Clean rerun
A fresh clone and a pinned install give the same numbers: the code and inputs reproduce the result, which is not the same as the result being right.
Go deeper · AnalystWhat a commit stores, and why its id changes
  • A snapshot, not a list of edits. A commit stores every tracked file as staged, plus the author, the time, the message and its parent’s id. Untracked files and unstaged edits are not in it; unchanged files are shared with the parent.

  • The id is a fingerprint. Git computes it with SHA-1 over all of that (a SHA-256 format also exists). Change one byte, the message or the parent, and the id changes.

  • Branches are labels. main and high-gas each point at one commit; a new commit moves the current label forward. Creating a branch copies no files.

  • Merging. git merge high-gas joins two lines of work:

    Before the merge What Git does
    main has not moved moves main’s label forward (a fast-forward)
    both lines changed combines them line by line
    both edited the same lines stops with a conflict for you to resolve

    This page’s simulation compares whole files, not lines.

Go deeper · ModelerMake reruns automatic
  • Tests that run themselves. Keep the asserts (the balance, totals, a known case) in test files and run them on every commit, on your computer or on a hosted service that runs them for each push.
  • Notebooks without hidden state. Execute them from a fresh kernel without a browser (jupyter nbconvert --to notebook --execute day.ipynb), or keep the model in .py files and let the notebook call and plot.
  • Exact environments. A lock file records the exact version of every package, including the ones your packages depend on.
  • Tag the result. git tag v1.0 marks the commit behind a published number, so anyone can return to it.
  • Where next: M1’s notebook asserts the browser’s prices; R5 puts a whole model through planted bugs, a benchmark and a clean-clone rerun.

Check yourself

Myth or fact? “Saving a file in the editor records it in Git's history.”

  • Myth
  • Fact
Answer

Myth. Saving changes the working folder only; git add and then git commit record a snapshot.

Myth or fact? “If every cell of a notebook ran without an error, its outputs match the code on the page.”

  • Myth
  • Fact
Answer

Myth. In step 7, cell 4 showed 78600 under a cell that says 55, with no error; only Restart and run all shows the outputs come from the cells as written.

Myth or fact? “If a fresh clone reruns and gives the same numbers, the model's answer is right.”

  • Myth
  • Fact
Answer

Myth. Commit 4's sign error reran just as cleanly and gave 4,787 MWh every time; a check such as the balance assert is what catches an error like that.

You edit model.py, run git add model.py, then edit model.py again. What does git commit record?

  • Both edits
  • Only the first edit
  • Only the second edit
  • Nothing
Answer

Only the first edit: git add staged that version. The second edit waits in the working folder until you add it too.

Commit 1 of 9 passes the balance check and commit 9 fails it; once the bug appears, every later commit fails. Checking the middle each time, at most how many commits must you check?

  • 2
  • 3
  • 4
  • 8
Answer

3: eight suspects (commits 2 to 9), halved three times, leave one. Checking one by one can take 7.

Practice drill

With JavaScript on, a drill of seven kinds of item, about two minutes each (fifteen items take about 30 minutes). Three worked items:

  1. A commit's diff shows “- gas_cost: 40” and “+ gas_cost: 30” in params.yml. The model makes 1,965 MWh of electricity from gas. What is the day's gas cost after this commit, in $?

    Answer: $58,950.

    Why: 1,965 MWh × $30/MWh = $58,950 (it was $78,600).

  2. Commit 1 of 64 passes the check; commit 64 fails it, and once the bug appears every later commit fails. Checking the middle commit each time, at most how many commits must you check to find the first bad one?

    Answer: 6.

    Why: 63 suspects; each check halves them: 2^6 = 64 ≥ 63 > 2^5 = 32, so 6 checks.

  3. Fresh kernel. Cells: (1) load the day, (2) gas_cost = 40, (3) gas_mwh = … (1,965), (4) gas_mwh * gas_cost. You: run cell 3, run cell 1, run cell 2, run cell 4. What does cell 4 show?

    Answer: an error: a name is not defined.

    Why: NameError: name 'gas_mwh' is not defined: a cell it needs has not run yet.

Commands, sources and what’s next

Commands to remember

Command What it does
git status Lists staged, edited and new files.
git diff Shows edited lines not yet staged; git diff <id> <id> compares two commits.
git add <file> Stages a file's current version for the next commit.
git commit -m "why" Records the staged snapshot with a message.
git log --oneline The history, one commit per line, newest first.
git switch -c <name> Starts a branch here; git switch <name> moves between branches.
git restore <file> Throws away a file's edits since it was last staged.
git revert <id> Adds a commit that undoes an earlier one.
git clone <source> Makes a fresh copy of a project with its whole history.

Next

M1 · From dispatch to locational prices: the linear program behind the market

Sources and further reading

  • Wilson, G., et al. (2017). Good enough practices in scientific computing. PLOS Computational Biology 13(6): e1005510.
  • Rule, A., et al. (2019). Ten simple rules for writing and sharing computational analyses in Jupyter Notebooks. PLOS Computational Biology 15(7): e1007007.
  • Chacon, S. and Straub, B. (2014). Pro Git, 2nd edition. Apress. Free to read online from the Git project; chapter 10 explains what a commit stores.
  • EIA. Hourly Electric Grid Monitor (Form EIA-930): the Southwest Power Pool data behind Prairie Town's day, 2025.
  • Bridge B2, Python and data, is the first notebook; M1's notebook asserts the browser's prices. Researcher lesson R5 is on verification and reproducibility.

Spotted an error, or stuck? Write to hlli@ksu.edu. Corrections are made in place and dated here.

Text licensed CC BY 4.0, code MIT: teachers and students may reuse and adapt it, with credit to Honglin Li.

© 2026 Honglin Li · Kansas State University · hlli@ksu.edu

 

Last updated: November 2026 · Built with Quarto