Git reflog

  1. Definition
  2. The basic usage of git reflog command
  3. Reflog references
  4. Timed reflogs
  5. Subcommands of git reflog
  6. Recovering lost commits

Definition

The git reflog command is used for Git to record updates made to the tip of branches. It allows to return to commits even to the ones that are not referenced by any branch or any tag. After rewriting history, the reflog includes information about the previous state of branches and makes it possible to go back to that state if needed.


There are some git commands, to which a reference specifying parameter or a “ref” can be applied. This parameter serves to point to a commit. With the help of this reflog mechanism, you can keep track of the update time of git refs in the local repository.

The basic usage of git reflog command

Generally git reflog is used like the following:

git reflog

It is the shortcut of this:

git reflog show HEAD

The command above outputs the HEAD reflog. The output looks like the following:

a32556a HEAD@{0}: commit: migrating content
ab371fd HEAD@{1}: commit: adding git reflog outline
23a491a HEAD@{2}: checkout: moving from stage to feature/solver
7b119cb HEAD@{3}: checkout: moving from feature/solver to stage
56a183a HEAD@{4}: commit: changing color scheme
7a2aa71 HEAD@{5}: commit: adding more color palettes
a56322b HEAD@{6}: commit: adding color tool package

Reflog references

Be default, git reflog outputs the reflog of the HEAD reference, which is considered to be an iconic reference to the branch, which is currently active. You can access a git ref by using the name@{qualifier} syntax.

Execute the following command for getting the entire reflog of all the references:

git reflog show --all

Pass the current branch name to git reflog show, if you want to see the reflog for it. In the example below displays a reflog for the test_branch branch.

git reflog show test_branch
#32a591f test_branch@{0}: commit: add snippets

#23bae4a test_branch{1}: commit (initial): initial commit

Using the command below will output a reflog for a git stash:

git reflog stash
#0d44de3 stash@{0}: WIP on git_reflog: a567574 adding Vue.js

Timed reflogs

There is an attached timestamp to each reflog entry.They can be leveraged as a qualifier which is token of Git ref pointer syntax. This allows to filter Git reflogs by time. Here are some examples of time qualifiers:

  • 1.minute.ago
  • 1.hour.ago
  • 1.day.ago
  • yesterday
  • 1.week.ago
  • 1.month.ago
  • 1.year.ago
  • 2011-05-17.09:00:00

You can also have a combination of time qualifiers (e.g. 1.week.3.hours.ago), and plural forms (e.g. 5.hours.ago). The refs of time qualifiers can be given to other git commands, like this:

git diff master@{0} master@{1.week.ago}

Here we will have a diff of the current master branch against master 1 week ago.

Subcommands of git reflog

There exist some arguments, considered to be subcommands, that are accepted by git reflog. These subcommands are presented below.

Show - git reflog show subcommand

The git reflog show subcommand is an alias for git log -g --abbrev-commit --pretty=oneline. It is passed by default. In the following example, the two commands are equivalent to each other:

git reflog master@{0} = git reflog show master@{0}

Expire - git reflog expire subcommand

The git reflog expire subcommand is used for cleaning old or unapproachable reflog entries. The danger of this subcommand is the possibility of data loss. In fact, the expire subcommand is not used by users. It is used only by the Git. By default, the reflog date of expiry is set to 90 days. Pass --expire=time argument to git reflog expire for specifying an expire time.

Delete - git reflog delete subcommand

The git reflog delete subcommand is designed for deleting passed reflog entries. However, the end users avoid executing this subcommand, because, as in the case of git reflog expire , there is a risk of data loss.

Recovering lost commits

Actually, commits are never being lost in Git, even during history rewriting operations. Let’s see an example of a git log --pretty=oneline that looks like this:

2b43ceab309da94256db8fb1f35b1678fb74abd4 changes in content
c32557493a95185997c87e0bc3a9481715279351 adding Vue.js
abc234f986d270d7f97c77618314a06f024c4563 migrating content
a5673cd762d8ef2e146d7f0226e81a92f91956b1 adding git reflog outline
2bce4a4404c42128bee8468a9517418ed0ea412 initial commit

Now suppose we commit some new changes to this repository and run the following:

#make changes to HEAD

git commit -am "API changes"

As a result, the log now looks like this:

37656e19d4e4f1a9b419f57850c8f1974f871b07 API changes
2b43ceab309da94256db8fb1f35b1678fb74abd4 changes in content
c32557493a95185997c87e0bc3a9481715279351 adding Vue.js
abc234f986d270d7f97c77618314a06f024c4563 migrating content
a5673cd762d8ef2e146d7f0226e81a92f91956b1 adding git reflog outline
2bce4a4404c42128bee8468a9517418ed0ea412 initial commit

At this stage, in order to make an interactive rebase against the master branch, we need to execute the following:

git rebase -i origin/master

While rebasing, the s rebase subcommand marks commits for squashing into the most recent "API changes" commit. As a result of squashing the commits, the git log output now has a look, like this:

40dhsoi37656e19d4e4f1a9b419f57850ch87dah987698hs  API changes
35aee4a4404c42128bee8468a9517418ed0eb3dc initial commit

It now seems that commits marked for squashing are no longer there. If you need to operate on a squashed commit, you can leverage the reflog.

git reflog
37656e1 HEAD@{0}: rebase -i (finish): returning to refs/heads/git_reflog
37656e1 HEAD@{1}: rebase -i (start): checkout origin/master
37656e1 HEAD@{2}: commit: API changes

There are reflog entries for the start and finish of the rebase and preceding those is the "API changes" commit. The reflog ref can be passed to git reset in order to reset a commit before the rebase.

git reset HEAD@{2}

This command will move HEAD to that commit with "API changes", and restore the other squashed commits.




Do you find this helpful?

Related articles