Introduction to git reset
Git is a resourceful platform to work with especially when collaborating with other software developers. However, you must understand most of its operations to benefit while using it including the git reset
command which is our topic of focus in this tutorial. That does not only apply to amateur developers but also the advanced developers.
It’s likely that you will commit errors in codes as a developer and this is where git reset
command will be of help. Such errors may include committing to a wrong branch, writing an inappropriate commit, or even losing some codes.
Our focus for this tutorial is an in-depth exploration of how git reset
works, scenarios for git reset such as git reset file, git reset origin, and git reset master.
Lab Environment
Let us do first things first before learning how to use the git reset
. We must set up an environment in which we are going to work. To understand the basics, I have set up a project git_test
in my gitlab account to illustrate this tutorial.
I’m running my local workstation on windows 10 pro and will first clone the git_test
local repo using the git clone
syntax to my computer. It is vital when starting a project or collaborating with others remotely to clone it to your local workstation. Do not worry about interfering with other developers' work during the implementation as git always creates a local copy for you from the master copy.
$ git clone https://github.com/git-testing-account/git_test.git
Sample output:
When should you use git reset?
For you to understand how to work best with the git reset
function, it is important that you comprehend how git stores changes in its working environment. How does git operate to store repositories, working directories and its indexes?
A working directory is where your source code will be kept while working and the relevant repo. It is in the directory where you will access all your files and folders for the current project.
A repository stores all the commits that you perform during coding while maintaining both the local copy and remote copy.
While working as a programmer, it’s inevitable to stage all your project files, line of codes and folders before you commit them. You may run into errors and you might want to go back to your default branch/main. It is through such experiences that utilizing the get reset
command becomes helpful. Going back to your primary line of codes is known as git reset hard
in git environment.
Before you can use git reset
function, you will first need to apply git status
command below to see all your staged files in the local working environment.
$ git status
Sample output:
From the above illustration, you will notice that we have several files that are yet to be committed but rather staged to be deployed later. Note that the files here are stored in the directory and not in the repository. The reason is that the files are yet to be committed.
Different ways to perform git reset
Git usually provides you with three ways of working with the git reset command:
git reset --soft commit
- TheÂ
--soft
 changes the HEAD ref to point to the given commit. - The contents of your index and working directory are left unchanged.
- This version of the command has the least effect, changing only the state of a symbolic reference so it points to a new commit.
git reset --mixed commit
- The
--mixed
changes HEAD to point to the given commit. - Your index contents are also modified to align with the tree structure named by commit, but your working directory contents are left unchanged.
- This version of the command leaves your index as if you had just staged all the changes represented by commit, and it tells you what remains modified in your working directory.
NOTE:
--mixed
 is the default mode for git reset.
git reset --hard commit
- This variant changes the HEAD ref to point to the given commit.
- The contents of your index are also modified to agree with the tree structure named by the named commit.
- Furthermore, your working directory contents are changed to reflect the state of the tree represented by the given commit.
Following Table summarizes the behaviour:
Option | HEAD | Index | Working Directory |
---|---|---|---|
--soft | Yes | ||
--mixed | Yes | Yes | |
--hard | Yes | Yes | Yes |
Method-1: git reset --hard
Below are various ways of implementing git reset --hard head
while using git to manage your projects.
## Here you are directed back to the head on implementing the command
git reset --hard HEAD
## Here you are directed back to the commit done before the head
git reset --hard HEAD^
## Here you have directed backwards two commits before head
git reset --hard HEAD~2
git reset command enables you to connect your active head to the commit called out by the command. Using the git reset --hard commit
will enable you to reset the file staged and located in your active directory branch.
Example-1: git reset --hard HEAD
The git reset command also saves the original HEAD
 value in the ref ORIG_HEAD
