'git status' shows changed files, but 'git diff' doesn't
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When git status shows files as modified but git diff shows nothing, the changes are already staged (in the index). git diff compares the working tree against the index, while git status compares both the index against HEAD and the working tree against the index. Use git diff --staged (or --cached) to see staged changes. The other common cause is line-ending or file permission changes that git diff considers insignificant by default.
The Discrepancy Explained
This happens because the file changed in a way git diff does not display by default (line endings, permissions), or more commonly, the changes are staged.
Cause 1: Changes Are Already Staged
git diff = working tree vs index (staging area)
git diff --staged = index vs last commit (HEAD)
Understanding the Three Trees
Cause 2: Line Ending Changes (CRLF vs LF)
Git's core.autocrlf or .gitattributes with text=auto converts line endings on checkout. git status detects the difference, but git diff considers it a no-op after normalization.
Fix:
Cause 3: File Permission Changes
On Unix/macOS, chmod +x script.sh changes the file mode. git status reports this as modified, but git diff may show only the mode change (no content diff).
Fix: Either commit the permission change or ignore it:
Cause 4: Submodule Changes
When a submodule has new commits, git status reports it as modified, but git diff does not show file-level diffs for submodules by default.
Cause 5: Stat-Only Changes (Timestamps)
Git uses file timestamps and sizes to quickly detect changes. Sometimes a file's timestamp changes (from a build tool or touch) without content changing:
Diagnostic Commands
Quick Reference
| Scenario | git status shows | git diff shows | Solution |
| Staged changes | "Changes to be committed" | Nothing | Use git diff --staged |
| Line ending changes | "Changes not staged" | Nothing | git add --renormalize . |
| Permission changes | "Changes not staged" | Mode change only | git config core.fileMode false |
| Submodule updates | "modified (new commits)" | Nothing | git diff --submodule |
| Stale timestamps | "Changes not staged" | Nothing | git update-index --refresh |
Common Pitfalls
- Forgetting
--staged: The most common cause of confusion.git diffonly shows unstaged changes. Usegit diff --stagedfor staged changes andgit diff HEADfor everything. - Mixed staged and unstaged: After
git addfollowed by more edits, the file appears in both "staged" and "unstaged" sections.git diffshows the unstaged part,git diff --stagedshows the staged part. .gitattributesautocrlf surprises: Cloning a repo on Windows withtext=autoconverts all line endings, making every file appear modified. Rungit add --renormalize .to fix.core.fileModeon shared filesystems: NFS, Docker mounts, and WSL can change file permissions unexpectedly. Setcore.fileMode falsein these environments.- Assuming
git diffshows all changes: By default, it only compares the working tree to the index. There are four possible comparisons (working vs index, index vs HEAD, working vs HEAD, commit vs commit). Use the right flags for each.
Summary
git diffshows unstaged changes (working tree vs index)git diff --stagedshows staged changes (index vs HEAD)git diff HEADshows all changes (working tree vs HEAD)- Line ending and permission changes cause
statusto report modifications thatdiffconsiders insignificant - Use
git status --porcelainto see the exact state of each file git update-index --refreshclears false positives from stale timestamps

