02 — History Hygiene: Interactive Rebase, Bisect & PR Discipline
At a glance
After completing this lesson you can:
- Explain how
git rebasereplays commits onto a new upstream base by computing patch diffs. - Implement an automated
git bisectbinary-search algorithm over a linear commit history in $O(\log n)$ steps. - Clean dirty commit histories into atomic, reviewable commits before opening a Pull Request.
Time: ~45 minutes · Prerequisites: 01 — Git Object Model
Reading Companion
- Book: Pro Git (2nd Edition) — Scott Chacon & Ben Straub
- Chapter 3.6: Git Branching - Rebasing (The Perils of Rebasing, Rebase vs Merge).
- Chapter 7.1: Git Tools - Revision Selection & Searching (
git bisect,git log -S).
Why this matters in production
When a critical production bug is reported after a Friday deploy, engineers cannot afford to manually test 80 messy commits like "fix typo", "wip 2", "try again". By maintaining atomic commits and knowing how to run automated git bisect, teams isolate the exact breaking commit and author within 90 seconds.
Deep dive
1. Merge vs Rebase
- Merge (
git merge): Preserves complete commit history with a two-parent merge commit. Can result in tangled "railroad track" graphs if used for every minor branch. - Rebase (
git rebase): Rewrites history by cherry-picking commits one by one onto the target branch tip, creating a linear, clean history. - The Golden Rule of Rebasing: Never rebase commits that exist outside your local branch (e.g., shared
mainor public releases)!
2. Automated Binary Search with git bisect
If commit 1 is good and commit 100 is broken, binary search finds the first culprit in $pprox \lceil \log_2(100) ceil = 7$ steps.
Hands on
python3 phase0-foundations/02-git-and-workflow/02-history-hygiene-and-rebasing/examples/01_demo.py
python3 phase0-foundations/02-git-and-workflow/02-history-hygiene-and-rebasing/examples/02_trap.py
AI Trap & Code Review
# BAD AI-GENERATED CODE — LINEAR SCAN INSTEAD OF BISECT
def find_breaking_commit(commits: list[str], test_fn) -> str:
# O(N) linear scan — tests all 500 commits one by one!
for commit in commits:
if not test_fn(commit):
return commit
return ""
Exercises
- Rung 1 (
parse_rebase_todo): Parse agit-rebase-todoscript string ("<action> <sha> <message>") into a list of tuples(action, sha, message). Valid actions:pick,reword,edit,squash,fixup,drop. Ignore comments (#) and empty lines. RaiseValueErroron invalid actions. - Rung 2 (
simulate_git_bisect— Fix the AI Bug): Implement $O(\log n)$ binary search over a chronological list of commit IDscommits(commits[0]is known GOOD,commits[-1]is known BAD). Return the first bad commit ID. - Rung 3 (
filter_conventional_commits): Validate commit messages against the Conventional Commits specification:f"{type}({optional_scope}): {description}". Allowed types:feat,fix,docs,style,refactor,perf,test,build,ci,chore. - Rung 4 (
squash_commit_plan): Given a rebase plan, compress consecutivesquashandfixupactions into their parentpickaction, returning the unified list of resulting atomic commits. - Rung 5 (
recover_reflog_head): Parse simulatedgit reflogentries ("<sha> HEAD@{<n>}: <action>: <description>") to determine what commitHEADpointed to before a specific failed command.
Wrapping up
Can you explain?
- Why must you never rebase a branch that multiple developers are collaborating on?
- How does
git bisect run ./test.shautomate finding regressions in CI? - What makes a commit "atomic"?
Further Reading & References
- Pro Git Book (Chacon & Straub): Git Internals - Git Objects
- Git Plumbing and Porcelain Commands Reference
- Conventional Commits v1.0.0 Specification
- Mary Rose Cook: A Git implementation explained
Show reference solution notes
Solution & Engineering Notes — 02 History Hygiene & Bisect
- Rebasing public branches: Rebasing rewrites commit hashes. If colleague Alice branched off commit
A, and Bob rebases and force-pushesAinto new hashA', Alice's next pull will cause duplicate, conflicting commits. git bisect run: Runs an automated test script on each candidate commit. If the script exits0, Git marks it good; if it exits1..127, Git marks it bad, finding regressions in CI automatically.
Self-check
Run python3 -m unittest phase0-foundations/02-git-and-workflow/02-history-hygiene-and-rebasing/test_exercises.py -v until green, then record it here. Saved to progress/rungs.json; commit it.
Completion edits PROGRESS.md; commit it with the lesson.