Today, it's hard to imagine the work of a programmer or IT professional without version control. Among the various SCM tools, Git stands out, having quickly gained popularity and becoming the de facto standard in the world of version control systems. Git allows you to easily track project file changes, manage branches, collaborate, and centrally store code and other files.
One of Git's strengths is its flexible ability to undo or remove changes. One such way to undo changes is with the git reset
command, which supports three different modes. In this tutorial, we'll explore how to undo changes using git reset
and its modes through practical examples.
We'll focus on practical use cases of the git reset
command, so it's necessary to have Git installed beforehand.
We'll use a Linux-based operating system for this tutorial, specifically Ubuntu 22.04. However, any Linux distribution will work, as Git is available in nearly all modern package managers.
In most distributions, Git comes pre-installed, though the version may not always be the latest. For Ubuntu-based systems, you can install Git from the official repository with the following commands:
add-apt-repository ppa:git-core/ppa && apt -y install git
For other Debian-based distributions (Debian, Linux Mint, Kali Linux, etc.), you can install Git using:
apt -y install git
For RHEL-based distributions (RedHat, CentOS, Fedora, Oracle Linux), the installation command will vary depending on the package manager:
For yum
package manager:
yum -y install git
For dnf
package manager:
dnf -y install git
After installation, verify the Git version:
git --version
The git reset
command is used to undo local changes. Technically speaking, git reset
moves the HEAD
pointer to a previous commit in the repository. HEAD
is a pointer to the current branch and points to the latest commit in that branch.
The git reset
command operates with three key elements: the working directory, the HEAD
pointer, and the index. These elements are often referred to as "trees" in Git, as they are structured using nodes and pointers. We'll go into detail about each of these elements below.
It's worth noting that various Git-based web services like GitHub, GitLab, and Bitbucket offer the ability to undo actions through their web interface. However, they typically use a safer alternative, git revert
, which preserves the entire project history, unlike git reset
which can permanently remove commits.
The working directory is where files are stored and tracked by Git. When you run the git reset
command, Git knows which directory is being tracked because of a hidden .git
folder created when you initialize a repository with git init
.
Here's how the working directory works in practice:
Create a new directory and navigate into it:
mkdir new_project && cd new_project
Initialize a new Git repository:
git init
Once you initialize the repository, a hidden .git
folder containing Git configuration files is created in the root directory.
HEAD
points to the current branch and the latest commit in that branch. Every time you switch branches with git checkout, HEAD
updates to point to the latest commit in the new branch.
Here's a practical example:
touch new1.txt
git add new1.txt
git commit -m "Initial commit"
HEAD
is pointing, use the git cat-file command:git cat-file -p HEAD
Since there's only one commit, HEAD
points to it.
Now, let's modify the file and add it again.
echo "This is a test file" > new1.txt
git add new1.txt
git commit -m "Added content to new1.txt"
git cat-file -p HEAD
As you can see, HEAD
now points to the new, latest commit.
The index (or "staging area") is where files go after being added with git add
. Think of it as a pre-commit area. Files in the index are tracked by Git but not yet part of the actual commit. You can remove or modify files in the index before they are committed.
Create a new file:
touch new2.txt
Add it to the index:
git add new2.txt
Check the status:
git status
The file is now in the staging area but not yet committed.
The git reset
command supports three modes: soft, mixed, and hard.
The soft mode undoes the last commit but keeps the changes in the index. This means that you can modify and recommit them.
Create a new file:
touch new3.txt
Add it to the index:
git add new3.txt
Commit the file:
git commit -m "Added new3.txt"
If we run git log
now, that's what we'll see:
To undo the last commit:
git reset --soft HEAD~1
The commit is undone, but the file remains in the index.
The mixed mode is the default for git reset
. It undoes the commit and resets the index, but leaves the working directory untouched.
Create three new files:
touch new{1..3}.txt
Add and commit them:
git add new1.txt new2.txt new3.txt
git commit -m "Added three files"
Now undo the commit:
git reset HEAD~1
The files remain, but the last commit is removed.
The hard mode deletes the commit, resets the index, and removes the files from the working directory. This is the most destructive option.
Create and commit a file:
touch readme.md
git add readme.md
git commit -m "Added readme.md"
To remove the commit and the file:
git reset --hard HEAD~1
The file and the commit are permanently deleted.
You can also reset to a specific commit using its hash:
git reset --hard <commit-hash>
This will reset the repository to that specific commit.
In this tutorial, we explored the git reset
command and its modes: soft, mixed, and hard. While git reset is a powerful tool for undoing local changes, it's essential to understand each mode's impact, especially the potential risks of using the hard mode to avoid irreversible data loss.