Undoing commits in git is a common task that developers perform when they want to undo changes that they have made to a repository. Whether you made a mistake in a commit or want to go back to a previous version of the code, git provides you several ways to undo a commit.
Using git reset to undo a commit
Using git reset is the most common way to undo changes that have been made to a repository. Resetting is a way of moving the current tip of a branch to a previous commit and thus resetting it to a previous state. This can be done to remove commits from the current branch that are no longer needed, or to undo changes that have already been made.
To use git reset, you need to specify the mode and the commit you want to reset the branch to. This takes the form:
$ git reset <mode> <commit>
Run in Warp
For <mode> there are three flag options:
- --soft will reset back to the specified commit, but the changes made in the subsequent commits will remain as part of the working directory and will be staged to be committed.
- --mixed is the default flag which is used when no other flag is specified. With this, while the working directory is not changed, meaning that no files are changed, none of these changes are staged to be committed. This means that if you run git status you will see all the files that were changed are in red, waiting to be committed.
- --hard flag will change both the staged snapshot and the working directory to remove all the changes beyond the commit specified. This means that the changes made in subsequent commits will act like the other commits never existed.
And <commit> is then the specific commit you want to refer back to.
You can undo your last commit(s) using HEAD
For example:
$ git reset --hard HEAD~2
Run in Warp
Which will reset the current branch back two commits and will remove all changes that had been made in the last two commits from the working repository.
Save this git reset command for easy re-use later
Warp has a predefined Workflow available that Warp terminal users can call by pressing CTRL-SHIFT-R and starting to type “undo most recent git commit”. One of very many Warp Workflows, this is an easier way to remember the syntax for undoing the last commit while leaving the working tree (the state of the files on disk) untouched:
$ git reset HEAD~
Run in Warp
A word of caution: be careful with using git reset. It will overwrite the commit history. While this isn’t a problem if you are undoing local changes, it can be difficult to untangle when the commits have already been pushed to a remote repository.
Using git checkout to undo a commit
Another way of undoing commits is to checkout a previous commit either for the whole repository or for a specific file. This is commonly used to checkout different branches of code but can also be used to checkout specific commits.
To checkout a specific commit, you need to specify the hash of the commit you want to checkout. This can be done using the command:
$ git checkout
Run in Warp
For this, replace <commit_hash> with the hash of the commit you want to check out. When running this command, `git` will switch the repository to the state that it was in on the specified commit.
The issue with this approach is that you will end up in a detached HEAD state. This means that you are not currently on any branch, so any changes you make will not be saved in a branch. If you want to make changes, you will need to create a new branch. This can be done using:
$ git checkout -b
Run in Warp
Where <branch_name> is the name of the new branch you want to create. From here you can start making new commits on this branch as usual.
Undoing changes to a specific file with git checkout
Alternatively, you can undo changes to a specific file by checking out that version of the file from a previous commit. The command for this is:
$ git checkout
Run in Warp
Which will reset the file to that state from the specific commit. It is important to note that this is a destructive operation since it permanently discards any changes made to the file after that commit.
Using git revert to undo a commit
Another approach that could also be used to “undo” commits is git revert. git revert works to undo a change by creating a new commit. This makes it a safe way for undoing changes in a public repository, as it does not change the history. An example:
$ git revert
Run in Warp
This will undo all the changes in the <commit_hash> commit and then will create a new commit with those changes undone. If there are no merge conflicts, an editor will open up asking you to name the new commit, and then it will be added to the end of the current head.
This approach preserves the commit history and potentially reduces the amount of merge conflicts that you may have to deal with compared to the use of either git reset or git checkout.
Tread carefully with undoing commits in remote repositories
While the methods above seem simple when it comes to undoing commits in a local repository, this can become an issue when undoing commits in a remote repository. If you are using a remote repository and collaborating with others, changing that history can affect the development path taken and can create merge conflicts. The effect of this depends on the method you use:
- git reset overwrites commit history. This means that your history will be different to the remote repository. If other developers are using the commits you have undone, then this will cause conflicts. This is why `git reset` is generally not recommended for use with a remote repository unless you are working on your own development branch.
- git checkout can also overwrite commit history when you checkout a previous commit for the full repository. To resolve this issue, you will need to create a new branch and then resolve the merge conflicts when merging back into the main branch.
- git revert is the safest way of undoing commits as it does not overwrite the commit history. Instead it creates a new commit that undoes the changes introduced in a previous commit while retaining the history of the origin commit. Other contributors will be able to see the commit was reverted and adjust their work accordingly.
If you decide to use git reset or git checkout to overwrite commits, then you can use git push --force to overwrite the remote branch with your local branch. This will overwrite any commits that were made after your last pull. This can create problems if other contributors have made changes that conflict with those that you are pushing, so you need to make sure you communicate clearly with others and coordinate your changes carefully.
How do I decide which approach to use?
If you don’t care about commit history, you should use git reset. If you don’t care about keeping the same branch, then you can use git checkout. If you care about history and the branch structure, then you can use git revert.
Written by
Philip Wilkinson
Software Engineer, Amazon
Filed Under
Related Articles
Undo A Git Pull
How to effectively remove the commits introduced by a pull in Git using git-reset and preserve your local changes using git-stash. Also, how to cancel an unmerged pull request on GitHub.
Undo a Git Merge
How to rollback the changes introduced by a merge in Git by adding new opposite commits using git-revert and effectively removing commits using git-reset.
Prompt Show Git Branch In Prompt
Enhance your terminal with a custom Git prompt. Learn different ways to integrate this contextual info, from custom shell functions to Warp context chips and toolkits like Starship and P10K.
How To Remove Secrets From The Git History Remove Secrets From The Git History
Learn how to remove secrets from the Git history using the BFG and git-filter-repo command-line tools.
Adding a Submodule in Git
This post will show you how to simply add a submodule to a local repository, clone a repository with a submodule, and work within a repository that has a submodule.
Undo a git push
This post will show you had to simply undo a git push three different ways.
Undo Git Add
Learn how to effectively use 'git add' to stage files in Git for committing, and discover two powerful methods to undo accidental stagings.
Undo a Git Rebase
This post will show you how to undo a rebase using git reset, git rebase and git revert
Git Push Origin
A breakdown of git push origin
Create Folder In GitHub Repository
Learn how to create and push one or more empty directories in a Git repository using `.placeholder` and `README.md` files using both the CLI and the GitHub interface.
Git Push Tags
This post will show you how to push a single tag, multiple tags, all tags, and tags with commits.
Delete Local Git Branch
Learn how to delete local branches from your git repository, including ones with unmerged changes, as well as local remote-tracking branches.