Rolling back time remotely with git reflog

2026-02-18

We've all done a bad force-push at some point. Even just the memory of it might invoke the feeling of diamonds being created in the seat of your pants. It rewrote history, there's no way to get it back, right?

Well don't fret, because git is a time machine.

Let's setup a small hypothetical example, where I have a feature branch at mikansoro.my-feature. I want to push to a development branch dev to trigger a CI build without waiting for a PR. In a momentary lapse of judgement, I add the --force flag without thinking about what the state of the remote might be.

git push --force origin mikansoro.my-feature:dev

The push succeeds, the CI build starts, and all is well. Time for coffee.

The ding of a slack DM pierces through the tranquil silence. I've pushed over someone's commits on dev, and I didn't fetch dev before pushing over it. I don't have a rollback point.

Thankfully, git keeps a history of every action taken in its reflog, and git's state can be rolled back to any point on it. Each state in the reflog is denoted by a reference to HEAD like HEAD@{1}. HEAD@{1} is the reflog point equivalent of HEAD~1 for the commit tree.

git reflog
8ac32e5 (HEAD -> main, origin/main) HEAD@{0}: commit (amend): init
f923da8 HEAD@{1}: commit (initial): init

This has saved me countless times over the years from bad stash pops, rebases, merges, etc., but the real magic here is that reflog works on remote branches, and you can reset your local state to the remote reflog's rollback point.

To undo my force push I can checkout a copy of the dev branch, roll it back to the state it was in before pushing, and push it back to how it used to be.

git checkout --track origin/dev
git reflog origin/dev
git reset --hard origin/dev@{1}
git push --force origin dev

For more panic-fueled git rollback tips, check out https://ohshitgit.com (or it's less fruity cousin, https://dangitgit.com/). They're great resources in a crisis.