Daniel D. Beck

Git reflogs don't have to be scary

If you’re keeping your documentation in Git (along with everything else, as in a docs-as-code workflow), then there are more opportunities than ever to get Git into a weird or seemingly catastrophic state. You can amend a commit or rebase a branch, only to find that some of your hard work has gone missing.

Lots of Git troubleshooters suggest using git reflog to rescue yourself. For example, in the excellent cheat sheet zine Oh shit, git!, Julia Evans and Katie Sylor-Miller suggest using git reflog as a “time machine”. It’s good advice, but the output can be intimidating:

238134c14 (HEAD -> prepare-release, origin/prepare-release) HEAD@{0}: commit: Add release note for #9821
feeb4120d refs/heads/prepare-release@{1}: rebase (finish): refs/heads/prepare-release-2021-06-03 onto efd75785a3788f84f585033e9e46002167cb248b
feeb4120d HEAD@{1}: rebase (finish): returning to refs/heads/prepare-release
feeb4120d HEAD@{2}: rebase (pick): Add release note for #10695

To make matters worse, you’re likely to only ever run git reflog when something bad has happened, such as suspected data loss. But under threat is the worst time to learn a new tool. It’s no wonder that git reflog has a reputation for being scary.

I can’t make git reflog any less cryptic, but I can do something about the “scary” part.

Look at reflogs in non-emergencies!

To take the fright out of git reflog, take git reflog out of the fright. Try running git reflog before and after routine, low-stakes Git actions.

For a small example, try running git reflog just before changing branches. This is what my git reflog output looks like while on the main branch:

$ git reflog
d1a3f06 (HEAD -> main) HEAD@{0}: commit: Add new parameter
119de7f HEAD@{1}: commit: Add function
3da172d HEAD@{2}: commit: Add additional link

Next, I run git switch --create example-branch (to create a new branch and immediately check it out). This state change is reflected in the output of git reflog, run immediately after git switch:

$ git reflog
d1a3f06 (HEAD -> example-branch, main) HEAD@{0}: checkout: moving from main to example-branch
d1a3f06 (HEAD -> example-branch, main) HEAD@{1}: commit: Add new parameter
119de7f HEAD@{2}: commit: Add function
3da172d HEAD@{3}: commit: Add additional link

Even though I did something fairly routine, git reflog gives me a comprehensive view into Git’s representation of the state of my checkout. git reflog shows:

  1. The last action that Git did, which affected the state of the repository: checkout: moving from main to example-branch.
  2. The current state of HEAD (that is, the currently checked-out branch or, in git reflog’s terms, HEAD@{0}) points to example-branch.
  3. The hashes—that is, the actual state of the files of my repository—are the same for the current HEAD (HEAD@{0}) and the previous HEAD (HEAD@{1}).

That’s a lot of information for something as supposedly simple as starting a new branch!

You can learn more about Git’s operations by trying this before more complex commands too. For example, if you run git rebase, then you might see several steps added to your git reflog output at once, one for each commit on your branch.

To illustrate, here’s my git reflog output after a recent rebase:

feeb4120d HEAD@{103}: rebase (finish): returning to refs/heads/prepare-release-notes
2e6072db5 HEAD@{104}: rebase (pick): Add release note for #10581
31c52bfb5 HEAD@{105}: rebase (pick): Add release note for #10646
f5a911c95 HEAD@{106}: rebase (pick): Bump version to v3.3.6
efd75785a HEAD@{107}: rebase (start): checkout main

For each commit on my prepare-release-notes branch, there was a corresponding pick entry in the git reflog output.

Try it yourself

Git has a (richly deserved) reputation for unnerving new Git users. But often the difference between a successful and unsuccessful Git troubleshooting session is confidence.

Try running git reflog more routinely to get some of that confidence. The next time you’re faced with a problem, you won’t be in a break-glass-in-emergency situation. Instead, you’ll be relaxed because you’re using one of several familiar tools in your Git toolbox.