Andrew Mercer
on this page
diff file1 file2                       # default format
diff -u old.conf new.conf              # unified format (what patches and git use)
diff -y --width=160 a b                # side by side
diff -w a b                            # ignore whitespace changes
diff -q dir1 dir2                      # only report which files differ
diff -qr dir1 dir2 | sort > diffs.txt  # recursive, sorted list of differences
diff -rq --exclude='.git' dir1 dir2

Across hosts

Process substitution runs a command on each side and compares the output without temporary files:

diff <(ssh user@host1 'cat /etc/fstab') <(ssh user2@host2 'cat /etc/fstab')
diff -b <(ssh host1 'ls -l /srv/app') <(ssh host2 'ls -l /srv/app')     # -b ignores changes in amount of whitespace

# One remote file against a local one
ssh host cat /etc/hosts | diff /etc/hosts -

To compare whole directory trees between hosts, checksum both sides first (find . -type f -exec sha256sum {} + | sort -k2) and diff the lists, or use rsync -avn as a dry run.

"The files differ but I can't see how"

Hidden differences are usually whitespace, tabs versus spaces, CRLF versus LF line endings, or non-printing characters. Reveal them:

cat -A file                    # $ marks line ends, ^I tabs, ^M carriage returns
diff <(cat -A a) <(cat -A b)

In vim, :set list shows tabs and end-of-line markers. Convert line endings with dos2unix.

Produce and apply patches with patch.