git reset examples [hard vs soft vs mixed]

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.

Advertisement

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:
git reset with simple examples [hard vs soft vs mixed]

 

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.

Advertisement

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:
git reset with simple examples [hard vs soft vs mixed]

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:

OptionHEADIndexWorking Directory
--softYes
--mixedYesYes
--hardYesYesYes

Advertisement

 

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
NOTE:

You cannot perform hard reset by using some PATH, in such case you will get following error:

$ 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:
git reset with simple examples [hard vs soft vs mixed]

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
git reset with simple examples [hard vs soft vs mixed]

 

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:
git reset with simple examples [hard vs soft vs mixed]

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:
git reset with simple examples [hard vs soft vs mixed]

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

 

Further reading

git-reset –hard,git-reset-soft

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment