Understanding Diff Formats: A Developer’s Guide to Making Sense of Changes
Shrijith Venkatramana

Shrijith Venkatramana @shrsv

About: Founder @ hexmos.com

Joined:
Jan 4, 2023

Understanding Diff Formats: A Developer’s Guide to Making Sense of Changes

Publish Date: Jul 14
7 1

Hi there! I'm Shrijith Venkatrama, founder of Hexmos. Right now, I’m building LiveAPI, a first of its kind tool for helping you automatically index API endpoints across all your repositories. LiveAPI helps you discover, understand and use APIs in large tech infrastructures with ease.

Diff formats are the backbone of tracking code changes in development. Whether you're debugging, reviewing pull requests, or collaborating on a project, understanding how diffs work is critical. This post dives into the various diff formats, with a focus on Git's diff output, explaining their structure, use cases, and practical examples. We'll break it down into digestible chunks, complete with code examples you can run and tables to clarify key points.

What Is a Diff, Anyway?

A diff (short for difference) is a way to show changes between two versions of a file or set of files. It highlights what’s been added, removed, or modified. Diffs are used everywhere—version control systems like Git, code reviews, and even simple file comparisons. The goal? Make it easy to spot changes without manually comparing every line.

Think of a diff as a snapshot of edits. Each format presents this snapshot differently, balancing readability and detail. Let’s explore the main types, starting with the simplest.

Key point: Diffs are essential for collaboration and auditing changes in codebases.

The Classic Unified Diff Format

The unified diff format is the most common, used by Git, diff -u, and many code review tools. It’s compact, showing both old and new versions of changed lines in a single block, with context lines for clarity.

How It Works

  • Lines starting with - are removed.
  • Lines starting with + are added.
  • Lines without prefixes are unchanged (context).
  • A hunk header like @@ -3,5 +3,6 @@ shows the line numbers and counts for old and new files.

Example

Create two files, old.txt and new.txt:

# old.txt
Hello, world!
This is a test.
Line three here.
Goodbye.

# new.txt
Hello, world!
This is a new test.
Line three here.
Added this line.
Goodbye.
Enter fullscreen mode Exit fullscreen mode

Run diff -u old.txt new.txt:

--- old.txt
+++ new.txt
@@ -1,4 +1,5 @@
 Hello, world!
-This is a test.
+This is a new test.
 Line three here.
+Added this line.
 Goodbye.
Enter fullscreen mode Exit fullscreen mode

Output explanation:

  • Line 2 changed from This is a test. to This is a new test..
  • A new line (Added this line.) was added after line 3.
  • Context lines (Hello, world!, Line three here., Goodbye.) help orient you.

Why it’s great: Unified diffs are readable and widely supported. Most tools, like GitHub, display diffs this way.

Learn more: GNU Diffutils Documentation

Context Diff Format: The Older Cousin

The context diff format (diff -c) is an older alternative to unified diffs. It’s less common today but still supported by tools like patch. It includes more verbose context, showing separate blocks for old and new file versions.

Structure

  • Old file lines are prefixed with ***.
  • New file lines are prefixed with ---.
  • Hunk headers show line ranges for both files.

Example

Using the same old.txt and new.txt, run diff -c old.txt new.txt:

*** old.txt
--- new.txt
***************
*** 1,4 ****
  Hello, world!
! This is a test.
  Line three here.
  Goodbye.
--- 1,5 ----
  Hello, world!
! This is a new test.
  Line three here.
+ Added this line.
  Goodbye.
Enter fullscreen mode Exit fullscreen mode

Output explanation:

  • The ! marks changed lines.
  • The + marks added lines.
  • Context lines are shown for both files, making it slightly bulkier than unified.

Use case: Context diffs are useful for tools requiring explicit old/new separation, but they’re less concise.

Link: Context Diff Format Specs

Normal Diff: The Bare-Bones Option

The normal diff format (diff without flags) is the simplest but least readable. It only shows changed lines without context, making it hard to use for large files.

Example

Run diff old.txt new.txt:

2c2
< This is a test.
---
> This is a new test.
3a4
> Added this line.
Enter fullscreen mode Exit fullscreen mode

Output explanation:

  • 2c2 means line 2 changed in both files.
  • < shows the old line, > shows the new line.
  • 3a4 means a line was added after line 3, now at line 4.

Why it’s limited: No context makes it hard to understand changes in larger files. Rarely used in modern workflows.

Git Diff: The Developer’s Workhorse

Git diff builds on the unified diff format but adds Git-specific metadata, like commit hashes and file modes. It’s what you see when you run git diff to compare changes in your working directory or between commits.

Key Features

  • Shows file renames, mode changes, and binary file differences.
  • Includes Git-specific headers like index and commit info.
  • Supports color output for readability (enable with git diff --color).

