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 abc1234When 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 offWhat this demonstrates:
- Named stashes with
-mmake it easy to identify them later stash popapplies 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..def5678What this demonstrates:
- Cherry-pick copies a commit, creating a new commit with a new hash
--no-commitlets 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 = badReflog — 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 abc1234Clean — 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 -iTags
# 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.0Reset 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 committingRule 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-hotfixWorktrees 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 conflicts —
git stash poptries to apply and drop the stash. If there are conflicts, the stash is NOT dropped. Fix: Resolve conflicts, thengit stash dropmanually. -
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: Alwaysgit stashbefore doing a hard reset. Or usegit reset --softto keep changes. -
Bisect forgetting to reset — You finish bisecting but forget
git bisect resetand stay on a detached HEAD. Fix: Rungit bisect resetto return to your branch. -
Clean removing needed files —
git clean -fdxdeletes everything not tracked, including.envfiles. Fix: Always do a dry run first withgit clean -n.
Alternatives
Other ways to solve the same problem — and when each is the better choice.
| Alternative | Use When | Don't Use When |
|---|---|---|
git stash vs committing WIP | Quick context switch, coming back soon | Leaving WIP for days — commit it on a branch |
git revert vs git reset | The commit is already pushed/shared | Local-only commits where reset is cleaner |
git cherry-pick vs git rebase | You need one or two specific commits | You need an entire branch's changes |
git worktree vs git stash | Long-running parallel work on two branches | Quick one-off branch switch |
FAQs
What is the difference between git stash pop and git stash apply?
popapplies the stash and removes it from the stash listapplyapplies the stash but keeps it in the list- Use
applywhen 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
goodorbadand 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
popencounters 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 abc1234What is the difference between git reset and git revert?
resetmoves HEAD backward, rewriting history (use on local/unpushed commits)revertcreates a new commit that undoes a previous one (safe for shared branches)
Gotcha: Why did git clean -fdx delete my .env file?
- The
-xflag 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 versionto updatepackage.jsonversion automatically
Related
- Essential Git Commands — Staging, committing, branching basics
- Merging & Rebasing — Branch integration strategies
- GitHub CLI — Manage PRs, issues, and releases from the terminal