April 06, 2021 • 4 min read
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?
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.
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!
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
Resources