codeshot.io

How to read a git diff — and write commit messages that explain it

Read git diff output line by line, use flags that make changes easier to review, write commit messages that explain why, and share diffs clearly.

WorkflowBy the Codeshot team6 min read

Quick answer: In a git diff, lines starting with - were removed, lines starting with + were added, and lines starting with a space are unchanged context. Each @@ -14,7 +14,8 @@ header says where a change sits: in the old file, 7 lines starting at line 14; in the new file, 8 lines starting at line 14. The diff shows what changed — the commit message is where you explain why.

Diffs and commit messages are how code changes are explained hundreds of times a day: in pull requests, code reviews, changelogs, incident write-ups and "here's what we shipped" posts. Reading diffs fluently makes you a faster reviewer; presenting them well makes your changes easier to approve.

Anatomy of a unified diff

Here is the output of git diff for a small bug fix:

diff --git a/src/cart.ts b/src/cart.ts
index 3b18e51..a1c9f02 100644
--- a/src/cart.ts
+++ b/src/cart.ts
@@ -14,7 +14,8 @@ export function total(items: Item[]) {
   let sum = 0;
   for (const item of items) {
-    sum += item.price;
+    // price is per unit, so multiply by quantity
+    sum += item.price * item.quantity;
   }
   return sum;
 }

Line by line:

Line Meaning
diff --git a/src/cart.ts b/src/cart.ts The file being compared: a/ is the old version, b/ the new one
index 3b18e51..a1c9f02 100644 Abbreviated hashes of the old and new file contents, and the file mode (100644 is a regular, non-executable file)
--- a/src/cart.ts / +++ b/src/cart.ts Which side is "minus" and which is "plus"
@@ -14,7 +14,8 @@ The hunk header: old file from line 14 for 7 lines, new file from line 14 for 8 lines
export function total(...) after @@ Git's guess at the enclosing function, for context
Lines starting with a space Unchanged context
Lines starting with - Removed
Lines starting with + Added

A hunk is one contiguous block of changes with its surrounding context. A diff of a large change contains many hunks, possibly across many files.

Special cases you will see

  • New file: --- /dev/null and new file mode 100644; every line starts with +.
  • Deleted file: +++ /dev/null; every line starts with -.
  • Renamed file: rename from and rename to lines, plus a similarity index percentage.
  • Binary file: Binary files a/logo.png and b/logo.png differ — git does not show the content.
  • \ No newline at end of file: the last line has no trailing newline; often the only "change" when editors disagree.

git diff commands every reviewer should know

Command What it shows
git diff Unstaged changes in your working tree
git diff --staged Changes staged for the next commit
git diff main...feature What feature changed since it branched from main
git show <commit> A single commit's message and diff
git diff --stat A summary of files changed and lines added/removed
git diff -w Ignores whitespace changes, so re-indentation does not drown real edits
git diff --word-diff Highlights changed words instead of whole lines — ideal for prose and long lines
git diff -U10 Shows 10 lines of context instead of the default 3
git diff --color-moved Colors moved blocks differently from genuinely new code
git log -p path/to/file The history of a file, with each commit's diff

The full list of options is in the official git diff documentation.

How to review a diff efficiently

  1. Read the description first. Know what the change is supposed to do before you read how it does it.
  2. Start with --stat. See which files changed and where the bulk of the change is.
  3. Find the core change. Usually one or two files hold the real logic; the rest is wiring, tests and renames.
  4. Read the tests. They tell you what behavior the author intended and which cases they considered.
  5. Hide the noise. Use -w for whitespace and --color-moved for moved code.
  6. Check what is missing. Error handling, documentation, migrations and tests for edge cases rarely show up as red flags in a diff — because they are not there.

Make your own diffs easy to review

  • One logical change per commit. Mixing a refactor with a bug fix forces reviewers to untangle them. Split them.
  • Separate formatting from behavior. Reformatting a file in the same commit as a logic change hides the logic change. Commit the formatting on its own.
  • Keep pull requests small. Smaller changes get faster and more careful reviews.
  • Rename in a separate commit. A pure rename shows up as a clean rename from/rename to instead of a full delete and re-add.
  • Point reviewers to the core change in the pull request description when the change touches many files.

How to write a good commit message

The diff already shows what changed. The commit message is the only place to record why — the bug, the constraint, the trade-off. Months later, git blame will lead someone to your commit, and the message is all they get.

A widely used structure:

Fix cart total ignoring item quantity

total() added each line item's unit price once, so a cart with
three €10 items showed €10 instead of €30. Multiply by quantity
and add a regression test for multi-quantity carts.

Fixes #482
  • Subject line: imperative mood ("Fix", "Add", "Remove"), about 50 characters, no trailing period. Read it as "If applied, this commit will… fix cart total ignoring item quantity."
  • Blank line, then a body wrapped at about 72 characters.
  • The body explains the problem and the reasoning, not a narration of the diff.
  • References to issues or tickets at the end.

The 50/72 convention exists because many git tools — git log --oneline, email patches, GitHub's commit list — truncate or wrap at those widths.

Conventional Commits

Many teams use Conventional Commits, which prefixes each subject with a type:

fix(cart): include quantity in total
feat(api): add idempotency keys to invoice creation
docs: document rate-limit headers

The structure lets tools generate changelogs and choose semantic version numbers automatically. Whichever convention you pick, consistency across the repository matters more than the specific format.

Sharing a diff outside the repository

In changelogs, blog posts, talks and social posts, readers have no diff viewer and less patience. A focused, styled diff communicates "before and after" instantly.

  • Show only the interesting hunk — usually 3 to 15 lines.
  • Keep the file path visible so readers know where the change lives.
  • Keep the + and - markers. They make the diff readable for color-blind readers and in grayscale.
  • Add a one-sentence takeaway: "One missing multiplication was undercounting multi-item carts."
  • For a release announcement, a single styled commit — hash, author, date and message — can be the whole story.

When the structure of the code changed significantly, two separate before-and-after snippets are often clearer than a diff, because readers can study each version as a whole.

The git diff image generator colors added and removed lines, hunk headers and file paths, and the git commit image tool styles the hash, author, date and message for release notes and launch posts. For general snippet-sharing advice, see the code screenshot best practices.

Frequently asked questions

What does @@ mean in git diff?

It marks a hunk header. @@ -14,7 +14,8 @@ means the hunk covers 7 lines starting at line 14 in the old file and 8 lines starting at line 14 in the new file. Text after the second @@ is the enclosing function or section, shown for context.

What do + and - mean in git diff?

A line starting with + was added in the new version, a line starting with - was removed, and a line starting with a space is unchanged context shown to help you place the change.

How do I ignore whitespace in git diff?

Use git diff -w (or --ignore-all-space) to ignore all whitespace differences, or git diff -b to ignore only changes in the amount of whitespace.

How long should a git commit subject line be?

About 50 characters, written in the imperative mood, with no trailing period. Wrap the body at about 72 characters. Many git tools display commit subjects at these widths.

How do I see what changed in a single commit?

Run git show <commit-hash>. It prints the commit's message followed by its diff. Add --stat for a summary of changed files.

Related guides