React SME Cookbook
All FAQs

Search Documentation

Search across all documentation pages

gitstashbisectcherry-pickreflog

Git Utilities

Power tools for everyday situations — stashing WIP, finding bug-introducing commits, moving commits between branches, and recovering from mistakes.

Recipe

Quick-reference recipe card — copy-paste ready.

# Stash current changes
git stash
git stash pop
 
# Cherry-pick a commit from another branch
git cherry-pick abc1234
 
# Find the commit that introduced a bug
git bisect start
git bisect bad          # current commit is broken
git bisect good v1.0.0  # this tag was working
# Git checks out commits for you to test, then:
git bisect good  # or  git bisect bad
git bisect reset # when done
 
# Recover a lost commit
git reflog
git checkout -b recovery abc1234

When to reach for this: When basic add/commit/branch isn't enough — context switching, debugging regressions, moving specific commits, or recovering from mistakes.

Working Example

Stash — Quick Context Switch

# You're mid-feature but need to fix a bug on main
git stash -m "WIP: dashboard chart component"
git checkout main
git checkout -b hotfix/login-error
# ... fix the bug, commit, push, merge ...
git checkout feature/dashboard
git stash pop
# Back to your WIP exactly where you left off

What this demonstrates:

  • Named stashes with -m make it easy to identify them later
  • stash pop applies and removes the stash in one step
  • Your working directory is restored exactly as it was

Cherry-Pick — Grab a Specific Commit

# A teammate fixed a utility function on their branch
# You need just that one commit, not their whole branch
git cherry-pick abc1234
 
# Cherry-pick without committing (stage changes only)
git cherry-pick --no-commit abc1234
 
# Cherry-pick a range of commits
git cherry-pick abc1234..def5678

What this demonstrates:

  • Cherry-pick copies a commit, creating a new commit with a new hash
  • --no-commit lets you modify the changes before committing
  • Useful for backporting fixes to release branches

Deep Dive

Stash Management

# Stash including untracked files
git stash -u
 
# Stash including ignored files
git stash -a
 
# List all stashes
git stash list
# stash@{0}: On feature/dashboard: WIP: chart component
# stash@{1}: On main: quick experiment
 
# Apply a specific stash (keep it in the list)
git stash apply stash@{1}
 
# Drop a specific stash
git stash drop stash@{1}
 
# Clear all stashes
git stash clear
 
# Create a branch from a stash
git stash branch new-feature stash@{0}
 
# Show what's in a stash
git stash show -p stash@{0}

Bisect — Binary Search for Bugs

git bisect performs a binary search through your commit history to find exactly which commit introduced a bug.

# Manual bisect
git bisect start
git bisect bad                 # HEAD is broken
git bisect good abc1234        # this commit was working
 
# Git checks out a commit halfway between good and bad
# Test it, then tell Git:
git bisect good   # this commit works fine
# or
git bisect bad    # this commit is broken
 
# Repeat until Git finds the first bad commit
# "abc1234 is the first bad commit"
 
git bisect reset  # return to your original branch
 
# Automated bisect with a test script
git bisect start HEAD abc1234
git bisect run npm test
# Git automatically runs the test at each step
# Exit code 0 = good, non-zero = bad

Reflog — Your Safety Net

The reflog records every time HEAD moves. It's your undo history for Git itself.

# View reflog
git reflog
# abc1234 HEAD@{0}: commit: feat: add search
# def5678 HEAD@{1}: rebase (finish): returning to refs/heads/feature
# ghi9012 HEAD@{2}: rebase (start): checkout main
# jkl3456 HEAD@{3}: commit: feat: add dashboard
 
# Recover after a bad rebase
git reflog
# Find the commit hash before the rebase started
git reset --hard HEAD@{3}
 
# Recover a deleted branch
git reflog
# Find the last commit on the deleted branch
git checkout -b recovered-branch abc1234

Clean — Remove Untracked Files

# Preview what would be removed (dry run)
git clean -n
 
# Remove untracked files
git clean -f
 
# Remove untracked files and directories
git clean -fd
 
# Remove ignored files too (full reset)
git clean -fdx
 
# Interactive mode
git clean -i

Tags

# Create a lightweight tag
git tag v1.0.0
 
# Create an annotated tag (recommended for releases)
git tag -a v1.0.0 -m "Release version 1.0.0"
 
# Tag a specific commit
git tag -a v0.9.0 abc1234 -m "Beta release"
 
# List tags
git tag -l
git tag -l "v1.*"
 
# Push tags to remote
git push origin v1.0.0
git push origin --tags
 
# Delete a tag
git tag -d v1.0.0
git push origin --delete v1.0.0

Reset vs Revert

