Back to Git & Dev Tools
2026-01-157 min read

How to undo a commit with git reset (Git & Dev Tools)

Learn How to undo a commit with git reset (Git & Dev Tools) step by step with clear examples and exercises.

Why This Matters

Undoing changes is an essential skill for every developer, and Git provides several ways to do this. In this lesson, we'll focus on using git reset to undo commits and explore its various options.

Why This Matters

Mistakes happen, and sometimes you may need to undo changes in your Git repository. git reset is a powerful command that helps you revert changes, move between different states of your project, or even discard entire commits. Understanding how to use it effectively can save you from losing work and help you maintain a clean and organized Git history.

Prerequisites

To follow along with this lesson, you should have a basic understanding of Git and its fundamental concepts such as branches, commits, and the Git workflow. If you're new to Git, consider checking out our previous lessons on Git Basics and Branching and Merging first.

Core Concept

Basic Usage

The git reset command allows you to move the HEAD pointer of your current branch to a different commit, effectively undoing changes made after that commit. Here's a simple example:

$ git checkout my-branch # Switch to the desired branch
$ git reset --hard HEAD^ # Move the HEAD pointer one commit back (^ denotes the previous parent)

In this example, we're moving the HEAD pointer of my-branch to its previous commit. The --hard option discards all changes made since that commit, including any unstaged changes in your working directory and any commits on top of it.

Hard Reset vs Soft Reset

There are two main types of resets: hard reset (git reset --hard) and soft reset (git reset without the --hard option). A hard reset discards all changes, while a soft reset keeps them staged but uncommitted. This allows you to continue working on the undone changes if needed.

$ git checkout my-branch # Switch to the desired branch
$ git reset HEAD^ # Move the HEAD pointer one commit back (soft reset)

In this example, we're moving the HEAD pointer of my-branch to its previous commit using a soft reset. The changes made after that commit are still present in the staging area and can be committed again if desired.

Mixed Reset

A mixed reset (git reset ^) is a combination of both hard and soft resets. It unstages all changes from the specified commit but keeps them in your working directory, allowing you to choose which changes to discard or commit later.

$ git checkout my-branch # Switch to the desired branch
$ git reset 5abcd123 # Move the HEAD pointer to the specified commit (mixed reset)

In this example, we're moving the HEAD pointer of my-branch to the commit with the SHA-1 hash 5abcd123. All changes made after that commit are unstaged but still present in your working directory.

Worked Example

Let's walk through a practical example using the following Git history:

A - B - C (current HEAD) - D (uncommitted changes)
  1. First, let's stage some changes for commit D.
$ git add .
$ git status
On branch my-branch
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: example.txt

Untracked files:
(use "git add <file>..." to include in what will be committed)
example2.txt
  1. Now, let's create a new commit D with the staged changes.
$ git commit -m "Add example.txt and untracked example2.txt"
[my-branch 456abcde] Add example.txt and untracked example2.txt
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 example.txt
Untracked files would be ignored by this commit if not previously tracked
  1. Next, we'll make some changes in our working directory that haven't been staged yet (commit D is still uncommitted).
$ echo "New content" >> example.txt
$ git status
On branch my-branch
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: example.txt

Untracked files:
(use "git add <file>..." to include in what will be committed)
example2.txt
  1. Now, let's undo the last commit D using a soft reset. This unstages all changes made after commit C, but the changes are still present in our working directory.
$ git reset HEAD^ # Move the HEAD pointer to commit C (soft reset)
Unstaged changes after reset:
M example.txt
  1. We can now choose to discard or stage the uncommitted changes made in step 3.
$ git add . # Stage all changes
$ git status
On branch my-branch
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: example.txt

Untracked files:
(use "git add <file>..." to include in what will be committed)
example2.txt
  1. Finally, let's commit the changes from commit D again.
$ git commit -m "Add example.txt and untracked example2.txt (again)"
[my-branch 456abcde] Add example.txt and untracked example2.txt (again)
1 file changed, 0 insertions(+), 0 deletions(-)

Common Mistakes

Forgetting the Branch Name

When using git reset, it's crucial to specify the correct branch name if you're not on the desired branch. Otherwise, Git will attempt to reset the current branch, which could lead to unwanted changes.

$ git checkout another-branch # Switch to another branch
$ git reset HEAD^ # Move the HEAD pointer of my-branch (current branch) one commit back on another-branch

In this example, we're trying to move the HEAD pointer of my-branch on the wrong branch (another-branch). To avoid this mistake, always ensure you're on the correct branch before running the reset command.

Using --hard Without Care

The --hard option discards all changes made since the specified commit, including any unstaged changes in your working directory and any commits on top of it. Be cautious when using this option, as it can lead to data loss if you haven't committed your changes yet.

Mixed Reset Without Understanding the Implications

A mixed reset (git reset ^) unstages all changes from the specified commit but keeps them in your working directory. This can be confusing, as it may seem like the changes have been discarded when they're actually still present in your working directory. Be sure to understand the implications of a mixed reset before using it.

Practice Questions

  1. You accidentally committed some unfinished work and want to undo the commit. What command should you use, and what are the potential consequences if you don't stage or commit your changes first?
  2. You have made several commits on a feature branch, but now realize that you need to revert those commits to their original state. How would you achieve this using git reset?
  3. You have a Git history with multiple commits and want to discard all changes made after a specific commit while keeping the commit itself. What command should you use, and what are the potential consequences if you don't stage or commit any changes before running the command?
  4. You have made some changes in your working directory that haven't been staged yet. You then realize that these changes conflict with another feature branch. How would you handle this situation using git reset?
  5. You are on a branch that has several commits, and you want to move the HEAD pointer to an earlier commit on a different branch. What commands should you use, and what are the potential consequences if you're not careful?

FAQ

  1. Can I undo changes made in a previous commit without using git reset?

Yes, you can use git revert to create a new commit that undoes the changes made in a previous commit. However, git reset provides more flexibility by allowing you to move the HEAD pointer to any commit or even discard uncommitted changes.

  1. What happens when I run git reset --hard without specifying a commit?

When you run git reset --hard without specifying a commit, Git will discard all local changes and revert your working directory to the latest commit in the repository's remote. Be cautious when using this command, as it can lead to data loss if you haven't committed your changes yet.

  1. Can I undo a merge commit with git reset?

Yes, but it's not recommended. Instead, use git revert or git cherry-pick to undo the effects of the merge commit without affecting the merge itself. If you still want to undo a merge commit using git reset, be aware that doing so will create a new, non-merge parent for the affected commits and may cause issues with your Git history.

  1. What is the difference between git reset --hard and git checkout in terms of discarding changes?

Both commands can discard changes, but they do so differently. git reset --hard moves the HEAD pointer to a different commit and discards all changes made after that commit, while git checkout switches your branch to the specified commit and discards all changes made since that commit in the current branch. The main difference is that git reset --hard also discards uncommitted changes in your working directory, whereas git checkout leaves those changes intact unless you explicitly use the --force option.

How to undo a commit with git reset (Git & Dev Tools) | Git & Dev Tools | XQA Learn