Elena' s AI Blog

Debugging Git Commits: Finding Exactly What Broke

12 Jul 2026 (updated: 17 Jul 2026) / 12 minutes to read

Elena Daehnhardt


Matrix fell, Midjourney Nov 2023


TL;DR:
  • Use git log, git show, and git diff to isolate regressions. Create a safety branch first, then merge or cherry-pick only what you need.

Previous: Part 6 — Git Log

Next: Part 9 — Reverting Commits in GitHub

Comparing Git Commits to Debug a Regression

A feature worked yesterday. It’s broken today. I don’t guess when this happens — I compare the two commit states directly and let Git tell me exactly what changed. Commit comparison is the practice of diffing two points in a repository’s history to isolate which commit introduced a regression. Here’s the workflow I actually use: pick a good and a bad commit, diff them precisely, and recover only what you need without dragging the rest along with it.


Step 1: Identify the Commit Range with git log

Start with the shape of your history:

git log --oneline --decorate --graph

From that graph, pick two points:

  • GOOD_COMMIT — the last commit you know worked.
  • BAD_COMMIT — the first commit where things broke.

Everything else in this workflow hangs off those two references.

The commit range between GOOD_COMMIT and BAD_COMMIT GOOD_COMMIT..BAD_COMMIT commit GOOD_COMMIT commit BAD_COMMIT commit last known good first broken

The range GOOD_COMMIT..BAD_COMMIT covers every commit in between — that’s what git diff, git log -p, and the recovery commands in the next steps all operate on.


Step 2: Compare Commit States with git diff and git show

git diff is a Git command that compares two references — commits, branches, or the working tree — and prints the line-by-line changes between them. Once you have your range, git diff shows you exactly what changed:

git diff GOOD_COMMIT..BAD_COMMIT

Narrow it to one file when you already suspect where the regression lives:

git diff GOOD_COMMIT..BAD_COMMIT -- path/to/file.py

git show is a Git command that displays a single commit’s metadata (author, date, message) together with its full patch. When you want the full picture on the bad commit in one go, git show gives you that:

git show BAD_COMMIT

Step 3: Inspect the History in the Range with git log -p

A diff tells you what changed overall, but sometimes you need it commit by commit. git log is a Git command that lists commits reachable from a given range; with -p, it also prints each commit’s patch:

git log --oneline GOOD_COMMIT..BAD_COMMIT
git log -p GOOD_COMMIT..BAD_COMMIT

The first command gives you a quick list of suspects. The second shows the actual patch for each one, so you can spot which commit introduced the regression rather than just knowing it happened somewhere in the range.


Step 4: Create a Safety Branch Before Recovery

Before I touch anything, I pin down where I am right now with git branch, a Git command that creates a new reference pointing at the current commit without changing the working tree:

git branch backup-before-fix

Creating this branch costs nothing — it’s just a new pointer — and it means I can experiment freely. If a cherry-pick goes wrong or a revert gets messy, I still have an untouched copy to fall back on.


Step 5: Recover Good Changes with git cherry-pick or git revert

Git gives you two distinct recovery strategies once you know which commits are good and which are bad:

Approach Command History shared with others? What happens
Rebuild clean git checkout -b fix-branch GOOD_COMMIT + git cherry-pick <hash> Safe on private branches Builds a new branch containing only the commits you choose
Revert in place git revert BAD_COMMIT Safe on shared/public branches Adds a new commit that undoes the bad one; history stays intact
Two Git recovery patterns: cherry-pick onto a new branch versus revert in place A) Cherry-pick onto a new branch main commit GOOD_COMMIT commit BAD_COMMIT main unchanged fix-branch cherry-pick cherry-picked commit HEAD B) Revert in place main commit GOOD_COMMIT commit BAD_COMMIT kept in history revert commit undoes HEAD

Cherry-pick builds a new branch from GOOD_COMMIT and copies chosen commits onto it — the old history (including BAD_COMMIT) is left untouched elsewhere. Revert stays on the same line of history and simply appends a new commit that undoes BAD_COMMIT, so BAD_COMMIT itself is never removed.

A) Build a new clean branch from the known-good commit

Start fresh from the point where things worked:

git checkout -b fix-branch GOOD_COMMIT

git checkout -b creates and switches to a new branch starting at the given commit. Then bring across only the commits you actually want, one at a time, with git cherry-pick — a Git command that applies the changes from a specific commit onto your current branch as a new commit:

git cherry-pick <commit-hash>

This is my preferred route when the bad range is a mix of good and bad commits — I choose exactly what comes along. See the official git cherry-pick documentation for conflict-handling flags like --continue and --abort.

B) Keep the current branch and revert the bad commit

If history is shared with others and rewriting it isn’t an option, git revert — a Git command that creates a new commit reversing the changes of an earlier one, rather than removing that commit from history — is the safer move. See the official git revert documentation:

git revert BAD_COMMIT

git revert doesn’t erase the bad commit — it adds a new one that undoes it, so history stays intact and traceable. Anyone pulling the branch later can see exactly what was reverted and why.


Step 6: Resolve Merge Conflicts During Cherry-pick or Revert

Cherry-picks and reverts can both trigger merge conflicts — cases where Git can’t automatically reconcile overlapping changes to the same lines. When that happens, the routine doesn’t change:

  1. Resolve the conflicting files by hand.
  2. Stage them: git add <resolved-files>.
  3. Continue the operation — git cherry-pick --continue, or complete the merge commit if you’re mid-revert.

No panic, please. A conflict just means Git needs your judgement on a line it can’t merge automatically.


Mental Model: Commits as Before-and-After Photographs

Think of GOOD_COMMIT and BAD_COMMIT as two photographs of the same room, taken before and after someone rearranged the furniture. git diff lays the photos side by side and circles what moved. git log -p gives you the flipbook in between, frame by frame, so you can see who moved what and when. You’re not guessing which piece of furniture is out of place — you’re watching it happen.


Checklist for Debugging a Regression by Comparing Commits

  1. Find your good and bad commits with git log --oneline --decorate --graph.
  2. Diff the range: git diff GOOD_COMMIT..BAD_COMMIT.
  3. Read the history in between with git log -p GOOD_COMMIT..BAD_COMMIT.
  4. Branch off a safety copy before you change anything: git branch backup-before-fix.
  5. Recover with cherry-pick for a clean rebuild, or revert when history is shared.

Summary: Debugging Git Regressions by Comparing Commits

Debugging a regression by commit comparison is a systematic method, not a panic event: define your good and bad points, diff precisely, keep a safety branch, and recover with the smallest change that fixes the problem. Once you’ve done this a few times, “it worked yesterday” stops being scary — it’s just a range of commits waiting to be diffed.


References

desktop bg dark

About Elena

Elena, a PhD in Computer Science, simplifies AI concepts and helps you use machine learning.



Citation
Elena Daehnhardt. (2026) 'Debugging Git Commits: Finding Exactly What Broke', daehnhardt.com, 12 July 2026. Available at: https://daehnhardt.com/blog/2026/07/12/git-commit-differences/
All Posts