To revert a commit in Git, run git revert with the commit’s hash. Git records a new commit that applies the opposite changes, and the original commit stays in the branch history.
The branch only moves forward, so this works fine on commits that are already pushed to a shared branch. A reset would rewrite history that other developers have pulled.
The Git 2.54 manual draws a line that plenty of tutorials blur. Throwing away uncommitted changes is a job for git reset --hard, and pulling files from another commit is a job for git restore --source. Neither one is a revert.
How to Revert a Commit in Git

Find the hash with git log --oneline, then run git revert a7c3f91. Git builds a new commit that undoes that commit’s changes and leaves the original where it was.
- Run
git statusand check for uncommitted work. - Run
git log --onelineand copy the hash of the commit you want to undo. - Run
git revertwith that hash. In a terminal an editor opens with a default message, so save and close it. - If Git stops on a conflict, edit the files, run
git add, thengit revert --continue. To cancel instead, rungit revert --abort. - Run
git pushif the branch is shared.
Git wants a clean working tree before it will revert anything, so checking the repository state with git status comes first.
To confirm it worked, run git log --oneline -3. The newest entry starts with Revert and quotes the original message.
The synopsis in the Git 2.54 documentation takes one or more commits, so you can pass several hashes to a single command.
What git revert Does to Your History
It never removes a commit. Git works out the inverse of the chosen commit’s patch, applies that to the current branch, and records the result as a new commit.
The branch pointer advances by one commit and never moves back. The original commit stays in the log, intact and reachable. The default message reads Revert “original message” and adds a line naming the reverted hash. The working tree has to be clean, meaning no modifications from the HEAD commit.
The Git manual strongly recommends writing down why you reverted. The default message tells you what happened but not the reason, and the reason is what someone will want in six months.
Commit or stash local edits before you start. The manual requires a clean tree, and Git stops the revert when local changes collide with it.
If you want the commit-level behavior laid out separately, there’s a dedicated explainer on git revert.
Choosing the Commit: Hash, HEAD and Relative References
HEAD~3 points to the fourth last commit, not the third. Git counts back from zero, where HEAD is the newest commit (Git 2.54 manual).
| Reference | Points to | Example |
|---|---|---|
| HEAD | Newest commit | git revert HEAD |
| HEAD~1 | Second last commit | git revert HEAD~1 |
| HEAD~3 | Fourth last commit | git revert HEAD~3 |
| Hash | One exact commit | git revert a7c3f91 |
The commit’s unique hash is the only reference that stays put. HEAD~n shifts every time someone adds a commit to the branch.
Reverting the last commit
git revert HEAD undoes the newest commit. Add --no-edit if the default message is fine and you’d rather skip the editor. It behaves the same before and after a push.
Reverting an older commit
Any commit on the branch can be reverted, even one from months back. The older it is, the more likely that later edits touched the same lines, and those overlaps stop the revert with conflicts.
Confirm the target first. Reading the history with git log gives you the hash and the message.
Then run git show on that hash. It prints the commit’s patch, so the inverse Git will apply is visible before anything gets written.
How to Revert a Pushed Commit Without a Force Push
Revert locally, then push normally. No force flag involved.
The revert commit sits on top of the remote tip, so a plain git push sends it as a fast-forward. The Git documentation says a push is refused when the remote ref isn’t an ancestor of the local ref. A revert passes that check. A reset followed by a push doesn’t.
Teammates get the revert on their next pull, since it’s an ordinary commit in the shared remote repository.
If the commit breaks the build or production, revert straight away. Same if nobody has time to write the proper fix yet. And when other branches have already merged the commit, a revert is usually the quicker way out.
Fixing forward makes more sense when the bug is a single line and the patch is ready, or when the commit also holds changes worth keeping.
A revert doesn’t reach into local branches. Anyone who already pulled the bad commit keeps it until they pull the revert.
Git Revert or Git Reset: Which One Fits?
Revert when the commit is pushed or shared. Reset when it only exists on your machine.
| Attribute | git revert | git reset | git restore |
|---|---|---|---|
| History effect | Adds a new commit | Moves the branch pointer back | Leaves branch history alone |
| Safe after push | Yes | No | Not a commit undo |
| Force push needed | No | Yes, on a pushed branch | No |
| What it changes | Branch, via a new commit | Branch, index, optionally working tree | Working tree or index files |
| Recovery path | Revert the revert | git reflog | Discarded edits are lost unless stashed |
The modes of git reset differ in how far the rewind reaches. --soft leaves the working tree and the index unchanged. --mixed is the default and resets the index while keeping the working directory. --hard overwrites files with the target commit’s version, and it may overwrite untracked files as well.
Resetting a pushed branch means forcing the push with --force-with-lease. That flag refuses the push if the remote moved since your last fetch, while plain --force skips the check entirely.
A commit dropped by a reset can be found again with git reflog, but the window is finite. Entries older than 90 days are pruned by default, and entries for commits no longer reachable from the branch tip go after 30 days (git gc manual, settings gc.reflogExpire and gc.reflogExpireUnreachable).
A commit dropped by a reset is no longer reachable from the tip, so the 30-day figure is the one that applies.
git restore pulls working tree files from the index or another commit and doesn’t touch your branch. The older git checkout form does the same file job with a commit and a path.
I’d default to revert. Reset gives a cleaner log, but only for commits that never left your machine.
How to Revert Multiple Commits
Pass a range such as git revert HEAD~3..HEAD, or list several hashes in one command. Git writes one revert commit per reverted commit, working from the newest back to the oldest.
Range syntax and the off-by-one trap
Tutorials disagree on the range form. Some write oldest^..newest and others write older..newer, and only the first includes the oldest commit.
The gitrevisions manual settles it. r1..r2 selects commits reachable from r2 and excludes r1 along with its ancestors, so the start of the range is never part of it.
| Range | Commits reverted |
|---|---|
| HEAD~3..HEAD | The last three commits |
| a7c3f91..HEAD | Everything after a7c3f91, not a7c3f91 itself |
| a7c3f91^..HEAD | a7c3f91 and everything after it |
The Git 2.54 manual’s own example, git revert -n master~5..master~2, covers the fifth last through the third last commit.
Collapsing a range into one commit
The -n flag (--no-commit) applies each inverse patch to the working tree and the index and records nothing. With it, your index doesn’t have to match HEAD, and the revert runs against the starting state of your index.
When you’re done, run git commit once with a message that names the range and the reason. A single commit is easier to undo again later, though you lose the per-commit granularity a plain range keeps.
How to Revert a Merge Commit
Run git revert -m 1 MERGE_HASH. A merge commit has two or more parents, so Git needs the mainline parent number to know which side to keep.
Leave out -m and Git refuses. The manual explains that it can’t tell which side of the merge counts as the mainline.
Choosing the parent number
Use -m 1 in nearly every case, since it keeps the branch you merged into. -m 2 returns the tree to the merged-in branch’s state, which only makes sense when the mainline is the side you want gone.
To check the order, run git show on the merge commit. It prints a Merge: line, and the first hash listed is parent 1. GitLab’s documentation confirms that the branch you merged into is always the first parent.
Re-merging after a reverted merge
Reverting a merge declares that you never want the tree changes the merge brought in, according to the Git manual. The revert undoes the data, not the history, so later merges still treat the original merge as the last shared state.
What happens next depends on the side branch. The revert-a-faulty-merge how-to in the Git documentation describes both paths.
If the side branch was fixed with new commits on top, revert the revert commit first. That brings the original changes back. Then merge the branch again.
If the side branch was rebuilt from scratch, merge the rebuilt branch without reverting the revert. The old merge and its revert sit behind the merge base and stay out of the way.
The how-to also warns against reverting the revert blindly. Rebuilding the branch by rebasing it onto the updated mainline is the route that avoids it.
Linus Torvalds adds a preference in the same document. Before reverting a merge, try to bisect the problem down to the single commit inside the merged branch, then fix or revert that commit instead.
Git Revert Options and Conflict Handling
Two flags change how a revert is recorded, and a handful of subcommands manage one that stopped. All of them are in the Git 2.54 manual.
| Option | Effect | Use it when |
|---|---|---|
| –no-edit | Skips the message editor | The default message is enough |
| –no-commit (-n) | Changes the working tree and index only | You want one combined commit or a review first |
| –continue | Resumes the sequence | Conflicts are resolved and staged |
| –skip | Drops the current commit, continues with the rest | One commit in a range is not worth reverting |
| –abort | Returns to the pre-sequence state | The revert went wrong |
There’s one more, --quit, which forgets the operation without rolling anything back. It clears the sequencer state left in .git/sequencer after a failed revert.
Choosing between abort, skip and quit
Abort when the revert targeted the wrong commit and you want a clean start. Skip when one commit in a range collides but the rest still need reverting. Quit only when the files already look the way you want and the stale sequencer state is all that’s left.
Resolving conflicts during a revert
A revert stops when later commits changed the same lines. Git lists the conflicted files and prints its own options: --continue after resolving, --skip to drop that commit, --abort to go back.
- Open each conflicted file and pick the lines to keep.
- Stage the files with
git add. - Run
git revert --continue.
The markers are the same ones you meet when resolving merge conflicts in Git.
In a range, the stop happens at the commit that collided. Commits still waiting sit in the sequencer until you continue or abort.
When git revert Is the Wrong Tool
It can’t erase data. A secret, key or large file stays in every earlier commit, so a revert cleans the current files and nothing more.
A leaked credential stays readable in history. Merge and revert pairs make bisecting harder later. And a clean revert can still break the build when later commits depend on what you removed.
For a leaked credential, rotate it first. GitHub’s documentation notes that rotation alone may be enough, and that rewriting history may not be warranted. If you do need to remove the data, use git filter-repo, which GitHub’s documentation runs on a fresh clone with the --sensitive-data-removal flag.
GitHub’s documentation also states that sensitive data can’t be removed from other users’ clones. GitHub Support assists only where rotating the affected credentials can’t reduce the risk.
Torvalds’ how-to names a second cost. A reverted merge is one large commit that undoes everything the merge brought in, so a later bisect can’t narrow the problem down to a small change inside it.
A clean revert is a textual result. If later commits build on the reverted change, the patch can apply without a conflict and the code still fails, so run a round of regression testing before pushing.
When the data has to disappear, revert is the wrong command. When the history can stay, it’s the right one.
git revert FAQ
Can you revert a commit from GitHub without the command line?
Yes. On a merged pull request, click Revert near the bottom of the page. GitHub opens a new pull request that reverses the original merge commit, and you need write permission on the repository.
If that revert hits conflicts, GitHub’s documentation says you may need to revert the individual commits instead.
Do Git GUI clients support reverting a commit?
Most do. In GitKraken, right-click the commit in the graph and choose Revert commit.
The client runs the same operation as the command line, so conflicts and merge commits behave exactly as described above.
How do you undo a revert commit that has not been pushed?
Run git reset --hard HEAD~1 to drop the revert commit from your local branch. The reset moves the branch pointer back one commit and discards uncommitted edits, so stash any you want to keep.
Once the revert is pushed, revert the revert commit instead.
Can git revert restore a single file from an earlier commit?
No. git revert works on whole commits. To bring one file back to its state in an earlier commit, run git restore --source followed by the commit and the file path.
That command changes the working tree only and leaves your branch history alone.
Reapplying a Fixed Change After a Revert
After git revert removes a faulty change, commit the corrected version as a new commit on top of the revert commit. Keep a revert of the revert for changes that were sound and only badly timed.
A revert of the revert commit restores the original patch exactly, defect included, so the branch carries the bug again until the fix lands.
Make sure the branch passes its tests with the revert in place. Commit the corrected change separately and name the reverted hash in the message. Revert the revert only when the original change needs no fix at all.
The cost of the new-commit route is a longer log. The original commit, its revert and the fix stay as three entries.
The Git manual adds one caution for the other route. Repeatedly reverting reverts piles up subject lines like Reapply “Reapply “original subject””, so reword them to something shorter and more unique.
- Notepad++ Android Options: Apps That Come Close - October 21, 2026
- MongoDB Cheat Sheet - October 20, 2026
- Adding AI Video Generation to a Software Product: Architecture, Cost Guardrails and QA - October 20, 2026




