Advanced Git
Rebase, cherry-pick, stash, reset, reflog
Git Stash
Stash = Temporarily save uncommitted changes. Perfect when you need to switch branches but aren’t ready to commit.
Basic Stash
# Save current changes
git stash
# Your working directory is now clean
git status # Nothing to commit
# Switch branches, do other work...
git checkout other-branch
# Come back and restore changes
git checkout original-branch
git stash pop # Restores and removes from stash
Stash with Message
# Name your stash (easier to find later)
git stash save "WIP: login validation"
# Or modern syntax
git stash push -m "WIP: login validation"
Managing Multiple Stashes
# List all stashes
git stash list
# stash@{0}: WIP: login validation
# stash@{1}: WIP: fixing header
# Apply specific stash (keep in list)
git stash apply stash@{1}
# Apply and remove specific stash
git stash pop stash@{1}
# Delete a stash
git stash drop stash@{0}
# Clear all stashes
git stash clear
Git Rebase
Rebase = Move your branch to start from a different commit. Creates a cleaner, linear history compared to merge.
Rebase vs Merge
MERGE (creates merge commit):
main: A ─── B ─── C ─── M
\ /
feature: D ─── E ──
REBASE (linear history):
main: A ─── B ─── C
\
feature: D' ─── E'
Basic Rebase
# On your feature branch
git checkout feature
# Rebase onto main (move feature to tip of main)
git rebase main
# If conflicts occur:
# 1. Fix conflicts in files
# 2. git add .
# 3. git rebase --continue
# Abort if things go wrong
git rebase --abort
Interactive Rebase
Edit, squash, reorder, or drop commits:
# Rebase last 3 commits
git rebase -i HEAD~3
This opens an editor:
pick abc1234 Add login form
pick def5678 Fix typo in login
pick ghi9012 Add validation
# Commands:
# p, pick = use commit
# r, reword = edit commit message
# e, edit = stop to amend commit
# s, squash = combine with previous commit
# f, fixup = squash but discard message
# d, drop = remove commit
Squash Commits
# Combine last 3 commits into one
git rebase -i HEAD~3
# Change 'pick' to 'squash' (or 's'):
pick abc1234 Add login form
squash def5678 Fix typo in login
squash ghi9012 Add validation
# Save and edit the combined commit message
Cherry Pick
Cherry-pick = Copy a specific commit to your current branch. Grab just the commits you need without merging everything.
# Copy one commit
git cherry-pick abc1234
# Copy multiple commits
git cherry-pick abc1234 def5678
# Copy a range of commits
git cherry-pick abc1234..ghi9012
Common Use Cases
# Hotfix: Apply bugfix from develop to main
git checkout main
git cherry-pick abc1234 # The bugfix commit
# Oops: Wrong branch - move commit to correct branch
git checkout correct-branch
git cherry-pick abc1234
git checkout wrong-branch
git reset --hard HEAD~1 # Remove from wrong branch
Cherry-Pick Options
# Don't commit automatically (stage only)
git cherry-pick -n abc1234
# Edit commit message
git cherry-pick -e abc1234
# If conflicts, after resolving:
git cherry-pick --continue
# Abort cherry-pick
git cherry-pick --abort
Reset vs Revert
Two ways to undo changes. Different purposes.
Git Reset (Rewrite History)
# Soft: Undo commit, keep changes staged
git reset --soft HEAD~1
# Mixed (default): Undo commit, keep changes unstaged
git reset HEAD~1
# Hard: Undo commit AND discard changes ⚠️
git reset --hard HEAD~1
Before: A ─── B ─── C ─── D (HEAD)
git reset --hard HEAD~2
After: A ─── B (HEAD)
C and D are gone!
Git Revert (Safe Undo)
Creates a new commit that undoes a previous commit. Safe for shared branches.
# Revert a specific commit
git revert abc1234
# Revert without auto-commit
git revert -n abc1234
Before: A ─── B ─── C ─── D (HEAD)
git revert C
After: A ─── B ─── C ─── D ─── C' (HEAD)
C' undoes C's changes
Git Reflog (Your Safety Net)
Reflog = Reference log. Records every move HEAD makes. Even after reset --hard, your commits aren’t truly gone.
View Reflog
git reflog
# Output:
# abc1234 HEAD@{0}: reset: moving to HEAD~2
# def5678 HEAD@{1}: commit: Add feature X
# ghi9012 HEAD@{2}: commit: Fix bug Y
# jkl3456 HEAD@{3}: checkout: moving from main to feature
Recover “Lost” Commits
# Oops! Accidentally reset --hard
git reset --hard HEAD~3 # Deleted 3 commits!
# Find them in reflog
git reflog
# abc1234 HEAD@{1}: commit: Important work
# Recover!
git reset --hard abc1234
# Or create a branch at that point
git branch recovered abc1234
Recover Deleted Branch
# Deleted a branch by mistake
git branch -D feature-important # Oops!
# Find it
git reflog | grep feature-important
# Shows: checkout: moving from feature-important
# Find the commit hash and recreate
git branch feature-important abc1234
Amend & Fixup
Amend Last Commit
# Fix last commit message
git commit --amend -m "Better message"
# Add forgotten file to last commit
git add forgotten-file.js
git commit --amend --no-edit # Keep same message
# Change author of last commit
git commit --amend --author="Name <email@example.com>"
Fixup Older Commits
# Create a fixup commit
git commit --fixup abc1234
# Later, squash all fixups automatically
git rebase -i --autosquash main
Git Bisect (Bug Hunt)
Bisect = Binary search through commits to find when a bug was introduced. Tests hundreds of commits in just a few steps.
# Start bisect
git bisect start
# Mark current commit as bad (has bug)
git bisect bad
# Mark a known good commit (before bug existed)
git bisect good abc1234
# Git checks out middle commit
# Test if bug exists, then:
git bisect good # No bug
# or
git bisect bad # Bug exists
# Repeat until Git finds the culprit
# "abc1234 is the first bad commit"
# Done - return to normal
git bisect reset
Automate with Script
# Run a test script automatically
git bisect start HEAD abc1234
git bisect run npm test
# Git will find the commit that broke the tests!
Cleanup & Maintenance
Remove Untracked Files
# See what would be deleted (dry run)
git clean -n
# Delete untracked files
git clean -f
# Delete untracked files AND directories
git clean -fd
# Delete ignored files too
git clean -fdx
Garbage Collection
# Optimize repository
git gc
# Aggressive cleanup (slower but thorough)
git gc --aggressive
Check Repository Health
# Verify integrity
git fsck
# Show repository size
git count-objects -vH
Quick Reference
# Stash
git stash # Save changes
git stash pop # Restore and remove
git stash list # List all stashes
git stash drop stash@{0} # Delete stash
# Rebase
git rebase main # Rebase onto main
git rebase -i HEAD~3 # Interactive rebase
git rebase --abort # Cancel rebase
# Cherry-pick
git cherry-pick <commit> # Copy commit
git cherry-pick -n <commit> # Stage only, don't commit
# Reset
git reset --soft HEAD~1 # Undo commit, keep staged
git reset HEAD~1 # Undo commit, keep changes
git reset --hard HEAD~1 # Undo commit, discard all
# Revert
git revert <commit> # Create undo commit
# Recovery
git reflog # View all HEAD movements
git reset --hard <hash> # Recover to any point
# Amend
git commit --amend # Edit last commit
git commit --amend --no-edit # Add to last commit
# Bisect
git bisect start # Start bug hunt
git bisect good/bad # Mark commits
git bisect reset # End bisect
Practice Exercise
# Setup
mkdir advanced-practice && cd advanced-practice
git init
echo "v1" > file.txt && git add . && git commit -m "v1"
echo "v2" > file.txt && git commit -am "v2"
echo "v3" > file.txt && git commit -am "v3"
echo "v4" > file.txt && git commit -am "v4"
# Exercise 1: Stash
echo "work in progress" >> file.txt
git stash
git stash list
git stash pop
# Exercise 2: Interactive Rebase (squash v2,v3,v4 into one)
git rebase -i HEAD~3
# Change 'pick' to 'squash' for last two commits
# Exercise 3: Reset and Recover
git log --oneline # Note the commit hash
git reset --hard HEAD~1 # "Lose" a commit
git reflog # Find it
git reset --hard <hash> # Recover!
# Exercise 4: Amend
git commit --amend -m "Better commit message"