
Introduction
Every developer has been there: you push a commit, then realize it contains a bug, a typo, or a feature that shouldn't be in production yet. Panic sets in — but Git provides several safe ways to undo a push. This guide covers the essential workflows: git revert, git reset with force push, and git commit --amend. You'll learn when to use each, their trade-offs, and how to avoid common mistakes.
Understanding the Problem: Local vs. Remote
Before undoing a push, you must distinguish between local and remote state. A pushed commit exists in both your local repository and the remote (e.g., GitHub, GitLab). Undoing it requires updating both, but the remote may have protections (e.g., branch protection rules) that prevent force pushing.
Key concepts:
- HEAD: your current commit pointer.
- Working tree: your files on disk.
- Index (staging area): changes ready to commit.
- Remote: the shared repository (e.g.,
origin/main).
Method 1: git revert — Safe and Recommended
git revert creates a new commit that undoes the changes of a previous commit. It does not rewrite history, making it safe for shared branches.
How to use
# Revert the most recent commit
git revert HEAD
# Revert a specific commit by its hash
git revert <commit-hash>
# Revert a range of commits (e.g., last 3)
git revert HEAD~3..HEAD
Worked example
Suppose you have three commits on main:
A — B — C (HEAD, origin/main)
Commit C introduced a bug. To undo it:
git revert HEAD
This creates commit D, which is the inverse of C:
A — B — C — D (HEAD)
Now push D to remote:
git push origin main
The remote now has A — B — C — D. The bug is gone, and history is intact.
When to use
- Shared branches (
main,develop). - You want a clear audit trail.
- You need to undo multiple commits (one revert per commit, or use a range).
Pitfalls
- Reverting a merge commit requires the
-mflag to specify which parent to keep. - If you revert a revert, you re-apply the original changes.
Method 2: git reset + Force Push — Destructive but Clean
git reset moves the branch pointer backward, discarding commits. Use with extreme caution on shared branches.
How to use
# Soft: keep changes in staging
git reset --soft HEAD~1
# Mixed (default): keep changes in working tree
git reset --mixed HEAD~1
# Hard: discard all changes
git reset --hard HEAD~1
Worked example
Same scenario: undo commit C permanently.
git reset --hard HEAD~1
Now local branch looks like:
A — B (HEAD)
To update remote, force push:
git push origin main --force
# or
git push origin main -f
Remote now has A — B. Commit C is gone.
When to use
- Local branches or personal forks.
- You need to completely remove a commit (e.g., sensitive data).
- You are the only developer on the branch.
Pitfalls
- Never force push to a protected branch without team agreement.
- Other developers who pulled
Cwill have divergent history; they mustgit pull --rebaseor reset. --harddeletes uncommitted changes — use--softor--mixedif you want to keep them.
Method 3: git commit --amend — Fix the Last Commit
If you just pushed the last commit and want to modify its message or add/remove files, --amend is the simplest.
How to use
# Stage additional changes
git add .
# Amend the last commit (without changing message)
git commit --amend --no-edit
# Or change the message as well
git commit --amend -m "New message"
Then force push:
git push origin main --force
When to use
- You forgot to include a file in the last commit.
- You want to correct a typo in the commit message.
- The commit has not been pulled by others.
Pitfalls
--amendrewrites the commit hash — same force-push caveats apply.- If the commit was already pulled, team members will have conflicts.
Comparison Table
| Method | History Rewritten | Safe for Shared Branches | Use Case |
|---|---|---|---|
git revert |
No | Yes | Undo any commit without losing history |
git reset --hard |
Yes | No | Completely remove commits (local/personal) |
git commit --amend |
Yes (last commit only) | No | Fix last commit message or content |
| New branch from old commit | No | Yes | Start fresh from a previous state |
Common Pitfalls
- Force pushing to protected branches: Many remotes block force pushes to
mainby default. Check branch protection settings. - Reverting a merge commit incorrectly: Use
git revert -m 1 <merge-commit>to revert to the first parent. - Losing uncommitted work with
--hard: Always stash or commit before a hard reset. - Not communicating with the team: If others have pulled the commit, coordinate to avoid chaos.
FAQ
What's the difference between git revert and git reset?
git revert creates a new commit that undoes changes, preserving history. git reset moves the branch pointer backward, deleting commits from history. Use revert for shared branches, reset for local work.
Can I undo a push that contains sensitive data (e.g., passwords)?
Force push to remove the commit from history, but assume the data is compromised — change passwords immediately. git revert leaves the sensitive data in history, so it's not suitable for secrets.
How do I undo multiple pushed commits?
Use git revert HEAD~N..HEAD (revert range) or git reset --hard HEAD~N (destructive). For revert, each commit gets a revert commit; for reset, all N commits are removed at once.
What if I already pulled the bad commit on another machine?
After force pushing, run git fetch origin and git reset --hard origin/main on the other machine to sync. Or use git pull --rebase if you have local commits.
Is there a GUI way to do this?
Most Git GUIs (GitHub Desktop, GitKraken, IDE integrations) support revert and reset. For example, in IntelliJ IDEA, right-click a commit and select "Revert Commit" or "Reset Current Branch to Here". Try it in our Git memo to visualize the process.
Conclusion
Undoing a Git push is a common task that every developer should master. git revert is the safest choice for shared branches, while git reset offers a clean slate for personal work. Always communicate with your team and understand the implications of rewriting history. With these tools, you can recover from mistakes confidently.