Oh Shit, Again Git?! — Rescue Recipes in Plain English

Suman SharmaSuman Sharma

Oh Shit, Git?! — Rescue Recipes in Plain English

Git is hard: screwing up is easy, and figuring out how to fix your mistakes can feel impossible.

The docs have a chicken-and-egg problem—you cannot search for how to get out of a mess unless you already know the name of the thing you need. So you stare at git help and close the tab.

This post is the opposite: bad situations in plain English, then the commands that fixed them for me.

Inspired by the legendary Oh Shit, Git!?! (hat tip to Katie Sylor-Miller and everyone who contributed). I adapted and organized the flows I actually use on real repos.

Git version control concept illustration

Oh shit, I did something terribly wrong — does Git have a time machine?

Yes. It is called reflog.

git reflog # You will see everything you've done in Git, across all branches. # Each entry has an index: HEAD@{index} # Find the one from BEFORE you broke everything.
git reset HEAD@{index} # Magic time machine

Use this to recover deleted work, undo a bad merge attempt, or go back to when things actually worked. I use reflog constantly.

Oh shit, I committed and immediately need one small change

You committed, ran tests, and realized you forgot a space. Again.

# Make your change, then: git add . # or: git add path/to/file git commit --amend --no-edit # Your last commit now includes that change

Faster than an interactive rebase for a one-line fix.

Oh shit, I need to change the message on my last commit

git commit --amend # Follow the prompts to change the message

Stupidly strict commit message rules? Fixed in thirty seconds.

Oh shit, I committed to main but it should have been a new branch

# Create a branch from current state (keeps your commit) git branch some-new-branch-name # Remove the last commit from main git reset HEAD~ --hard # Switch to the branch where the commit now lives git checkout some-new-branch-name

Your work is on some-new-branch-name. main is clean again.

Note: If you already pushed to a shared main, this gets painful—you may need git reset HEAD@{n} from reflog instead of HEAD~. If you tried other fixes first, the index number changes. Reflog is your friend.

Oh shit, I committed to the wrong branch

Option A: reset, stash, move

git reset HEAD~ --soft git stash git checkout name-of-the-correct-branch git stash pop git add . git commit -m "Your message here"

Option B: cherry-pick

git checkout name-of-the-correct-branch git cherry-pick wrong-branch-name git checkout wrong-branch-name git reset HEAD~ --hard

Pick whichever matches how your brain works. I use stash more; cherry-pick is cleaner when the commit is already perfect.

Oh shit, I ran git diff and nothing showed up

You changed files, but git diff is empty because you already staged everything.

git diff --staged

Yes, it is a feature. No, it is not obvious the first time. File under ¯\_(ツ)_/¯.

Oh shit, I need to undo a commit from five commits ago

You do not have to manually copy old file contents. Revert creates a new commit that undoes an old one.

git log # Arrow keys to scroll; copy the hash of the commit to undo git revert <saved-hash> # Git opens an editor for the revert message — save and exit

Safe for shared branches because it does not rewrite history—it adds a new “undo” commit on top.

Oh shit, I need to undo changes to one file

git log # Find a commit from BEFORE the file broke; copy its hash git checkout <saved-hash> -- path/to/file # Old version is now staged git commit -m "Restore file to known-good version"

When I finally learned this, it felt huge. On what planet is checkout -- the intuitive “undo file” command? Still: it works.

Oh shit, I give up — nuclear option

cd .. sudo rm -r fucking-git-repo-dir git clone https://some.github.url/fucking-git-repo-dir.git cd fucking-git-repo-dir

Thanks to Eric V. for the joke. (All complaints about sudo in a Git blog post can go to him.)

The actually-approved nuclear reset

If your branch is so broken you need to match the remote exactly—destructive, unrecoverable locally:

git fetch origin git checkout main git reset --hard origin/main # Remove untracked files and directories git clean -d --force # Repeat checkout / reset / clean for each broken branch

Quick reference

SituationCommand to remember
“Go back in time”git refloggit reset HEAD@{n}
“Fix last commit”git commit --amend
“Undo old commit safely”git revert <hash>
“Restore one file”git checkout <hash> -- path/to/file
“Diff staged stuff”git diff --staged
“Wrong branch”reset --soft + stash or cherry-pick

Disclaimer

This is not exhaustive Git documentation. There are purer, more theoretical ways to do almost everything here—I arrived at these through trial and error, swearing, and table-flipping.

Take what helps. When in doubt, reflog first, ask second, reset --hard last.

If you want the long-form “build Git from scratch” mental model, check out Build Your Own Git From Scratch. If you want collaboration workflows, see Git & GitHub from Zero to Collaborating.

Contact

Get in Touch

Want to call me? book a call and I'll respond in the available time slot. I will ignore all soliciting.

GitHub
LinkedIn
youtube