What Is Git Diff? How to Compare File Changes

Summarize this article with:
Every commit you make tells a story. But without checking what actually changed, you are committing blind.
That is exactly what git diff solves. It is the command that shows you line-by-line differences between files, branches, commits, and your version control staging area. Whether you are reviewing your own work before a commit or comparing two branches during a code review, git diff gives you the full picture.
This guide covers how git diff works, how to read its output, and how to use its most practical flags and options. You will also learn how it compares to related commands like git log and git show, and where visual diff tools fit into everyday workflows.
What is Git Diff

Git diff is a command that shows the differences between two data sources inside a Git repository. It compares files line by line, marking what was added, removed, or left unchanged.
The command works across multiple reference points. You can compare your working directory against the staging area, the staging area against your last commit, or two entirely separate branches and commits. When you run git diff with no arguments, it defaults to showing unstaged changes, meaning everything you have modified but not yet added with git add.
Linus Torvalds built Git in 2005 to manage Linux kernel development. The diff functionality was baked in from day one because tracking code changes across thousands of contributors was the whole point.
According to RhodeCode, Git adoption among developers rose from 87.1% in 2016 to 93.87% in 2025. That means almost every developer using version control is running git diff (or some visual wrapper around it) as part of their daily workflow.
The output follows the unified diff format, which is a standard that predates Git itself. It originated from the Unix diff utility and was later adopted by GNU diff. Git kept this format because it was already familiar to most developers working on open-source projects.
What makes git diff different from simply eyeballing file changes is precision. It does not just tell you that a file changed. It tells you exactly which lines changed, what the old content was, and what the new content is. That level of detail matters when you are reviewing changes before a commit or trying to understand what a teammate modified in a pull request.
How Git Diff Output Works

Reading git diff output feels tricky at first. Once you understand the structure, though, it becomes second nature.
Every diff block starts with a header. The first line looks something like diff --git a/file.txt b/file.txt, which just tells you which file is being compared. The a/ prefix represents the old version and b/ represents the new one.
Below that, you will see an index line showing abbreviated commit hashes and the file mode. Then come the --- and +++ lines, which label the old and new versions of the file respectively.
Line markers work like this:
- Lines starting with
+were added - Lines starting with
-were removed - Lines with no prefix are context lines (unchanged code shown for reference)
By default, Git shows three context lines around each change. You can adjust this with the -U flag if you need more or less surrounding code for clarity.
Diff Hunks and Line Ranges
Each block of changes is called a “hunk.” Hunks are marked by lines that start with @@.
A typical hunk header looks like @@ -12,8 +12,9 @@. The -12,8 means the old file shows 8 lines starting at line 12. The +12,9 means the new file shows 9 lines starting at the same position. So one line was added in this section.
When a single file has changes in multiple places, you will see multiple hunks separated by their own @@ headers. Took me a while to figure out that these are independent sections, not a continuous block. Each hunk is its own little window into the change.
GitClear analyzed 12,638 pull requests in 2024 and found that improved diff algorithms could reduce the number of lines a reviewer needs to read by more than 20%, compared to the default Myers algorithm that Git uses.
Git Diff Between Working Directory, Staging Area, and Commits

This is where most people actually use git diff, and it is also where the confusion starts.
Git tracks files across three main areas: your working directory (the actual files on disk), the staging area (what you have marked for the next commit), and the repository itself (your committed history). The diff command lets you compare any two of these.
| Command | What It Compares | When to Use It |
|---|---|---|
git diff | Working directory vs. staging area | See what you changed but have not staged yet |
git diff --staged | Staging area vs. last commit | Review what is about to be committed |
git diff HEAD | Working directory vs. last commit | See all local changes, staged or not |
The --staged flag (also called --cached, they do the same thing) is the one people forget about. You have already run git add on your files, and now you want to double-check what is queued up before you actually commit. That is what git diff --staged is for.
A SonarSource survey found that developers spend only 32% of their time writing or modifying code. The rest goes to maintenance, testing, and operational tasks. Running diff commands before each commit is one of those small habits that keeps the 68% from ballooning.
If you are wondering which one to use, think of it this way. Just typed git add . and want to verify? Use --staged. Still editing and want to see what you have touched? Plain git diff. Want the full picture of everything, staged or not? git diff HEAD.
Comparing Branches and Commits with Git Diff

