The anatomy of a git diff
Run git diff HEAD~1on any repository and you'll see something like this:
diff --git a/src/api.ts b/src/api.ts
index 3a1b2c4..7d8e9f0 100644
--- a/src/api.ts
+++ b/src/api.ts
@@ -12,7 +12,9 @@ async function fetchUser(id: string) {
const response = await fetch(`/api/users/${id}`);
- return response.json();
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}`);
+ }
+ return response.json();
}Let's break this down line by line.
The header lines
The first two lines identify what's being compared:
diff --git a/src/api.ts b/src/api.ts— Git's internal comparison command. Thea/prefix is the original version,b/is the new version.index 3a1b2c4..7d8e9f0 100644— The SHA-1 object hashes of both file versions in Git's object database, plus the Unix file permissions (100644 = regular file, 100755 = executable).--- a/src/api.tsand+++ b/src/api.ts— The file names for the original (---) and new (+++) versions. For new files, the original is/dev/null; for deleted files, the new version is/dev/null.
The hunk header: @@ -12,7 +12,9 @@
This is the most important and most misread part of a diff. The format is:
@@ -<original_start>,<original_count> +<new_start>,<new_count> @@
-12,7— In the original file, this hunk starts at line 12 and spans 7 lines.+12,9— In the new file, this hunk starts at line 12 and spans 9 lines (2 more because we added 3 lines and removed 1).
The numbers after the comma are the total line counts shown in the hunk — including context lines. If the count is 1, the comma and count are often omitted: @@ -12 +12,4 @@. Anything after the final @@ is optional context — Git often shows the function or class name that contains the change, which is extremely helpful for navigating large diffs.
The diff lines themselves
- Lines starting with a space are context lines — they appear in both the original and new files unchanged. By default Git shows 3 context lines around each change. Increase this with
git diff -U10. - Lines starting with -(red in colored output) were in the original and are gone in the new version. They've been deleted or replaced.
- Lines starting with + (green in colored output) are new additions. They exist in the new version but not the original.
A modification shows as a deletion followed by an addition. The line wasn't edited in place — from the diff's perspective, the old version was deleted and the new version was added. Many diff viewers (GitHub, GitLab) apply additional word-level highlighting within the +/- lines to show exactly which words changed.
Useful git diff flags
git diff --stat— Summary view: files changed, insertions, deletions. Great for getting an overview of a large PR.git diff --word-diff— Shows word-level changes inline rather than full line replacements. Useful when lines have small text changes.git diff --ignore-whitespace— Ignores whitespace-only changes. Essential when comparing code that was reformatted.git diff main...feature-branch— Shows all changes on the feature branch relative to where it diverged from main. This is the canonical way to see what a PR contains.git diff --cached— Shows staged changes (what will be committed if you rungit commit).
Reading merge conflict markers
When a merge conflict occurs, Git inserts markers directly into the conflicted file:
<<<<<<< HEAD
return response.json();
=======
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
>>>>>>> feature/error-handling- Everything between
<<<<<<< HEADand=======is your current branch's version. - Everything between
=======and>>>>>>> feature/...is the incoming branch's version. - To resolve: edit the file to contain the correct final version, delete all three marker lines, then
git addand commit.
Related tools
Diff Checker — Compare Two Texts →