Made a Mistake in Git? Keep Calm and Hit Undo
Hi Friends.
My first exposure to programming was when I was studying at university. There were modules where my course lecturers would talk about things ranging from programming techniques to algorithms. We’d do various exercises to help us understand the concepts, and there would generally be a coursework for each module. The computing laboratory where we did our work was full of computers dual bootable for Linux and Windows. We were encouraged to use Linux; most of the tutorial sessions were on Linux too, furthering the bias. This was before Visual Studio Code was a thing, and the promoted editor at the time was Emacs.
While extremely capable and feature rich, Emacs is not an Integrated Development Environment (IDE): features like debugging and source control are not (or at least were not at the time) integrated into the editor. We’d debug by inserting console-output lines into the code; we’d do source control by manually copying the (admittedly small set of) source files into a (hopefully well-named) backup directory somewhere on the disk.
I encountered proper source control in my first programming job, where I was introduced to Git. It was a new concept to me. When I was ready to make my first ever commit, I asked my mentor how to proceed. He happily walked me through the process, and I made notes on each of the steps as they were described to me: I wanted to be able to do this on my own in the future, and I also didn’t want to distract him from his work just because I wanted to commit my code.
I was working on a large piece of work – or at least large for me at the time – and roughly two weeks went by. In that time, I made a few milestone-commits so that I could revert if things went wrong. I then came to a point where I needed to refresh my local copy of the code to include the work of my teammates. I opened Git Bash, referred to my notes, and typed in a few commands on the command line.
I can’t remember exactly what I did, but I do still remember how I felt. I somehow managed to lose my local branch containing around two weeks’ worth of work. Bear in mind I wasn’t experienced enough at that point to know to push to a remote branch regularly for backup purposes.
I sat there with a sinking feeling, not knowing what to do. Trying to remain calm, I slowly turned to my mentor who was sat at the desk next to mine. I slowly explained what had happened, or at least to the best of my ability. He looked a little worried, moved over to my computer, and then started to click on various things trying to understand what I had done. A few minutes later, he called over to his mentor. A few discussions led to confused expressions, and then to a few online searches.
Luckily the team was understanding, and they were able to help me recover my work before too long. I learned two things from this episode.
The first was what they told me while unsure of whether I’d have to remember and rewrite what I’d done for half a month: always create backups of branches containing important work. Push to a remote branch for an offsite backup – these can always be deleted later when they are no longer needed. If there is any reason why pushing to a remote branch is either not possible or not a good idea, create another local branch at the very least. That way you always have somewhere to reset/revert to if things go wrong.
Secondly, there is an Undo if you need it.
Restoring a Lost Commit
While not as simple as pressing Ctrl+Z, undoing an action is not too difficult once you understand the procedure. I’ve created a basic repository to illustrate the process and opened it in Git Extensions. You can see a screenshot of it in Image 1.
I’ve busily been working in this repository and created three commits. I then ‘accidentally’ reset my branch and working directory back to the second commit. I’ve lost all the work that was in Third commit. My repository now looks like Image 2 in Git Extensions:
If this ever happens, there’s no need to panic. It is possible to see all the changes that have happened to the repository and jump to any point in that list. The first step is to open a console and navigate to the repository. I’m using (and showing screenshots of) Git Bash, but any console with Git in its path environment variable should do. After that, type git reflog
to display its history. It should be something like that shown in Image 3.
Note that Third commit is still in the history. It’s that point that we want to revert to – the commit before the main branch was reset back to Second commit. We can see the commit hash for Third commit on the left in yellow: 57c5152
. We can then checkout that commit in the console:
The information in the console (pictured in Image 4) tells us that our repository is in the same state as it was at commit 57c5152
. This is where we want to be, so that we can recover our lost commit. We are also in a detached HEAD state, meaning that we are not currently on any branch. We can then create a new branch at this point:
Doing so returns us to familiar territory. Looking at our repository in Git Extensions (Image 6), we can see that we have recovered our lost commit!
Wrapping Up
Mistakes are easy to make when using Git. The best strategy for avoiding the stress that comes with losing work is to make a backup of your working branch. The easiest way to do this is to push to a remote branch. This can later be deleted when it is no longer needed. If creating/pushing to a remote branch is not an option, creating another local branch also gives you a pointer to your latest work if things go wrong.
If you have neither and something does go wrong, there’s still a good chance that you can restore your work. By looking at the reference logs, it’s possible to jump to any point in the displayed history and create a new branch. This will set the repository to the same state as it was when the commit was made.
Knowing this information has saved both me and a few of my teammates more than once. And now that you know about Git’s reference logs and how to navigate them, you too can be the one who saves the day when disaster strikes!