If you’re in a panic there’s a TL;DR version at the bottom of the page
We’ve all done it. Working for ages tracking down that elusive bug in a project. Diligently committing away on our local repo as we make small changes. We’ve found the convoluted 50 lines of tortured logic, replaced it with 5 simple easy to read lines of code and all the test have passed. So we push it backup to github and wander off to grab some a snack as a reward
Halfway to the snacks you suddenly have a nagging doubt in the back of your mind that you don’t remember starting a new branch before starting on the bug hunt.
Snack forgotten you hustle back to your desk, mistype your password twice as you try to login, and there it is. You’ve pushed directly into the main branch!
Fear and embarassment kick in. Hell, how am I going to fix this! And how much of an idiot am I going to look!
Been there, done that, got enough T-Shirts I really don’t need to buy clothes.
First off, don’t panic. You aren’t the first, and you won’t be the last. We’ll walk through some simple steps to recover from this moden faux pas (I don’t think Debrett’s cover this situation yet, but if they’d like to I’m happy to syndicate)
First off, jump on Slack/Teams/Email or whatever you use to communicate across the project to let everyone know what you’ve done. It’s much less embarrassing to do it now that when someone’s forked off of your unchecked code, or checks something in and merges with it
Now you need to get your commits out of main branch. As these have been committed there’s 2 git options to look at, revert or reset. As this is a public SNAFU then revert is the correct way to do this
git revert creates a commit that undoes the commits you’re reverting so everything is logged in the history.
git reset will remove the evidence it ever happened from the commit history, which makes it hard to pinpoint errors if you don’t get it perfectly right
This doesn’t mean a git revert isn’t without it’s issues or potential pitfalls. But, because you alerted everyone in step 1 (you did fess up didn’t you?) you’ve got some breathing space, so take it slowly and don’t screw it up again
First you need to work out how far back you need to revert to. Your options are to revert a set number of commits or to revert to a specific commit
To revert a x commits, you’d use this syntax
git revert HEAD-x
So to revert 2 commits you’d use:
git revert HEAD-2
But how would you know how many commits to revert? That leads into the next bit, working out which commit to revert to. There are 2 options here, github or git log
Getting Commit ID from git log
git log is the more complex way of doing this, but is much more flexible. And if you’re like me and spend most of your git time on the command line then it saves finding the mouse and a different window. We’ll look at 2 command line options that should be enough to sort out anything but the worst messages
Running git log on it’s own produces a lot of verbose output:
That’ll keep paging through as much history in that branch as has been kept. To exit just hit q
For some brevity we use the –oneline switch to just return the basic facts:
This is much easier to read, but still returns everything in the history. So let’s reduce that with the -x parameter, where x is an integer saying how many lines you want returning:
Hopefully if you’ve caught the issue quickly and warned everyone else of the issue you won’t have too many commits you need to scan. For the revert you need enough of the Commit ID to be unique, which –oneline gives you
Getting Commit ID from Github
As you’ve pushed the commits to github, github offers a nice way to see the commit history. Below is a snapshot of a repository I’ve just had to revert because I wasn’t paying attention.
To get the commit history, click on the highlighted number of commits.
This pops up a history list of all the commits with their commit hash:
There’s a handy clipboard button next to each commit to grab the Commit ID for the revert
Reverting the Commits
Now we need to revert the unwanted commits. There are 2 options. You can revert a specific number of commits from the current HEAD of the branch. For example, to revert the last 2 commits in the branch you’d use:
git revert HEAD-2
or you can revert to a specific commit id
git revert 93cd242
Personally, I always go with the commit hash. When you’re in a bit of a panic the first thing that goes for me is counting, so having an exact value to revert to saves a lot of double checking
And you can revert commit by commit if you wanted. In the example I’ve been using here I wanted to make sure exactly what was being taken out of files as I went along. So if you look a the git history from after I’d fixed things you can see 2 reverts at the top of the history
So now you’re reverted your local repository, the next thing you need to do it to push the changes back up to the github repository. I know you know how to do this as that’s what caused this issue in the first place!
Finally, let everyone know that they can use the main branch again and make a not to check in future
Let everyone know the branch is not right to stop any pulling/pushing/branching from it
Then get the commit history:
git log --oneline -20
Then revert to the CommitID before the wrong commits:
git revert <CommitID>
Finally push everything back to the origin:
Let everyone know the main branch is safe to use again.