Revert a pushed Git commit with a new commit
To revert a pushed Git commit, create a new commit that reverses the selected change and then share that new commit through the normal branch workflow. The original commit stays in history; check the target, current branch and working tree before applying an inverse patch.
Revert a pushed commit without rewriting its ancestry
The example reverts the current commit because its fictional change is deliberately at the branch tip. Git records a new commit that reverses the selected patch; the earlier commit remains reachable as an ancestor1. That distinction is why revert can be appropriate when a commit is already shared. It does not establish that a particular inverse patch is free of conflicts or is the right business decision.
Inspect the actual commit and the branch before choosing a target. A subject line alone may not identify the change, and a later commit can depend on the one being reversed. Review the patch and consider subsequent work. If the intended change spans multiple commits, the order and interactions deserve separate analysis rather than assuming one inverse operation will restore an entire feature.
Establish a clean starting point
The official revert reference requires a clean working tree relative to the current commit for its basic operation1. Save and inspect any work that is not part of the reversal. The example begins with a committed base, adds a single line in a second commit and pushes both to a local bare remote. The bare repository stands in for a remote destination without contacting a server or another person.
After creating the second commit, the script records its object identifier. It then writes a small editor script that exits successfully and supplies that script to the revert operation. This makes the editor step reproducible while retaining Git’s default proposed commit message. After confirming the target is the current commit, run git revert HEAD in an ordinary interactive session, review the proposed message in your configured editor, and save or cancel it deliberately. Cancelling stops the commit but leaves the reversed changes staged, so commit them or discard them before other work. The example does not claim that every editor or signing configuration behaves the same way.
Interpret what the test establishes
The example checks the note’s content, the number of commits and the ancestor relationship after the revert. The note returns to the base text, but the earlier shared commit is still an ancestor. The branch therefore contains both the change and a later reversal, rather than acting as though the first change never existed. That is a history statement for this fixture; it does not erase copies, logs or consequences of a change already used elsewhere.
The script pushes the new tip to its local bare remote and compares the resulting branch identifier. The official push reference describes updating the remote reference with local commits2. A successful push to this local fixture does not demonstrate server permissions, a protected branch, an approval requirement or a deployment. A real remote can reject the update, and the team may require a separate review path.
Read the inverse patch in context
A revert operates on changes introduced by a commit, applied against the current state. Later edits to the same lines can make that inverse patch conflict or produce a result requiring human judgment. The safest target is not always the most recent visible subject. Read the selected diff, inspect later work that touches the same area and decide whether a direct revert would preserve the intended behavior.
If Git stops with a conflict, do not treat an unfinished revert as a successful new commit. Preserve relevant work, inspect status and follow the operation-specific instructions before continuing or abandoning it. The present example does not run that case, so it does not predict how a particular conflict should be resolved. It also does not use a destructive reset to move shared branch history backward.
Share the result deliberately
After a successful local revert, inspect the new commit and run whatever checks the project requires before sharing. A reversal that removes one line can still affect users, data or later changes. Its meaning is the inverse patch actually produced, not simply the word “revert” in a subject line. Confirm that the remote destination and branch are the ones intended before pushing.
If the push is rejected because the remote has advanced, first obtain and inspect the new state and choose an integration procedure consistent with the team workflow. Do not assume that forcing an update is required or safe. Fetching and integration are different decisions, discussed in the fetch and pull guide. Reverting a change already in use is a coordination task as well as a local command.
Run the complete local example
Before running: Revert creates a new commit and can conflict with later work. Check the target and preserve uncommitted changes before using it on a real branch. Run this complete MIT-licensed example with Git 2.56.0 in an empty directory. It creates revert-example/, including its own local bare remote. It performs no network access and refuses to reuse an existing example directory.
Download the complete example. The printed file is the one that ran.
#!/bin/sh
# SPDX-License-Identifier: MIT
set -eu
export TZ=UTC LC_ALL=C
export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null
export GIT_AUTHOR_NAME='Example Author' GIT_AUTHOR_EMAIL='author@example.invalid'
export GIT_COMMITTER_NAME='Example Author' GIT_COMMITTER_EMAIL='author@example.invalid'
export GIT_AUTHOR_DATE='2026-10-27T12:00:00+00:00'
export GIT_COMMITTER_DATE='2026-10-27T12:00:00+00:00'
test "$(git version)" = 'git version 2.56.0'
mkdir revert-example
cd revert-example
git init --template= --bare -q --initial-branch=main origin.git
git init --template= -q --initial-branch=main writer
cd writer
printf 'original\n' > note.txt
git add note.txt
git commit -qm 'Base'
git remote add origin ../origin.git
git push -q -u origin main >/dev/null
printf 'shared change\n' >> note.txt
git commit -qam 'Shared change'
git push -q origin main
shared=$(git rev-parse HEAD)
printf '#!/bin/sh\nexit 0\n' > ../editor.sh
chmod +x ../editor.sh
GIT_EDITOR=../editor.sh git revert HEAD >/dev/null
git merge-base --is-ancestor "$shared" HEAD
test "$(cat note.txt)" = original
test "$(git rev-list --count HEAD)" = 3
printf 'Revert made a new commit; shared commit remains an ancestor\n'
git push -q origin main
test "$(git rev-parse HEAD)" = "$(git --git-dir=../origin.git rev-parse refs/heads/main)"
printf 'Local bare remote received the new revert commit\n'
Both runs produced:
Revert made a new commit; shared commit remains an ancestor
Local bare remote received the new revert commit
The script leaves its example directory and its repositories in place. Remove that newly created directory when it is no longer needed; inspect the name first so cleanup does not remove another project. The assertions stop the run if the demonstrated state differs. No command in the example connects to an external remote.
Not covered on this page
- Reverting a merge commit, which requires choosing a mainline parent with
-m. - Resolving a revert conflict or reversing a sequence of interdependent commits.
- Server permissions, deployment effects or branch-protection rules.
Sources
-
Git 2.56.0 revert reference. Git v2.56.0; checked 27 October 2026 UTC. ↩ ↩2
-
Git 2.56.0 push reference. Git v2.56.0; checked 27 October 2026 UTC. ↩
How we test: methodology. Found a mistake? Corrections.