Safely Undo a Git Commit with git revert
You will finish with a new commit that reverses an earlier commit, without rewriting the branch's existing history. That is the normal choice for a change already pushed or shared with other people. The examples use Git 2.43.0 from Ubuntu package git 1:2.43.0-1ubuntu7.3, and the installed manual dated 2 July 2025.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow ten to fifteen minutes. You need a Git repository, a clean working tree, and permission to commit to the branch. No command in this guide needs elevated privileges. Read the target commit and its diff before reverting it: the operation changes files and, unless you use --no-commit, creates a commit immediately.
1. Confirm the repository and target
Start by checking where you are and whether local work is present:
$ git status --short
$ git log --oneline -5
An empty first command means the working tree and index are clean. If it prints paths, stop and save or commit that work first. A normal git revert requires a clean tree. The exception is --no-commit, whose starting point is the current index, but mixing an intentional staged change with a reversal is easy to misunderstand.
Inspect the commit you intend to reverse. Replace COMMIT_ID with a full or abbreviated object name from git log:
$ git show --stat --oneline COMMIT_ID
$ git show --format=fuller COMMIT_ID
Checkpoint: confirm that the commit's files and patch are the change you want removed. git revert acts on the patch introduced by that commit, not on an arbitrary snapshot of the whole project.
2. Revert one ordinary commit
Use --no-edit when the generated message is sufficient and you want a non-interactive command:
$ git revert --no-edit COMMIT_ID
[main 4d2c9f1] Revert "Disable maintenance mode"
1 file changed, 1 insertion(+), 1 deletion(-)
Git creates a new commit whose patch reverses the selected commit. The original commit remains in the log. Check both the new history and the resulting status:
$ git log --oneline -2
4d2c9f1 Revert "Disable maintenance mode"
8a1b2c3 Disable maintenance mode
$ git status --short
The status command should again print nothing. Without --no-edit, Git opens the commit message editor when run from a terminal. Edit the message when the reason for the reversal matters to future readers; the manual specifically recommends explaining why the original change is being undone.
3. Review first with --no-commit
Use --no-commit to apply the inverse patch to the working tree and index without creating a commit:
$ git revert --no-commit COMMIT_ID
$ git diff --cached --stat
$ git diff --cached
This is useful when you want to review the combined result, adjust files, or revert more than one commit before making one deliberate commit. The index does not need to match HEAD in this mode, and Git applies the reversal against the index's beginning state. That flexibility is also a trap: inspect both git diff and git diff --cached before committing.
When the staged result is correct, finish it with a message that explains the reason:
$ git commit -m "Revert maintenance mode change"
$ git status --short
If you decide not to keep an uncommitted reversal, stop first. The following command discards tracked working-tree and index changes, so use it only after checking that there is nothing else to preserve:
$ git restore --source=HEAD --staged --worktree -- .
4. Revert several commits carefully
You can name multiple commits, but Git does not traverse a range by default. For a contiguous range, use the documented revision range with --no-commit, then review the combined result:
$ git revert --no-commit OLDEST_COMMIT^..NEWEST_COMMIT
$ git diff --cached --check
$ git diff --cached
$ git commit -m "Revert the faulty release changes"
The caret includes the oldest commit's parent so the oldest commit itself is included. This is not a request to reset the branch to an old snapshot. It applies inverse patches in sequence, and later changes may depend on earlier ones. Use a small, explicit set when the commits are unrelated, and review the final diff before committing.
5. Resolve a conflict or undo the revert
A reversal can conflict when later work changed the same lines. Git pauses the sequence and leaves conflict markers in affected files. Resolve each file, remove the markers, stage the result, and continue:
$ git status
$ git add PATH/TO/RESOLVED_FILE
$ git revert --continue
Run your tests before accepting the resulting commit. If the selected commit should not be part of this sequence, use git revert --skip. To abandon the entire in-progress sequence and return to its pre-sequence state, use:
$ git revert --abort
--quit only forgets the sequencer state; it does not promise to restore files. Use it only when you understand and want to keep the current files and index.
If a completed revert was itself a mistake, revert the revert commit. That creates another new commit and preserves the audit trail:
$ git revert --no-edit REVERT_COMMIT_ID
6. Treat merge reverts as a policy decision
A merge has more than one parent, so Git cannot infer which side is the mainline. Select the parent number explicitly, starting at 1:
$ git show --no-patch --pretty=raw MERGE_COMMIT_ID
$ git revert --no-edit --mainline 1 MERGE_COMMIT_ID
Choose the parent that represents the line of development you want to keep. Reverting a merge tells Git that the tree changes brought in by that merge are not wanted. Later merges may therefore omit changes that are ancestors of the reverted merge. Confirm that long-term effect with the branch owner before running this command.
Done means
git status --shortis empty after the operation.- The new commit reverses the intended patch, confirmed with
git show. - Tests or an equivalent project check pass after conflict resolution.
- The branch history contains the original and reversal commits; neither was rewritten.
- Any merge reversal used the deliberately chosen mainline parent.