Difficulty: Beginner
How do git diff and git stash work? When would you use each, and what are the different forms of git diff?
git diff compares changes between different states in Git. Without arguments, it shows unstaged changes (working directory vs staging area). With --staged (or --cached), it shows what will go into the next commit. You can also diff between branches, commits, or specific files.
git stash temporarily shelves changes you have made to your working directory so you can work on something else, then come back and re-apply them later. It saves both staged and unstaged changes by default and reverts your working directory to match HEAD.
Common use case: You are working on a feature, but need to switch to a hotfix branch. Stash your current work, fix the bug, switch back, and pop the stash to continue where you left off. Stashes are stored as a stack (LIFO), and you can have multiple stashes with descriptive names.
# Unstaged changes (working dir vs staging area)
git diff
# Staged changes (staging area vs last commit)
git diff --staged
# (--cached is a synonym)
git diff --cached
# All changes since last commit (working + staged)
git diff HEAD
# Diff between two branches
git diff main..feature/auth
# Diff between two commits
git diff a1b2c3d e4f5g6h
# Diff for a specific file
git diff -- src/app.ts
git diff main..feature/auth -- src/app.ts
# Only show file names that changed
git diff --name-only main..feature/auth
# Show stats (insertions/deletions)
git diff --stat main..feature/auth
# src/auth.ts | 45 ++++++++++++++++++
# src/app.ts | 3 ++-
# 2 files changed, 46 insertions(+), 1 deletion(-)
# Word-level diff (useful for prose)
git diff --word-diff
Remember: git diff (unstaged), git diff --staged (staged), git diff HEAD (both). The double-dot notation main..feature means 'changes in feature that are not in main'.
# Stash current changes (staged + unstaged)
git stash
# Saved working directory and index state WIP on main: a1b2c3d ...
# Stash with a descriptive message
git stash push -m "WIP: user authentication form"
# Stash including untracked files
git stash -u
# Or: git stash --include-untracked
# List all stashes
git stash list
# stash@{0}: On main: WIP: user authentication form
# stash@{1}: WIP on main: a1b2c3d fix: resolve CORS
# Apply most recent stash (keep it in stash list)
git stash apply
# Apply and remove from stash list
git stash pop
# Apply a specific stash
git stash apply stash@{1}
# Show what is in a stash
git stash show -p stash@{0}
# Drop a specific stash
git stash drop stash@{1}
# Clear all stashes
git stash clear
git stash push -m gives your stash a name so you can identify it later. Use -u to include new untracked files. git stash pop = apply + drop.
# Generate a patch file from diff
git diff > my-changes.patch
# Generate patch from staged changes
git diff --staged > staged-changes.patch
# Generate patch from commits
git format-patch -1 HEAD
# Creates: 0001-feat-add-auth-module.patch
# Generate patches for last 3 commits
git format-patch -3 HEAD
# Apply a patch (check first)
git apply --check my-changes.patch
git apply my-changes.patch
# Apply a formatted patch (preserves commit info)
git am 0001-feat-add-auth-module.patch
# Stash only specific files
git stash push -m "auth changes" src/auth/
# Create a branch from a stash
git stash branch new-feature stash@{0}
# Creates branch, checks it out, applies stash, drops stash
Patches are useful for sharing changes without pushing to a remote. git format-patch preserves commit metadata. git stash branch is great when your stashed changes conflict with current work.
git diff, git stash, Working Tree, Staged Changes, Patch