DEV Community

Shakil Alam
Shakil Alam

Posted on • Edited on

A Practical Guide to Finding Bugs Using Git

Strong engineers don't debug by staring at code. They debug by asking: When did reality change?

Every debugging situation reduces to four questions:

  1. What changed?
  2. Who touched this?
  3. Why was it changed?
  4. 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

Git checks out the midpoint. You test, then respond:

git bisect bad   # still broken
git bisect good  # working here
Enter fullscreen mode Exit fullscreen mode

Each step cuts the search space in half. Eventually:

<commit_hash> is the first bad commit
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Git will checkout, test, classify, and repeat — automatically — until the culprit is found.

Always Reset When Done

git bisect reset
Enter fullscreen mode Exit fullscreen mode

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)