Git Recovery & History Surgery
Destroy work four different ways and get it back, then remove a secret from history and understand why that is not the fix.
- Time
- 45 min
- Level
- Intermediate
- Objectives
- 4 objectives
- Cost
- Free
Where this fits in the platform
Already built
This lab adds
- The ability to recover work you thought you destroyed
Which lets you
—
Before you start
You will be able to
- Recover commits after a hard reset, a deleted branch or a bad rebase
- Choose between revert, reset and restore deliberately
- Remove a file from history, and know what that does not achieve
Cost — Free
— a local repository is enough.
Nothing to pay in the browser. Open the terminal runs this against a simulated cloud — the same API calls and the same commands, with no account and no bill. The figure above applies only if you build it in your own.
The scenario#
You reset the wrong branch. A colleague force-pushed over your work. There is an API key in a commit from three weeks ago.
All three are recoverable, and knowing that changes how confidently you work.
Hands-on environment
Run this lab in a real terminal, free and in your browser. The environment is temporary and yours alone — break it as much as you like.
Open the terminalOpens in Killercoda, in a new tab — keep this page open for the steps.
Run it on your own machine
Run this lab on your own machine. One command starts the environment, with everything the lab needs already installed:
You will need:
- git
git clone https://github.com/EgyKode/EgyKode-lab.git
cd EgyKode-lab
./egykode start
./egykode shellYou need Docker and Git installed. Everything else runs inside the environment. The first start downloads it and takes a few minutes; later starts are seconds.
Not sure what you already have? Run: npm run doctor — it checks and changes nothing.
Anything you tick here is your own record. EgyKode cannot see inside that terminal, so the success criteria stay self-assessed even when the environment checks your work for you.
reset --hard, undone
Step 1 of 5
Set up a repository to break#
mkdir /tmp/git-recovery && cd /tmp/git-recovery && git init
for i in 1 2 3 4 5; do echo "line $i" >> file.txt; git add -A; git commit -qm "commit $i"; done
git log --onelineWhat you are proving: You can recover commits the reflog still knows about after a hard reset
Marking this settles success criterion 1.
git reset --hard HEAD~3
git log --oneline # two commits left
git reflog # every position HEAD has held
git reset --hard HEAD@{1} # backgit reflog is the repository's own undo history. A commit stays reachable
for about 90 days even when no branch points at it. Almost nothing done locally
is truly destructive.
What you are proving: You can restore a branch you deleted, from the hash the reflog kept
Marking this settles success criterion 1.
git switch -c feature && echo work >> file.txt && git commit -qam "feature work"
git switch master
git branch -D feature # "permanently" deleted
git reflog | grep feature # the commit hash is still here
git switch -c feature-restored <hash>What you are proving: You can abandon a rebase mid-flight and return the repository to where it started
Marking this settles success criterion 1.
git rebase -i HEAD~3 # not available non-interactively; abort instead
git rebase --abort # puts everything back exactly as it was--abort is always available mid-rebase, and it is complete. Trying a rebase
costs nothing.
What you are proving: You can choose between revert, reset and restore by what each does to shared history
Marking this settles success criterion 2.
The three are not interchangeable, and picking the wrong one on a shared branch is how you create the next problem:
| Command | Does | Use when |
|---|---|---|
git restore <file> | Discards uncommitted changes to a file | You edited something by mistake |
git reset --hard <ref> | Moves the branch, discards commits | The work is local and unpushed |
git revert <commit> | Adds a commit undoing another | The commit is already pushed |
Never reset a branch other people have pulled. revert is the shared-branch
answer: history stays intact and everyone's clone still agrees.
git revert --no-edit HEAD
git log --oneline -2 # the original and its revert, both presentWhat you are proving: You can remove a secret from every commit and verify by searching that it is gone
Marking this settles success criteria 3 and 4.
echo "AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG" > .env
git add .env && git commit -qm "add config"
echo "more work" >> file.txt && git commit -qam "unrelated"
git log --oneline -- .env # still there
git rm --cached .env -q && echo ".env" >> .gitignore
git commit -qm "stop tracking .env"
git log -p --all -S 'wJalrXUtnFEMI' | head -5 # the value is STILL in historyThat last command is the point. Removing the file going forward does nothing about the commits that already contain it, and every clone has them.
# git-filter-repo is the maintained tool; BFG is the alternative
pip install git-filter-repo
git filter-repo --path .env --invert-paths --force
git log --all --oneline -S 'wJalrXUtnFEMI' # goneThe order that actually matters:
- Rotate the credential. Assume it is compromised the moment it was pushed. This is the only step that protects anything.
- Then rewrite history.
- Then force-push and tell everyone with a clone to re-clone.
Doing 2 without 1 is theatre. The key was in a public repository, in CI logs, in forks, and quite possibly in a scraper's database within minutes.
reflog does not show the commit
Reflog is per-clone and local. If the work was only ever on another machine or a deleted remote branch, it is not here.
filter-repo refuses to run
It requires a fresh clone by default. Use --force only when you understand it is rewriting this working copy.
Colleagues' branches break after a rewrite
Expected — every commit hash changed. They must re-clone or rebase onto the new history.
The secret still appears on GitHub after rewriting
GitHub keeps unreferenced commits accessible for a while and caches PR views. Contact support to purge, and rotate regardless.
Success criteria
0 of 4
The concept behind it
Next up
Lab 7 of 59 on the project path