. This is useful, for example, if you wish to use that original HEAD’s commit log message as the basis for some follow-up commit.
In terms of the object model, git reset moves the current branch HEAD within the commit graph to a specific commit. If you specify --hard
, your working directory is transformed as well.
I will create a new file and perform some commit
$ touch master_file
$ echo "Commit One" >> master_file
$ git add master_file
$ git commit -m "Added master file" master_file
[new-feature b29dfd4] Added master file
1 file changed, 1 insertion(+)
create mode 100644 templates/master_file
As you can see, the HEAD is currently at b29dfd4
commit
$ git log --oneline b29dfd4 (HEAD -> new-feature) Added master file 20412c0 (origin/main, origin/HEAD, main) Added index.html template cf00196 (origin/new-issue-7843, origin/new-feature, new-issue-7843) Added patch-1 e126b0b Adding new group 5e04f57 Created new script to add groups 1b6369c Added create_users.sh script ...
Now we will add a second file but we will not perform commit:
$ touch second_file $ git add second_file
So currently there are three files in my staging environment:
$ git ls-files index.html master_file second_file
I am yet to commit the second_file
:
$ git status
On branch new-feature
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: second_file
Let's perform a HARD reset:
$ git reset --hard HEAD
HEAD is now at b29dfd4 Added master file
As you can see, the last command has taken our local branch at b29dfd4
commit ID and we have lost all our changes from the working directory
$ git status
On branch new-feature
nothing to commit, working tree clean
$ git log --oneline
b29dfd4 (HEAD -> new-feature) Added master file
20412c0 (origin/main, origin/HEAD, main) Added index.html template
cf00196 (origin/new-issue-7843, origin/new-feature, new-issue-7843) Added patch-1
e126b0b Adding new group
$ git reset --hard HEAD 20412c0
fatal: Cannot do hard reset with paths.
Instead you will have to use:
$ git reset --hard 20412c0
Example-2: git reset --hard HEAD^
I had recently added master_file
with commit id b29dfd4
which is the current HEAD of our branch:
$ git ls-files
index.html
master_file
You can also verify the same using git log:
$ git log --oneline b29dfd4 (HEAD -> new-feature) Added master file 20412c0 (origin/main, origin/HEAD, main) Added index.html template cf00196 (origin/new-issue-7843, origin/new-feature, new-issue-7843) Added patch-1 e126b0b Adding new group
Now I just realised that I did a mistake by committing master_file
and I want to go back by one commit id. In such case we can use HEAD^
with git reset. For example:
$ git reset --hard HEAD^
HEAD is now at 20412c0 Added index.html template
As you can see, the last command has reset our branch to one commit behind the HEAD commit i.e. 20412c0
Check the list of files available:
$ git ls-files
index.html
So the master_file
has been deleted from the branch.
Example 3: git reset --hard HEAD@{n}
We were able to perform the git -reset- head
from our first example which led to our active test-patch branch pointing out to the first commit after the head different from the initial setup.
In this example, here you can see I have multiple commits
$ git reflog
cf00196...HEAD@{0}: checkout: moving from new-issue-7843 to new-feature
cf00196...HEAD@{1}: checkout: moving from main to new-issue-7843
20412c0...HEAD@{2}: clone: from gitlab.com:golinuxcloud/git_examples.git
Reading through this list, the third line down records a clone operator. At that time, 20412c0
was the master HEAD. So, you could directly use 20412c0
or you could use the symbolic name HEAD@{2}
:
$ git rev-parse HEAD@{2} 20412c0ca53072b566be633ab082a3b8dc43ec6b $ git reset --hard HEAD@{2} HEAD is now at 20412c0 Added index.html template $ git show-branch ! [main] Added index.html template * [new-feature] Added index.html template ! [new-issue-7843] Added patch-1 --- +* [main] Added index.html template +*+ [new-issue-7843] Added patch-1
As just shown, the reflog
can frequently be used to help locate prior state information for refs, such as branch names.
Method-2: git reset --mixed
In the git working environment, git reset --mixed
is usually the default mode.
Git reset mix works in the same way as the git reset --hard
but with some slight difference. Running git reset --mixed
changes the head and the index only which is not the case with the git reset --hard
. The git reset --hard
, not only changes the head and the index but also your working directory.
Here I have a bunch of commits on my branch
$ git log --oneline 7786058 (HEAD -> new-feature) Added second_file a098c09 Added master_file 20412c0 (origin/main, origin/HEAD, main) Added index.html template cf00196 (origin/new-issue-7843, origin/new-feature, new-issue-7843) Added patch-1 e126b0b Adding new group 5e04f57 Created new script to add groups
Additionally I have third_file
in the staging environment which is waiting to be committed:
Next we will perform git reset --mixed
to one commit before the HEAD commit i.e. a098c09
commit ID:
$ git reset --mixed HEAD^
Check the list of commits, our HEAD is now at a098c09
commit id and we have lost our index value for 7786058
commit:
$ git log --oneline a098c09 (HEAD -> new-feature) Added master_file 20412c0 (origin/main, origin/HEAD, main) Added index.html template cf00196 (origin/new-issue-7843, origin/new-feature, new-issue-7843) Added patch-1 e126b0b Adding new group 5e04f57 Created new script to add groups ..
If you check git status
, you will notice the all the commits before a098c09
has been reverted to untracked state. But we have not lost the changes unlike git reset--hard
. So this explains how git reset --mixed
is different from git reset --hard
Method-3: git reset --soft
Here are the list of commits on my branch:
$ git log --oneline fb12818 (HEAD -> new-feature) Added second file a098c09 Added master_file 20412c0 (origin/main, origin/HEAD, main) Added index.html template cf00196 (origin/new-issue-7843, origin/new-feature, new-issue-7843) Added patch-1 e126b0b Adding new group 5e04f57 Created new script to add groups ..
Additionally I have also kept one file in the staging environment i.e. it has been added to git but I have not yet done a commit:
Here are the list of files available in the git repo:
$ git ls-files
index.html
master_file
second_file
third_file
Next we will do a soft reset to one commit behind HEAD i.e. a098c09
commit id:
$ git reset --soft HEAD^
After performing git soft reset also we can see that our files are in staging environment unlike git reset --mixed
where the files went into untracked state:
$ git ls-files
index.html
master_file
second_file
third_file
Although all the files modified before a098c09
commit id has been removed from the repo, but they are still present in our staging environment:
Here are the list of commits at this stage:
$ git log --oneline a098c09 (HEAD -> new-feature) Added master_file 20412c0 (origin/main, origin/HEAD, main) Added index.html template cf00196 (origin/new-issue-7843, origin/new-feature, new-issue-7843) Added patch-1 e126b0b Adding new group 5e04f57 Created new script to add groups ..
Understanding the basic difference between git reset hard vs soft vs mixed
Here is the simplest explanation of all three types of reset. For more details you can check the examples which I have shared above:
- --soft: uncommit changes and the changes are left staged (index).
- --mixed (default): uncommit + unstage changes, changes are left in working tree (untracked).
- --hard: uncommit + unstage + delete changes, nothing left (all data deleted in working directory till the reset point).
Summary
We have covered the following topics about git reset
in this tutorial that will help you to use it like a pro:
- git reset syntax
- when should we perform git reset
- Different git reset methods with examples