Strong engineers don't debug by staring at code. They debug by asking: When did reality change?
Every debugging situation reduces to four questions:
- What changed?
- Who touched this?
- Why was it changed?
- When did it break?
1. What Changed? → git diff
If behavior changed, code changed. git diff compares snapshots in your repository.
# Working directory vs last commit (HEAD)
git diff
# Show what's staged for the next commit
git diff --staged
# Compare two commits or tags
git diff v1.2.0 v1.3.0
# Compare branches before merging
git diff main feature/refactor
When to use it: Run git diff before every commit. Most bugs start with "I didn't realize that line changed."
2. Who Touched This? → git blame
Once you find a suspicious line, trace it to its author:
# Annotate every line with commit hash, author, and date
git blame path/to/file.php
# Ignore whitespace-only changes (avoids misleading formatting commits)
git blame -w file.php
What it shows: Who last modified each line — not who originally wrote the feature.
Use blame to understand decisions, not to assign guilt.
3. Why Was It Changed? → git log --patch
Blame shows who. To understand reasoning, walk through the file's full history:
git log --patch -- path/to/file.php
This reveals:
- Commit messages (the why)
- Exact diffs (the what)
- Business logic shifts, hotfixes, refactors
Instead of reading 2,000 lines blindly, you read evolution. Git becomes your documentation.
4. When Did It Break? → git bisect
This is where most developers waste hours guessing. Professionals use binary search.
Given 100 commits between a good and bad state:
- Manual testing = up to 100 tries
-
git bisect= about 7 tries
Basic Workflow
# Start the bisect session
git bisect start
# Mark current state as broken
git bisect bad
# Mark the last known working commit as good
git bisect good <commit_hash>
Git checks out the midpoint. You test, then respond:
git bisect bad # still broken
git bisect good # working here
Each step cuts the search space in half. Eventually:
<commit_hash> is the first bad commit
You now have: the exact commit, change, author, and timestamp. No guessing required.
Automated Bisect (Most Powerful)
If you have tests, let Git do all the work:
git bisect run npm test
Git will checkout, test, classify, and repeat — automatically — until the culprit is found.
Always Reset When Done
git bisect reset
Professional Debugging Order
When something breaks, follow this sequence:
| Step | Question | Command |
|---|---|---|
| 1 | What did I change locally? | git diff |
| 2 | What changed between releases? | git diff <old> <new> |
| 3 | What does this specific commit contain? | git show <hash> |
| 4 | Who last touched this line? | git blame |
| 5 | When exactly did this break? | git bisect |
Common Scenarios
Production bug with no clear owner
→ git diff between last working release and current → git blame suspicious lines → git show the commit → facts, not assumptions.
Joining a legacy codebase
→ git log --patch -- critical_file.php to read how the rules evolved rather than reading everything cold.
"It worked yesterday"
→ This is not an emotional statement. It's a git bisect case. Let the algorithm search.
The Mental Shift
Git is not just a commit tool or a GitHub bridge. It's:
- A historical database of every change ever made
- A forensic timeline you can query at any point
- A binary-search debugger that finds root causes in minutes
- A safety net that means nothing is ever truly lost
Master these four commands and you debug faster than 90% of developers — not because you're smarter, but because you stopped guessing.
Top comments (0)