diff — compare files line by line

Two files, one truth: the exact lines that differ.

Every git diff you have ever read is this command wearing a costume. Learn the original and the unified format stops being a mystery of line numbers and becomes a sentence you can read aloud.

What it does

diff compares two files (or entire directory trees with -r) line by line and prints just the differences. Two files that match produce no output. When they differ, diff shows the offending lines: a line added on one side, removed on the other, or changed — each prefixed with < for the first file and > for the second. Its exit status is a truth machine: 0 means identical, 1 means different, 2 means trouble. That exit code is what makes diff usable inside shell scripts and is the whole reason git, patch, and every CI pipeline lean on it.

Why it matters

diff is the answer to the oldest sysadmin question: 'what changed, and where?' You point it at two nginx configs, two versions of a deploy script, two directories before and after a release, and diff tells you the exact lines. Its sibling patch can then apply those differences to other copies of the original for you. Master diff's exit code and the -r and -q flags and you stop eyeballing files side by side — the machine does the scanning.

Examples

diff nginx-old.conf nginx-new.conf
4a5
>     server_tokens off;

Normal diff. '4a5' reads 'after line 4 of file 1, add the line that is line 5 of file 2'. < means from the first file, > from the second. Exit code is 1 because the files differ.

diff -r /tmp/d1 /tmp/d2
Only in /tmp/d1: extra.txt
Only in /tmp/d2: other.txt
diff -r /tmp/d1/sub/config /tmp/d2/sub/config
2c2
< line2
---
> line2 changed

-r recurses into directories, reporting files present in only one tree and recursing into the ones that exist on both. This is the go-to check before and after a deploy.

diff -q nginx-old.conf nginx-new.conf
Files nginx-old.conf and nginx-new.conf differ

-q (brief) prints only a yes/no, making it perfect for shell scripts: if diff -q a.txt b.txt; then echo same; else echo diff; fi — no noise to parse.

diff -y nginx-old.conf nginx-new.conf
server {							server {
    listen 80;							    listen 80;
    server_name example.com					    server_name example.com;
    root /var/www/html						    root /var/www/html;
							      >	    server_tokens off;
}								}

-y prints both files side by side with a > marker where they diverge. Great for a quick eyeball on short configs.

Flags

FlagMeaning
-uunified format with context lines — the git-diff style; best for humans and patch
-q / --briefreport only whether files differ, used in scripts to test equality
-ssay when files are IDENTICAL (default is silence on a match)
-rrecursively compare matching files inside two directories
-yside-by-side output in two columns instead of a change list
-Ntreat files missing from one side as empty, so additions show as content not 'only-in'
-x PATTERNexclude files matching a pattern when recursing (e.g. -x '*.log')

Origin

diff was written by Douglas McIlroy at Bell Labs and first shipped in the fifth edition of Unix (1974). McIlroy headed the lab's computing research and had a knack for small tools that composed — diff was the template for the whole 'compare two things' genre, and it spawned patch, sdiff, and the format that still powers version control today.

The unified revolution

The default diff format (the 4a5 / 2c2 you see by default) is terse and hard to read. In 1990 Wayne Davison designed the unified format — the -u you now reach for reflexively — which folds removals and additions into one run of context lines. It was so obviously better that it became the de facto standard, and it is exactly what git diff, GitHub, and every code-review tool print today.

Fun facts

Pros

Cons

Takeaways