There will be times when you will realize “Oh, no! What’ve I done?”.
That moment is a classic moment in every developer’s life. Usually, it happens right after when you do something silly, and it costs you hours of re-work.
We tend to become careless in tasks that we do on a regular basis. And one such task for me was Git Squash.
I like my commits to be clean and understandable. Also, I have got a habit of making quick, short commits while I’m working locally. This way helps me to get back to the earlier version without losing much work. I personally recommend “Quick Commits” to everyone.
One downside of it is that you will have a lot of commits in your branch. Some of these commits are a single line change.
It is super okay when you are working alone or in a small team. But when the team size is big or there are multiple teams working on the same codebase then its really important that you maintain a clean commit history that clearly explains what is happening there.
That is why I squash the commits with a relevant message stating “What I Did” and in the description “Why I Did It” before pushing it to the master.
I frequently use Git Squash to make commits clean.
But sometimes… Things don’t go your way 😀
Git Squash
Let me explain “Git Squash” quickly for those who have not heard of it.
As the name suggests, Git Squash is basically squashing multiple commits into one.
I wrote a little example for you to follow.
So, this is how it works.
Now, that you got the idea, let’s see where I made a mistake and why I had to undo the squash.
Git Squash Undo
I was working on a project’s code for 2 days. There were a lot of small careful changes that I made. There were more than 25 commits in the code. And when I squashed the commits, I squashed them with the wrong one.
So, there was a master commit and then there were my commits (on top of the master). But what actually happened was that I merged the commits with the master. Now, the master commit itself was changed and all my changes were in it.
Laugh all you want, but it can happen to you too.
Not only that, but I also got a lot of conflicts in the codebase. And if you are working on a large codebase, you know how hard it is to resolve the conflicts. But that was not even my concern.
The concern was, I changed the master commit. I will have to force push it to put it there. And on top of that, it would create a mess for all the team members. Because the head of the branch will no longer be in sync with the remote. And this will create conflicts for them.
So, there were only two options left –
- I start from scratch
- Undo SQUASH.
I would never go for the first option. It’s time-consuming, repetitive and boring. I stick with the second option.
However, there is no direct way to un-squashing the commits in Git.
UnSquashing is not even a word :p
After 30 minutes of struggle, I reached out to one of my colleague about the problem and he suggested me a life-saving command –
git reflog
Git Reflog to the Rescue
Whenever you make changes to your branch, git records it. Git has it into consideration already that “You will make mistake”.
So, it maintains a history of all the actions that you do inside your Git.
Reflog is a mechanism to record when the tip of branches are updated. This command is to manage the information recorded in it. Basically every action you perform inside of Git where data is stored, you can find it inside of the reflog.
When you run git reflog
, this is what you see.
Here you can find the list of all the commits that you made so far.
Now, all I had to do is create a new branch from the master and cherry-pick each one of the commits that I see on executing reflog
command.
The current branch structure is like this.
Once I have the temp branch, I start picking each commit one-by-one (it is still better than starting from scratch, plus it takes less than 5 minutes to cherry-pick).
All I had to do is fire these commands in order.
git cherry-pick 0cbda5e
git cherry-pick c8b4401
git cherry-pick 4b3affb
git cherry-pick dd4394e
git cherry-pick cfff6b3
git cherry-pick 518699b
After cherry-picking each commit into a new branch, you can safely squash and merge the temp
branch with your master
. And you will not lose any data. You will be sure that all your changes are there. Just be a little more careful this time 😀
It was a relief.
Well, that’s how you save your ass 😀
Do you have a better way, please let me know in the comments below.