How to Undo Git Commits with reset, revert, and rebase
In my previous posts “GIT in 10 minutes” and Collaboration in GitHub, I have covered the basics of Git setup, a few workflow commands to get started using Git (version control system), and collaborative work, including operations with forks and pull requests. As promised, I will go into more detail about working with Git repositories. Here, I focus on reverting your changes. Sometimes it’s good to step back and think about something different, right?
Git Fork-and-Pull-Request Workflow Setup
I assume here the following setup:
- We work on a GitHub project with other team members working together on an “upstream” repository.
- We have forked this upstream repository and named our fork “origin.”
- We have a local copy of the origin repository (which we sync regularly with the upstream repository)
- This local copy of the origin repository (forked one) is changed with the next code contributions.
- We commit our local changes to the origin forked repository.
- In the forked repository, we create a Pull Request to the upstream repository.
The workflow can be described with the following example.
Cloning your forked repo locally
git clone https://<token>@github.com/<user>/<repo>.git
cd repo
Add upstream
git remote add upstream https://github.com/<upstream_user>/<repo>.git
Working on your branch
git checkout master
git checkout -b your_branch_name
git fetch upstream
Make changes
git add .
git commit -m 'message'
# use -u for your first push
git push -u origin your_branch_name
Possibly, we revert our changes
We might reconsider the changes at this step and try to revert the commit.
Pull Request
Next, go to your GitHub forked repository — GitHub shows a “Compare & pull request” green button next to your recently pushed branch, and clicking it starts the pull request. Or, on your fork page, press the “Pull Request” button and pick the base and compare branches yourself.
We might want to do the changes after PR
At this stage, we can’t just revert the commit quickly — we need to open a new PR.
Update Frequently with git pull upstream master
When working with a remote repository, pull the most recent changes from master often — don’t let your branch drift too far. First, check that the upstream remote is set up correctly, with git remote -v.
git pull upstream master
git reset vs git revert: When to Use Each
Sometimes we do not want to keep changes that are already committed. Let’s consider the following cases of when and how we revert or disregard these changes.
git reset moves the current branch tip to an earlier commit, discarding the commits after it (history-rewriting). git revert creates a new commit which undoes the changes of a previous commit while preserving history (non-destructive). The two main ways to undo committed changes:
| Command | What it does | History | Safe on shared branches? |
|---|---|---|---|
git reset [hash] |
Moves the branch tip back, dropping later commits | Rewrites history | No — only for local, unpushed commits |
git revert [hash] |
Adds a new commit that cancels a previous one | Preserves history | Yes — preferred for pushed commits |
Reverting a Commit with git revert [hash]
GitHub Docs “Reverting a commit” confirm that reverting a commit is itself a commit, and that it’s good practice to revert commits in order, from newest to oldest — reverting out of order can leave you resolving merge conflicts you didn’t need.
Use git log to check the commit history and hashes of commits.
git log
This output will include the hash strings you can use to revert a commit. The identifier string is located to the right of the word “commit.”
commit ec427b9199866d88dd67db744012264c3bfb4b62
Author: Elena Daehnhardt my@mail.com
Date: Mon Jul 11 13:28:22 2022 +0200
+_posts/2022-07-11-tf-nlp.md
commit 3fb88a4c6aa122f9fdd0a38adec3bb46fd9f2d67
Author: Elena Daehnhardt my@mail.com
Date: Mon Jul 11 13:27:52 2022 +0200
+forks update, fetch upstream
A hash code identifies each commit and lets you inspect or manage it directly. Running git checkout with a hash puts you in a detached HEAD state — you can look around and try things out, but you’re not on a branch anymore.
git checkout [hash]
With git revert, you undo the changes from that commit by adding a new one on top.
git revert [hash]
Resetting a Commit with git reset [hash]
git reset sets a repository back to a specific commit.
git reset [hash]
You can also undo a hard reset, but only while Git still holds onto the old commit. Run git reflog to find the commit hash from before the reset, then git reset --hard <hash> to jump back to it. This trick only rescues committed work — the reflog doesn’t track uncommitted changes, so anything you hadn’t committed yet is gone for good.
Avoid rewriting commit history on remote repositories, especially when you’re collaborating with others — save reset for local cleanup, and reach for revert once anything is pushed.
When you haven’t pushed a commit to a remote yet, here are your options for resetting to an earlier point.
Option 1 wipes out every change in your working directory and staging area, permanently — no reflog rescue for uncommitted work.
git reset --hard [hash]
To update the remote after a hard reset, force push with git push --force.
Here, “origin” is the name of the remote, and “main” is its branch name.
git push -f origin main
Option 2 keeps your changes by stashing them first: save with git stash, hard reset, then bring the changes back with stash pop.
git stash
git reset --hard [hash]
git stash pop
Option 3 moves the branch tip back but leaves your changes staged, ready to commit again — that’s --soft.
git reset --soft [hash]
Option 4 is the default: it resets to the commit but unstages the changes, leaving them sitting in your working directory.
git reset --mixed [hash]
Option 5 resets to the commit right before HEAD — shorthand for undoing just your last commit.
git reset --mixed HEAD~
Option 6 is the nuclear option, for when things go properly wrong: fetch the latest from the remote, then force your local branch to match it exactly, including wiping untracked files with git clean.
git fetch origin
git checkout main
git reset --hard origin/main
git clean -d --force
Reverting Pushed Changes on a Remote Repository
Prefer git revert when undoing changes already pushed to a remote repository. git revert keeps the history intact for other people working on the repository, whereas git reset followed by a force push rewrites shared history and can break their clones.
Rewriting History with git rebase –interactive
git rebase reapplies commits onto a new base, letting you edit, delete, reorder, or squash commits to rewrite branch history. Use it with caution — GitHub’s own docs call rebasing commits you’ve already pushed “bad practice,” since it rewrites history other people may be building on.
The interactive form lets you work with the latest five commits in your current branch.
git rebase --interactive HEAD~5
Resolving “Updates were rejected because the tip of your current branch is behind”
After a git reset or git rebase that rewrites commits you’d already pushed, a normal git push fails with:
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs
Updates were rejected because the tip of your current branch is behind its remote counterpart.
Cause: your local history no longer fast-forwards onto the remote, because you rewrote commits locally. Fix it by force-pushing your rewritten branch (only on branches you own):
git push -f origin main
If you hit this same error after a git revert instead, don’t reach for --force — revert doesn’t rewrite history, so the rejection almost always means someone else pushed new commits while you were working. Pull first, then push normally.
For a full walkthrough of this error, see Fix “Updates were rejected” non-fast-forward push errors.
Conclusion: reset vs revert vs rebase for Undoing Commits
That’s the toolkit for fixing commit mistakes in Git.
git revert is the safer, non-destructive choice — it undoes a commit by adding a new one, instead of rewriting history the way git reset does. Use git log to find the commit hashes you need, and git stash to keep your changes safe while you reset.
git rebase is the more surgical option, letting you cherry-pick, reorder, squash, or delete commits interactively. Next up, I’ll get into GitHub merge conflicts.
Git Reverting and Resetting Commits FAQ
What is the difference between git reset and git revert?
git reset moves the branch tip to an earlier commit and discards the later commits, rewriting history — use it only on local, unpushed commits. git revert creates a new commit that undoes a previous one while preserving history, so it is the safe choice for commits already pushed to a shared remote.
How do I undo a commit that I already pushed to a remote repository?
Use git revert [hash] to add a new commit that cancels the pushed commit while keeping history intact for collaborators. Avoid git reset --hard plus a force push on shared branches, because rewriting public history can break other people’s clones.
What is the difference between git reset –soft, –mixed, and –hard?
git reset --soft [hash] moves the branch tip but keeps your changes staged. git reset --mixed [hash] (the default) keeps the changes in your working directory but unstages them. git reset --hard [hash] discards all changes after the target commit permanently.
How do I keep my changes while resetting a commit?
Stash first, then reset, then restore: run git stash, git reset --hard [hash], and git stash pop. Alternatively, use git reset --soft [hash] to move the tip while leaving your changes staged.
How do I find the commit hash to revert or reset to?
Run git log to list the commit history. Each entry shows a 40-character hash to the right of the word commit; copy that hash and pass it to git revert [hash] or git reset [hash].
References
Reverting a commit in GitHub Desktop
Creating a pull request from a fork
Did you like this post? Please let me know if you have any comments or suggestions.
Git posts that might be interesting for you
Stork 'Teens' and Me
Enjoyed this? Get more like it.
Weekly notes on AI tools, Python, and what I'm actually building — plus two free gifts: the 15-page Fantastic AI: The 2026 Toolkit and a Git Commands & Contribution Workflow Cheatsheet.