How Git’s reflog can save your ass

I think we all know, and hopefully love Git. Git is very powerful and even so, a lot of people (including myself) haven’t experienced the full power of Git. I for myself haven’t used reflog or even heard about it for a long time. However, reflogs can probably become really important.

What is this reflog?

Git describes reflogs as:

Reference logs, or “reflogs”, record when the tips of branches and other references were updated in the local repository. Reflogs are useful in various Git commands, to specify the old value of a reference.

Sure, this sounds a bit complicated, but in the end it’s fairly simple:

For every “update” we do in our local repository, Git will create a reference log entry.

An example

Let’s say you’ve a git project with some files in it:

We check the status of our local repository and all looks fine:

Now we want to add a new feature and therefor we create a new branch:

Let’s say our feature needs a new file and a change on an existing one:

Looks fine, so let’s stage the files and commit them into our awesome-feature branch:

Time flies and we’ve to work on another topic now, however our feature isn’t finished yet. So we’ll switch back to the develop branch:

After some changes our develop branch diverged from the awesome-feature branch and we have all those new shiny commits:

Now we could easily jump between branches or commits we’ve done in the past, just by using our lovely git checkout command.

However, we could also use our reference log to see what we’ve done so far!


The reference log is a list of local actions, if you want so:

As you can see, these are all the actions you’ve done with git – not only commits! While git log shows only the logs of commits, git reflog shows you all your local actions. This might be comparable with the bash history.

For example I see that “4 changes ago” I’ve commited the commit  awesome feature. I can now reference to this commit with its SHA string  de5ed6e or by using the HEAD@{4} syntax.

Now you might say: All fine comrade, but I can also use the normal git log as I can see the same commit in there too. So why/when the heck should I use the reflog over log?

First of all, the reflog is a “changelog” of all the steps you’ve done so far. This is quite nice, but trust me it gets better!

Let’s say you’ve pushed your awesome-feature branch to the remote origin, or already merged it into your develop. So you might no longer need the branch in your local repository and therefor you delete it:

Now you’ll have a look at the log again:

Oh, farts… Did I just delete the awesome-feature branch before merging it locally or pushing it to the origin? Did I just lost all my changes? Exactly this happened to me twice so far. It’s late night, you’re jumping between branches and accidentally deleting the wrong branch (it was really late and I was tired as f*).

Now you’re lost, aren’t you? No, you’re not, because there’s our saviour, our magic reference log:

And there it is, our missing commit. Let’s get it and restore our branch:

A quick look on our log tells us we’re safe again:

The Git reference log finally saved our asses – YAY! This is awesome, innit? And the best thing is, it also works when you messed up your (local) rebase 😉

Reflog and expire

But be warned. Git reference logs can be expire, which can be controlled with the expire argument. The expire time can also be configured via gitconfig! However this must be explicitly configured.

If you didn’t knew reference logs so far then you might ask yourself: Wait, you say all those sensitive commits (e.g. accidentally commited passwords) I removed in the past by rewriting the history are still there in the reflog? Yes mate, all those sensitive commits might still be existing if they didn’t expire – which they don’t do by default 😉


  • Ivan Reply

    nice one

  • Bill Gale Reply

    Very helpful. Here are some additional useful reflog tricks.
    $ git reflog

    display file from reflog commit
    $ git show HEAD@{}:./

    create local copy of file from reflog commit
    $ git show HEAD@{}:./ >

    $ git show HEAD@{31}:./.gitlab-ci.yml
    $ git show HEAD@{31}:./.gitlab-ci.yml > ./.gitlab-ci.yml.31

    also git diff works with commits in the reflog.
    $ git diff ./

    $ git diff e9f1f87 25dae48 ./.gitlab-ci.yml

  • Bill Gale Reply

    Trying again the web page swallowed my code :(.

    display file from reflog commit:
    $ git show HEAD@{##}:./filepath

    create local copy of file from reflog commit:
    $ git show HEAD@{##}:./filepath > newfile

    diffing file across reflog commits:
    $ git diff oldsha newsha ./filepath

    $ git show HEAD@{31}:./.gitlab-ci.yml
    $ git show HEAD@{31}:./.gitlab-ci.yml > ./.gitlab-ci.yml.31
    $ git diff e9f1f87 25dae48 ./.gitlab-ci.yml

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.