How to Read a Diff
A practical guide to reading unified diffs — understand the +/- notation, hunk headers, file headers, and how diffs appear in git, pull requests, and patch files.
What is a diff?
A diff (short for difference) is a representation of the changes between two versions of text. The most common format is the unified diff, produced by the diff -u command on Unix systems and used by git diff, GitHub pull requests, and patch files. It shows exactly which lines were removed and which were added.
Anatomy of a unified diff
A unified diff has four types of lines. The file headers identify the original and new files. Hunk headers (@@ lines) mark each changed region. Lines prefixed with - were in the original and are being removed. Lines prefixed with + are new additions. Context lines (no prefix, usually 3 before and after) show surrounding unchanged code.
--- a/src/greeting.js ← original file
+++ b/src/greeting.js ← new file
@@ -4,7 +4,7 @@ ← hunk header (explained below)
function greet(name) {
- return "Hello, " + name; ← removed line
+ return `Hello, ${name}!`; ← added line
}
module.exports = { greet };Reading the @@ hunk header
The @@ line tells you which line numbers the change covers. The format is @@ -originalStart,originalCount +newStart,newCount @@. The - side describes the original file and the + side describes the new file.
@@ -4,7 +4,7 @@
↑ ↑ ↑ ↑
| | | └─ 7 lines from the new file starting at line 4
| | └──── new file starts at line 4
| └─────── 7 lines from the original file starting at line 4
└────────── original file starts at line 4
@@ -12,4 +15,6 @@ ← 4 lines removed starting at line 12; 6 lines added starting at line 15git diff output
git diff shows unstaged changes, git diff --staged shows staged changes, and git diff HEAD shows everything since the last commit. The file header is slightly different — it shows the git object hash (a/ and b/ prefixes are git conventions, not filesystem paths).
# Common git diff commands
git diff # unstaged changes vs working tree
git diff --staged # staged changes vs last commit
git diff HEAD # all changes vs last commit
git diff main feature # difference between two branches
git diff abc123 def456 # difference between two commits
git diff -- path/to/file # diff a specific file onlyApplying a patch file
A .patch file is just a saved unified diff. The patch command applies it to your files. The -p1 flag strips one level of directory prefix (the a/ and b/ that git adds).
# Create a patch from git
git diff > my-changes.patch
git format-patch HEAD~1 # create a patch from the last commit
# Apply a patch
patch -p1 < my-changes.patch
# Check if a patch will apply cleanly (dry run)
patch -p1 --dry-run < my-changes.patchWhat does a line with no prefix mean in a diff?
Lines with no prefix (called context lines) are unchanged. They are included to show the surrounding code so you can understand where the change happened. By default, diff shows 3 context lines on each side of a change.
What is the difference between a unified diff and a side-by-side diff?
A unified diff (the standard format) interleaves removed and added lines in a single column with - and + prefixes. A side-by-side diff shows the original and new versions in parallel columns. Both convey the same information — side-by-side is often easier to read for large changes.
Why does my diff show changes to every line even though I only changed whitespace?
Whitespace-only changes are real changes at the byte level. Use diff -b (ignore trailing whitespace) or diff -w (ignore all whitespace) to suppress them. In git, use git diff -w or git diff --ignore-space-change.
How to Validate JSON
A practical guide to checking JSON for syntax errors, understanding common mistakes, and formatting it for readability.
Read guide →How to Use Regular Expressions
A practical guide to regular expressions — learn the core syntax, common patterns, and how to write regex for real-world tasks like email validation, URL matching, and log parsing.
Read guide →How to Write a Regex Pattern Step by Step
A practical guide to building regular expressions from scratch — breaking down the problem, choosing the right tokens, testing incrementally, and avoiding common traps.
Read guide →How to Use Git: Core Workflows
A practical guide to everyday Git usage — committing, branching, merging, resolving conflicts, and keeping a clean history.
Read guide →