Comparing across branches is where git diff really earns its keep. Especially during code reviews or before merging feature work.
The basic syntax is git diff branch1..branch2. This compares the tip of branch1 against the tip of branch2. You can also swap in SHA hashes directly: git diff abc123 def456.
According to Hutte’s research, nearly 90% of developers have faced merge conflicts at some point. Running a diff between branches before attempting a merge is one of the simplest ways to spot conflicts early and plan your resolution strategy.
Double-Dot vs. Triple-Dot Diff
This trips people up constantly, and honestly the naming does not help.
Double-dot (..): Compares the tips of two branches directly. You get every difference between the current state of branch A and the current state of branch B. Useful for seeing the total delta between two branches right now.
Triple-dot (...): Compares the tip of branch B against the common ancestor (the merge base) of both branches. This shows only the changes that branch B introduced since the two branches diverged. Much more useful during code review because you are not looking at everything, just what the feature branch actually changed.
Most developers I have worked with default to double-dot and then wonder why the diff looks so noisy. If you are reviewing someone’s feature branch, triple-dot is almost always what you want.
A study published in the Journal of Systems and Software (2024) examined 143 open-source projects and found that 19.32% of merge commits resulted in conflicts. Running git diff main...feature-branch before merging helps you anticipate those conflicts instead of stumbling into them.
Common Git Diff Options and Flags

Plain git diff output is fine for small changes. But when you are dealing with dozens of modified files or need a quick summary, the flags make a big difference.
–stat: Shows a summary of changed files with line counts instead of the full diff. I run this before pretty much every commit to get a quick sense of scope.
–name-only: Lists just the filenames that changed. Nothing else. Handy for scripting or piping into other commands.
–name-status: Like --name-only but adds a letter prefix showing the type of change: M for modified, A for added, D for deleted, R for renamed.
–word-diff: Compares changes at the word level instead of full lines. This is a lifesaver for documentation or content files where small text edits get buried in line-level diffs.
–color-words: Similar to word-diff but renders the output inline with color. Makes word-level changes much easier to scan visually.
GitHub’s Octoverse 2025 report revealed that developers pushed nearly 1 billion commits in 2025 alone, a 25% increase year-over-year. With that volume of changes flowing through repositories, these flags become more than convenience. They become a way to stay sane.
| Flag | Output Type | Best For |
|---|---|---|
--stat | File summary with line counts | Quick commit scope check |
--name-only | File names only | Scripts and automation |
--word-diff | Word-level inline comparison | Docs and content files |
--no-index | Full diff between any two files | Comparing files outside Git |
The --no-index flag deserves a special mention. It lets you use git diff to compare any two files on your system, even if they are not inside a Git repository at all. Useful when you need a quick diff and do not want to install a separate tool.
Git Diff for Specific Files and Directories
You do not always want to see every change across an entire repository. When a project has hundreds of files, an unscoped git diff produces a wall of output that is hard to parse.
Narrowing the diff to a specific file path is straightforward: git diff -- path/to/file.js. The double dash (--) separates the command options from the file path. You can skip it most of the time, but it prevents confusion if your filename could be mistaken for a flag or branch name.
You can also diff entire directories. Running git diff -- src/components/ will show changes only inside that folder. This is useful on large codebases where different teams own different parts of the repository.
Combining path filters with branch or commit comparisons works too:
git diff main..feature -- src/api/shows only API directory changes between branchesgit diff HEAD~3 -- config.ymlcompares the config file against three commits agogit diff --stat -- "*.css"gives a summary of changes to all CSS files
Stack Overflow’s 2024 Developer Survey collected responses from 65,437 developers across 185 countries. Among the findings, the heavy reliance on command-line Git workflows persists, with path-scoped diffs being one of the most common operations in larger projects.
Glob patterns work in most shells, but your mileage may vary depending on the operating system. On Windows, you might need to quote the patterns differently than on Linux or macOS. If you are working across platforms, consider using a .gitignore file to keep unwanted files from cluttering your diffs in the first place.
Git Diff with Binary Files

