What is Git Diff
Git diff is a command that shows the differences between various states of a Git repository. It compares files, commits, branches, and working directory changes to reveal exactly what has been added, modified, or removed. Understanding git diff is fundamental to working with version control because it is the primary way developers inspect changes before committing, review code during pull requests, and investigate when and how code was modified. Every Git workflow, from solo projects to large team collaborations, relies on diff output at multiple stages.
At its core, git diff performs a line-by-line comparison between two versions of a file and presents the differences in a standardized format called unified diff. Lines that exist only in the old version are marked with a minus sign, lines that exist only in the new version are marked with a plus sign, and unchanged lines surrounding the changes provide context. This format is compact yet informative, showing you exactly what changed without requiring you to read the entire file. The unified diff format has been the standard for decades and is used not only by Git but by code review tools, patch files, and diff utilities across all platforms.
Git diff is more than just a comparison tool. It is the foundation of the code review process that keeps software quality high. When a developer creates a pull request, reviewers examine the diff to understand what changed, why it changed, and whether the changes are correct. Automated tools use diff output to annotate code coverage, highlight potential issues, and enforce coding standards on changed lines. A strong understanding of git diff makes you more effective as both a contributor and a reviewer, enabling you to communicate about code changes precisely and efficiently.
Basic Git Diff Commands
The most basic invocation of git diff with no arguments shows the differences between your working directory and the staging area, also called the index. This shows you unstaged changes: modifications you have made to tracked files that have not yet been added with git add. This is the diff you should review before staging, ensuring that every change you are about to stage is intentional and correct. It is common to discover unintended debug statements, temporary code, or accidental whitespace changes during this review.
To see changes that have been staged and are ready to be committed, use git diff with the staged flag. This shows the differences between the staging area and the last commit, revealing exactly what will be included in the next commit. Reviewing the staged diff before committing is a best practice that catches mistakes like accidentally staging unrelated files, forgetting to include a necessary change, or staging a file with merge conflict markers. Many developers make this review a habit before every commit.
Comparing your working directory to a specific commit shows all changes made since that commit, whether staged or unstaged. This is useful for reviewing the total scope of your work since you branched off or since the last release. You can also compare two specific commits by providing both commit hashes, which shows all changes introduced between those two points in the repository's history. This is valuable for understanding what changed in a release, investigating when a bug was introduced, or reviewing the complete history of a feature branch.
Git diff accepts file paths to limit the comparison to specific files or directories. Adding a path at the end of any git diff command restricts the output to changes in that file or directory. This is essential in large repositories where a full diff might contain hundreds of changed files but you only need to review changes in a specific module or directory. Combining path filters with branch or commit comparisons lets you answer targeted questions like what changed in the authentication module between these two releases.
Reading Diff Output
Unified diff output begins with a header for each changed file that identifies the old and new versions being compared. The header lines starting with three minus signs and three plus signs show the file paths, with the old version prefixed by a/ and the new version prefixed by b/. Between these headers, Git may show the file mode, index hash, and similarity information for renamed or moved files. Understanding these headers helps you quickly identify which files changed and whether any files were renamed or had their permissions modified.
The actual changes are organized into hunks, each introduced by a line starting with two at signs. The hunk header contains line numbers in the format of the starting line and count of lines shown for both the old and new versions of the file. This tells you exactly where in the file the changes occur, which is useful for navigating to the corresponding location in your editor. After the line numbers, Git often includes the name of the enclosing function or class as additional context, making it easier to orient yourself when reviewing changes in large files.
Within each hunk, lines prefixed with a minus sign have been removed, lines prefixed with a plus sign have been added, and lines with a leading space are unchanged context lines included to help you understand the surrounding code. Git shows three lines of context by default, which is usually enough to understand where the change occurs and what it affects. When a line has been modified rather than purely added or removed, it appears as a removal of the old line followed by an addition of the new line. Training your eye to scan for these plus and minus markers is the key skill in reading diff output quickly.
Color coding, enabled by default in modern Git terminals, significantly improves diff readability. Removed lines appear in red and added lines appear in green, with unchanged context lines in the default text color. Some configurations also highlight the specific characters within a line that changed, using inverse color or bold styling to draw your eye directly to the modification. If your terminal does not show colors, configuring Git's color output is one of the most impactful quality-of-life improvements you can make to your development environment.
Comparing Branches and Commits
Comparing two branches is one of the most common uses of git diff, especially when preparing or reviewing a pull request. Using the two-dot syntax between branch names shows you all the differences between the current state of both branches. However, this shows the absolute difference, which can include changes made to the base branch after you branched off. The three-dot syntax instead shows only the changes introduced on the second branch since it diverged from the first, which more accurately represents the changes a pull request would introduce.
Understanding the distinction between two-dot and three-dot diff is important for accurate code review. When a feature branch has been in development for a while, the main branch may have received many other changes. A two-dot diff between main and the feature branch shows these unrelated changes as well, making the diff larger and harder to review. The three-dot diff isolates just the feature branch's changes relative to the point where it branched from main, giving you a clean view of exactly what the feature branch introduces.
Comparing specific commits is useful for investigating the history of a particular change or debugging regressions. You can compare any two commits by specifying their hashes, short hashes, tags, or any other commit reference. This is often combined with git log and git bisect when tracking down the commit that introduced a bug. Once you have identified a suspicious commit range, diffing the boundary commits shows you exactly what code changed, helping you pinpoint the problematic modification.
Git also supports comparing commits across different files and directories using various flags. The stat flag shows a summary of changed files with insertion and deletion counts rather than the full line-by-line diff, giving you a high-level overview of a commit's scope. The name-only flag lists just the changed file paths, which is useful for scripting and automation. The diff-filter flag lets you show only files that were added, modified, deleted, or renamed. These options help you navigate large diffs by first getting an overview and then drilling into specific files of interest.
Advanced Diff Options
Word-level diff is one of the most useful advanced options for reviewing prose, documentation, or code with minor inline changes. By default, git diff operates at the line level, so changing a single word on a long line shows the entire line as removed and re-added. The word-diff option instead shows changes at the word level, highlighting exactly which words were added, removed, or modified. This makes reviewing documentation changes, comment updates, and variable renames dramatically easier because your eye is drawn directly to the meaningful change rather than having to scan the entire line.
Ignoring whitespace changes is essential when reviewing code after reformatting. If a commit changes indentation, converts tabs to spaces, or adjusts line wrapping, the standard diff will show nearly every line as changed even though the logic is untouched. Whitespace-ignoring flags filter out these cosmetic changes to reveal only the substantive modifications. Different flags offer different levels of whitespace sensitivity: you can ignore changes in the amount of whitespace, ignore all whitespace within lines, or ignore blank line changes, depending on how much noise you want to filter out.
The color-words option combines word-level diffing with color highlighting to produce extremely readable output for inline changes. Instead of showing entire lines with plus and minus prefixes, it shows the surrounding text in the default color with removed words in red and added words in green, all flowing naturally as readable text. This mode is ideal for reviewing changes to configuration files, documentation, and any content where the changes are granular modifications within lines rather than wholesale line additions or removals.
Diff algorithms can be changed to improve the quality of the output for certain types of changes. Git's default algorithm sometimes produces confusing output when code blocks are moved, duplicated, or when multiple adjacent hunks interact. The patience algorithm produces cleaner diffs by matching unique lines first, resulting in more intuitive groupings of changes. The histogram algorithm extends patience with better performance on large files. If you find that diffs frequently look confusing or group changes in unexpected ways, experimenting with alternative algorithms can significantly improve readability.
Using Online Diff Tools
Online diff tools provide a visual, side-by-side comparison interface that many developers find easier to review than command-line diff output. These tools display the old and new versions of a file in adjacent panels with corresponding lines aligned, making it immediately clear how each section of code has changed. Added lines are highlighted in one color, removed lines in another, and modified lines show the specific character-level changes. This visual format reduces the cognitive load of code review compared to reading unified diff output in a terminal.
The diff checker tool available on StringTools allows you to paste two versions of any text and instantly see the differences highlighted. This is useful not only for code comparison but for any text comparison task: checking changes between two configuration files, comparing API responses before and after a change, verifying that a migration script produced the expected output, or reviewing edits to documentation. The tool works entirely in the browser, so your data is never sent to a server, which is important when comparing sensitive configuration or proprietary code.
GitHub, GitLab, and Bitbucket all provide rich diff viewing interfaces for pull requests that build on the basic diff format with additional features. These platforms add inline commenting, where reviewers can attach feedback to specific lines of the diff. They show commit-level diffs alongside the cumulative pull request diff, allowing reviewers to understand how the changes evolved over time. Code owners are automatically assigned based on the files changed, and automated checks annotate the diff with test results, coverage changes, and linting violations.
Desktop diff tools like VS Code's built-in diff editor, Beyond Compare, Meld, and Kaleidoscope offer the most powerful comparison experience with features like three-way merge, directory comparison, and syntax-aware diffing. These tools can be configured as Git's default diff tool, launching automatically when you run git difftool instead of git diff. For complex merges and large-scale refactors, a dedicated diff tool's ability to navigate between changes, expand and collapse context, and visually map the relationships between file versions can save hours compared to reviewing the same changes in a terminal.
Tips for Effective Code Review
Start every code review by reading the pull request description and understanding the goal of the changes before looking at any code. The diff only shows you what changed, not why it changed. Context about the motivation, design decisions, and trade-offs helps you provide relevant feedback and avoid suggesting alternatives that were already considered and rejected. A pull request without a clear description forces reviewers to reverse-engineer the intent from the code, which is slower and more error-prone.
Review the diff in a logical order rather than the default file-alphabetical order. Start with data model changes, then review business logic, followed by API endpoints, and finally tests and configuration. This order follows the dependency chain and helps you build a mental model of the changes from the foundation up. If the pull request modifies a database schema, understanding the schema change first makes the corresponding application code changes much easier to evaluate. Most code review tools allow you to reorder files or mark files as reviewed to track your progress through a large diff.
Focus your review on correctness, security, performance, and maintainability rather than style preferences. If the codebase has a linter and formatter, style issues should be caught automatically rather than consuming review time. Look for logic errors, missing edge cases, potential security vulnerabilities like unvalidated input or SQL injection, performance issues like N+1 queries or unnecessary allocations, and maintainability concerns like duplicated code, unclear naming, or missing documentation. These substantive issues are where human reviewers add the most value beyond what automated tools can detect.
Provide actionable feedback with clear explanations of the issue and suggested alternatives when possible. Instead of simply noting that something seems wrong, explain what the specific problem is, why it matters, and what a better approach might look like. Distinguish between required changes that block merging and optional suggestions that the author can consider at their discretion. This clarity helps authors prioritize their revisions and reduces back-and-forth discussion. A review that combines thoroughness with clear, constructive communication accelerates the development process and helps everyone on the team improve their skills.