git
version control
software development
code comparison
commit diff

How to diff a commit with its parent

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Diffing a commit against its parent is one of the fastest ways to answer a very practical question: what did this commit actually introduce? It is useful in code review, incident analysis, release verification, and when you are trying to understand a historical change without reading an entire branch. The basic command is simple, but merge commits and root commits need slightly different handling.

For an ordinary commit, you can think of the diff as “parent state versus commit state.” Git gives you more than one command for that comparison, and choosing the right one depends on whether you want a patch, a summary, or a script-friendly result.

Diff a Normal Commit

For a regular single-parent commit, the explicit comparison is:

bash
COMMIT_SHA=3f8c2a1

git diff "$COMMIT_SHA"^ "$COMMIT_SHA"

That shows the exact patch introduced by the commit relative to its immediate parent. The ^ syntax means “first parent.” For a normal commit, there is only one parent, so this is the comparison most people want.

For interactive review, git show is even more convenient:

bash
git show "$COMMIT_SHA"

git show combines commit metadata and patch output, so it is great when you are reading history by hand. git diff parent commit is more explicit and often easier to compose into scripts or tooling.

Use Narrower Output When the Full Patch Is Too Much

You do not always need every changed line immediately. Git has lighter-weight views that help you scope the change first.

Changed file names only:

bash
git diff --name-only "$COMMIT_SHA"^ "$COMMIT_SHA"

Per-file summary statistics:

bash
git diff --stat "$COMMIT_SHA"^ "$COMMIT_SHA"

Limit the diff to a single path:

bash
git diff "$COMMIT_SHA"^ "$COMMIT_SHA" -- src/server/app.py

A good review flow is to start with file names, then look at the stats, then open the full patch. That sequence keeps the overall scope visible before you dive into details.

Merge Commits Need an Explicit Parent Choice

Merge commits are different because they have more than one parent. Before diffing one, inspect the parent list:

bash
MERGE_SHA=7ac91d0
git rev-list --parents -n 1 "$MERGE_SHA"

If you want to see what the merge introduced into the target branch, compare the merge commit with its first parent:

bash
git diff "$MERGE_SHA"^1 "$MERGE_SHA"

If you want to compare against the branch that was merged in, use the second parent:

bash
git diff "$MERGE_SHA"^2 "$MERGE_SHA"

This distinction matters a lot during review. The first-parent view usually answers the question most release engineers care about. The second-parent view is useful when you want to understand how the merge result differed from the topic branch tip.

Handle Root Commits in Scripts

A root commit has no parent, so commit^ is invalid. If you are automating commit inspection, guard that case explicitly.

bash
1COMMIT_SHA=$(git rev-parse HEAD)
2
3if git rev-parse "$COMMIT_SHA"^ >/dev/null 2>&1; then
4  git diff --name-only "$COMMIT_SHA"^ "$COMMIT_SHA"
5else
6  git show --root --stat "$COMMIT_SHA"
7fi

Using git show --root is a reasonable fallback because it tells Git to display the initial commit as a patch against an empty tree.

Practical Commands for Daily Work

A few small variations are worth remembering.

Show only commit names and patch headers in a compact form:

bash
git show --stat --summary "$COMMIT_SHA"

Inspect the last commit on the current branch:

bash
git diff HEAD^ HEAD

Review a commit while ignoring whitespace-only changes:

bash
git diff -w "$COMMIT_SHA"^ "$COMMIT_SHA"

These are not different concepts, just different views of the same parent-versus-commit comparison.

Common Pitfalls

The biggest mistake is using default parent syntax on a merge commit without thinking about which parent should be the baseline. That can answer the wrong question even though the command succeeds.

Another common problem is jumping straight into the full patch and missing the scope that --name-only or --stat would have shown faster.

A third issue appears in scripts that assume every commit has a parent. Root commits break that assumption and need a fallback path.

Summary

  • For a normal commit, use git diff commit^ commit or git show commit.
  • Start with --name-only or --stat when you want a faster overview.
  • For merge commits, choose the correct parent with ^1 or ^2.
  • Root commits need special handling because they have no parent.
  • Pick the diff view that matches the question you are trying to answer.

Course illustration
Course illustration

All Rights Reserved.