Key takeaways
Undoing work in Git is operationally sensitive because the wrong choice can rewrite history, disrupt teammates, or make incident response harder. The core rule is simple: use git revert when the commit may already be shared, and use git reset only when you control the branch history or are working locally and understand the consequences.
git revert adds a new commit that negates an earlier one, which keeps history intact and is safer for shared branches. git reset moves the branch pointer, which can remove commits from the visible history and is powerful but risky in collaborative repositories. If you need a clean rollback on a public branch, prefer revert; if you need to repair local work before publishing, reset is usually the right tool.
Before changing anything, verify whether the commit has been pushed, whether anyone else may have based work on it, and whether your branch protection rules allow history changes. If you are deciding between undoing a change and reconstructing history, the workflow considerations are similar to those in Git Rebase vs Merge: Choosing the Right Workflow and Git Rebase vs Merge: When to Use Each Strategy, especially when branch collaboration and auditability matter.
Why this matters in shared repositories
In a personal sandbox, undoing a commit is mostly about convenience. In a shared repository, it becomes a coordination problem. A command that rewrites history can invalidate another engineer’s local branch, break a pull request review, or make incident investigation harder because the evidence no longer matches what was originally pushed.
That is why revert and reset are not interchangeable. They solve different operational problems. revert preserves the record of what happened and adds a compensating change. reset changes where a branch points, which can be exactly what you want during local cleanup but is a liability once other people depend on the branch.
For security, platform, and systems teams, this distinction matters during emergency response, failed deployments, configuration rollbacks, and maintenance windows. The goal is not merely to undo code, but to do so without creating a second incident.
Git revert vs reset: what each command actually does
git revert creates a new commit that applies the inverse of a selected commit. If the original commit added a file, the revert commit removes it. If the original commit changed a line, the revert commit changes it back. The important operational property is that the original commit remains in the history, so collaborators and auditors can still see what happened.
git reset moves the current branch reference to another commit. Depending on the mode, it may also update the staging area and working tree. In practical terms, a reset can make commits disappear from the current branch view. Those commits may still exist in object storage for a while, but they are no longer part of the branch history you are publishing.
That difference leads to the safest rule of thumb:
- Use
reverton branches other people may already have pulled. - Use
reseton private or local work that has not been shared, or in tightly controlled situations where history rewriting is expected.
If you need a compact comparison, think of revert as “undo by adding” and reset as “undo by moving.”
A practical workflow block for safe undo decisions
1. Identify whether the commit is already pushed or shared.
2. If shared: prefer git revert and keep history intact.
3. If local only: choose git reset based on whether you want to keep staged or unstaged changes.
4. Verify the result with git log, git status, and a targeted diff.
5. If the branch was already published and you must rewrite it, confirm policy, coordinate with the team, and force-push only with explicit approval.
This is not a full procedural guide; it is the decision path that prevents most avoidable mistakes.
How the commands behave in real branches
The simplest way to understand the operational difference is to follow the branch pointer. With git revert, the pointer moves forward because a new commit is created. History remains linear and reviewable. With git reset, the pointer moves backward to an earlier commit, and the branch no longer advertises the removed commits.
That has implications for every downstream clone. If a teammate already fetched the original branch and based work on it, a reset can create a divergence that is difficult to reconcile. They may need to rebase, re-merge, or re-check out the branch, depending on how far they progressed.
git revert is therefore the safer default for shared branches, especially release branches, hotfix branches, and integration branches with protection rules. git reset is usually best reserved for local cleanup, for example when you want to drop an accidental commit before opening a pull request, or when you need to re-stage changes more carefully.
A scenario you are likely to recognize
Imagine a release branch used by a system engineering team to prepare a production deploy. A commit lands that accidentally changes a service configuration file and causes an application to fail health checks. The commit has already been pushed, the pipeline has consumed it, and a second engineer has started review.
In that situation, git reset --hard may seem tempting because it makes the bad commit disappear. But it would also rewrite a branch that others have already seen. The safer move is usually git revert of the offending commit, followed by validation in the CI pipeline and a clear note in the incident record that the change was reverted rather than erased.
Now consider the same mistake on your local feature branch before it is pushed. If you made three commits while experimenting and want to collapse or remove the last one, git reset is appropriate because you are still controlling the branch state. The risk profile is completely different.
Common forms of reset and when they are appropriate
git reset is often discussed as if it were a single action, but the mode matters. The three most common modes behave differently:
--softmoves the branch pointer but keeps changes staged.--mixedmoves the branch pointer and unstages the changes, which is the default behavior.--hardmoves the branch pointer and discards working tree changes, which is the most destructive option.
For shared repository work, the dangerous mode is usually --hard, because it can remove both commits and uncommitted edits from your local state. Even locally, you should treat it as a deliberate action and confirm you are not discarding anything you still need.
A useful validation habit is to check the target commit before resetting, then inspect the branch afterward with git log --oneline --decorate -n 5 and git status. If the result is not exactly what you expected, stop before pushing.
Common forms of revert and what to watch for
git revert is safer, but it is not magic. It creates a new change that undoes an earlier one, which can still conflict if subsequent commits modified the same lines. This is especially common when the bad commit is not isolated or when later commits depend on the same code path.
If the commit introduced a configuration change, revert usually behaves cleanly. If the commit was part of a larger refactor, the revert may produce conflicts or only partially restore the previous behavior. In those cases, review the resulting diff rather than assuming the revert fully restored the prior state.
When multiple commits must be undone, revert can be applied to a range or to a sequence of commits, but the order matters and conflicts can increase. If the repository is in a rebasing state or you are cleaning up a complex integration branch, it may help to revisit the conflict-handling discipline described in Git Rebase Conflicts: Resolve and Continue Safely.
What this means in practice
The operational question is not “Which command is better?” It is “Which command preserves the right evidence while producing the right branch state?” In production-oriented repositories, that usually means preserving history unless there is a compelling reason to rewrite it.
In practice, git revert is the default for anything already published. It produces a traceable correction that supports code review, auditability, and incident analysis. Teams can see both the mistake and the fix, which is valuable when a commit was part of a failed deployment or a security-sensitive change.
git reset is the default for local branch hygiene. It is especially useful when you need to rework commit boundaries, discard an accidental WIP commit, or prepare a clean change set before publishing. The key is to keep the operation private until the branch is ready for collaboration.
If your repository uses protected branches, merge checks, or required reviews, those controls are usually signaling the same policy: do not rewrite public history casually. Follow that policy unless you have an explicit incident procedure that says otherwise.
Decision guidance for shared repositories
If the commit has been pushed and other people may have based work on it, choose git revert. That is the normal case for mainline, release, and integration branches.
If the commit is local only and you want to remove or reshape it before anyone else sees it, choose git reset. Prefer --soft or --mixed when you still want to keep the changes available for re-commit or review, and reserve --hard for deliberate discard.
If you need to change published history anyway, stop and confirm three things first: whether the branch is protected, whether teammates have already pulled it, and whether your team has a documented force-push procedure. If any of those answers are unclear, do not rewrite history blindly.
The right decision is usually the one that minimizes surprise for everyone else.
Common mistakes to avoid
One frequent mistake is using reset --hard on a shared branch because it appears faster than reverting. That may appear to solve the problem locally while creating divergence for everyone else.
Another common error is assuming revert always restores the exact prior behavior. If later commits depend on the reverted change, the branch may still need follow-up adjustments or verification.
A third mistake is forgetting that branch protection and repository policy may matter more than the command itself. Even a technically correct history rewrite can violate operational policy if the branch is shared or if audit trails are required.
Finally, people often validate only the absence of the bad commit and forget to validate the resulting application state. After an undo operation, verify the branch, the working tree, and the runtime behavior that mattered in the first place.
Production readiness checklist
Before using git revert or git reset in a production-adjacent repository, verify the following:
- The commit is local, or you have confirmed the team is ready for history changes.
- You know whether the branch is protected or mirrored in automation.
- You understand whether other people may already depend on the branch tip.
- You have chosen
revertfor shared history andresetfor private cleanup. - You have checked the resulting
git log,git status, and targeted diff. - You have confirmed the branch still builds, tests, or deploys as expected.
- If rewriting history is unavoidable, you have explicit approval and a communication plan.
Final takeaway
Use git revert when you need a safe, auditable undo on a shared branch. Use git reset when you are cleaning up private history or intentionally repositioning a local branch. In a collaborative repository, the safer command is usually the one that preserves what others have already seen.
Use this guidance together with JWT authentication and authorization to connect the workflow with related operational context already available on the site.
Part of the Programming: Git Insights content cluster.