Skip to main content

Diff, Stash & Tags 🔧

Three essential Git tools for advanced workflows: understanding changes, temporarily saving work, and marking releases.

Diff: Understanding Changes 📊

Diff shows the differences between versions of files.

Basic Diff

See unstaged changes in your working directory:

git diff

# Output example:
# diff --git a/app.js b/app.js
# index a1b2c3d..x1y2z3d 100644
# --- a/app.js
# +++ b/app.js
# @@ -5,3 +5,4 @@
# console.log('Start');
# -console.log('Old line');
# +console.log('New line');
# console.log('End');

Understanding Diff Output

diff --git a/app.js b/app.js      # File being compared
index a1b2c3d..x1y2z3d 100644 # Hash and permissions

--- a/app.js # Original version (before)
+++ b/app.js # New version (after)

@@ -5,3 +5,4 @@ # Starting at line 5, 3 lines
# (new version: 5, 4 lines)
console.log('Start'); # Context (unchanged)
-console.log('Old line'); # Removed (-)
+console.log('New line'); # Added (+)
console.log('End'); # Context

Diff Variations

# Show staged changes (ready to commit)
git diff --staged
# or
git diff --cached

# Show diff between branches
git diff main..feature
git diff main feature

# Show what feature has that main doesn't
git diff main...feature

# Show diff for specific file
git diff app.js

# Show diff between commits
git diff a1b2c3d x1y2z3d

# Show diff with statistics
git diff --stat

# Show just file names that changed
git diff --name-only

# Show changes with different formatting
git diff --color-words # Word-level diff
git diff --unified=5 # 5 lines of context

Word-Level Diff

# Color words that changed
git diff --color-words

# Example output:
# The quick brown fox → The fast brown fox
# Only "quick" → "fast" highlighted

Viewing Formatted Diff

# Unified diff (default)
git diff --unified=3

# Context diff
git diff --ignore-all-space
git diff --ignore-space-at-eol

# See changes in patch format
git diff --patch

Diff Between States

Working Directory vs Staging

# What you've changed but not staged
git diff

Staging vs Repository

# What you've staged but not committed
git diff --staged

Repository Versions

# Between commits
git diff a1b2c3d x1y2z3d

# Between branches
git diff main feature

# Between HEAD and previous commit
git diff HEAD~1

Summary Diff

# Just show statistics
git diff --stat

# Output:
# app.js | 5 +++++--
# config.js | 3 +++
# 2 files changed, 8 insertions(+), 2 deletions(-)

# Show which files changed
git diff --name-only

# Show files and change type
git diff --name-status

# Output:
# M app.js (modified)
# A config.js (added)
# D old-file.js (deleted)

Viewing History Diffs

Diff for Specific Commit

# See changes in a commit
git show a1b2c3d

# See specific file in a commit
git show a1b2c3d:app.js

# See diff from previous commit
git show a1b2c3d

# See diff between commits
git diff a1b2c3d x1y2z3d

Log with Diff

# Show commits with diffs
git log -p

# Show last 3 commits with diffs
git log -p -3

# Show diff for specific file's history
git log -p app.js

# Show statistics
git log --stat

Stash: Saving Work Temporarily 📦

Stash saves your work without committing it. Perfect for interruptions!

Basic Stash

# Save current changes
git stash

# Clears working directory
# Changes stored safely

# Your work is ready to be brought back

Real-World Scenario

# You're working on feature
git add .
git commit -m "WIP: Adding new feature"

# Suddenly, critical bug reported!

# Save your work
git stash

# Working directory is clean
# You can now switch branches safely

git checkout main
# Fix bug...

# When done
git checkout feature
git stash pop # Get your work back

Stash List

# See all stashes
git stash list

# Output:
# stash@{0}: WIP on feature: a1b2c3d Add new UI
# stash@{1}: On main: x1y2z3d Fix typo
# stash@{2}: WIP on develop: m1n2o3p Refactor

# Most recent first

Retrieving Stash

# Apply and remove (most common)
git stash pop

# Apply but keep stash
git stash apply

# Apply specific stash
git stash apply stash@{1}
git stash pop stash@{1}

# Apply stash to new branch (prevents conflicts)
git stash branch feature-from-stash

Stashing Selectively

# Stash only staged changes
git stash push --staged

# Stash only unstaged changes
git stash push --keep-index

# Stash with descriptive message
git stash save "WIP: Feature login system"
# or modern way:
git stash push -m "Feature login system"