# Reset — move HEAD backward (rewrites history)
git reset --soft HEAD~1   # undo commit, keep changes staged
git reset --mixed HEAD~1  # undo commit, keep changes unstaged (default)
git reset --hard HEAD~1   # undo commit, discard changes entirely
 
# Revert — create a new commit that undoes a previous one (safe for shared branches)
git revert abc1234
git revert HEAD~3..HEAD   # revert a range
git revert --no-commit abc1234  # stage the revert without committing

Rule of thumb: Use reset on local/unpushed commits. Use revert on shared/pushed commits.

Worktrees — Multiple Branches Simultaneously

# Create a worktree for a different branch
git worktree add ../project-hotfix hotfix/login-error
 
# List worktrees
git worktree list
 
# Remove a worktree when done
git worktree remove ../project-hotfix

Worktrees let you have multiple branches checked out simultaneously in separate directories — no stashing required.

Gotchas

Things that will bite you. Each gotcha includes what goes wrong, why it happens, and the fix.

  • Stash pop with conflictsgit stash pop tries to apply and drop the stash. If there are conflicts, the stash is NOT dropped. Fix: Resolve conflicts, then git stash drop manually.

  • Cherry-pick creates duplicate commits — The picked commit gets a new hash. If the source branch is later merged, you'll have two copies. Fix: This is usually harmless — Git handles it during merge. But for cleanliness, consider rebasing instead.

  • Reset --hard loses uncommitted work — There's no recovering unstaged changes after git reset --hard. Fix: Always git stash before doing a hard reset. Or use git reset --soft to keep changes.

  • Bisect forgetting to reset — You finish bisecting but forget git bisect reset and stay on a detached HEAD. Fix: Run git bisect reset to return to your branch.

  • Clean removing needed filesgit clean -fdx deletes everything not tracked, including .env files. Fix: Always do a dry run first with git clean -n.

Alternatives

Other ways to solve the same problem — and when each is the better choice.

AlternativeUse WhenDon't Use When
git stash vs committing WIPQuick context switch, coming back soonLeaving WIP for days — commit it on a branch
git revert vs git resetThe commit is already pushed/sharedLocal-only commits where reset is cleaner
git cherry-pick vs git rebaseYou need one or two specific commitsYou need an entire branch's changes
git worktree vs git stashLong-running parallel work on two branchesQuick one-off branch switch

FAQs

What is the difference between git stash pop and git stash apply?
  • pop applies the stash and removes it from the stash list
  • apply applies the stash but keeps it in the list
  • Use apply when you want to apply the same stash to multiple branches
How do I stash only specific files instead of everything?
git stash push -m "partial stash" src/components/Button.tsx
  • You can list multiple file paths after the message
What does git cherry-pick --no-commit do?
  • It applies the changes from the picked commit but does not create a new commit
  • The changes are left staged so you can modify them before committing
  • Useful when you need to adjust the cherry-picked code for a different context
How does git bisect work, and when should I use it?
  • It performs a binary search through commit history to find the commit that introduced a bug
  • You mark commits as good or bad and Git narrows it down in O(log n) steps
  • Use it when a regression appeared and you do not know which commit caused it
Can I automate git bisect with a test script?
git bisect start HEAD v1.0.0
git bisect run npm test
  • Git runs the script at each step; exit code 0 = good, non-zero = bad
  • Fully automatic bug-hunting
Gotcha: Why did git stash pop leave my stash in the list after a conflict?
  • When pop encounters a merge conflict, it applies the stash but does not drop it
  • Resolve the conflicts, then manually run git stash drop
What is the reflog and how long does it keep data?
  • The reflog records every HEAD movement (commits, rebases, resets, checkouts)
  • Entries expire after ~90 days by default
  • It is local only and not shared with remotes
How do I recover a branch I accidentally deleted?
git reflog
# Find the last commit hash on the deleted branch
git checkout -b recovered-branch abc1234
What is the difference between git reset and git revert?
  • reset moves HEAD backward, rewriting history (use on local/unpushed commits)
  • revert creates a new commit that undoes a previous one (safe for shared branches)
Gotcha: Why did git clean -fdx delete my .env file?
  • The -x flag removes files ignored by .gitignore, including .env
  • Always run git clean -n (dry run) first to preview what will be deleted
How do I use git worktree to work on two branches at once?
git worktree add ../project-hotfix hotfix/login-error
# Work in ../project-hotfix independently
git worktree remove ../project-hotfix
  • Each worktree is a separate directory with its own checked-out branch
When working in a TypeScript project, how can I tag a release?
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
  • Use annotated tags (-a) for releases as they store author, date, and message
  • Pair with npm version to update package.json version automatically