Git was built for text. Binary files are where it gets awkward.
When you run git diff on an image, a PDF, or a compiled binary, Git just tells you “Binary files differ.” No line-by-line comparison, no added or removed content. Just a flat statement that something changed.
This happens because binary data has no line structure. Git’s diff algorithm works by comparing text line by line. When it cannot find readable lines, it gives up and flags the file as binary. For teams working in game development, design, or any project that includes media assets alongside code, this is a real limitation.
Options for getting more out of binary diffs:
--binaryflag generates a binary patch that can be applied withgit apply, but it is not human-readable- Custom textconv filters in
.gitattributesconvert binary files to text before diffing - Tools like
exiftool(for images) orpandoc(for documents) can act as textconv drivers
The textconv approach is the one worth knowing. You define a filter in your Git config that converts the binary into a text representation, and then Git diffs that text output instead. For PDFs, this might mean extracting the raw text content. For images, it could mean comparing EXIF metadata.
Perforce notes that every modification to a binary file stores the entire file again in the repository, unlike text files where Git only stores the delta. This is why repositories that track lots of binary assets bloat quickly.
Git Large File Storage (LFS) helps with the storage problem by replacing binary files with lightweight pointer files in the repository. But even with LFS, git diff still cannot meaningfully compare two versions of an image or a 3D model. For that, you need external comparison tools specific to the file type.
Git Diff in GUI Tools and Editors

Not everyone wants to read diffs in the terminal. And honestly, for large changesets, a visual side-by-side comparison is just faster to scan.
Git ships with git difftool, a command that opens an external visual diff application instead of printing output to the console. It accepts the same arguments as git diff, so you can compare branches, commits, or specific files the same way.
Stack Overflow’s 2025 Developer Survey shows VS Code at 75.9% usage among developers, making it the most common environment where people interact with Git diffs visually. Its built-in source control panel highlights changed lines directly in the editor, and the side-by-side diff view is available with one click.
| Tool | Type | Diff Display |
|---|---|---|
| VS Code | Editor with built-in Git | Inline and side-by-side |
| Beyond Compare | Standalone diff tool | Side-by-side with folder sync |
| Meld | Open-source diff viewer | Two and three-way merge |
| KDiff3 | Open-source diff/merge | Three-way with auto-merge |
To configure an external diff tool, set it in your Git config: git config --global diff.tool vscode. Then run git difftool instead of git diff whenever you want the visual version.
Pull request interfaces on GitHub, GitLab, and Bitbucket also show diffs visually. These web-based views add features like inline commenting, which makes them the default way most teams review code changes before merging branches.
GitHub’s Octoverse 2025 report shows monthly pull request merges averaged 43.2 million, a 23% year-over-year increase. Every one of those pull requests involved reviewing a diff in some form.
Git Diff vs. Git Log and Git Show

