
Git Time Travel: reset, reflog, bisect and saving doomed branches
Learn how to time travel with Git: reflog, reset, revert, bisect and disaster-recovery techniques without taking the team down.
✨TL;DR / Executive Summary
Learn how to time travel with Git: reflog, reset, revert, bisect and disaster-recovery techniques without taking the team down.
💡 TL;DR (Too Long; Didn't Read)
Git lets you time travel and fix mistakes.
git reflogrecovers anything still in the system.git resetrewrites local history.git revertundoes commits without rewriting (safe for shared history).git bisectautomatically finds which commit broke everything. Use these tools confidently — Git was built for this.
If you use Git long enough, you eventually do the classics: wrong git push, deleted branch, commit on the wrong branch, that bug that "came out of nowhere" after a merge.
The difference between a constantly-suffering dev and a battle-hardened one is simple: the latter knows how to time travel with Git.
In this article we'll go beyond the basics (git log, git reset --hard and other dangerous toys) and into what really separates adults from kids in Git:
- How to actually see history (not just default
git log) - How to use reflog to recover almost anything
- When to use
resetvsrevert(and how not to become the team villain) - How to hunt bugs with
git bisectlike a pro - A survival kit for production disasters
By the end, you'll be able to break things with confidence — because you know how to go back.
1. Understanding time in Git (no cheap philosophy)
Before you start throwing reset --hard around, you need a decent mental model of what Git is doing.
1.1. Commits, refs and this HEAD thing
In a very simplified way:
- Each commit is a snapshot of the project.
- Branches (
main,develop, etc.) are pointers to commits. HEADis "where you are" right now — usually pointing to a branch.
See it in practice:
git log --oneline --graph --decorate --allThis shows:
- The commit graph (
--graph) - All refs (branches, tags,
HEAD) (--decorate --all)
Use this every day. Devs who only use plain git log are playing on easy mode.
1.2. What it really means to "lose" a commit
Most of the time you didn't lose anything. You just removed the reference to a commit.
As long as Git still remembers that commit somewhere (spoiler: reflog), you can bring it back.
2. git reflog: the secret history that saves your career
git log shows the history of commits.
git reflog shows the history of HEAD movements.
That includes everything you do:
- Branch checkouts
- Resets
- Merges
- Rebases
- Commits
- Hopping between branches like crazy
git reflogTypical output (simplified):
1a2b3c4 (HEAD -> main) HEAD@{0}: commit: Fix error logging
9f8e7d6 HEAD@{1}: reset: moving to HEAD~1
abcd123 HEAD@{2}: commit: Remove legacy code
...Each line is a frame in your time-travel movie.
2.1. Recovering a commit you "deleted"
Classic scenario:
# You got emotional
git reset --hard HEAD~3Now what?
- Check the reflog:
git reflog- Find the entry before the reset — something like:
abcd123 HEAD@{3}: commit: Feature you just wiped- Go back to that commit by creating a rescue branch:
git checkout -b saving-my-life abcd123Boom. Your "deleted" commit is back.
2.2. Recovering a deleted branch
You nuked a remote and local branch:
git branch -D feature-topIf you worked on it recently, the last commit will still show up in the reflog.
- Look for something with the branch name or commit hash:
git reflog --all | grep feature-top || git reflog --all | head -n 30- Once you find the commit, recreate the branch on top of it:
git checkout -b feature-top-v2 <commit-hash>Reflog is basically Git's extended Ctrl+Z.
Use it freely — it's read-only.
Spicy take: if you don't know how to use
git reflog, you're not ready to usegit reset --hard.
3. git reset vs git revert: when to erase, when to undo
These two confuse even senior devs. Let's make it clear.
3.1. git reset
reset changes pointers and, depending on the mode, your working directory.
Three main modes:
--soft: only moves the branch pointer; keeps changes staged.--mixed(default): moves the pointer and unstages files, but keeps them in the working directory.--hard: moves the pointer and discards everything — stage + working directory.
Examples:
# Go back 1 commit, keeping changes staged
git reset --soft HEAD~1
# Go back 1 commit, keeping changes as local modifications (unstaged)
git reset HEAD~1
# Go back 1 commit, throwing code away for real
git reset --hard HEAD~1Golden rule:
- Use
resetto rewrite local history. - Avoid
reseton branches that are already shared (pushed).
3.2. git revert
revert does not delete a commit. It creates a new commit that undoes the changes made by another commit.
# Undo the last commit by creating a new one
git revert HEAD
# Undo a specific commit
git revert a1b2c3dPerfect for:
- Fixing mistakes already pushed to remote
- Undoing a bad merge on
main/master
# Revert a specific merge commit
git revert -m 1 <merge-commit-hash>-m 1 indicates which parent is considered the mainline (usually the target branch, like main).
3.3. Quick guide: which one to use?
- Working locally, before pushing:
- Use
resetfreely (but know yourreflog).
- Use
- After pushing:
- Prefer
revert. - Only use
resetif EVERYONE agrees to rewrite history (git push --force-with-lease).
- Prefer
# Shared history? Be an adult.
# Instead of rewriting everything:
git revert HEADSpicy take:
git push --forceis not evil. Using it without understanding what you're rewriting is.
4. Hunting bugs with git bisect (sniper mode)
You know that bug that "always worked" and broke at some point in the past?
You could guess commits… or you can use git bisect and find the culprit in O(log n) steps.
4.1. Concept
You need two things:
- A good commit (where the bug didn't exist)
- A bad commit (where the bug exists)
Git will test the middle until it finds the first bad commit.
4.2. Manual mode
# Start bisect
git bisect start
# Mark current commit as bad
git bisect bad
# Mark an older commit as good
git bisect good <hash-or-tag>Git will place you on an intermediate commit.
You test your system:
- If the bug is present:
git bisect bad- If it's not:
git bisect goodRepeat until Git tells you which commit introduced the bug.
When you're done:
git bisect reset4.3. Automatic mode (for smart lazy devs)
If you can automate the test (script that returns 0 for good and 1 for bad), Git will do the whole search for you.
# Example of a simple test script
cat << 'EOF' > test-bug.sh
#!/usr/bin/env bash
# run tests, lints, or anything that proves the bug exists
npm test > /dev/null 2>&1
EOF
chmod +x test-bug.sh
# Now run automated bisect
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run ./test-bug.shGit will jump across commits on its own.
This sounds like overkill… until you hit a weird bug in production.
5. Disaster survival checklist
When things go wrong, instead of panicking, follow this sequence:
-
Don't freak out. Seriously.
-
Run:
bashgit status git log --oneline --graph --decorate --all -n 20 git reflog -n 20 -
Identify:
- What do you want to go back to (commit, branch, merge)?
- Has this history already been pushed?
-
If it's local only:
- Use
git reset(soft/mixed/hard as needed). - If you reset too much, recover with
git reflog.
- Use
-
If it's already on remote:
- Prefer
git revert. - Talk to the team before using
git push --force-with-lease.
- Prefer
-
If you need to find which commit introduced a bug:
- Use
git bisect.
- Use
6. Time-travel aliases for power users
Add this to your ~/.gitconfig to live a better life:
[alias]
lg = log --oneline --graph --decorate --all
undo-last = reset --soft HEAD~1
undo-hard = reset --hard HEAD~1
hist = reflog
who-broke = bisectTypical usage:
# see a pretty history
git lg
# regret the last commit (but keep the code)
git undo-last
# post-disaster inspection
git hist7. Cheat sheet to pin on your wall
git log --graph --decorate --allto understand history.git reflogto recover "lost" commits and branches.git resetto rewrite local history.git revertto undo things in shared history.git bisectto find the commit that introduced a bug.
Use Git as a time machine, not as Russian roulette.
If you enjoyed this deeper dive into Git internals, share it with that friend who's still afraid of git reset.
Find me on X/Twitter: @gss_62
#git #gittips