# Stash specific files only
git stash push app.js config.js

# Include untracked files
git stash --include-untracked
git stash -u

Viewing Stash Contents

# See what's in a stash
git stash show

# See detailed diff
git stash show -p

# Show specific stash
git stash show stash@{1} -p

Cleaning Up Stashes

# Delete specific stash
git stash drop stash@{1}

# Delete all stashes
git stash clear

# Be careful! This is permanent

Stashing Best Practices

# Good practice: named stashes
git stash push -m "Feature authentication WIP"

# Don't leave stashes indefinitely
git stash list # Check often

# Pop stashes soon after creating
# Stashes from weeks ago might be hard to reapply

Tags: Marking Releases 🏷️

Tags mark important points in history, usually releases.

Lightweight Tags

Simple reference to a commit:

# Create lightweight tag
git tag v1.0.0

# Just points to current commit
# Minimal storage

Annotated Tags

Full object with metadata:

# Create annotated tag
git tag -a v1.0.0 -m "Release version 1.0.0"

# Includes:
# - Tagger name & email
# - Date
# - Message
# - Can be signed

Creating Tags

# Tag current commit
git tag v1.0.0

# Tag with message
git tag -a v1.0.0 -m "Release 1.0.0"

# Tag previous commit
git tag v1.0.0 a1b2c3d

# Tag with annotation
git tag -a v1.0.0 a1b2c3d -m "Release 1.0.0"

# Sign tag (requires GPG)
git tag -s v1.0.0 -m "Signed release"

Viewing Tags

# List all tags
git tag

# Search tags
git tag -l "v1.*" # Find all v1.x tags

# Show tag details
git show v1.0.0

# Show just message
git tag -n # Show with first line of message
git tag -n3 # Show first 3 lines

Pushing Tags

# Push specific tag
git push origin v1.0.0

# Push all tags
git push origin --tags

# Force push tag (rarely needed)
git push origin v1.0.0 --force

# Delete tag locally
git tag -d v1.0.0

# Delete tag on remote
git push origin --delete v1.0.0
git push origin :v1.0.0 # Older syntax

Semantic Versioning 📌

Standard versioning format: MAJOR.MINOR.PATCH

# MAJOR: Breaking changes
git tag v2.0.0 # Completely new API

# MINOR: New features, backwards compatible
git tag v1.1.0 # Added new functions

# PATCH: Bug fixes
git tag v1.0.1 # Fixed bugs

# Pre-release
git tag v1.0.0-alpha
git tag v1.0.0-beta
git tag v1.0.0-rc.1

Release Workflow with Tags

# 1. Ensure main is clean
git checkout main
git pull origin main

# 2. Create release commit (update version file)
echo "1.0.0" > VERSION
git add VERSION
git commit -m "Bump version to 1.0.0"

# 3. Create tag
git tag -a v1.0.0 -m "Release version 1.0.0"

# 4. Push everything
git push origin main
git push origin v1.0.0

# 5. Create release on GitHub
# (with changelog, artifacts, etc.)

Comparing Tags

# See changes between tags
git diff v1.0.0 v1.1.0

# See commits between tags
git log v1.0.0..v1.1.0

# See commits since tag
git log v1.0.0..HEAD

# Show tag info
git log --oneline v1.0.0..HEAD

Common Patterns 🎯

Finding Changes

# What changed in last commit?
git show HEAD

# What changed in feature branch?
git diff main..feature

# What files changed?
git diff --name-only main..feature

# See specific file changes
git diff main..feature -- app.js

Stashing for Quick Switch

# Working on feature, need to check main
git stash # Save work
git checkout main # Switch
# Do work...
git checkout feature # Go back
git stash pop # Restore work

Creating Releases

# After all work is done
git tag -a v2.0.0 -m "Major release: New API"
git push origin v2.0.0

# Now create GitHub Release with:
# - Changelog
# - Download links
# - Migration guide

Advanced Diff Options

# Ignore whitespace changes
git diff -w
git diff --ignore-all-space

# Show empty diff context
git diff --function-context

# Patience algorithm (better for some files)
git diff --patience

# Histogram algorithm (faster)
git diff --histogram

# Compare ignoring specific files
git diff ':!package-lock.json'

# See what commits are ahead/behind
git log origin/main..main # Ahead
git log main..origin/main # Behind

You've learned three powerful tools! Next, master Managing History to control your Git timeline. ⏱️

Next: Managing History