OMBD#23: Time-Traveling in Git? Meet Git Reflog

Let’s learn to use the power of this advanced tool for Git disaster‑saving

Jon Portella
Level Up Coding
Published in
3 min readApr 6, 2021

--

Welcome to issue #23 of One Minute To Become a Better Developer, where you become a more successful software developer by reading short nuggets of knowledge, one minute at a time.

⏮️ 🔛

Art by my buddy Loor Nicolas

THE PROBLEM

A local branch deleted by accident, squashed commits that we would like to be un-squashed… when a catastrophe occurs, wouldn’t it be great if we could time-travel in Git?

A SOLUTION

Let’s learn how to use git reflog. First, a bit of context.

Reference logs, or “reflogs”, record when the tips of branches and other references were updated in the local repository.

git reflog by default targets HEAD — a symbolic reference to the currently active branch — but other branches, tags, remotes, and the Git stash can also be targeted.

git reflog shows “movements” with the syntax name@{qualifier}. E.g. HEAD@{2} means “where HEAD used to be two moves ago”.

Let’s put it into practice.

Recovering a locally deleted branch

We’ve deleted a local branch, how can we recover it?

git branch -D navbar-feature

We can use git reflog to find a point in history to time‑travel to. We see that one move ago we did the last commit on that branch that we just deleted.

3b7a6fdb (HEAD -> master) HEAD@{0}: checkout: moving from navbar-feature to master
9a07e99f HEAD@{1}: commit: feat: add Navbar
3b7a6fdb (HEAD -> master) HEAD@{2}: checkout: moving from master to navbar-feature

So we can just create a new branch with the content of that point in history:

git checkout -b navbar-feature HEAD@{1}

Fantastic, we have recovered our branch and its commits!

Recovering squashed commits

We have 3 commits:

747ef1e feat: add Button
19d9327 feat: add Navbar
effb3b4 initial commit

We realize that we forget to add something on the Navbar commit, so we add those changes and we commit with a fixup git commit --fixup 19d9327. Our history now:

c2149d1 fixup! feat: add Navbar
747ef1e feat: add Button
19d9327 feat: add Navbar
effb3b4 initial commit

And now, to clean up our history by squashing this last commit with its reference, we usegit rebase --autosquash --interactive HEAD~4. Our history is clean now:

de1e9de feat: add Button
b3b4932 feat: add Navbar
effb3b4 initial commit

However, how can we go back to our history pre‑rebase? git reflog shows that when we committed that fix was 4 moves ago HEAD@{4} , while the most recent moves are part of the rebase.

4610b383 HEAD@{0}: rebase -i (finish): returning to refs/heads/master
4610b383 HEAD@{1}: rebase -i (pick): feat: add Navbar
52d0c48c HEAD@{2}: rebase -i (fixup): feat: add Navbar
07097c96 HEAD@{3}: rebase -i (start): checkout HEAD~4
c2149d1 HEAD@{4}: commit: fixup! feat: add Navbar

So we can just git reset HEAD@{4} and we have recovered our history pre-squash! This is what git log shows now:

c2149d1 fixup! feat: add Navbar
747ef1e feat: add Button
19d9327 feat: add Navbar
effb3b4 initial commit

Thanks for reading! Keep learning, and don’t stop coding 😊

--

--

Software Engineer @ Pinterest - Teacher, maker, and general things do-er. - https://www.linkedin.com/in/jonportella/ - Toronto, Canada