Safely Undoing a Pushed Commit on a Shared Branch
1. What is it?
If an incorrect commit has already been pushed to a shared branch, such as main, the safest approach is usually:
git revert <commit-id>
git revert does not delete or rewrite the existing commit history. Instead, it creates a new commit that reverses the changes introduced by the incorrect commit.
This is important on a shared branch because other developers may already have pulled the original commit.
2. Simple Syntax / Sample
First, find the incorrect commit:
git log --oneline
Example:
a7c1234 Fix payment validation
b8d5678 Add login feature
c9e9012 Initial changes
Suppose a7c1234 is incorrect.
Revert it:
git revert a7c1234
Then push the new revert commit:
git push origin main
Typical flow:
Find incorrect commit
↓
git revert <commit-id>
↓
Resolve conflicts if any
↓
Test
↓
git push origin main
3. Detailed Explanation
Suppose the shared main branch contains:
A --- B --- C
↑
Incorrect commit
Commit C has already been pushed:
Local main: A --- B --- C
Remote main: A --- B --- C
Other developers may already have pulled C.
Don't normally use reset
You might think about:
git reset --hard HEAD~1
git push --force
That would rewrite the branch history:
Before:
A --- B --- C
After:
A --- B
The problem is that other developers may still have:
A --- B --- C
Now their history conflicts with the rewritten remote history.
For a shared branch, this can create confusion and potentially cause commits to be lost.
Step 1: Identify the bad commit
Run:
git log --oneline
For example:
7fa12bc Update payment logic
5be83ad Add customer validation
1ac92de Initial payment API
Suppose:
7fa12bc
is the bad commit.
Step 2: Revert the commit
Run:
git revert 7fa12bc
Git creates a new commit that applies the opposite changes.
The history becomes:
A --- B --- C --- R
↑ ↑
Bad Revert
commit commit
Importantly, C is still in Git history.
R reverses the changes made by C.
For example, if C changed:
var timeout = 30;
to:
var timeout = 60;
the revert would normally restore the previous behavior:
var timeout = 30;
while preserving both commits in history.
Step 3: Resolve conflicts if necessary
Sometimes Git cannot automatically revert the commit because later commits have modified the same code.
Git may report a conflict.
Check:
git status
Resolve the conflicting files manually.
Then:
git add .
git revert --continue
If you decide not to continue:
git revert --abort
Step 4: Build and test
Before pushing, verify that reverting the change hasn't broken something else.
For a .NET application, for example:
dotnet build
dotnet test
This is especially important because newer commits might depend on the code you're reverting.
Step 5: Push the revert commit
Once everything is correct:
git push origin main
Now the remote history is:
A --- B --- C --- R
Everyone gets the same consistent history.
4. git revert vs git reset
git revert |
git reset |
|---|---|
| Creates a new commit | Moves the branch pointer |
| Preserves existing history | Can rewrite history |
| Safe for shared branches | Better suited to local/unshared commits |
| Original bad commit remains visible | Commit may disappear from branch history |
| Usually normal push afterward | Rewriting remote history may require force push |
| Good for pushed commits | Good for unpushed local commits |
Simple rule
Not pushed / private history
↓
reset / amend can be appropriate
Already pushed to shared branch
↓
git revert is usually safer
5. What About git push --force?
Avoid doing this on a shared branch just to undo a bad commit:
git reset --hard HEAD~1
git push --force
It rewrites the remote branch history.
Even:
git push --force-with-lease
is still a history-rewriting operation.
--force-with-lease is safer than plain --force because it checks whether the remote branch has moved unexpectedly, but that doesn't make history rewriting appropriate for a shared main branch.
Follow your team's branch protection and incident/hotfix process.
6. What If main Is Protected?
In many teams, developers cannot directly push to main.
In that case, a practical workflow may be:
git switch main
git pull origin main
git switch -c revert/bad-payment-change
git revert 7fa12bc
git push origin revert/bad-payment-change
Then create a Pull Request:
main
│
└── revert/bad-payment-change
│
└── Revert commit
↓
Pull Request
↓
Code Review
↓
CI checks
↓
Merge to main
This is often preferable in professional environments because the revert still goes through review, automated tests, and branch policies.
7. Key Points
- If a bad commit has already been pushed to a shared branch, prefer:
git revert <commit-id>
git revertcreates a new commit that reverses the bad commit.- It preserves the existing Git history.
- It is safer when other developers may already have pulled the commit.
- If conflicts occur:
git add .
git revert --continue
- To cancel an in-progress revert:
git revert --abort
- Build and test before pushing the revert.
- Avoid
reset + force pushon shared branches unless there is an exceptional, coordinated reason and team policy explicitly permits it. - On protected branches, create the revert on a separate branch and submit a Pull Request.
Easy interview rule
Wrong commit, NOT pushed
↓
git reset / git commit --amend
Wrong commit, ALREADY pushed/shared
↓
git revert
8. Interview Answer
If an incorrect commit has already been pushed to a shared branch, I would normally use
git revert <commit-id>rather thangit reset.git revertcreates a new commit that reverses the bad commit while preserving the existing history, so it is safe for other developers who may already have pulled the changes. I would resolve any conflicts, build and test the application, and then push the revert. Ifmainis protected, I would create the revert on a separate branch and raise a Pull Request so it goes through the normal review and CI process.