Example

Create a Git repo and modify a file:

# Initialize repo
mkdir myrepo && cd myrepo && git init
echo -e "Line 1\nLine 2\nLine 3" > file.txt
git add file.txt && git commit -m "Initial commit"

# Modify file.txt
echo -e "Line 1\nLine 2 modified\nLine 3\nLine 4" > file.txt

# Run git diff
git diff
Enter fullscreen mode Exit fullscreen mode

Output:

diff --git a/file.txt b/file.txt
index 1234567..abcdefg 100644
--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,4 @@
 Line 1
-Line 2
+Line 2 modified
 Line 3
+Line 4
Enter fullscreen mode Exit fullscreen mode

Output explanation:

  • diff --git a/file.txt b/file.txt: Shows the file being compared.
  • index 1234567..abcdefg 100644: Git’s internal file hashes and mode.
  • The rest is unified diff format, showing the change to line 2 and addition of line 4.

Pro tip: Use git diff --cached to see staged changes.

Link: Git Diff Documentation

Side-by-Side Diff: Visual Clarity

The side-by-side diff format (e.g., diff -y) displays old and new versions in parallel columns, making it easier to compare visually. It’s great for quick scans but can be cluttered for large files.

Example

Run diff -y old.txt new.txt:

Hello, world!                            Hello, world!
This is a test.                        | This is a new test.
Line three here.                        Line three here.
                                        > Added this line.
Goodbye.                                Goodbye.
Enter fullscreen mode Exit fullscreen mode

Output explanation:

  • | indicates changed lines.
  • > indicates added lines.
  • < indicates removed lines.
  • Columns align old and new versions.

Use case: Great for manual reviews or when teaching diffs to beginners.

Inline Diff: Git’s Word-Level Precision

Git’s inline diff (git diff --word-diff) highlights changes within lines, not just whole lines. It’s perfect for small edits, like fixing typos or tweaking a sentence.

Example

Using the same file.txt from the Git example, run:

git diff --word-diff
Enter fullscreen mode Exit fullscreen mode

Output:

diff --git a/file.txt b/file.txt
index 1234567..abcdefg 100644
--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,4 @@
 Line 1
-Line 2
+Line 2 {+modified+}
 Line 3
 {++Line 4++}
Enter fullscreen mode Exit fullscreen mode

Output explanation:

  • {+text+} shows added words.
  • {-text-} shows removed words.
  • Only changed words are highlighted, making it precise.

Why it’s useful: Ideal for reviewing small, granular changes.

Patch Files: Diffs That Do Work

A patch file is a diff (usually unified) that can be applied to update files using the patch command or git apply. It’s a portable way to share changes.

Example

Save a unified diff as changes.patch:

diff -u old.txt new.txt > changes.patch
Enter fullscreen mode Exit fullscreen mode

Apply it:

cp old.txt temp.txt
patch temp.txt < changes.patch
Enter fullscreen mode Exit fullscreen mode

Output (contents of temp.txt after patching):

Hello, world!
This is a new test.
Line three here.
Added this line.
Goodbye.
Enter fullscreen mode Exit fullscreen mode

Key point: Patch files are critical for sharing changes outside Git, like in email-based workflows.

Link: GNU Patch Manual

Comparing Diff Formats: Which to Use When?

Here’s a table summarizing the formats:

Format Command Pros Cons Best For
Unified Diff diff -u Compact, widely supported Less verbose than context Code reviews, Git, most tools
Context Diff diff -c Clear old/new separation Verbose, less common Legacy tools, patch files
Normal Diff diff Simple, minimal output No context, hard to read Quick checks, small files
Git Diff git diff Git metadata, color support Git-specific Git workflows, PRs
Side-by-Side Diff diff -y Visual clarity Cluttered for large files Manual reviews, teaching
Inline Diff git diff --word-diff Word-level precision Less clear for large changes Small edits, documentation

Key point: Choose the format based on your tool and task. Unified and Git diffs are the most versatile.

Tips for Working with Diffs in Practice

  • Use color: Enable color in Git (git config --global color.ui auto) for better readability.
  • Filter noise: Use git diff --ignore-space-change to ignore whitespace changes.
  • Visual tools: Tools like Meld or VS Code’s diff viewer enhance readability.
  • Test patches: Always test patch files before sharing to avoid errors.
  • Break down large diffs: Split changes into smaller commits for easier reviews.

Diffs are a developer’s best friend for understanding and communicating code changes. By mastering these formats, you’ll navigate code reviews, debugging, and collaboration with ease. Pick the right format for your task, and you’ll save a ton of time.

Comments 1 total

  • victory
    victoryJul 19, 2025

    Quite a complex topic, well explained! 🫡

Add comment