Sometimes you might commit changes to your Git repo, but then realize you made a mistake. Now you want to undo those commits to get your code working again.
In this guide, we’ll look at the git reset command for local and remote commits to a repository.
Difference Between a git reset and git revert
It’s important to understand the difference between resetting vs reverting commits when using Git.
- The git reset command undoes commits by removing previous commits from the repository and resetting the Git HEAD to an earlier commit. Some Git history might be lost by doing this, depending on what option is used.
- The git revert command undoes commits by creating a new commit that represents an earlier state of the repository. No Git history will be lost by doing this.
Already pushed changes and someone else pulled those changes? You should not use git reset to undo changes, you should use git revert as described in our Git rollback commit guide instead.
Using the git reset Command to Undo a Commit
For the following examples, assume our local Git tree looks like this:
X | A-B-C
The X represents our local, uncommitted change to our Git HEAD, indicated by C.
To undo the commit named “C “due to a mistake, we can run a git reset command.
Depending on file tracking needs, you’ll want to use the git reset command with different flags.
Case 1: Use git reset and Remove Files From the Staging Area
We can use the git reflog command to see our Git history.
We can use git ls-files to see the currently staged files for our project:
$ Git reflog
f326d13 HEAD@{0}: commit: Added C
358d535 HEAD@{1}: commit: Added B
00b61d5 HEAD@{2}: commit (initial): Added A
$ Git ls-files
A
B
C
X
To keep any tracked files since commit C, but remove them from the Git index, you can run:
Git reset HEAD~1
You can use the Git shorthand of HEAD~1 to remove the commit one commit before HEAD.
If you used HEAD~5, this would remove the commit that is five commits before HEAD.
Changes to the Git index, also called the “staging area,” will be lost, so the Git tree would now be:
X | A-B
Which we can confirm with these commands:
$ Git reflog
358d535 HEAD@{0}: reset: moving to HEAD~1
f326d13 HEAD@{1}: commit: Added C
358d535 HEAD@{2}: commit: Added B
00b61d5 HEAD@{3}: commit (initial): Added A
$ Git ls-files
A
B
$ Git status
On branch master
Untracked files:
(use "Git add ..." to include in what will be committed)
C
X
When just using git reset with no flags, we don’t remove any files; they are just un-staged:
$ ls
A B C X
You do end up removing the log entry for the commit you reset, however:
$ Git log
commit 358d535bc5e06730e61d272be34a6d0e568f42af
Author: User
Date: Tue Feb 10 13:54:55 2015 -0500
Added B
commit 00b61d53fe06ee672fa0497b175fb7bd89e26b72
Author: User
Date: Tue Feb 10 13:54:55 2015 -0500
Added A
Case 2: Use git reset –soft and Preserve Changes to Files
If you use the –soft flag, any changes to tracked files and the Git index are preserved:
Git reset --soft HEAD~1
Any files that were staged remain so, and no files are physically removed:
$ Git ls-files
A
B
C
X
$ ls
A B C X
$ Git status
On branch master
Changes to be committed:
(use "Git reset HEAD ..." to unstage)
new file: C
new file: X
Using the –soft flag, you still end up removing the log entry for the commit you reset.
Case 2: Use git reset –hard and Remove All Changes to Files
If you use the –hard flag, any changes to tracked files and the Git index are lost:
$ Git reset --hard HEAD~1
HEAD is now at 3bf1b55 Added B
All files after the commit you reset to are un-staged and physically removed:
$ Git ls-files
A
B
$ ls
A B
$ Git status
On branch master
nothing to commit, working directory clean
You again remove the Git log entry for the commit that you reset.
Try to Use git revert When Commits Are Already Pushed
As stated above, if you’ve already pushed your changes and someone else pulled in those changes, you should not use git reset to undo changes, use git revert instead.
However, if you really want to, you can apply the same steps as in the previous section to delete some previous Git commits.
After that, you can do a git push -f to use the force option. Again, this is not recommended, because it can create serious conflicts between the various repository states of other Git users.
HostingAdvice.com is a free online resource that offers valuable content and comparison services to users. To keep this resource 100% free, we receive compensation from many of the offers listed on the site. Along with key review factors, this compensation may impact how and where products appear across the site (including, for example, the order in which they appear). HostingAdvice.com does not include the entire universe of available offers. Editorial opinions expressed on the site are strictly our own and are not provided, endorsed, or approved by advertisers.
Our site is committed to publishing independent, accurate content guided by strict editorial guidelines. Before articles and reviews are published on our site, they undergo a thorough review process performed by a team of independent editors and subject-matter experts to ensure the content’s accuracy, timeliness, and impartiality. Our editorial team is separate and independent of our site’s advertisers, and the opinions they express on our site are their own. To read more about our team members and their editorial backgrounds, please visit our site’s About page.