Lesson 29 · Recovery
Find a lost commit with reflog
Find a commit that a hard reset left behind in the local reflog, check its file before you trust it, and put a branch on it, without moving your current checkout.
- Level: Advanced
- 8 min read
- 5 min video
- Updated
- Before this lesson: Reset: soft, mixed and hard
Progress saved in this browser.
Playing loads the video from YouTube (privacy-enhanced mode).
What you will learn
- Read the reflog as this repository's record of where HEAD and branches have been.
- Check a candidate commit's content before rescuing it.
- Create a branch at the measured commit without checking it out.
- Say what the reflog cannot bring back: uncommitted work and expired entries.
Before you start
You are on private/lost-signup, a branch from lesson 18's result M. You committed a note, "docs: keep the signup recovery note", which added docs/signup-recovery.md, and then ran a hard reset one commit back. The note is gone from the branch, from the graph and from your files. You have no rescue branch yet, and you changed nothing else.
Everything is local and on the Free plan (GitTree asks you to sign in): no hosting account, no provider, no internet. Every identity is fictional (example.com). Never run this lesson in a real project. The hard reset in the preparation is a rehearsal in a disposable copy.
Make the changes in GitTree or with the native Git commands, not both in the same copy. Reading the result is always safe. The menu labels come from GitTree 2.0's own strings and the native commands were run with Git 2.43 in disposable copies. The GitTree steps were not run on macOS, Windows or Linux.
Concept and state effects
The reflog is a local diary of ref movements. HEAD has one, and so does each branch. It records "commit", "checkout", "reset" and the like, with the commit each one landed on. Another clone does not have your diary. A commit that no branch names can still exist, and the reflog is how you find it.
Selectors such as HEAD@{1} count entries back from now, so they change with every later operation. Read the action, the time, the ID and the file of a candidate before you use it. Do not memorise an offset as a recipe.
The reflog finds commits that were saved. It cannot find an edit that was never committed, as lesson 27 showed. Entries expire: by default Git keeps entries for commits no branch reaches for about thirty days, and a repository can change that. Do not run cleanup or expiry commands while you recover.
Creating a branch at the commit adds one ref and nothing else. The current branch, the index and your files stay where they are.
Prepare the exact project state
Start from a separate ordinary copy of lesson 18's result M and leave your original untouched. Create the branch, save DOC_LOST, commit it and hard-reset one commit back. This destructive preparation is for a disposable copy only.
Complete file inputs
Save only at the phase named below. These are full UTF-8/LF bodies with a final newline; never paste Markdown fences. Unchanged runnable files inherit the named input. Versions in separate variants must not overwrite the original.
docs/signup-recovery.md — DOC_LOST
# Recovered signup work
Keep a branch name before leaving useful experimental work.In GitTree
Open the palette with Command+Shift+P (Ctrl+Shift+P on Ubuntu).
- Build the rehearsal as the next section shows and note the subject of the lost commit.
- Open the palette and run View Reflog…. The dialog "Reflog" opens with Reflog of set to HEAD; the entries are listed newest first.
- Read the top entries. The newest says "reset" and the one below it says "commit" with the subject "docs: keep the signup recovery note". Use Show Older Entries if the list is long. Do not assume the second row is always the right one.
- Select the commit entry. The dialog shows Show in Graph and New branch name. Show in Graph can only place a commit that a branch reaches, so for this lost commit it closes the dialog and the graph stays on M: reopen the reflog for the next step. You read the commit's file after you restore it.
- Back in the dialog, select the same entry, type
rescue/signupin New branch name and choose Restore as Branch. The notice says "Created branch rescue/signup. Undo removes it again." - Check the result:
rescue/signuppoints at the lost commit, the current branch is stillprivate/lost-signupon M, and your files are unchanged. Select the restored commit and open its filedocs/signup-recovery.md: it is DOC_LOST. - Leave the rescue branch in place. Do not run any cleanup to tidy the graph.
For every ordinary commit in the course: Summary is the stated subject, Description is empty and the options Amend Previous Commit, Skip Hooks, Add Signed-off-by, Different Author, Push After Commit and Allow Empty Commit stay off.
In the terminal
Only in a separate, clean copy of lesson 18's result:
git switch --create private/lost-signupSave DOC_LOST as docs/signup-recovery.md, then:
git add -- docs/signup-recovery.md
git commit --quiet -m "docs: keep the signup recovery note"
git reset --hard HEAD~1
git reflog show --format=%gs -2 HEADreset: moving to HEAD~1
commit: docs: keep the signup recovery noteList the candidates with their IDs and check the one you think is lost:
git reflog show --format='%H %gs' HEAD
git show "<lost-sha>:docs/signup-recovery.md"Replace <lost-sha> with the ID on the "commit: docs: keep the signup recovery note" line. In this immediate example HEAD@{1} is the same commit, but that offset is not a rule. Create the rescue branch without checking it out:
git branch rescue/signup "<lost-sha>"
git show rescue/signup:docs/signup-recovery.md
git symbolic-ref --short HEAD
git status --shortThe file is DOC_LOST, the branch printed is private/lost-signup and the status is empty. Your files do not show the note, because HEAD stayed on M. No expiry or cleanup command is part of this.
Result
Where you end: rescue/signup points at the lost commit and its file is DOC_LOST. The current branch, the index and your files are exactly as they were after the reset, and nothing was pushed.
Common mistakes
- Using
HEAD@{1}as a fixed recipe instead of reading the entry. - Resetting or checking out again before saving a branch, which adds more entries and buries the one you want.
- Expecting the reflog to hold an edit that was never committed.
- Running cleanup commands while looking for something.
If something goes wrong
If the commit is not in the list, you may be looking at the wrong ref: switch Reflog of between HEAD and the branch, and use Show Older Entries. If it is truly gone, it expired or was never committed. In the app, the notice after Restore as Branch says Undo removes the branch again.
Check your understanding
Answer each question, then read why. Questions marked “Required” count toward completing the lesson.
0 of 6 correct
Answer the required questions correctly to complete the lesson.
Checked in this browser.
Practice
Report the two newest reflog lines, the ID of the lost commit, the first line of the recovered file and the branch your checkout is on. Then say what the reflog would show for an edit you never committed.
Your own confirmation: the site cannot see your computer.
To complete the lesson, answer the required questions correctly and confirm the practical exercise.
Recap
- The reflog is a local diary of ref moves.
- Check the candidate, then branch from it.
- It finds commits, not unsaved edits.
Related
Glossary terms introduced
Reflog — سجل المراجع; rescue branch — فرع حفظ; selector — محدِّد.
Video transcript
The narration of the video, cue by cue.
Show the transcript
- A commit seems gone. Git still remembers where it was.
- The reflog is a local diary of where HEAD and branches have been.
- A commit no branch names can still be listed in it.
- In a disposable copy: commit a note, and then hard reset it away.
- The graph shows only M. The note is nowhere to be seen.
- Don't reset, or clean up, now. Look first.
- Open the palette, and run View Reflog.
- The dialog opens on HEAD. The newest move is first.
- The newest row is the reset. Just below it is the lost commit.
- If the list is long, show older entries.
- You can switch between HEAD and the branch.
- Don't memorize HEAD at one. Read the entry instead.
- Select the commit entry. New choices appear.
- Show in Graph cannot place it: no branch reaches this commit.
- So restore it as a branch first, then read its file.
- Go back, and select the same entry.
- Name the branch rescue slash signup.
- Restore it as a branch. The notice says undo removes it again.
- The rescue branch is on the lost commit. You are still on M.
- Your files did not change.
- In the terminal, the two newest lines are the reset and the commit.
- With IDs, we pick the commit by its line.
- git show with a path reads the file from that commit.
- git branch makes the rescue branch. Our checkout stays put.
- The status is empty, and the file is safe on the branch.
- An edit that was never committed is not in the reflog.
- Entries expire. Don't run cleanup while you recover.
- It is local. Other clones don't have your diary.
- Practice: report the lines, the ID, the first line, and the branch.
- Next, GitTree's own Undo and Redo.