The power of Git Reflog

Introduction

Reflog is a powerful tool provided by Git and helps us in solving a variety of problems. This blog will try to address some of the scenarios that I face which are solved by Reflog.

What is Reflog?

A local version history which records each & every move you make in the repository. It keeps track of all commits, even those that were rewritten. It stores information such as which branch you checked out from, which stash you applied, what commits you ammend, your merges, your rebases, every little detail about what happens in your local repository. Suffice to say, it is really helpful in cases when you mess up history, or even to reference old commits or changes that are no longer part of the "main" history of the project.

Ready? Run the following in your command to see what I mean:

How to access reflog?

Here, you can see all of what you have done in your local repository.


Recover a lost commit due to accidental reset

Now, let's take an example. Your current repository looks like this:

Let's say you did a git reset --hard HEAD~ to remove everything from the most recent commit. You realize that you actually wanted some part of the code or maybe it's commit message as you don't want to rewrite it.

If you do a git log now, as you would expect, the commit is gone!

Here, you can do a git reflog

As you can see, the commit 0d818eb can be seen here. Now, we have a commit hash. As long as we have a commit hash, we can do pretty much anything.

Suppose you wanted to see what changes were made:

You can checkout to the commit

You can reset back to this commit. It will make so as if you never deleted the commit in the first place.


Recover lost commit due to force push [Reflog + Cherry Pick]

Suppose your colleague didn't know that you pushed some commits, and they are trying to fix their commit history. They amend their most recent commit (which was already pushed), now, when try to push normally, they will see a message about diverged histories. They force push out of habit, which fixed their commit history, but had the accidental effect of losing your commit. Now, you have pulled from the remote repository and you lost the commit as well. What a mess! Now you feel the only option left is to redo whatever you original committed. Fear not, reflog comes to rescue.

Assuming you have lost the commit after pull.

You can see the original commit that was made by you.

Now, since you have the commit hash, you can apply it using cherry-pick.

You will see a message such as the patch was successfully applied.

Your lost changes have now been recovered!


Identifying commits made in the current machine

What to do when you have committed large files in a repository

I wanted to figure out what commits were made by using a particular machine.
The problem was that a large file was commited by mistake and was not pushed. We did not realize this at the moment, but afterwards we kept pulling changes from other machines. One day, it so happened, that we needed to push from the "Server" Machine and this is when we realized, that it won't be possible to do so because of the large file.

The first approach we thought of, was to rebase to the last good commit i.e. the commit before the "large file commit". However, this proved to be very problematic. The reason:

So we abandoned this approach and searched the internet for answers, but to no avail.

Finally, we decided, that the best thing to do was to reset to the original commit and pull the other changes into machine. This posed another problem,

So, now, we needed to identify commits made from the current machine.

With a little bit of thinking and trying different things, the solution was found.

Enter REFLOG

Keyword Description
reflog shows all changes (including commits) made in the current machine
author this identifies the user from which commits were made. In our case, each machine only has one account associated with them. For the server machine, that happened to be Kunal's Git account.
grep this is a command line utility which lets us filter out response from a command based on the search string we pass to it.

In reflog, the commits made can be identified by the following pattern:

So channeling the output to grep can help us identify the commits easily.

Now, we had all the commits that were not pushed to master branch because of the "large file commit". The remaining steps can be summed up as:

  • reset to last good commit

  • pull1 changes from master branch

  • cherry-pick the commits collected in previous step

  • push to master

    [1]: When pulling I was getting an error

    I followed the solution mentioned in this answer and ran

    After which I was able to pull without issues. However, as a side effect, reflog was lost.

This is how Reflog ended this Git nightmare and saved the day! Albeit, it was sacrificed in the process.

Thank the author. Fork this blog.


Tagged in git