Git Diff a File Between Branches: A Complete Guide
When you work with Git, comparing the same file across different branches is a frequent need—whether you’re reviewing a feature, preparing a merge, or troubleshooting a regression. Consider this: the command git diff a file between branches lets you see exactly what changed in that file without wading through unrelated modifications. This guide walks you through the concept, the syntax, practical examples, and best‑practice tips so you can confidently inspect file differences whenever you need It's one of those things that adds up..
You'll probably want to bookmark this section And that's really what it comes down to..
Why Compare a File Across Branches?
Branches isolate work, but eventually you must bring changes together. Before merging, you often want to know:
- What new lines were added to a specific file in the feature branch?
- Did someone accidentally overwrite a critical section?
- How does the current version of a configuration file differ from the baseline in
main?
Answering these questions with a focused diff saves time, reduces noise, and helps you make informed decisions about conflicts or code quality The details matter here. Turns out it matters..
Core Concept: The Three‑Dot Syntax
Git’s diff command can compare two commits, two branches, or a commit and the working tree. The most convenient way to git diff a file between branches uses the three‑dot notation:
git diff branchA...branchB -- path/to/file
branchA...branchBtells Git to find the merge base (the common ancestor) of the two branches and diff that ancestor against the tip ofbranchB.- Adding
-- path/to/filelimits the output to the single file you care about.
If you prefer an explicit two‑dot range, you can also write:
git diff branchA..branchB -- path/to/file
Here Git diffs the tip of branchA directly against the tip of branchB. The three‑dot form is usually safer because it ignores changes that happened on branchA after the merge base, focusing on what branchB introduced since the branches diverged.
Step‑by‑Step Examples
Assume you have two branches: main (the stable line) and feature/login (a new login flow). You want to see how src/auth/login.js changed in the feature branch.
1. Basic File Diff
git diff main...feature/login -- src/auth/login.js
Output shows lines prefixed with - (removed in the merge base) and + (added in feature/login). If the file is identical, Git returns nothing.
2. Viewing Only the File Names That Changed
Sometimes you just need confirmation that the file is part of the diff set:
git diff --name-only main...feature/login
Add the path filter if you want to limit the list:
git diff --name-only main...feature/login -- src/
3. Adding Context with --stat
A quick summary of insertions and deletions helps gauge the magnitude of change:
git diff --stat main...feature/login -- src/auth/login.js
Sample output:
src/auth/login.js | 27 +++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 5 deletions(-)
4. Ignoring Whitespace
Whitespace‑only changes can clutter the view. Use -w to ignore them:
git diff -w main...feature/login -- src/auth/login.js
5. Using a Diff Tool for Visual Comparison
If you prefer a side‑by‑side GUI, configure a diff tool (e.g., meld, vimdiff, vscode) and run:
git difftool main...feature/login -- src/auth/login.js
Git will launch the configured tool, presenting the file differences in a more readable format But it adds up..
6. Comparing Against the Merge Base Explicitly
Sometimes you want to see what the merge base itself looks like:
git merge-base main feature/login # returns the commit hash
git show :src/auth/login.js # view the file at the merge base
Then diff that version against the feature branch tip:
git diff feature/login -- src/auth/login.js
This approach mirrors the three‑dot behavior but gives you full control over the base commit And it works..
Practical Scenarios
Scenario A: Preparing a Pull Request
Before opening a PR, you run:
git diff main...feature/login -- src/components/
to verify that only the intended components changed. If you see unexpected modifications, you can amend commits or stash stray changes.
Scenario B: Tracking a Bug Regression
You suspect a regression was introduced in release/v2.In practice, 3. Compare the problematic file between the good tag `v2 Small thing, real impact..
git diff v2.2...v2.3 -- src/utils/api.js
Inspect the added/removed lines to locate the faulty logic And it works..
Scenario C: Aligning Configuration Files
Configuration often drifts between environments. To see how config/production.json differs from the template in main:
git diff main...env/staging -- config/production.json
Any divergence highlights environment‑specific overrides that may need consolidation Worth keeping that in mind. That's the whole idea..
Advanced Tips
-
Limit diff to recent commits – If you only care about the last n commits on a branch, combine
git logwithdiff:git diff main~5...feature/login -- src/auth/login.jsThis compares the file as it was five commits ago on
mainagainst the tip of the feature branch Simple, but easy to overlook.. -
Binary files – Git diff treats binary files as “different” without showing content. To see if a binary changed, use:
git diff --raw main...feature/login -- path/to/binary.binThe output includes a mode change indicator if the file’s SHA‑1 altered.
-
Detect renames – If a file was moved, add
-Mto detect renames:git diff -M main...feature/login -- src/old/util.js src/new/util. Git will show a rename entry instead of a delete/add pair. -
Ignore submodule changes – When working with submodules, add
--ignore-submodules=allto avoid noisy diffs:git diff --ignore-submodules=all main...feature/login -- .
Common Pitfalls and How to Avoid Them
| Pitfall | Symptom | Fix |
|---|---|---|
Forgetting the pathspec (-- file) |
Diff shows every changed file, overwhelming output | Always include -- path/to/file when you need a single file |
| Using two‑dot range incorrectly | Seeing changes that originated on the other branch | Prefer three‑dot (`branchA... |