guide/read-unified-diff.md

How to Read a Unified Diff (Patch) — A Guide for Code Review

Walk through git diff and patch files with examples: the --- and +++ headers, the numbers in @@ hunk headers, context lines, the No newline at end of file marker, and diff --git extended headers.

Last updated: 2026-09-23

Most patches exchanged in code review, bug reports, and email use the unified diff format. git diff, diff -u, and GitHub's "raw diff" all use it. It looks full of symbols at first, but the rules are simple.

Overall shape

diff --git a/greet.py b/greet.pyindex 3b18e51..a6f4c2d 100644--- a/greet.py+++ b/greet.py@@ -1,5 +1,6 @@ def greet(name):-    print("Hello " + name)+    message = f"Hello, {name}!"+    print(message)  def main():     greet("world")

From the top come the git extended headers, the file headers (---, +++), and then hunks (blocks starting with @@). One file can have several hunks, and one patch can contain several files.

File headers: --- and +++

The hunk header @@ -a,b +c,d @@

@@ -1,5 +1,6 @@ means "this shows 5 lines starting at line 1 of the old file, and 6 lines starting at line 1 of the new file".

If you count them yourself, the example above has 4 context lines (lines starting with a space): def greet(name):, a blank line, def main():, and greet("world"). The old line count is 4 context lines plus 1 - line = 5, and the new line count is 4 context lines plus 2 + lines = 6, so the header is -1,5 +1,6.

The three kinds of lines in the body

First characterMeaning
SpaceA context line present on both sides
-A line only in the old version (deleted)
+A line only in the new version (added)

The default context is 3 lines before and after each change (you can change it, e.g. git diff -U5). Context lines are used to find the right place when applying the patch. Even if line numbers are slightly off, patch shifts the position (offset) and applies it as long as the context matches.

An edit to a single line appears as a - line followed by a + line. The unified format has no separate symbol for "modified", so the trick is to read a run of - lines against the run of + lines below it.

\ No newline at end of file

@@ -1,2 +1,2 @@ host=example.com-port=8080\ No newline at end of file+port=8080

This marks that the line right above is the last line of the file and has no newline character at the end. In the example above, the content is the same, and only the new file gained a final newline. For more, see Line endings and invisible differences.

git extended headers

The lines after diff --git a/path b/path are extra information specific to git.

Tips for reviewing

  1. Look at the difference in line counts in the hunk header first to gauge the size of a change. -10,7 +10,30 means it grew by 23 lines.
  2. To filter out hunks where only whitespace changed, use git diff -w. This is especially useful for commits that mix indentation cleanup with real changes (Whitespace options).
  3. To see what changed within a line, use git diff --word-diff, or paste the diff into a tool that supports in-line highlighting, like this site.
  4. Before applying a patch, check that it applies cleanly with git apply --check file.patch. Outside a git repository, use patch -p1 --dry-run < file.patch.

Try it in this tool

The unified view of the Text Diff Checker shows a run of - lines followed by a run of + lines, in the same order as this format, and highlights the changed words within lines once more. The patch button in the result bar copies standard unified diff text, and the save button next to it downloads a diff.patch file. A patch created with all ignore options turned off can be applied to the original with patch -p1 or git apply.

Go to the text diff tool