Safely Undo a Commit with git revert
git revert undoes a commit by creating a new one that reverses it, leaving history intact for anything already pushed. That is the normal choice for a change already shared with other people, where rewriting the branch is not an option. 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 here 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, which starts from the current index, but mixing an intentional staged change with a reversal is easy to misread later.
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 the commit's files and patch are the change you want removed. git revert acts on the patch that commit introduced, not on an arbitrary snapshot of the whole project.
2. Revert one ordinary commit
Use --no-edit when the generated message is enough 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 one; the original commit stays 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 starting 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 and check there is nothing else to preserve. The following command discards tracked working-tree and index changes:
$ git restore --source=HEAD --staged --worktree -- .
4. Revert several commits carefully
You can name multiple commits, but Git does not walk 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 covered. 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 a 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 keeps the audit trail intact:
$ 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
Warning
Reverting a merge tells Git the tree changes brought in by that merge are unwanted, and later merges may then omit changes that are ancestors of the reverted merge. Choose the parent that represents the line of development you want to keep, and confirm that long-term effect with the branch owner before running this command.
Done means
- git status --short is 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 keeps both commits, original and reversal, with neither rewritten.
- Any merge reversal used the deliberately chosen mainline parent.