Time-Traveling in Git? Meet Git Reflog

April 06, 2021 • 4 min read

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

Presentation image

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 Button19d9327 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 Navbare
ffb3b4 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 😊


Resources


WDYT about this post? I read you here:

Get notified of new blog posts?

RSS FeedGet an Email

RSS is the correct choice, btw.