Git · 10 of 11
The scenarios that don't map cleanly to one earlier chapter — a commit on the wrong branch, a conflict that looks unresolvable, a force-push that broke someone else's day — collected as direct fixes instead of concepts, closing out the series.

Every chapter in this series explained the concept first and the command second — on purpose.
When something's actually broken, nobody wants the concept. They want the fix.
This closing chapter is the opposite structure: real situations, straight to the command, with a pointer back to the earlier chapter if the "why" is worth revisiting later.
main instead of a feature branch"git branch feature/my-work # 1. create a branch at main's current tip
git reset --hard origin/main # 2. move main back to where it should be
git switch feature/my-work # 3. your commit is safe here
How it works: Step 1 captures the current tip (including your commit) before you move main back. Nothing is lost — you've just relabeled which branch the commit belongs to.
--hard here because you just created a branch pointing at the exact commit you're resetting away from.git reset --soft HEAD~1
Un-commits, keeps everything staged, ready to re-commit properly.
If you want the changes un-staged too (so you can pick which parts to re-commit):
git reset HEAD~1 # --mixed is the default
See the undo chapter for the full breakdown of reset modes.
git merge --abort
Backs out of the merge entirely — back to exactly how things were before you ran git merge.
Take a breath, re-read the conflict resolution section, and try again with fresh eyes. Conflicts almost always look worse mid-resolution than they actually are once you understand what each side actually changed.
Step 1: Check if it was a mistake on your end first.
git reflog # find what the branch looked like before the force-push
If you force-pushed the wrong thing, push back to the correct commit:
git push --force-with-lease origin main # force-push, guarded by the expected remote state
Step 2: Help your teammate recover.
Their local branch now disagrees with the remote's rewritten history. If they have no unpushed local work:
git fetch origin
git reset --hard origin/main
If they do have local work they want to keep, they should save it first:
git branch backup-before-reset # save their current state
git fetch origin
git reset --hard origin/main
# then cherry-pick or rebase their backup commits as needed
git push --force-with-lease to git push --force. It refuses the update when the remote no longer matches your local tracking state, which catches many accidental overwrites. It is a safeguard, not a guarantee: a background fetch can make that local state misleading.git reflog
# Look for the last commit the branch pointed at
# e.g.: a1b2c3d HEAD@{4}: commit: Add checkout validation
git branch recovered-branch a1b2c3d
The reflog remembers where HEAD was even after the branch label pointing at it is gone. Full explanation in the reflog chapter.
git bisect start
git bisect bad # current commit is broken
git bisect good <known-good-commit> # this older commit was fine
# Git checks out a commit halfway between — test it
git bisect good # or: git bisect bad
# repeat ~8 times
git bisect reset # return to where you started
If you have an automatable test:
git bisect run ./test.sh # fully automated binary search
See the bisect section for the full walkthrough.
git rebase -i HEAD~<n>
# In the editor: change "pick" to "fixup" for WIP commits
# Save and close
The interactive rebase chapter covers this in depth, including the safety rule: only squash commits nobody else has already pulled.
Step 1 — Rotate the credential immediately.
Treat it as compromised the moment it was pushed, regardless of whether the repository is public or private. This step has nothing to do with Git and is the one people skip when they shouldn't.
Step 2 — Remove it from history.
# Install git-filter-repo (recommended tool)
pip install git-filter-repo
# Remove the secret from all history
git filter-repo --path-glob '*.env' --invert-paths
# or target a specific file
git filter-repo --path config/secrets.js --invert-paths
# Force-push the rewritten history
git push --force-with-lease origin main
# Have everyone with a clone re-clone or hard-reset
Older alternatives: git filter-branch (deprecated, slow), BFG Repo-Cleaner.
Two habits worth building regardless of which specific problem you're facing:
git status # understand where you actually are before doing anything
git reflog # your local undo history — almost always has a way back
And before any destructive command on a commit you care about:
git branch backup-$(date +%Y%m%d) # cheap insurance policy
Creates a branch pointing at your current HEAD. If the command goes wrong, you can always reset to that branch. Costs nothing if you didn't need it.
| Problem | Command |
|---|---|
| Committed to wrong branch | git branch <new> → git reset --hard origin/main → git switch <new> |
| Undo last commit, keep staged | git reset --soft HEAD~1 |
| Undo last commit, keep editing | git reset HEAD~1 |
| Conflict looks unresolvable | git merge --abort |
| Force-push broke someone | git push --force-with-lease (to undo), teammate runs git reset --hard origin/main |
| Deleted a branch | git reflog → git branch <name> <hash> |
| Find which commit broke something | git bisect start / git bisect run |
| Squash WIP commits before PR | git rebase -i HEAD~<n> |
| Committed a secret | Rotate credential + git filter-repo |
That's the full arc: the local repository model, branching and merging, rewriting history safely, undoing mistakes, working with remotes, what's actually inside .git, extending Git with hooks/submodules/LFS, team conventions, and now the troubleshooting reference to tie it together.
Every command in this series traces back to the same small set of ideas from the internals chapter — a handful of object types, addressed by content, referenced by pointers that move. Once that model is solid, new Git commands stop being things to memorize and start being things you can reason about from first principles.
Get an email when I publish the next chapter. No spam — just new technical deep-dives.
Comments
Share feedback or questions about this blog post.
No comments yet. Be the first to share your thoughts.