Real-World Git Scenarios
A practical problem-to-solution cookbook for the messy situations every developer eventually hits. Each scenario describes the situation in plain language, explains what is happening, and gives you the exact commands to fix it. Find your problem, copy the commands, understand why they work.
I committed to the wrong branch
You meant to commit on a feature branch but you were on main. The fix: move the commit(s) to the correct branch, then reset the wrong branch back. This works as long as you have not pushed the bad commit.
Move the last commit to a new (or existing) branch
# You are on main with a commit that belongs on a feature branch. # Option A: the target branch does not exist yet git branch feature-x # create feature-x pointing at the bad commit git reset --hard HEAD~1 # move main back one commit git switch feature-x # your commit is now safely on feature-x # Option B: the target branch already exists git switch feature-x git cherry-pick main # copy main's tip commit onto feature-x git switch main git reset --hard HEAD~1 # remove it from main
I need to undo my last commit but keep the changes
The commit was premature but the code is fine. A soft (or mixed) reset moves the branch pointer back without throwing away your work — the changes return to the staging area or working tree.
Undo a commit, keep the changes
# Keep changes staged (ready to re-commit) git reset --soft HEAD~1 # Keep changes in the working tree, unstaged (the default) git reset --mixed HEAD~1 # same as: git reset HEAD~1
I committed a secret or password
The single most important step is not a Git command: rotate the credential immediately. Assume it is compromised the moment it is committed. Then remove it from history. How you remove it depends on whether you have pushed.
Remove a secret from history
# 1. ROTATE THE SECRET FIRST. Treat it as leaked. # If you have NOT pushed yet and it is only in the last commit: git rm --cached .env echo ".env" >> .gitignore git commit --amend --no-edit # If it is deeper in history (or already pushed), use git-filter-repo: pip install git-filter-repo git filter-repo --path .env --invert-paths # or replace just the secret string everywhere: git filter-repo --replace-text <(echo 'mySecret123==>REMOVED') # Then force-push every branch; all collaborators must re-clone: git push origin --force --all
I need to combine my last 3 commits into one
You made several "wip" commits and want a single clean commit before opening a PR. Interactive rebase lets you squash them together.
Squash the last 3 commits
git rebase -i HEAD~3 # An editor opens with: # pick a1b2c3 first commit # pick d4e5f6 second commit # pick 7g8h9i third commit # # Change the 2nd and 3rd "pick" to "squash" (or "s"): # pick a1b2c3 first commit # squash d4e5f6 second commit # squash 7g8h9i third commit # # Save and close. A second editor lets you write the combined message. # Fast alternative if you just want one commit on top of main: git reset --soft HEAD~3 git commit -m "Single clean commit message"
I accidentally ran git reset --hard and lost work
Do not panic. As long as the lost commits existed at some point, the reflog remembers where HEAD was. The reflog is your time machine for local history.
Recover with the reflog
git reflog
# You'll see something like:
# a1b2c3 HEAD@{0}: reset: moving to HEAD~3
# d4e5f6 HEAD@{1}: commit: the work you thought was gone
# ...
# Restore the branch to the state before the reset:
git reset --hard HEAD@{1}
# Or, safer, inspect first then create a branch at that point:
git checkout -b recovered d4e5f6I need to change a commit message I already pushed
Amending changes the commit's SHA, so the remote and your local copy diverge. You must force-push — use --force-with-lease so you do not clobber commits a teammate pushed in the meantime.
Reword the last (pushed) commit
git commit --amend -m "Correct commit message" git push --force-with-lease # To reword an OLDER commit, use interactive rebase and mark it "reword": git rebase -i HEAD~4 # change "pick" to "reword" on the target line, save, edit the message git push --force-with-lease
I want to pull but have local uncommitted changes
Git refuses to pull when uncommitted changes would be overwritten. Stash them, pull, then reapply. The stash is a temporary shelf for your in-progress work.
Stash, pull, reapply
git stash push -m "wip before pulling" git pull --rebase git stash pop # reapply your changes on top of the freshly pulled code # If 'pop' produces conflicts, resolve them, then: git add <resolved-files> git stash drop # remove the stash entry once applied cleanly
My merge went wrong, I want to abort
Mid-merge you realise the conflicts are a mess and you want to back out completely, as if you never started. Most in-progress operations have an --abort escape hatch.
Abort an in-progress operation
git merge --abort # restore to pre-merge state git rebase --abort # bail out of a rebase git cherry-pick --abort # bail out of a cherry-pick # If a merge already completed and you want to undo it: git reset --hard ORIG_HEAD # ORIG_HEAD points to where you were before the merge
I need to apply one commit from another branch
A bug fix lives on another branch and you need just that one commit on your current branch without merging everything. That is exactly what cherry-pick is for.
Cherry-pick a single commit
git switch my-branch git cherry-pick a1b2c3d # apply that commit here (new SHA) # Multiple commits at once: git cherry-pick a1b2c3d f4e5g6h # A continuous range (exclusive of the first): git cherry-pick startHash..endHash # Apply the changes but don't commit yet (lets you tweak first): git cherry-pick -n a1b2c3d
I committed as the wrong author or email
Your global Git config had the wrong name or email and it ended up on a commit. Fix the config first, then rewrite the affected commit(s).
Fix the author on commits
# Fix your config going forward:
git config --global user.name "Correct Name"
git config --global user.email "correct@email.com"
# Fix only the last commit:
git commit --amend --reset-author --no-edit
# Fix the author across many past commits with filter-repo:
git filter-repo --commit-callback '
if commit.author_email == b"wrong@email.com":
commit.author_email = b"correct@email.com"
commit.author_name = b"Correct Name"
'I need to find which commit introduced a bug
The bug exists now but worked in some older version. git bisect does a binary search through history — you mark commits good or bad and it zeroes in on the culprit in a logarithmic number of steps.
Binary-search for the bad commit
git bisect start git bisect bad # current commit has the bug git bisect good v1.0.0 # this older tag was fine # Git checks out a midpoint commit. Test it, then: git bisect good # ...if the midpoint is fine git bisect bad # ...if the midpoint has the bug # Repeat until Git prints "<sha> is the first bad commit". git bisect reset # return to where you started # Automate it with a test command (exit 0 = good, non-zero = bad): git bisect start HEAD v1.0.0 git bisect run npm test
I want to temporarily switch tasks
An urgent fix lands while you are mid-feature. You can shelve your work with stash, or — better when you need both checked out at once — use a second working tree with worktree.
Stash vs worktree
# Quick context switch on the same checkout: git stash push -u -m "wip feature" # -u also stashes untracked files git switch hotfix # ...do the hotfix... git switch feature git stash pop # Keep BOTH active at the same time in separate folders: git worktree add ../hotfix-tree hotfix # now ../hotfix-tree is a full checkout of the hotfix branch git worktree remove ../hotfix-tree # clean up when done
I deleted a branch and need it back
You ran git branch -D and immediately regretted it. The branch pointer is gone but the commits still exist and the reflog knows the SHA they pointed to.
Restore a deleted branch
# Find the tip commit of the deleted branch: git reflog # look for the last "checkout: moving from <branch>" or commit on it # Recreate the branch at that commit: git branch recovered-branch a1b2c3d # If nothing useful in reflog, search dangling commits: git fsck --no-reflogs --lost-found # then: git branch recovered-branch <dangling-sha>
I need to split a large commit into smaller ones
One giant commit mixes unrelated changes and reviewers hate it. Use interactive rebase to stop at that commit, undo it, and re-commit in logical pieces.
Split one commit into several
git rebase -i HEAD~3 # Mark the oversized commit with "edit" instead of "pick", save. # Git pauses ON that commit. Undo it but keep the changes: git reset HEAD~1 # Now stage and commit in coherent chunks (use -p to pick hunks): git add -p src/feature-a.js git commit -m "feat: add feature A" git add src/feature-b.js git commit -m "feat: add feature B" # When the working tree is clean, resume the rebase: git rebase --continue
Quick scenario index
Wrong branch? → create branch at HEAD, then reset the wrong branch back
Undo commit, keep code? → git reset --soft HEAD~1
Leaked secret? → rotate it, then git filter-repo to scrub history
Combine commits? → git rebase -i and squash
Lost work after reset --hard? → git reflog, then reset to HEAD@{n}
Bad pushed message? → git commit --amend, then push --force-with-lease
Pull with dirty tree? → git stash, pull, git stash pop
Merge gone wrong? → git merge --abort (or reset --hard ORIG_HEAD)
One commit from elsewhere? → git cherry-pick <sha>
Wrong author? → fix config, then git commit --amend --reset-author
Find the bug commit? → git bisect run <test>
Switch tasks? → git stash or git worktree add
Deleted branch? → git reflog, then git branch <name> <sha>
Commit too big? → git rebase -i, mark edit, reset, re-commit in pieces