We talked about the reflog, but I had initially told you that the magic comes from combining reflog and reset. Let’s see an example where we jump in the past to later jump back to the future.

Let’s take our 3-commit history again: c1, c2 and c3. If I do a git reset --keep c1, commits c2 and c3 get orphaned. My log no longer displays them.

My reflog recorded the reset as a new entry, because it moved the HEAD: “reset: moving to c1”. We can use that same reflog to figure out what the earlier position was, and find c3 as HEAD@{1}. So we can undo the reset using either of these references, say git reset --keep HEAD@{1}. And what do you know: we get our log back as it was before our clumsy reset.

If we look at our reflog again, we see it recorded a new HEAD movement, tracing all our commands. So we could “reset the reset’s reset” again with the same command: one step back, one step forward, then one back again. Kinda useless, but I love that we can.

(Example 15-back-to-the-future)

Let’s do that in our terminal for kicks.

We have 3 commits, and as an exercise I git reset --keep c23aa24. If I clear my terminal and display my log again, only the first commit remains. As my terminal got cleared, I can’t cheat and copy-paste the reference of now-orphan commits that I had displayed. So I need to look at my reflog to get my previous position. Let’s look at the 3 most recent ones: git reflog -3. I can see that the second most recent entry, HEAD@{1}, is the commit I was on just before, the one with the message “Update files”. I can use that to do a git reset --keep HEAD@{1}, then check my log. And to wide applause, ladies and gentlemen, here's my restored history! Thank you, thank you!