The Scenario: "Oops, I Made a Messy Commit History"
Imagine you're working on a feature branch called feature/login-page
. You’ve made a few commits, but now :
One of the commits has a bug.
Another commit has a wrong commit message.
Your commit history looks like a jumbled mess compared to
main
.
Time to clean it up! But… should you rebase, reset, or revert?
First, Let’s Understand the Core Idea of Each:
Command | What it Does | Safe for Shared Branches? |
---|---|---|
| Rewrites commit history to make it linear and clean | No, unless used carefully |
| Moves the HEAD and branch pointer to a different commit | No, dangerous on shared branches |
| Creates a new commit that undoes a previous commit | Yes, safe to fix public history |
1. Git Rebase : "Let’s Rewrite History Neatly"
What is it?
git rebase
allows you to move or "replay" your commits onto another branch or rearrange them to make a clean, linear history.
When to Use?
You want to clean up messy commit history before merging.
You want to squash commits.
You want to change commit messages.
Example:
You have these commits in feature/login-page
:
A — B — C — D (feature/login-page)
↑
Buggy commit (C)
You want to fix commit C
and clean up the message in D
.
Solution: Interactive Rebase
git rebase -i HEAD~3
You’ll see something like this:
pick abc123 B pick def456 C pick ghi789 D
You can now:
Change "pick" to "edit" for C to fix the bug.
Change "pick" to "reword" for D to fix the commit message.
Squash commits if needed.
Important:
This rewrites commit hashes.
If your branch is pushed and shared, rebasing can mess up others' history. Use with care!
2. Git Reset : "Let’s Go Back in Time (Dangerously Powerful)"
What is it?
git reset
moves your branch pointer (HEAD
) to a previous commit. It can unstage files, remove commits, or even delete code changes.
Types of Reset:
Command | What happens? |
---|---|
| Keeps your changes staged. |
| Unstages changes but keeps them in the working directory. |
| Deletes your changes completely. Dangerous! |
When to Use?
You made local commits you don’t want anymore.
You want to uncommit but keep the changes.
Example:
You made two useless commits on top of main
and want to remove them.
A — B — C — D (main)
↑
Your branch (HEAD)
To undo D and C:
git reset --soft HEAD~2
Your changes are still there but unstaged (due to --soft flag).
If you want to kill the changes, do
git reset --hard HEAD~2
After that your git timeline will look like this :
A — B (main)
↑
Your branch (HEAD)
Important:
Never reset a branch that is already pushed and shared with others.
Resetting can permanently lose work (especially
--hard
).
3. Git Revert : "The Safe Undo Button"
What is it?
git revert
creates a new commit that undoes the changes of a previous commit. It preserves history.
When to Use?
You want to undo a bad commit in a shared branch.
You want to keep history intact but fix a mistake.
Example:
Commit C
introduced a bug. But you’ve already pushed it to origin/main
.
A — B — C — D (main)
↑
Bug lives here
You can revert C safely:
git revert <commit-hash-of-C>
Git will create a new commit :
A — B — C — D — E (main)
↑
"Revert C"
Important:
Safe for shared/public branches.
Doesn’t remove the commit but inverts its changes.
Quick Summary: When to Use What?
Command | Use When… |
---|---|
| You want to rewrite and clean history (local-only). |
| You want to remove commits or unstage changes locally. |
| You need to undo commits safely in shared branches. |
Visual Cheat Sheet
"I messed up a commit and want to fix it before pushing" → Rebase / Reset (local only)
"I pushed a bad commit, now I need to undo it on remote" → Revert
"I made several ugly small commits, want to squash them" → Rebase -i
Final Tips
Never rebase or reset public history unless you know what you’re doing.
Use
git log --oneline --graph
to visualize the history before making changes.Always backup your branch with
git branch backup/my-branch
before risky operations.