Git is a version control system and source code management tool. It tracks and stores the version history of our project using commits.
Sometimes, we make mistakes and want to restore an older version of our project. Git provides the flexibility to do so. With Git, we can temporarily switch to a previous commit. Or we can reset our repository to an earlier version. Let's learn the different ways in which we can reset or revert our Git repository to a previous commit.
To merely view the changes made in a previous commit, we can directly check out that commit. The Git Checkout command helps to move our HEAD to a different commit. We need to pass the hash of the commit that we want to checkout.
git checkout <commit-hash>
Note that the above command will lead to a detached HEAD state. We can view the changes and even make experimental commits, but these changes(or commits) will be lost if we check out a different branch. Git returns the following output whenever we checkout a commit and have a detached HEAD.
git checkout 74f75b1
Output:
Note: switching to '74f75b1'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 74f75b1 Added main.py
To keep the new commits, we need to create a branch. Use the Git Checkout command with -b to go back to a previous and create a new branch pointing to that commit. We can then add new commits to this branch.
git checkout -b <new-branch-name> <commit-hash>
The Git Reset command helps us undo a series of the most recent commits. If you are working alone or if the commits have not been published to the remote repository, then Git Reset is the best command to use.
Use Git Reset with --hard option to undo changes and move our branch to a previous commit point. Pass the commit hash to the command.
git reset --hard <commit-hash>
We will lose any uncommitted changes with the --hard option. Use the --soft option to keep these changes.
git reset --soft <commit-hash> # keep the uncommitted changes
Or we can stash away the uncommitted changes by using the Git Stash command.
git stash # stash uncommitted changes
git reset --hard <commit-hash> # reset to an earlier version
git stash pop # un-stash the changes
Consider a repository with a master branch and five commits on it.
A -- B -- C -- D -- E <- master <- HEAD
We need to reset our repository back to commit C. We can use any one of the following Git Reset commands. If you have uncommitted changes, use the --soft option or stash your changes.
git reset --hard <hash-of-commit-C>
git reset --hard HEAD~2 # HEAD~N to go back N commits
The final state of our repository is shown below.
A -- B -- C <- master <- HEAD
The Git Reset command will remove commits from our local repository. We can't push the modified history if these commits exist on a remote repository. The Git Reset command rewrites the history of our project, and the local repository history doesn't match the remote repository's history. Because of the difference in history, Git will block the push. We can use the Git Revert command instead.
The Git Revert command will undo the changes but will not alter our version history. It does this by creating a new commit that contains the inverse of the changes of the previous commit. If we want to undo the effects of a single commit, then pass the hash of that commit.
git revert <hash-of-commit-to-undo>
Or, if you wish to undo multiple commits, pass the hash of all the commits. Git Revert will create a new commit for each commit that we undo.
git revert <commit-hash-1> <commit-hash-2> <commit-hash-3>
We can also pass a range by using the double dot notation(..). Note that the starting commit is not included.
git revert <starting-commit-hash>..<end-commit-hash> # starting commit not included
Consider a repository with a master branch and five commits.
A -- B -- C -- D -- E <- master <- HEAD
We need to go back to commit B. We want to undo the last three commits(C, D, and E). We can use any one of the following Git Revert commands to do so.
git revert <hash-of-commit-C> <hash-of-commit-D> <hash-of-commit-E>
git revert <hash-of-commit-B>..<hash-of-commit-E> # commit B not included
git revert HEAD~3..HEAD # HEAD~N..HEAD to revert last N commits.
The above commands will open our configured text editor, and we can add a message for each of the reverted commits. The final state of our repository is shown below. Three new commits(C', D', and E') are created. These contain the inverse of the changes of commits C, D, and E.
A -- B -- C -- D -- E -- C' -- D' -- E' <- master <- HEAD
Mistakes are bound to happen when working on a project. Git stores the version history of our projects with the help of commits. We can reset our repository to any of the previous project versions. The three methods discussed in this article are summarized below.
Use the Git Checkout command to switch to a previous commit and view the changes.
Use the Git Reset command to undo a series of most recent commits. Use it only when you are working alone and have not published the commits to a remote repository.
Use the Git Revert command to undo commits that have been published or pushed to a remote repository.