Git Reset Hard Explained: Irreversibly Deleting Commits (Caution!)
Correcting risky Git history? A guide to `git reset --hard`. Understand the dangers of data loss & `--force push`, plus when `git revert` is a better choice.

Table of Contents
Important Warning Upfront: git reset --hard
is a powerful but also dangerous tool. It irreversibly rewrites Git history and permanently discards changes. In combination with git push --force
, it can lead to significant problems in team projects. This command should only be used with caution and never carelessly on shared branches like main
or master
without explicit team agreement! Often, there are safer alternatives like git revert
.
The Need for a Git Reset
Sometimes you change your code, and suddenly something stops working. Unfortunately, it’s already been pushed to the repository’s master branch.
Or you accidentally pushed sensitive data like API keys or passwords into your repository (in this case, it’s still highly recommended to change the API keys or passwords anyway).
I notice that my code no longer works after a certain point.
I want to restore a different state and irretrievably delete everything in between.
What is Git Reset?
git reset
allows you to undo changes by moving the current branch pointer to a different commit. This has the effect of rewinding the repository’s state to an earlier point in time.
There are different modes that can be used with reset
:
--soft
: Moves the branch pointer but leaves the staging area and working directory unchanged.--mixed
: Moves the branch pointer and resets the staging area, but not the working directory (this is the default mode).--hard
: Moves the branch pointer and resets BOTH the staging area and the working directory.
Depending on the mode used, reset
can discard commits, undo changes, or even permanently delete work.
Identifying the Last Known Good Commit
Before performing a hard reset, you need to identify the last good state. This is the commit where the code worked as expected or before problematic changes were made.
I look in my repository management tool (in this case, GitHub) to find the ID of the commit corresponding to that state.
Executing the Git Reset Command
With the commit ID, I can now perform the Git reset. To do this, I open the terminal and navigate to my local Git repository. Then I execute the following command:
git reset --hard <commit-id>
Replace <commit-id>
with the actual ID of the commit you want to revert to. For example:
git reset --hard ac55a49123456789
The --hard
option means that not only the branch pointer is moved (as with --soft
or --mixed
), but also the staging area and the working directory are reset to the state of the target commit. All changes in these areas that were not yet committed will be lost! You should ensure that no uncommitted local changes are still needed.
Pushing the Changes to the Remote Repository
After git reset --hard
has been executed locally, your local commit history differs from that of the remote repository (e.g., on GitHub). A normal git push
will fail because Git recognizes that commits are “missing”.
To push the changes anyway, a force push must be used:
git push --force
# Or the safer alternative:
git push --force-with-lease
Extreme caution with git push --force
! This command overwrites the history in the remote repository with your local version. If team members have worked and pushed based on the old history in the meantime, their changes can be lost, or severe merge conflicts can arise.
- When might
--force
(used cautiously) be OK? On purely personal branches that no one else uses, or after clear agreement and coordination with the entire team. --force-with-lease
: Is slightly safer, as it refuses the push if someone else has pushed changes to the branch in the meantime. However, it doesn’t prevent rewriting history for everyone else.
This process deletes the problematic changes and resets the repository as if the subsequent commits never happened.
Merge Conflicts After a Git Reset
In some cases, a Git reset can lead to merge conflicts when other team members try to pull the latest changes. This happens because their local repository still contains the commits you removed.
To resolve merge conflicts, they need to perform a git pull
with the --rebase
flag:
git pull --rebase
This command reapplies their local changes on top of the reset state (the commit you reset to) and allows them to resolve any conflicts and continue working with the updated codebase.
Alternative Approaches
git reset --hard
is rarely the best solution for everyday problems, especially in team environments. Alternative approaches should be considered that may be less disruptive and better suited to the specific situation.
Git Revert
The git revert
command allows you to undo specific commits without losing commit history. This command creates a new commit that reverses the changes introduced by the specified commits.
Create a Branch
Another alternative to Git reset is creating a new branch starting from the last known good commit. This way, changes can be examined and tested without affecting the main branch.
To create a new branch, use the following command:
git checkout -b <new-branch-name> <commit-id>
Replace <new-branch-name>
with a descriptive name that indicates the purpose of the new branch. The <commit-id>
is the ID of the commit from which the new branch will be created.
After creating the new branch, specific commits from the problematic branch can be cherry-picked into the new branch to isolate and test the changes.
git cherry-pick <commit-id>
Git Stash
If you have uncommitted changes that you don’t want to lose, you can temporarily save them using the git stash
command.
After the reset, the changes can be retrieved using git stash pop
or git stash apply
.
Interactive Rebase
Rebase allows you to rewrite the commit history. While not a direct alternative to Git reset for reverting published changes, interactive rebasing can help clean up commit history and create a more linear and understandable sequence of changes.
git rebase -i <commit-id>
The <commit-id>
specifies the base commit for the rebase operation (e.g., the commit before the sequence you want to modify). It opens an editor window where you can specify actions for each commit, such as pick
, squash
, edit
, or drop
.
Interactive rebase requires a good understanding of Git and should be used with caution, as it rewrites commit history. It is best suited for cleaning up local commits before pushing them to a shared repository.
Conclusion
A git reset --hard
followed by git push --force
is a radical step to correct Git history. It can be useful for cleaning up local mistakes or removing sensitive data (which should still be changed anyway!) from commits that haven’t been widely shared yet.
Risks: Data loss and massive collaboration problems within the team are real dangers. For undoing changes in shared repositories, git revert
is almost always the safer and recommended method, as it keeps the history intact.
Using git reset --hard
should only be considered as a last resort.