---
title: 'Examining Diffs'
source: 'https://academia.sh/en/courses/introduction-to-version-control/examining-diffs'
course: 'Introduction to Version Control'
language: en
updated: '2026-08-17T18:10:47+00:00'
license: 'CC BY-SA 4.0'
---

# Examining Diffs

Three separate comparisons between the working directory, the staging area, and commits; reading the unified diff format, and diffing at the object level.

The log says which commit touched which file, but it does not show the change's
content. What is more, changes not yet committed never appear in the log at all: an
edit in the working directory is outside history until it is committed.

This lesson defines three separate forms of taking a **diff** and shows how to read
diff output. The three-region model earns its practical value here: the question of
which two regions are being compared determines which option to write.

## Three Comparisons

| Command | Compared | Question it answers |
|---|---|---|
| `git diff` | Working directory ↔ staging area | What have I not staged yet? |
| `git diff --staged` | Staging area ↔ last commit | What will go into the next commit? |
| `git diff HEAD` | Working directory ↔ last commit | What has changed in total since the last commit? |

The third row is the union of the first two. `--staged`'s synonym is `--cached`; the
former will be used throughout the course.

## Working Directory and Staging Area

The search script stays silent when no match is found and exits with status zero.
The script is changed to this:

```sh
#!/bin/sh
# terimler.txt içinde arama yapar.

if [ $# -ne 1 ]; then
    echo "kullanım: ara.sh ARANAN" >&2
    exit 1
fi

if ! grep -i -- "$1" terimler.txt; then
    echo "eşleşme yok: $1" >&2
    exit 2
fi
```

```bash
git diff
```

```
diff --git a/ara.sh b/ara.sh
index b87baa8..582ddde 100755
--- a/ara.sh
+++ b/ara.sh
@@ -6,4 +6,7 @@ if [ $# -ne 1 ]; then
     exit 1
 fi
 
-grep -i -- "$1" terimler.txt
+if ! grep -i -- "$1" terimler.txt; then
+    echo "eşleşme yok: $1" >&2
+    exit 2
+fi
```

## The Anatomy of Diff Output

The output is in **unified diff** format and has four parts.

**The header line.** `diff --git a/ara.sh b/ara.sh` — the two versions being
compared are named with the `a/` and `b/` prefixes. `a` is the old side, `b` the
new.

**The object line.** `index b87baa8..582ddde 100755` — the old and new blob IDs,
together with the file mode. This line records which two objects in the object
database the diff was computed between. If the mode is the same on both sides, a
single value is written at the end of the line; if the mode has changed, two
separate lines are added.

**The file lines.** `---` marks the old version, `+++` the new. For a newly
created file, the old side is `/dev/null`.

**The hunk header.** Every region where a change occurs is called a **hunk**, and
every hunk opens with a header. `@@ -6,4 +6,7 @@` — it carries four numbers: 4
lines starting at line 6 of the old file have been replaced by 7 lines starting at
line 6 of the new file. The text `if [ $# -ne 1 ]; then` at the end of the header
is the nearest enclosing line that gives the change's context; it is not part of
the diff itself.

Lines inside a hunk begin with one of three marks: a space (an unchanged context
line), `-` (removed), `+` (added). Context lines default to three; this is changed
with the `-U` option. A modified line appears in diff format as a delete-add
pair — there is no "modify" operation in the format.

## Staging Area and Last Commit

```bash
git add ara.sh
git diff
```

The command prints nothing: the working directory and the staging area now match.
The diff has moved:

```bash
git diff --staged
```

```
diff --git a/ara.sh b/ara.sh
index b87baa8..582ddde 100755
--- a/ara.sh
+++ b/ara.sh
@@ -6,4 +6,7 @@ if [ $# -ne 1 ]; then
     exit 1
 fi
 
-grep -i -- "$1" terimler.txt
+if ! grep -i -- "$1" terimler.txt; then
+    echo "eşleşme yok: $1" >&2
+    exit 2
+fi
```

`git add` did not move the content; it changed which blob the staging area points
at. Because the diff itself is computed between the same two objects, the output
is letter-for-letter identical.

## Two Regions at Once

A line is added to the term list but not staged:

```bash
git status --short
```

```
M  ara.sh
 M terimler.txt
```

