Finding the commit that broke it: log, blame, and git bisect
When something used to work and now does not, Git can point at the commit that changed it. Start with log and blame for quick clues, then let git bisect binary-search the history.
You know the feature worked in last month’s release and fails today. Somewhere in between is a commit that broke it. Git gives you tools from quick look-ups to a fully automatic search.
Quick clues from history
git log --oneline --graph -20
git log --oneline -- src/calc.sh
git log -S 'TAX_RATE' --oneline
git log -p -3 -- src/calc.sh
git show d7cb0d8
git blame -L 40,60 src/calc.sh
log -- pathlists only commits that touched that file.log -S 'text'(the “pickaxe”) finds commits where the number of occurrences of that text changed, which is great for “when did this line appear or vanish?”showprints one commit’s message and diff. Add--statfor just the file list.blame -Lshows, for each line in a range, the last commit that changed it and who made it. Use it to find context, not culprits.
If those clues point nowhere, it is time to bisect.
How bisect works
You tell Git one commit where the bug exists (bad) and one where it does not (good). Git checks out the commit halfway between, you test, and you report the result. Each answer halves the range, so the number of steps grows with the logarithm of the number of commits: about 10 steps for 1,000 commits.
git bisect start
git bisect bad # the current commit is broken
git bisect good v1.0 # this tag was fine
# Git checks out a commit in the middle. Test it, then:
git bisect good # or: git bisect bad
# ...repeat until Git prints "<hash> is the first bad commit"
git bisect reset # return to where you started
git bisect start HEAD v1.0 is a shorter way to give the bad and good commits in one step. If a commit cannot be tested (it does not build, for example), run git bisect skip and Git picks a nearby one.
Let a script do the testing
If a command can tell good from bad, Git can run the whole search for you. The command’s exit code is the answer:
0: this commit is good.1to127, except 125: this commit is bad.125: cannot test this commit, skip it.
git bisect start HEAD v1.0
git bisect run ./test.sh
git bisect reset
A test script can be as small as this:
#!/bin/sh
[ "$(./calc.sh 2 3)" = "5" ]
You can also run an existing test directly, for example git bisect run npm test or git bisect run python -m pytest tests/test_cart.py, as long as it exits non-zero when the bug is present.
Tips for a clean bisect
- Keep the test script outside the repository, or at least untracked, so checking out older commits does not change or delete it.
- Start with a clean working tree: commit or stash your changes first.
- Use
git bisect logto see your answers so far, and save it if you need to resume later withgit bisect replay. - On histories with many merged branches,
git bisect start --first-parentonly tests commits on the main line, which tells you which merge brought the bug in.
When bisect names the commit, read it with git show. Often the fix is obvious; if not, git revert it while you investigate.
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- commitpedia-admin +3,032 chars