Managing History ⏱️
Master your Git history with powerful tools to undo, rewrite, and reshape your commit timeline. Use carefully on shared branches!
Undoing Changes ↩️
Undo Unstaged Changes
Restore file to last commit:
# Discard changes in working directory
git restore app.js
# Discard all changes
git restore .
# Old syntax (still works)
git checkout -- app.js
Undo Staged Changes
Remove from staging area:
# Unstage file
git restore --staged app.js
# Unstage all files
git restore --staged .
# Old syntax
git reset HEAD app.js
git reset HEAD
Undo Last Commit
Three options depending on needs:
# Keep changes, remove commit
git reset --soft HEAD~1
# Keep changes in working directory
git reset --mixed HEAD~1 # default
# Discard changes completely
git reset --hard HEAD~1
# Safe option for pushed commits
git revert HEAD
Reset vs Revert 🔄
Reset (Rewrites History) ⚠️
Use only on unpushed commits!
# Soft reset: keep changes staged
git reset --soft HEAD~1
# Changes ready to recommit
# Mixed reset: keep changes unstaged (default)
git reset --mixed HEAD~1
# Changes in working directory
# Hard reset: discard changes
git reset --hard HEAD~1
# Dangerous! Changes lost
Revert (Safe for Shared Branches) ✅
Creates new commit that undoes changes:
# Create commit that undoes previous
git revert HEAD
# Revert specific commit
git revert a1b2c3d
# Revert without committing
git revert --no-commit a1b2c3d
# Revert multiple commits
git revert a1b2c3d..x1y2z3d
Visual Comparison
Original timeline:
commit A → commit B → commit C → commit D
git reset --soft HEAD~1:
commit A → commit B → commit C
(D's changes staged)
git revert HEAD:
commit A → commit B → commit C → commit D → commit E (undoes D)
Amending Commits ✏️
Amend Last Commit
Fix message or add forgotten files:
# Fix commit message
git commit --amend -m "Corrected message"
# Add forgotten file to last commit
git add forgotten-file.js
git commit --amend --no-edit # Keep same message
# Edit both message and content
git add file.js
git commit --amend
# Don't create new commit hash (only works if not pushed)
# Rewrites history
Amending Already Pushed Commits
# Fix locally
git commit --amend -m "Fixed message"
# Force push to remote (risky!)
git push origin main --force-with-lease
# --force-with-lease is safer than --force
# Fails if someone else pushed changes
Interactive Rebase 🎯
Powerful tool to rewrite commit history. Use only before pushing!
Basic Interactive Rebase
# Rebase last 3 commits
git rebase -i HEAD~3
# Opens editor with commits:
pick a1b2c3d Add feature
pick x1y2z3d Fix typo
pick m1n2o3p Add tests
# Modify, save, and exit
# Git replays commits with your changes
Rebase Commands
pick (p) - Use commit
reword (r) - Use commit, edit message
edit (e) - Use commit, but stop to amend
squash (s) - Use commit, but meld into previous
fixup (f) - Like squash, but discard log message
drop (d) - Remove commit
exec (x) - Run shell command
Example: Squashing Commits
# You have messy commit history:
pick a1b2c3d Add user model
pick x1y2z3d Fix user model
pick m1n2o3p Add user tests
# Change to:
pick a1b2c3d Add user model
squash x1y2z3d Fix user model
squash m1n2o3p Add user tests
# Result: 1 commit combining all 3
# With combined message
Example: Reordering Commits
# Current:
pick a1b2c3d Feature A
pick x1y2z3d Feature B
# Want:
pick x1y2z3d Feature B
pick a1b2c3d Feature A
# Just reorder lines in editor
# Git replays in new order
Example: Editing Commit Messages
# Current:
pick a1b2c3d Add feature
# Change to:
reword a1b2c3d Add user authentication feature
# Git stops at this commit
# Opens editor for new message
# Continues with remaining commits
Aborting Rebase
# Something went wrong?
git rebase --abort
# Stops and returns to original state
# No history changed
Cleaning Up History
Combining Multiple Commits
# You made 5 commits for one feature
git log --oneline
a1b2c3d WIP
x1y2z3d Fix
m1n2o3p More fixes
p1q2r3s Update tests
z9y8x7w Final touches
# Combine into one:
git rebase -i HEAD~5
# Edit:
pick a1b2c3d WIP
squash x1y2z3d Fix
squash m1n2o3p More fixes
squash p1q2r3s Update tests
squash z9y8x7w Final touches
# Result: single clean commit
Removing Bad Commits
# Oops! Committed sensitive data
git log --oneline
# a1b2c3d Oops! Added password
# x1y2z3d Feature X
# Remove it:
git rebase -i HEAD~2
# Edit:
drop a1b2c3d Oops! Added password
pick x1y2z3d Feature X
# Commit is completely removed
Cherry-Picking 🍒
Copy specific commits to another branch:
# Apply specific commit to current branch
git cherry-pick a1b2c3d
# Apply multiple commits
git cherry-pick a1b2c3d x1y2z3d m1n2o3p
# Apply range of commits
git cherry-pick a1b2c3d..m1n2o3p # Excludes a1b2c3d
git cherry-pick a1b2c3d^..m1n2o3p # Includes a1b2c3d
Real-World Example
# Bug fix was committed to develop
git log develop
# a1b2c3d Fix critical bug
# Need it in main now!
git checkout main
git cherry-pick a1b2c3d
# Commit applied to main
# Still exists in develop
# Creates new commit (different hash)
Cherry-Pick with Conflicts
# If there are conflicts:
# 1. Resolve them
git add fixed-file.js
# 2. Continue
git cherry-pick --continue
# Or abort
git cherry-pick --abort
Reflog: Recovery Tool 🆘
Reflog tracks where HEAD has been. Perfect for recovery!
Viewing Reflog
# See recent HEAD positions
git reflog
# Output:
# a1b2c3d HEAD@{0}: commit: Last commit
# x1y2z3d HEAD@{1}: rebase: Some commit
# m1n2o3p HEAD@{2}: checkout: switching to main
# p1q2r3s HEAD@{3}: reset: hard reset to previous
Recovering Lost Commits
# You did hard reset and lost commits
git reset --hard HEAD~5
# See what you lost
git reflog
# a1b2c3d HEAD@{0}: reset: hard reset
# (this is old position, has your commits)
# Get back to lost commits
git reset --hard a1b2c3d
# Or create branch at lost position
git checkout -b recovery a1b2c3d
Recovering Deleted Branch
# You deleted a branch
git branch -D feature
# Where is it?
git reflog
# a1b2c3d HEAD@{5}: branch: Created
# (this has your commits)
# Recreate it
git checkout -b feature-restored a1b2c3d
Search History 🔍
Find Commits by Message
# Search commit messages
git log --grep="login"
# Case-insensitive search
git log -i --grep="LOGIN"
# Search with regex
git log --grep="fix.*typo"
Find Commits by Content
# Find commits that added/removed text
git log -S "password"
# Find commits that changed specific function
git log -S "function_name"
# Find commits that touched specific word
git log -G "searchTerm" # Regex version
Find by Author
# Commits by specific person
git log --author="John Doe"
# Case-insensitive
git log -i --author="john"
# Commits by anyone except
git log --author="^(?!John)"
Find by Date
# Commits since date
git log --since="2024-01-01"
# Commits until date
git log --until="2024-01-31"
# Human-readable dates work
git log --since="2 weeks ago"
git log --since="1 month ago"
git log --before="yesterday"
Complex Search
# Show commits touching file, by author, since date
git log --since="1 month ago" \
--author="John" \
--grep="feature" \
-- path/to/file.js
# Commits where code was changed by specific author
git log -S "variable_name" --author="John"
# Recent changes on specific file
git log -p --follow -- src/app.js
Viewing History
One-Line History
# Compact view
git log --oneline
# a1b2c3d Add user auth
# x1y2z3d Fix login bug
# m1n2o3p Add tests
# With dates
git log --oneline --date=short --format="%h %ad %s"
Branching History
# Show as graph
git log --graph --oneline --all
# Better visualization:
git log --graph --oneline --all --decorate
# Really pretty:
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
File History
# See all changes to file
git log -p -- app.js
# See when lines were changed
git blame app.js
# Output shows:
# a1b2c3d (John Doe 2024-01-15 10:30:45 -0500) function hello() {
# x1y2z3d (Jane Smith 2024-01-14 14:20:00 -0500) return 'hi';
Diff History
# Show what changed in each commit
git log -p
# Show statistics
git log --stat
# Show patch with context
git log -p -5 # Last 5 commits with diffs
Best Practices ⚠️
The Golden Rules
✅ DO:
- Use reset/rebase on LOCAL branches only
- Use revert for shared/public branches
- Commit frequently with clear messages
- Review history before pushing
- Use reflog for recovery
❌ DON'T:
- Force push to shared branches (without discussion)
- Rewrite history on main/develop
- Cherry-pick across unrelated features
- Forget to test after rebasing
- Ignore merge conflicts
When to Use Each Tool
| Situation | Use | Command |
|---|---|---|
| Fix message on last commit | Amend | git commit --amend |
| Combine local commits | Squash via rebase | git rebase -i |
| Undo on local branch | Reset | git reset --soft HEAD~1 |
| Undo on shared branch | Revert | git revert HEAD |
| Copy specific commit | Cherry-pick | git cherry-pick <hash> |
| Recover lost commits | Reflog | git reflog |
| Clean up before push | Interactive rebase | git rebase -i |
Real-World Scenarios 📋
Scenario: Messy Local Commits Before Push
# You have 5 commits for one feature
git log --oneline
# a1b2c3d WIP
# x1y2z3d Fix
# m1n2o3p More fixes
# p1q2r3s Update tests
# z9y8x7w Final
# Clean up before pushing
git rebase -i HEAD~5
# Squash all into one:
# pick a1b2c3d WIP
# squash x1y2z3d Fix
# squash m1n2o3p More fixes
# squash p1q2r3s Update tests
# squash z9y8x7w Final
# Push clean history
git push origin feature-clean
Scenario: Accidental Commit to Wrong Branch
# You committed to main instead of feature
# main has: a1b2c3d, x1y2z3d (wrong), m1n2o3p
# Create feature branch at wrong commit
git branch feature-recovery x1y2z3d
# Reset main to before the wrong commit
git reset --hard a1b2c3d
# Now work on feature branch
git checkout feature-recovery
Scenario: Recovering Lost Work
# You did hard reset and lost everything
git reset --hard HEAD~10
# Check reflog
git reflog
# Find commit before reset
# a1b2c3d HEAD@{2}: (this is your lost work)
# Recovery options:
# 1. Create branch
git branch lost-work a1b2c3d
# 2. Create and switch to it
git checkout -b lost-work a1b2c3d
# 3. Reset to it
git reset --hard a1b2c3d
You've mastered Git! You now understand:
- Version control fundamentals
- Branching and workflows
- Advanced commands
- History management and recovery
Time to practice and build your Git expertise! 🚀
Congratulations! You've completed the Git Mastery guide. Keep practicing and refer back to these sections as needed. Happy coding! 🚀✨