These three commands overlap just enough to confuse people who are still getting comfortable with Git commands.
The short version: git log shows commit history. Git diff shows content differences. git show does a bit of both for a single commit.
| Command | What It Shows | Primary Use |
|---|---|---|
git log | List of commits (author, date, message) | Browsing project history |
git diff | Line-level differences between two states | Comparing changes before commit or merge |
git show | Single commit’s metadata + its diff | Inspecting what one specific commit changed |
git show is basically a shortcut. It takes a commit hash and displays the commit message followed by the diff against that commit’s parent. So git show abc123 tells you both what the commit says it did and what it actually changed.
Where things get interesting is git log -p. Adding the -p flag to log output appends a full diff to each commit in the history. It is like combining git log and git diff into a single output stream. Useful when you need to trace how a specific file changed over multiple commits.
GitHub reported over 5 billion contributions across repositories in 2024. At that scale, knowing which command to reach for (log for history, diff for comparison, show for a single commit) saves real time over guessing.
Practical Uses of Git Diff in Development Workflows
Knowing the syntax matters less than knowing when to actually use it. Here is where git diff fits into daily development work.
Pre-Commit Review
Running git diff --staged before every commit is the simplest quality check available. It takes seconds and catches leftover debug statements, accidental whitespace changes, or files you did not intend to include.
Hutte research indicates that 95% of projects run tests or checks before commits, either manually or through automation. A quick diff review is the most basic version of that habit.
Generating and Applying Patches
Patch workflow: git diff > changes.patch creates a file containing your changes in unified diff format. Someone else can apply it with git apply changes.patch.
This is still used in open-source projects where contributors do not have push access to the main repository. The Linux kernel, which Linus Torvalds manages with Git, still accepts patches through mailing lists in some cases.
The Linux kernel recorded 75,314 commits in 2024, with corporate developers accounting for 84.3% of all changes, according to Command Linux.
Comparing Releases and Tags
Running git diff v1.0..v2.0 shows every change between two tagged releases. Piping that output into other tools gives you quick analytics.
git diff v1.0..v2.0 --statfor a file-level summarygit diff v1.0..v2.0 | grep "^+" | wc -lfor a rough count of added lines
Teams that follow semantic versioning use this to generate changelogs or audit what went into a specific release. It is also useful during regression testing, when you need to know exactly what code changed between a stable version and a broken one.
CI/CD and Automation
Git diff output feeds directly into continuous integration pipelines. Some teams use git diff --name-only to determine which services or modules were affected by a commit, then run only the relevant test suites.
GitHub Actions workflows climbed to over 5 million daily in 2025, up from 4 million the year before, with a 50% increase in continuous deployment usage, according to CoinLaw’s GitHub statistics report. Many of those workflows include diff-based logic to decide what gets built and deployed.
Netflix, for one, has long used diff-based change detection in their build pipelines to avoid rebuilding services that were not actually modified in a commit.
FAQ on What Is Git Diff
What does git diff actually do?
Git diff compares two data sources in a repository and shows the differences line by line. It marks added lines with +, removed lines with -, and displays unchanged context lines around each change for reference.
What is the difference between git diff and git diff –staged?
Running git diff alone shows unstaged changes in your working directory. Adding --staged (or --cached) compares the staging area against your last commit, showing what is queued up for the next commit.
How do I compare two branches using git diff?
Use git diff branch1..branch2 to compare the tips of two branches directly. For reviewing only what a feature branch introduced since diverging, use the triple-dot syntax: git diff branch1...branch2.
Can git diff compare specific files instead of the entire repository?
Yes. Append the file path after a double dash: git diff -- path/to/file.js. This scopes the output to that single file. You can also use glob patterns or directory paths to filter results further.
Why does git diff show “Binary files differ” for some files?
Git’s diff algorithm is line-based and only works with text. Binary files like images, PDFs, and compiled code have no line structure, so Git cannot produce a meaningful comparison. Custom textconv filters can help extract readable data.
How do I read the @@ lines in git diff output?
The @@ markers are hunk headers. A line like @@ -12,8 +12,9 @@ means the old file shows 8 lines starting at line 12, while the new file shows 9 lines from the same position.
What is the difference between git diff and git show?
Git diff compares two states, like your working directory against the staging area or two commits against each other. Git show displays a single commit’s metadata and its diff against its parent commit.
How do I use git diff with a visual tool instead of the terminal?
Configure an external tool with git config --global diff.tool, then run git difftool. Popular options include VS Code, Beyond Compare, Meld, and KDiff3. Each offers side-by-side comparison that is easier to scan.
Can I generate a patch file from git diff output?
Yes. Run git diff > changes.patch to save the diff output to a file. Someone else can apply those changes with git apply changes.patch. This is common in open-source projects where contributors lack direct push access.
Does git diff work with commits from different points in history?
It does. Use git diff commit1 commit2 with SHA hashes to compare any two commits. You can also reference commits using HEAD notation, like git diff HEAD~3 HEAD, to compare against three commits ago.
Conclusion
Understanding what is git diff comes down to one thing: knowing exactly what changed in your code before you act on it. Every commit, every merge, every pull request benefits from that clarity.
The command handles everything from quick unstaged change checks to full branch comparisons and patch generation. Pair it with flags like –stat, –word-diff, or –name-only`, and you have a flexible tool that fits into any part of your workflow.
Whether you run diffs in the terminal, through a dedicated IDE, or inside a pull request interface on GitLab or Bitbucket, the core skill is the same. Learn to read the unified diff format, understand hunk headers, and use the right comparison mode for the situation.
Git diff is not flashy. But it is one of those source control habits that quietly prevents bugs, speeds up code reviews, and keeps your commit history clean.







