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, abit 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.