Unit 5.6 · about 4 h
32 / 324Git history, merges, rebases, bisect and recovery
History is the experiment log of the code. Bisect finds which change broke behavior, and reflog makes almost every Git mistake reversible.
- explain
- implement
You can now
- Explain commits, branches, merges, rebases and detached state using the snapshot graph.
- Isolate a regression with
bisect runfrom an automated failing test. - Recover a displaced commit with
reflogwithout discarding unrelated work.
Covers
- Commits, branches, merges, rebases and detached state
- Bisect, reflog and preservation-first recovery
Study, in this order
6 steps
- Version control and Git data modelThe Missing Semester of Your CS Education
Git data model: Snapshots, Modeling history, Objects and content-addressing, References; Staging area; Basics, Branching and merging; Advanced Git; the
recipe.txtmerge-conflict exercise - Pro Git: rebasingPro Git
The basic rebase flow; More Interesting Rebases with
--onto; The Perils of Rebasing; Rebase vs. Merge - Pro Git: debugging with GitPro Git
bisect start,bad,goodandrunwithtest-error.sh;blame -Lfor line-level attribution - Pro Git: undoing thingsPro Git
Undoing Things: Unstaging a Staged File; Unmodifying a Modified File; Undoing things with
git restore - Pro Git: data recoveryPro Git
Maintenance and Data Recovery: Data Recovery (
reflog,git log -g,fsck --fullfor dangling commits)
Focus on
- A commit is a snapshot plus parents, and a branch is a movable pointer. Merge preserves both parents; rebase rewrites commits onto a new base.
- Rebase only local, unpushed work. Rebasing pushed history forces everyone downstream to repair, which the book states as the rule.
- Bisect needs a monotonic test: nonzero exit on bad, zero on good, plus one known-good and one known-bad commit.
git bisect runautomates the search in logarithmic steps. - Recovery is preservation-first: stash or branch current state before any destructive command. Uncommitted work is invisible to
reflog, and unreachable entries expire after 30 days by default.
Reproduce closed-book
test.sh that exits 1 on the bad line. Run git bisect start, bad, good HEAD~6 and run ./test.sh: it tests commits 4, 6 and 5 and reports commit 6 as the first bad commit. Then delete a branch tip and recover it with git reflog plus git branch recovered <sha>. Observed with git 2.51.0.Traps
- Destructive commands before saving state. Uncommitted work never reaches the
reflog, so stash or commit beforereset --hardorclean. - Bisecting with a flaky or non-monotonic test. The search converges on the wrong commit, so stabilize the test first.
- Rebasing a shared branch then force-pushing. Use merge, or rebase only with coordination, and never rewrite pushed history silently.
Practice
Missing Semester class-website history exercise
Exercises, item 2: clone the class website, graph the history and find who last modified README.md
Missing Semester `recipe.txt` merge-conflict exercise
Exercises, item 8: two branches editing recipe.txt, merge, resolve the markers and graph the result
Self-test
-
Merge versus rebase for a finished feature branch: what differs in the graph?
Merge adds a merge commit with two parents and preserves branch history. Rebase replays the branch commits onto the main tip as new hashes with a linear history. -
git bisect runreports the wrong culprit. Name two causes.A flaky non-monotonic test, or a bad and good labeling error. Uncommitted changes skewing some checkouts is a third. -
You deleted a branch yesterday and need its tip. What is the exact recovery?
git reflog, find the tip sha, thengit branch recovered <sha>. It works while thereflogentry survives expiry. -
In detached
HEADstate, what does committing do, and what is the risk?The commit exists but no branch points at it. Switching away strands it except in thereflog, so create a branch to keep it.
Completion criterion
Stop when
Your bisect finds the seeded culprit without manual checkouts, and your recovered branch matches the displaced tip sha.
Mark passed, then open 5.7 Only mark this when you can do it without notes.Leads to
- 5.8 Dependency locks, run manifests and quality gates Version releases and lockfiles on top of a disciplined history.
- 5.4 Debuggers, logs, traces and competing hypotheses Bisect feeds the hypothesis log once it points at a recent change.
Comes after
- 5.3 Regression tests, failure injection and flaky testsBisect the history to find which commit introduced the regression.
- 5.4 Debuggers, logs, traces and competing hypothesesBisect the history once the log points at a recent change.
Resources for this unit
- The Missing Semester of Your CS Education Complete the 2026 lectures on the shell, command-line environment, development tools, debugging and profiling, Git, packaging and shipping code, and code quality. Apply every exercise to the same stage project.
- Pro Git Use Chapters 2-3 and the sections on debugging, internals and recovery while constructing a history for bisect and recovering a deliberately displaced commit.
Also in this section
- pytest documentation Use Get Started, fixtures, parametrization, monkeypatch, caplog and temporary paths to build behavior and failure-path tests without order dependence.
- Hypothesis documentation Follow the Quick start and property-based testing guides, then generate operation histories and retain the minimized example for one real defect.
- The Art of Debugging Use the Unix, Python and compiled-code sections during a real seeded defect. Follow the evidence and tiny-reproducer workflow rather than reading the unfinished book front to back.
- Stas' Python Cookbook - debugging and testing Use Part III and the packaging sections for debugger, traceback, pytest, logging, profiling and clean-environment recipes.
- AlgoMaster Python - mocking Use the Mocking lesson for
unittest.mock:MockversusMagicMock,patchtargets,autospecand the over-mocking trap. The pytest docs remain the reference for fixtures andmonkeypatch.