Git Diff — The Silent Merge That Deleted 200 Lines of Error Handling
A team merged a branch that looked clean in the PR diff, but 200 lines of error handling had been silently deleted.
20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.
- ✓Basic programming fundamentals (variables, functions, control flow)
- ✓No prior devops experience needed — we start from first principles
git diff shows unstaged changes. git diff --staged shows staged changes. git diff main..feature compares two branches. git diff --word-diff highlights word-level changes.
Git diff is like a highlighter pen for your code. It marks every line that was added (green) and every line that was deleted (red) between any two snapshots. Without it, reviewing changes would mean reading the entire file and trying to remember what it looked like before. Git diff is the foundation of every code review, every merge, and every debugging session.
| Chrome | Firefox | Safari | Edge |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
Git diff is the single most important command for code review and debugging. Every PR diff is powered by git diff. Every merge conflict shows you a three-way diff. Every bisect session uses diff to verify the fix. Yet most developers only use the default git diff output, missing powerful flags that catch silent regressions. This guide covers the essential diff modes, the incident where a PR diff hid 200 deleted lines, and how to use diff to prevent invisible changes from reaching production.
Diff Modes and When to Use Each
git diff (no arguments) shows unstaged changes — working tree vs index. git diff --staged (or --cached) shows staged changes (index vs HEAD). git diff <commit> shows changes since a specific commit. git diff <commit1>..<commit2> compares any two arbitrary commits.
For branches: git diff main..feature shows what's in feature that isn't in main. git diff main...feature (three dots) shows changes since the common ancestor — this is what GitHub PRs use.
Use --stat for a summary of changed files and line counts. Use --name-only to list only file paths. Use --name-status to include what type of change (A=added, D=deleted, M=modified, R=renamed).
git diff --diff-filter=D shows only deleted files. --diff-filter=AM shows only added and modified. This is invaluable for catching accidental deletions in large PRs. Chain with --name-only for a quick checklist.git diff --stat main...HEAD and git diff --name-status main...HEAD. This forces awareness of every changed file and the type of change. On CI, add a step that runs git diff --diff-filter=D --name-only main...HEAD and warns if any non-trivial files were deleted (e.g., exclude lock files and generated code). Some teams enforce that deletions require explicit justification in the PR description.git diff --stat and --name-status for a bird's-eye view. --diff-filter narrows to specific change types. Always expand all collapsed sections in GitHub's PR diff viewer before approving.Word Diff, Ignore Whitespace, and Catching Invisible Changes
git diff --word-diff highlights changes at the word level instead of line level. This is ideal for documentation, prose, or when a single line has both additions and deletions. --word-diff-regex= allows custom word boundaries.
git diff -w ignores whitespace changes (spaces, tabs, indentation). --ignore-space-change ignores whitespace-only changes but still shows whitespace that affects meaning. --ignore-blank-lines ignores empty line changes.
git diff --check checks for whitespace errors (trailing spaces, spaces before tabs) and lists them. git diff --color-moved highlights moved blocks of code with different colors — crucial for refactors where code is reorganized.
.git-blame-ignore-revs to keep blame useful after formatting commits.git diff --color-moved as the default via git config diff.colorMoved zebra. This makes moved code blocks visually distinct from added/deleted code in your terminal. In CI, run git diff --check to fail builds on whitespace errors. For large PRs (>500 lines changed), require the reviewer to run git diff main...HEAD --stat and git diff main...HEAD --name-status before approving.--word-diff for prose, -w to skip whitespace, --check for whitespace errors, --color-moved to track reorganized code. Separate formatting PRs from logic PRs to keep diffs readable.The PR That Looked Clean but Deleted 200 Lines
git revert of the offending commits. 2. Used git diff --check to verify no whitespace errors (also checks for subtle issues). 3. Required git diff --stat at the top of every PR description to show the change summary. 4. Added a PR template instructing reviewers to expand all collapsed diff sections before approving. 5. Added a CI check: git diff --diff-filter=D --name-only main...HEAD lists deleted files; git diff main...HEAD --name-status shows the change type for every file. 6. Team rule: if a PR has more than 10 files changed, require a secondary reviewer to look at only the deletions.- Default git diff (3-line context) can hide important changes.
- Always expand all sections in GitHub's PR diff viewer.
- Use
git diff --statfor a bird's-eye view of change types. - Pay special attention to files with both additions and deletions — they often contain hidden regressions.
git diff — shows working tree vs indexgit diff --staged (or --cached)git diff <commit1>..<commit2> or git diff main..featuregit diff --name-only — no content, just file pathsgit diff --ignore-space-change or -w to ignore all whitespace| File | Command / Code | Purpose |
|---|---|---|
| 01_diff_modes.sh | git diff # working tree vs index | Diff Modes and When to Use Each |
| 02_advanced_diff.sh | git diff --word-diff | Word Diff, Ignore Whitespace, and Catching Invisible Changes |
Key takeaways
-U<N> for more--stat and --name-status for a change summary, not just content diff--diff-filter=D catches accidental file deletions--word-diff for prose, -w to skip whitespace noise--color-moved reveals reorganized code that looks like add+deletegit diff --stat main...HEAD in PR descriptions20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.
That's Git. Mark it forged?
3 min read · try the examples if you haven't