LD

TIL: Recovering from an accidental force push in git

I don’t normally force-push to repos, but I wanted to overwrite the contents of an old project with a new one of the same name. So last night, I created my new project, set the git origin url to the correct one (git set-url origin git@…), and then ran git push -u origin main –force. […]

I don’t normally force-push to repos, but I wanted to overwrite the contents of an old project with a new one of the same name. So last night, I created my new project, set the git origin url to the correct one (git set-url origin git@...), and then ran git push -u origin main --force. After that, I switched off my laptop and went to bed.

Then, this morning, I switch on my other machine and pull the project I’m working on aaaand… everything disappears. Oops. I wasn’t thinking and set the wrong url in the repo, and force-pushed to the wrong repository. Luckily it was fairly easy to recover from this, and nothing there goes to prod so there were no services with downtime.

Getting back to the correct commit

My first instinct was to check git log, but because git push --force overrides the log, all I saw was the classic “initial commit” message from my new project. However, you can still get the full commit history using reflog.

Running git reflog show gave me a full log of every commit, even the ones from before the force-push. I could see after the two commits I’d accidentally pulled (one with my initial commit, one rebasing it onto my local repo), and then under that was the last real commit I made on the project. The entry looked a bit like this:

51f1269 HEAD@{4}: commit: Store authors alongside webmention

So, running git checkout HEAD@{n} where n was the number in the curly braces let me checkout my original changes in a detached state. Great, all was not lost!

Pushing back to main

I didn’t really care about the changes I currently had on the repo from the new project - it’s just boilerplate setup, and it’s still on my other machine anyway. So, to move my currently detached state back to the repo HEAD, I doubled down on my mistake and did a second force push: git push origin HEAD:main --force.

And that worked! My git commit history is back, the files are visible on the remote repository, all is not lost.

Lesson learned?

Eh, maybe? I wouldn’t use push --force on anything that: a) wasn’t owned by me, b) was deploying straight to production/was actually in use. This was just me being overtired and too lazy to delete & remake a repository. I’d probably do it again, which is why I’m writing this.

Responses