Git Bisect
Finding the commit that introduced a bug by binary search through history, testing the midpoint between a known-good and a known-bad version until one commit remains.
Git bisect finds the Commit that introduced a bug by running a Binary Search through history. You mark one version as good, where the bug is absent, and one as bad, where it appears. Git checks out the commit halfway between them, you test it and mark it good or bad, and Git halves the range again. Each answer discards half the remaining suspects, so a thousand commits take about ten steps, and a million take about twenty.
The command is git bisect start, followed by git bisect bad and git bisect good <commit>, then repeated marking until Git names the first bad commit. Bisection isn't specific to Git; Mercurial has the same command, and the technique works on any ordered history, including package versions and nightly builds.
The process becomes fully automatic with git bisect run, which takes a script and uses its exit code as the verdict: zero means good, most nonzero codes mean bad, and the special code 125 means "can't test this one, skip it." With a script that builds the code and checks for the bug, Git can search hundreds of commits without anyone watching. A good bisect script is a Reproducible Case turned into a command.
Bisection depends on a few properties of the history:
- Every commit should build and run. If many commits are broken for unrelated reasons, they have to be skipped, and the search may end with a range instead of one commit. Making each commit an Atomic Commit that compiles and passes tests keeps history bisectable.
- Small commits give precise answers. Bisect can only point at a whole commit. If the culprit is one giant change, the search ends at the right commit but leaves the hard part undone. A Squash Merge of a large branch trades readable history for coarser bisection.
- The test must be reliable. A Flaky Test that fails at random will send the search the wrong way once and silently produce the wrong answer, since bisect trusts every verdict.
Merge-heavy histories complicate the picture, since the "middle" of a graph with many branches isn't a single line. Git handles this by choosing commits that split the remaining candidates as evenly as possible, and --first-parent limits the search to the main line of merges.
Bisection is the simplest version of Delta Debugging, which generalizes the idea to sets of changes that don't have a natural order. It answers when a Regression arrived, which is often the fastest route to why: the diff of one small commit is usually short enough to read in full. Some teams bisect automatically in Continuous Integration when a test that passed yesterday fails today.
See also2
Minimal Reproducible Example
The smallest self-contained program or set of steps that still shows a bug, and why making one is often the moment the bug gets understood.
Testing & Verification10 connections
Detached HEAD
The Git state in which the current checkout points directly at a commit rather than a branch, harmless for looking around but a trap for new work, since commits made there belong to no branch and can quietly disappear.
Version Control & Delivery11 connections
Linked from14
- Atomic CommitVersion Control & Delivery
A commit containing exactly one logical change, complete and independently sound.
- Binary SearchComputation & Algorithms
Finding a value in a sorted range by repeatedly discarding half of it.
- Detached HEADVersion Control & Delivery
The Git state in which the current checkout points directly at a commit rather than a branch, harmless for looking around but a trap for new work, since commits made there belong to no branch and can quietly disappear.
- Fast-Forward MergeVersion Control & Delivery
The two basic ways Git joins branches, by sliding a branch pointer forward or by recording a new commit with two parents, and how the choice shapes a project's history.
- Git BlameVersion Control & Delivery
Showing, for every line of a file, the commit and author that last changed it, the starting point for finding out why code is the way it is.
- Interactive RebaseVersion Control & Delivery
Git's tool for rewriting a series of commits before sharing them, reordering, combining, splitting, and rewording them so the history tells a clear story rather than recording every false start.
- Minimal Reproducible ExampleTesting & Verification
The smallest self-contained program or set of steps that still shows a bug, and why making one is often the moment the bug gets understood.
- ReflogVersion Control & Delivery
Git's private record of everywhere HEAD and each branch has pointed, the safety net that makes a botched reset, rebase, or deleted branch recoverable for weeks.
- RegressionMethod
A previously working behavior that a change has broken.
- Regression TestingTesting & Verification
Rerunning existing tests after every change to confirm that what used to work still works, how the suite grows one fixed bug at a time, and how teams keep it fast enough to run.
- Reproducible CaseMethod
The smallest set of steps that reliably produces a fault, and the unit of real debugging.
- Shallow CloneVersion Control & Delivery
Ways to fetch less than a whole Git repository, by cutting history, deferring file contents, or checking out only some directories, and what each breaks.
- Squash MergeVersion Control & Delivery
Collapsing a branch's commits into one before merging, trading granularity for a clean main history.
- Staging AreaVersion Control & Delivery
The intermediate snapshot in Git between the working files and the next commit, which lets a developer choose exactly which changes go into each commit, down to individual lines.