Lesson 5 of 6 in Undoing Things

Rescuing lost work

Story: The Loose Cannon swears that branch is gone for good. The agency has a long memory.

Committed work is hard to lose. A reset, an amend or a deleted branch takes commits off a branch, but the commits themselves stay in the repository. What's gone is a name that points at them. In the Live Graph they turn faded, unless another branch still has them.

To get them back, you need to find them. That's what the reflog is for.

The reflog

Every time HEAD moves, git writes a line in the reflog: when you commit, switch, reset, amend, merge or revert. git reflog lists those lines, newest first.

Say you made three commits on main and reverted the last one. Then you made a branch dark-mode with one commit, switched back to main and deleted dark-mode:

$ git reflog
99af3e7 (HEAD -> main) HEAD@{0}: checkout: moving from dark-mode to main
df79e5b HEAD@{1}: commit: Darken the footer
99af3e7 (HEAD -> main) HEAD@{2}: checkout: moving from main to dark-mode
99af3e7 (HEAD -> main) HEAD@{3}: revert: Revert "Add the banner"
0067ace HEAD@{4}: commit: Add the banner
984ebf9 HEAD@{5}: commit: Style the heading
a0ec373 HEAD@{6}: commit (initial): Add the home page

Each line shows the commit HEAD pointed at, a name for that moment, and what happened. HEAD@{0} is now, HEAD@{1} is one move ago, and HEAD@{2} two moves ago. Switching between branches is called checkout here, even when you used git switch.

You can use these names anywhere git expects a commit: git reset --hard HEAD@{1}, git branch rescued HEAD@{3}, git merge HEAD@{2}. git reflog only reads, so running it is always safe.

Each branch also keeps a reflog of its own. main@{1} means where main was one move ago, which is what Moving a branch back used to undo a reset.

Undo a reset

A hard reset moved main back by mistake? main@{1} is where it was just before:

git reset --hard main@{1}

The same works for an amend: main@{1} is the commit as it was before you amended it.

Bring back a deleted branch

Deleting a branch deletes its own reflog too, so dark-mode@{1} no longer works. But HEAD was on that branch while you made its commits, so HEAD's reflog still has them. In the reflog above, HEAD@{1} is commit: Darken the footer, the last commit made on dark-mode.

Put a branch back on it:

git branch dark-mode HEAD@{1}

git branch <name> <commit> creates a branch at any commit, not only the one you're on. git switch -c <name> <commit> does the same and switches to it.

Read it right before you use it

The numbers shift. Every move adds a line at the top, so after your next commit, what was HEAD@{1} becomes HEAD@{2}. Run git reflog just before you use one of its names, and pick the line by what it says happened, not by its number.

What the reflog can't do

  • It only rescues commits. The reflog records where HEAD and your branches pointed. An edit you never committed has no line in it, so the reflog can't bring it back.
  • It's yours alone. It lives in your repository and isn't pushed or cloned. A teammate's reflog knows nothing about your moves.
  • It doesn't last for ever. On a real machine, git expires old entries in the end: by default after 30 days for commits no branch can reach, and 90 days for the rest. Rescue lost work soon.

New commands

  • git reflog

Explainer: The reflog remembers where you've been

project: your repo, you are here7cfc0e4 Write day 17cfc0e4d80b67d Write day 2d80b67d3997c22 Write day 33997c22a36c656 List the photosa36c656HEAD → mainphotos
The repository at the end of the Explainer.
Graph as text

project: your repo, you are here

  • HEAD → main at 3997c22 "Write day 3"

Branches and tags

  • main at 3997c22 "Write day 3"
  • photos at a36c656 "List the photos"

Commits, newest first

  1. a36c656 "List the photos"; parent 7cfc0e4; refs: photos
  2. 3997c22 "Write day 3"; parent d80b67d; refs: HEAD → main
  3. d80b67d "Write day 2"; parent 7cfc0e4
  4. 7cfc0e4 "Write day 1"; no parent

Challenge 1 of 3

Story: Two days of the field journal, wiped in one command. Wind them back in.

Someone ran git reset --hard HEAD~2 on main by mistake, and the commits Write day 2 and Write day 3 vanished from it. Put main back exactly where it was before the reset, with nothing left to commit.

Unlocks after Branching & Merging.

Terminal

Unlocks after Branching & Merging.

This Lesson can be played once Branching & Merging is complete. Its text and Explainer are open to everyone.