Have you ever committed something, tried to git rebase, and everything went horribly horribly wrong? Or accidentally git reset --hard HEAD^ when you meant to git reset HEAD^? Have no fear, git reflog is here!

When you use git, commits are never lost. You can always get back to any repository state as long as you committed your changes. The only time commits are actually deleted is if you git gc --prune (so be careful with that one!).

If you run git reflog right now in a repository you’ve been working in, you’ll see lots of changes that look something like this:

c5c3a82... HEAD@{0}: pull origin featureB: Merge made by recursive.
49d0608... HEAD@{1}: reset --hard HEAD^: updating HEAD
3ed01b1... HEAD@{2}: pull origin featureA: Merge made by recursive.
49d0608... HEAD@{3}: pull origin bugfixJ: Merge made by recursive.
854d44e... HEAD@{4}: commit: Add more cowbell to foo.c
6dbc22d... HEAD@{5}: pull origin bugfixI: Merge made by recursive.
9bdb763... HEAD@{6}: commit: Remove weevils
8518f9d... HEAD@{7}: checkout: moving from wickedfeature to master

These lines can be broken down into 4 parts: commit hash, commit pointer, action, and extra info.

It’s great that you can see this information but what use is it to us, you ask? Remember that git branches are just pointers. The only reason there is history associated with a branch is because the commit it points to has parents.

If we wanted to get back the commit that was lost at HEAD@{1}, we could just git reset --hard HEAD@{2}. Now our current branch (and working copy) are set to the repository state before we did the reset.

If we wanted to just see what that state was, we could git checkout -b temp HEAD@{2} (or git checkout HEAD@{2} if you have git 1.5.0 and up).

Being aware of git reflog will make you feel that much more comfortable when running commands that alter history. Just remember, as long as you’ve committed it, it’s still there!