Git Utilities
Power tools for everyday situations - stashing WIP, finding bug-introducing commits, moving commits between branches, and recovering from mistakes.
Search across all documentation pages
Power tools for everyday situations - stashing WIP, finding bug-introducing commits, moving commits between branches, and recovering from mistakes.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
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.
# 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:
-m make it easy to identify them laterstash pop applies and removes the stash in one step# 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:
--no-commit lets you modify the changes before committing# 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}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 = badThe 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# 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# 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 - 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.
# 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.
Things that will bite you. Each gotcha includes what goes wrong, why it happens, and the fix.
Stash pop with conflicts - git 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 files - git clean -fdx deletes everything not tracked, including .env files. Fix: Always do a dry run first with git clean -n.
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 |
pop applies the stash and removes it from the stash listapply applies the stash but keeps it in the listapply when you want to apply the same stash to multiple branchesgit stash push -m "partial stash" src/components/Button.tsxgood or bad and Git narrows it down in O(log n) stepsgit bisect start HEAD v1.0.0
git bisect run npm testpop encounters a merge conflict, it applies the stash but does not drop itgit stash dropgit reflog
# Find the last commit hash on the deleted branch
git checkout -b recovered-branch abc1234reset moves HEAD backward, rewriting history (use on local/unpushed commits)revert creates a new commit that undoes a previous one (safe for shared branches)-x flag removes files ignored by .gitignore, including .envgit clean -n (dry run) first to preview what will be deletedgit worktree add ../project-hotfix hotfix/login-error
# Work in ../project-hotfix independently
git worktree remove ../project-hotfixgit tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0-a) for releases as they store author, date, and messagenpm version to update package.json version automaticallyReviewed by Chris St. John·Last updated Jul 19, 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