Advanced Git: Rebase, Cherry-Pick, Bisect & Reflog Explained
Go beyond git add and commit. Learn interactive rebase, cherry-pick, bisect for bug hunting, reflog for recovery, worktrees, and advanced workflows used by professional developers.
Beyond the Basics
Most developers use 10% of Git. If your workflow is add → commit → push → pull, you're missing powerful tools that save hours of work. This guide covers the commands that separate everyday users from Git power users.
Interactive Rebase
Interactive rebase lets you rewrite commit history — squash commits, reorder them, edit messages, or drop them entirely.
# Rebase the last 4 commits
git rebase -i HEAD~4This opens your editor:
pick a1b2c3d feat: add user authentication
pick e4f5g6h fix: typo in auth middleware
pick i7j8k9l feat: add password reset
pick m0n1o2p fix: reset email template
Commands
| Command | What It Does |
|---------|-------------|
| pick | Keep the commit as-is |
| reword | Keep commit, edit the message |
| squash | Merge into previous commit (combine messages) |
| fixup | Merge into previous commit (discard this message) |
| edit | Pause here so you can amend the commit |
| drop | Delete the commit entirely |
Example: Clean Up Before PR
# Before: messy history
pick a1b2c3d feat: add user authentication
fixup e4f5g6h fix: typo in auth middleware # Merge into auth commit
pick i7j8k9l feat: add password reset
fixup m0n1o2p fix: reset email template # Merge into reset commit
# After: clean history
# feat: add user authentication (includes typo fix)
# feat: add password reset (includes template fix)
Auto-Squash Workflow
# When you make a fixup commit, name it with "fixup!" prefix
git commit -m "fixup! feat: add user authentication"
# Later, rebase will auto-arrange it
git rebase -i --autosquash HEAD~4Cherry-Pick
Cherry-pick copies a specific commit from one branch to another — without merging the entire branch.
# Copy commit abc123 to current branch
git cherry-pick abc123
# Copy multiple commits
git cherry-pick abc123 def456 ghi789
# Copy a range of commits
git cherry-pick abc123..ghi789
# Cherry-pick without committing (stage changes only)
git cherry-pick abc123 --no-commitWhen to Use Cherry-Pick
- Hotfix: A fix is on
developbut you need it onmainnow - Selective backport: Only some commits from a feature branch
- Cross-team: Grab a utility function from another team's branch
# Example: Hotfix workflow
git checkout main
git cherry-pick abc123 # The fix commit from develop
git push origin main
# Then tag the release
git tag -a v1.2.1 -m "Hotfix: fix payment processing"Handling Conflicts
# If cherry-pick has conflicts
git cherry-pick abc123
# CONFLICT: resolve manually, then:
git add .
git cherry-pick --continue
# Or abort
git cherry-pick --abortGit Bisect
Bisect uses binary search to find exactly which commit introduced a bug. Instead of checking commits one by one, it narrows it down in O(log n) steps.
# Start bisect
git bisect start
# Current commit is broken
git bisect bad
# This commit from 2 weeks ago was working
git bisect good v1.2.0 # or a commit hash
# Git checks out a middle commit. Test it, then:
git bisect good # If this commit works
# or
git bisect bad # If this commit is broken
# Repeat until Git finds the culprit
# Bisecting: 3 revisions left to test after this (roughly 2 steps)
# ...
# abc123 is the first bad commit
# Done — clean up
git bisect resetAutomated Bisect
If you have a test script that exits 0 for good and 1 for bad:
git bisect start HEAD v1.2.0
git bisect run npm test
# or
git bisect run ./test-script.sh
# Git automatically runs the test at each step
# and reports the first bad commitExample: Find When a Test Broke
git bisect start
git bisect bad # Tests fail now
git bisect good HEAD~50 # Tests passed 50 commits ago
git bisect run npx jest --testPathPattern="auth.test"
# Git finds the exact commit that broke the auth testReflog: Your Safety Net
Reflog records every time HEAD moves — even operations that "destroy" history like reset --hard. If you've lost commits, reflog can recover them.
# View reflog
git reflogOutput:
abc1234 HEAD@{0}: reset: moving to HEAD~3
def5678 HEAD@{1}: commit: feat: important feature
ghi9012 HEAD@{2}: commit: fix: critical bug fix
jkl3456 HEAD@{3}: checkout: moving from feature to main
Recovery Scenarios
# "I accidentally reset --hard and lost commits"
git reflog
# Find the commit before the reset
git reset --hard def5678
# "I deleted a branch with unmerged work"
git reflog
# Find the last commit on that branch
git checkout -b recovered-branch def5678
# "My rebase went wrong"
git reflog
# Find HEAD position before the rebase
git reset --hard HEAD@{5}Reflog Expiry
Reflog entries expire after 90 days (30 days for unreachable commits). For critical recovery, act sooner rather than later.
Git Stash
Stash saves your uncommitted changes temporarily, giving you a clean working directory.
# Stash current changes
git stash
# Stash with a message
git stash push -m "WIP: login form validation"
# Include untracked files
git stash push -u -m "WIP: new feature with new files"
# List stashes
git stash list
# stash@{0}: On feature: WIP: login form validation
# stash@{1}: On main: WIP: debugging
# Apply most recent stash (keep in stash list)
git stash apply
# Apply and remove from stash list
git stash pop
# Apply a specific stash
git stash apply stash@{1}
# Drop a stash
git stash drop stash@{0}
# Clear all stashes
git stash clearPartial Stash
# Interactively choose which hunks to stash
git stash push -p
# Stash only specific files
git stash push -m "stash auth only" src/auth/ src/middleware/Reset vs Revert
git reset (Rewrite History)
# Soft: undo commit, keep changes staged
git reset --soft HEAD~1
# Mixed (default): undo commit, unstage changes
git reset HEAD~1
# Hard: undo commit, discard all changes
git reset --hard HEAD~1Use reset for: local commits not yet pushed.
git revert (Safe Undo)
# Create a new commit that undoes abc123
git revert abc123
# Revert without auto-committing
git revert abc123 --no-commit
# Revert a merge commit (specify parent)
git revert -m 1 abc123Use revert for: public/shared commits that others may have pulled.
reset = "This commit never happened" (rewrites history)
revert = "This commit happened, and here's the undo" (safe for shared branches)
Worktrees
Worktrees let you have multiple branches checked out simultaneously in different directories. No more stashing to switch branches.
# Create a worktree for a hotfix
git worktree add ../hotfix-branch hotfix/payment-fix
# Now you have:
# /project/ → main branch (your current work)
# /project/../hotfix-branch/ → hotfix branch
# Work on the hotfix without touching your current branch
cd ../hotfix-branch
# make fixes, commit, push
# Remove when done
git worktree remove ../hotfix-branch
# List all worktrees
git worktree listUse Cases
- Code review: Check out a PR branch without losing your work
- Parallel builds: Run tests on one branch while coding on another
- Compare behavior: Run two versions side by side
Useful Aliases
Add to ~/.gitconfig:
[alias]
# Pretty log
lg = log --oneline --graph --all --decorate
# Show what I did today
today = log --since='midnight' --author='Your Name' --oneline
# Undo last commit (keep changes)
undo = reset --soft HEAD~1
# Amend without changing message
oops = commit --amend --no-edit
# List branches by last commit date
recent = branch --sort=-committerdate --format='%(committerdate:short) %(refname:short)'
# Show changed files between branches
changes = diff --name-only
# Clean merged branches
cleanup = "!git branch --merged | grep -v '\\*\\|main\\|master\\|develop' | xargs -n 1 git branch -d"Quick Reference
| Task | Command |
|------|---------|
| Squash last 3 commits | git rebase -i HEAD~3 |
| Copy commit to current branch | git cherry-pick <hash> |
| Find bug-introducing commit | git bisect start + good/bad |
| Recover lost commit | git reflog + git reset --hard <hash> |
| Save work temporarily | git stash push -m "message" |
| Undo public commit safely | git revert <hash> |
| Undo local commit | git reset --soft HEAD~1 |
| Work on two branches at once | git worktree add <path> <branch> |
| See all HEAD movements | git reflog |
Master these tools and you'll handle any Git situation with confidence. The key is knowing which tool to reach for — rebase for clean history, cherry-pick for surgical moves, bisect for detective work, and reflog for when things go wrong.