Git Back in Time the Right Way
git revert vs. git reset
Whether you’re working solo or with a team, you will run into bad commits occasionally on your Git project which you’ll need to undo. After messing up several times on my personal projects from using the wrong StackOverflow solution to save my work (in mid panic attack), I realized how important it is to differentiate between git revert and git reset and know when to use which. For major projects, it’s key to know how to properly salvage your work so it can be free of issues in the long term rather than looking for a quick & dirty fix that will inevitably come back to haunt you down the line. I wrote out a few common Git commands below that I use for different scenarios.
Help! I want to delete my unpublished commits!
If you’ve committed but have not published to a remote repository, then you can delete previous commits by using the
reset command. (Note: This is effective but dangerous since the "deleted" commits will become unreferenced or otherwise known as "orphaned"). To find and recover these unreferenced commits is with the command
git reflog. To quickly find a commit reference/hash you want to reset to, look it up using
--hard option in order to include the commit history reference pointers, staging index, and the working directory as part of your deletion process. This means ALL working changes will be lost with this command.
SOLUTION — Reset your local file to a previous commit (All commits after the specified commit will be removed from the branch history)
git reset --hard <hash-or-ref>//example: git reset --hard 65806eb
Help! I want to delete my published commits!
If you committed and pushed your code to the remote repository, it is HIGHLY ADVISED that you DO NOT use
git reset which rewrites history. The cleanest and safest solution is to
git revert so that the file is updated to a previous state while preserving the commit history of the branch. A new commit reference is generated to reflect this commit.
SOLUTION — Clones the file state of a previous commit and creates a new commit without manipulating the branch history.
git revert <hash-or-ref>
//example: git revert 65806eb
//Accept incoming changes from parent if asked
git revert HEAD
//This reverts to the most recent commit published without using a commit hash or reference
Help! I pushed and accidentally did git reset instead of git revert and now I can’t push to remote branch!
Because you rewrote history using a hard reset, a side effect is that Git can no longer accept a push from you because your new truncated local branch has a fewer number of commits than the remote branch. It is likely you’ll receive the following message when attempting to push:
>>Your branch is behind 'origin/main' by n commits, and can be fast-forwarded.
In order to update the remote branch with the truncated version, a force push needs to be done so that the remote branch’s HEAD is reset to the same commit as your local branch.
SOLUTION — Perform a force push to overwrite the history of the remote branch
git push --force origin <branch-name>
//example: git push --force origin main
Note: If you’re working on a team that’s updating the same branch, rewriting the history of this branch will create the same problems for your team members when they pull because their branch will have a different HEAD. For shared branches, it’s preferable to use
git revert instead of nuking the commit history with a hard reset.
Help! I’ve staged changes that I haven’t committed but a team member needs me to fix an urgent bug!
Save changes made when they haven’t been committed to a repository using
git stash and the file will return to the state of the last commit. If you are working on a different part of the file, be sure to publish the changes so it does not conflict with the stashed changes.
//save staged changesgit stash apply
//apply stashed changesgit stash clear
//delete stashed changes
This is a cleaner alternative to creating unnecessary branches and merges.