git diff shows how text differs between two versions of a file. Its default output uses a format called unified diff: a little context around each change, with prefixes that distinguish added, removed, and unchanged lines.
A small example
Suppose a file changes from:
color = "blue"
enabled = false
to:
color = "green"
enabled = true
A unified diff could look like this:
diff --git a/settings.txt b/settings.txt
index 12ab34c..56de78f 100644
--- a/settings.txt
+++ b/settings.txt
@@ -1,2 +1,2 @@
-color = "blue"
+color = "green"
-enabled = false
+enabled = true
File headers
The first lines identify the file and the versions being compared:
diff --git a/settings.txt b/settings.txtbegins a file’s diff. Thea/andb/prefixes conventionally refer to the old and new sides.index 12ab34c..56de78f 100644shows abbreviated object IDs for the old and new contents, followed by the file mode. This line may be omitted in some kinds of diff.--- a/settings.txtlabels the old file.+++ b/settings.txtlabels the new file.
For a newly created or deleted file, one side may instead be labeled /dev/null, meaning that there was no file on that side.
Hunk headers and line prefixes
A hunk is a section containing nearby changes. Its header looks like this:
@@ -1,2 +1,2 @@
The numbers describe ranges in the old and new files:
-1,2means the hunk covers 2 lines starting at line 1 of the old file.+1,2means it covers 2 lines starting at line 1 of the new file.
If a range contains only one line, Git may omit the count. For example, @@ -4 +4,2 @@ means one old line beginning at line 4 and two new lines beginning at line 4. Git may add a function or section name after the closing @@ to help orient you.
Within a hunk, the first character has a specific meaning:
context line: unchanged
-removed line: present only in the old version
+added line: present only in the new version
That leading space on an unchanged line is part of the diff format. It provides context but is not an addition to the file.
Reading counts
The hunk counts must match the lines shown:
- Count lines prefixed with a space and
-toward the old range. - Count lines prefixed with a space and
+toward the new range. - A removed line (
-) counts only toward the old range. - An added line (
+) counts only toward the new range.
For example:
@@ -10,3 +10,4 @@
keep this
-remove this
+add this
+add another line
keep that
The old range has three lines: two context lines and one removed line. The new range has four: two context lines and two added lines.
Other lines you may encounter
Some output contains information beyond ordinary text edits:
\ No newline at end of filenotes that a file does not end with a newline character. It is metadata, not a line to copy into the file.old mode 100644andnew mode 100755indicate a file permission change, such as making a script executable.rename from ...andrename to ...identify a detected rename. Git infers renames by comparing file contents; a rename may also have edits in its hunks.Binary files ... differmeans Git detected a binary change and did not print text hunks.+and-lines in a diff are markers. When copying code from a diff, remove those prefixes if you want the actual file contents.
Comparing different things
The format stays similar while the two sides you compare change:
# Unstaged edits compared with the index
git diff
# Staged edits compared with the last commit
git diff --cached
# Compare two commits
git diff main..feature
# Compare one file between two commits
git diff main..feature -- src/app.cpp
In git diff, main..feature compares the trees named by those two commits; it does not show the commit history between them. Use git log main..feature to inspect commits reachable from feature but not from main.
Useful display options
# Show fewer or more context lines around each hunk
git diff -U1
git diff -U10
# Show a summary of changed files
git diff --stat
# Show only paths that differ
git diff --name-only
# Ignore whitespace-only changes
git diff -w
Whitespace can matter in some languages and files, so -w is useful for review but should not be used to conclude that two files are equivalent in every context.
A quick mental model
Read a unified diff from the outside in: identify the file, read the hunk header to locate the changed lines, then interpret each line by its first character. A - line is removed, a + line is added, and a leading space is context. Once those conventions become familiar, even large diffs become much easier to scan.