The meaning of the two columns becomes clear here: `ara.sh` is marked in the
first column (staged), `terimler.txt` in the second (only in the working
directory).

```bash
git diff
```

```
diff --git a/terimler.txt b/terimler.txt
index 11660ec..17af3b8 100644
--- a/terimler.txt
+++ b/terimler.txt
@@ -4,3 +4,4 @@ kuyruk | queue
 ağaç | tree
 karma tablosu | hash table
 bağlı liste | linked list
+küme | set
```

`git diff` shows only the `terimler.txt` change, `git diff --staged` only the
`ara.sh` change. To see both at once, the comparison is made against `HEAD`:

```bash
git diff HEAD --stat
```

```
 ara.sh       | 5 ++++-
 terimler.txt | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)
```

`--stat` gives a per-file summary instead of line-by-line output. The bar made of
plus and minus marks shows the ratio of added to removed lines at scale; for
large diffs, the total count is fitted to a fixed width.

## The Diff Between Two Commits

When two refs are given, the diff describes the transition from the first to the
second:

```bash
git diff 13d31bf 60e13bd -- terimler.txt
```

```
diff --git a/terimler.txt b/terimler.txt
index 9b9ef70..11660ec 100644
--- a/terimler.txt
+++ b/terimler.txt
@@ -1,3 +1,6 @@
 yığıt | stack
 kuyruk | queue
 çizge | graph
+ağaç | tree
+karma tablosu | hash table
+bağlı liste | linked list
```

Order matters: `git diff B A` shows the same diff in the reverse direction. The
path separator is used here too, to limit the output to a single file.

## Diffing at the Object Level

Comparison is not limited to refs; the `ref:path` notation names a specific
object at that ref:

```bash
git diff 13d31bf:README.md 3132c78:README.md
```

```
diff --git a/README.md b/README.md
index 49daf90..c0a6e3d 100644
--- a/README.md
+++ b/README.md
@@ -6,4 +6,4 @@ Bilgisayar bilimi terimlerinin Türkçe karşılıklarını tutan küçük bir l
 
 `terimler.txt` dosyasında her satır şu biçimdedir:
 
-    turkce | english
+    türkçe | english
```

This notation makes the comparison possible even if the file name changed
between the two versions.

## Word-Level Diff

Line-based diff shows a small change in a long line as the whole line being
deleted and re-added. `--word-diff` improves readability in this case:

```bash
git diff --word-diff HEAD -- terimler.txt
```

```
diff --git a/terimler.txt b/terimler.txt
index 11660ec..17af3b8 100644
--- a/terimler.txt
+++ b/terimler.txt
@@ -4,3 +4,4 @@ kuyruk | queue
ağaç | tree
karma tablosu | hash table
bağlı liste | linked list
{+küme | set+}
```

The added portion is enclosed in `{+ +}`, the removed portion in `[- -]`. The
presentation format has changed; the diff itself and the content to be recorded
are the same.

## Recording the Changes

The two changes are split into separate commits:

```bash
git commit -m "Eşleşme bulunamadığında hata bildir"
git commit -a -m "Küme terimini ekle"
```

```
[main 2c883a7] Eşleşme bulunamadığında hata bildir
 1 file changed, 4 insertions(+), 1 deletion(-)
[main ece664b] Küme terimini ekle
 1 file changed, 1 insertion(+)
```

The first command recorded the staged `ara.sh` change; the second picked up the
remaining tracked change with the `-a` option.

## Summary

- `git diff` compares the working directory with the staging area, `--staged`
  compares the staging area with the last commit, and the form called with `HEAD`
  compares both at once.
- Unified diff output is made up of header, object, file, and hunk lines; the
  hunk header gives the starting line and line count on the old and new sides.
- There is no "modify" operation in the format; a changed line appears as one
  deletion and one addition.
- Giving two refs diffs between commits; the `ref:path` notation diffs between
  objects.
- `--stat` gives a per-file summary, `--word-diff` gives a word-level display.

## Next Step

The repository so far holds only files written by hand. But files also get
produced while working: the script's output, backups left by the editor, build
results. Letting these into history is both noise and risk. The next lesson takes
up the ignore rules that determine which files are kept out of the repository,
and why those rules do not apply to tracked files.
