git reset does know five "modes": soft, mixed, hard, merge and keep. I will start with the first three, since these are the modes you'll usually encounter. After that you'll find a nice little a bonus, so stay tuned.


Let's assume you have a repository with a history akin to this:

7e05a95  (HEAD -> main) Update a
e62add5  Update b
ca9ae0a  Update a
9b6060d  Add c
eebe372  Add b
947586a  Add a

Where the latest commit (7e05a95) contains these changes:

diff --git a/a b/a
index b66ba06..28b68e2 100644
--- a/a
+++ b/a
@@ -1 +1 @@
-new content
+new new content

Now what would happen when you run git reset with the various different modes? Let's find out!

soft

When using git reset --soft HEAD~1 you will remove the last commit from the current branch, but the file changes will stay in your working tree. Also, the changes will stay on your index, so following with a git commit will create a commit with the exact same changes as the commit you "removed" before.

How would this look like in practice? Like this:

> git reset --soft HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   a

As you see the changes in file a are on the index, and ready to be committed again.

mixed

This is the default mode and quite similar to soft. When "removing" a commit with git reset HEAD~1 you will still keep the changes in your working tree but not on the index; so if you want to "redo" the commit, you will have to add the changes (git add) before commiting.

In practice the result might look like this:

> git reset --mixed HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
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:   a

no changes added to commit (use "git add" and/or "git commit -a")

The changes of file a are still there but they're not on the index.

hard

When using git reset --hard HEAD~1 you will lose all uncommited changes and all untracked files in addition to the changes introduced in the last commit. The changes won't stay in your working tree so doing a git status command will tell you that you don't have any changes in your repository.

Tread carefully with this one. If you accidentally remove uncommited changes which were never tracked by git (speak: committed or at least added to the index), you have no way of getting them back using git.

A practical example might look like this:

> git reset --hard HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
nothing to commit, working tree clean

As you can see, no changes remain. Assuming you also had some uncommitted changes in the file b these would be lost too!

> echo 'some uncommitted changes' > b
> git status
On branch main
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:   b

no changes added to commit (use "git add" and/or "git commit -a")

> git reset --hard HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
nothing to commit, working tree clean

Bonus

keep

git reset --keep HEAD~1 is an interesting and useful one. It only resets the files which are different between the current HEAD and the given commit. It aborts the reset if one or more of these files has uncommited changes. It basically acts as a safer version of hard.

Let's revisit the example from before, where you had some uncommitted changes in b:

> echo 'some uncommitted changes' > b
> git status
On branch main
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:   b

no changes added to commit (use "git add" and/or "git commit -a")

> git reset --keep HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
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:   b

no changes added to commit (use "git add" and/or "git commit -a")

You removed the changes in file a but retained the uncommitted changes in file b!

So to reiterate: "hard" will remove all changes while "keep" only removes changes from the reset commit(s).


Each of these modes is explained in depths in the git reset documentation.

Note
When doing git reset to remove a commit the commit isn't really lost, there just is no reference pointing to it or any of it's children. You can still recover a commit which was "deleted" with git reset by finding it's SHA-1 key, for example with a command such as git reflog.

Answer from Alex Wolf on Stack Overflow
🌐
Git
git-scm.com › docs › git-reset
Git - git-reset Documentation
Update the index to match the new HEAD, so nothing will be staged. If -N is specified, mark removed paths as intent-to-add (see git-add[1]). ... Leave your working tree files and the index unchanged. For example, if you have no staged changes, you can use git reset --soft HEAD~5; git commit to combine the last 5 commits into 1 commit.
Top answer
1 of 5
373

git reset does know five "modes": soft, mixed, hard, merge and keep. I will start with the first three, since these are the modes you'll usually encounter. After that you'll find a nice little a bonus, so stay tuned.


Let's assume you have a repository with a history akin to this:

7e05a95  (HEAD -> main) Update a
e62add5  Update b
ca9ae0a  Update a
9b6060d  Add c
eebe372  Add b
947586a  Add a

Where the latest commit (7e05a95) contains these changes:

diff --git a/a b/a
index b66ba06..28b68e2 100644
--- a/a
+++ b/a
@@ -1 +1 @@
-new content
+new new content

Now what would happen when you run git reset with the various different modes? Let's find out!

soft

When using git reset --soft HEAD~1 you will remove the last commit from the current branch, but the file changes will stay in your working tree. Also, the changes will stay on your index, so following with a git commit will create a commit with the exact same changes as the commit you "removed" before.

How would this look like in practice? Like this:

> git reset --soft HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   a

As you see the changes in file a are on the index, and ready to be committed again.

mixed

This is the default mode and quite similar to soft. When "removing" a commit with git reset HEAD~1 you will still keep the changes in your working tree but not on the index; so if you want to "redo" the commit, you will have to add the changes (git add) before commiting.

In practice the result might look like this:

> git reset --mixed HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
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:   a

no changes added to commit (use "git add" and/or "git commit -a")

The changes of file a are still there but they're not on the index.

hard

When using git reset --hard HEAD~1 you will lose all uncommited changes and all untracked files in addition to the changes introduced in the last commit. The changes won't stay in your working tree so doing a git status command will tell you that you don't have any changes in your repository.

Tread carefully with this one. If you accidentally remove uncommited changes which were never tracked by git (speak: committed or at least added to the index), you have no way of getting them back using git.

A practical example might look like this:

> git reset --hard HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
nothing to commit, working tree clean

As you can see, no changes remain. Assuming you also had some uncommitted changes in the file b these would be lost too!

> echo 'some uncommitted changes' > b
> git status
On branch main
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:   b

no changes added to commit (use "git add" and/or "git commit -a")

> git reset --hard HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
nothing to commit, working tree clean

Bonus

keep

git reset --keep HEAD~1 is an interesting and useful one. It only resets the files which are different between the current HEAD and the given commit. It aborts the reset if one or more of these files has uncommited changes. It basically acts as a safer version of hard.

Let's revisit the example from before, where you had some uncommitted changes in b:

> echo 'some uncommitted changes' > b
> git status
On branch main
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:   b

no changes added to commit (use "git add" and/or "git commit -a")

> git reset --keep HEAD^ # Assuming HEAD points at 7e05a95
> git status
On branch main
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:   b

no changes added to commit (use "git add" and/or "git commit -a")

You removed the changes in file a but retained the uncommitted changes in file b!

So to reiterate: "hard" will remove all changes while "keep" only removes changes from the reset commit(s).


Each of these modes is explained in depths in the git reset documentation.

Note
When doing git reset to remove a commit the commit isn't really lost, there just is no reference pointing to it or any of it's children. You can still recover a commit which was "deleted" with git reset by finding it's SHA-1 key, for example with a command such as git reflog.

2 of 5
15

Git reset has 5 main modes: soft, mixed, merge, hard, keep. The difference between them is to change or not change head, stage (index), working directory.

Git reset --hard will change head, index and working directory.
Git reset --soft will change head only. No change to index, working directory.

So in other words, if you want to undo your commit, --soft should be good enough. But after that, you still have the changes from bad commit in your index and working directory. You can modify the files, fix them, add them to index and commit again.

With the --hard, you completely get a clean slate in your project. As if there hasn't been any change from the last commit. If you are sure this is what you want, then move forward. But once you do this, you'll lose your last commit completely. (Note: there are still ways to recover the lost commit).

Discussions

git reset --soft HEAD~1
Sometimes, I accidentally commit into a Branch I don't have permission to. This is because I need to create a new branch, switch to it, commit my changes there, and do a pull request. When this acc... More on github.com
🌐 github.com
5
January 29, 2020
Is my understanding of Git Reset Correct?
git reset --hard resets changes in the current working directory. If I'm ever in doubt about git and can't be bothered reading the documentation (the man pages are actually pretty good, but still...), I just make a new git, commit some meaningless text, and try out the command. More on reddit.com
🌐 r/git
16
15
August 26, 2021
I used command “git reset - -soft HEAD^” but it doesn’t work
What is the output of git status? Have the files been tracked? More on reddit.com
🌐 r/git
27
0
December 20, 2023
How to Undo "git reset -HEAD~"?
Find the commit hash you want to reset to with git reflog, then do a git reset [hash]. On mobile so sorry for formatting More on reddit.com
🌐 r/Frontend
11
13
October 17, 2022
🌐
Built In
builtin.com › software-engineering-perspectives › git-reset-soft-head
How to Undo the Last Commit Using Git Reset Command | Built In
git reset --soft: Moves HEAD to the previous commit, but leaves staging area and working directory unchanged.
🌐
Graphite
graphite.com › guides › how-to-use-git-reset-head
How to use Git reset HEAD - Graphite
Soft reset (--soft): This mode does not change the working directory or the staging area (index), but only the HEAD itself. Changes from reset commits move to the staging area.
🌐
GitHub
github.com › desktop › desktop › issues › 9005
git reset --soft HEAD~1 · Issue #9005 · desktop/desktop
January 29, 2020 - When this accident happens, I always have to Google how to undo a commit: git reset --soft HEAD~1 Because, when I use the "Revert this commit" option, GitHub Desktop does not keep the changes staged and automatically creates an extra commit.
Author   desktop
🌐
GitKraken
gitkraken.com › home › learn › git reset
Git Reset | Hard, Soft & Mixed | Learn Git
March 26, 2026 - If HEAD is pointed at f30ab when we start, and then perform a git reset –soft 98ca9, HEAD will move to that commit, along with the pointer that points to the last commit of the chain (in this instance, called main).
🌐
George Garside
georgegarside.com › home › technology › git of the day #13: git reset --soft head^
Git of the day #13: git reset --soft HEAD^ - George Garside
January 17, 2024 - This resets HEAD to a given commit without changing the files, and indeed stages the changes that would have been removed with --hard. Since --soft keeps the changes staged, it can be thought of as undoing the commit, but keeping the add. That is, the usual flow of operations is ... and therefore ...
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › git › practical-uses-of-git-reset-soft
Practical Uses Of 'git reset --soft'? - GeeksforGeeks
September 3, 2024 - You can use git reset --soft to unstage the commit while keeping the changes intact. This command will reset your branch to the previous commit (HEAD~1), but your changes will still be staged.
🌐
DataCamp
datacamp.com › tutorial › git-reset-revert-tutorial
Git Reset and Revert Tutorial for Beginners | DataCamp
December 16, 2022 - git reset is used to undo changes in your commit history or working directory. It allows you to reset your HEAD to a specific commit, and optionally modify the index (staging area) and working directory. --soft: Moves HEAD to the specified commit but keeps changes staged for commit.
🌐
Git Examples
gitexamples.com › examples › 4fdcbe5c-926a-46c8-ab6e-db80b8a0fe45
git reset --soft HEAD~1 - Git Examples
This command resets the current branch to the previous commit, moving the HEAD pointer back one step while keeping the changes from the undone commit staged.
🌐
CodingNomads
codingnomads.com › git-reset-head
Git Reset HEAD, Git Reset Soft, Git Reset Hard
Use the Git Reset HEAD command, `git reset --soft`, and `git reset --hard` to reset the current state of HEAD, clear the staging area, and reset the file system.
🌐
DataCamp
datacamp.com › tutorial › git-reset-soft-complete-guide
Git Reset Soft: Complete Guide with Examples | DataCamp
September 16, 2025 - I start with git log --oneline -3 to identify the oversized commit, then use git reset --soft HEAD~1. This command undoes the commit while keeping changes staged. Running git reset (without flags) unstages everything, giving me a clean slate. Now I can create focused commits: first the model, ...
🌐
DataCamp
datacamp.com › tutorial › git-reset-head-comprehensive-guide
Git reset HEAD: A Comprehensive Guide | DataCamp
October 1, 2025 - git reset --soft HEAD^ allows you to undo the last commit while keeping everything staged, letting you recommit properly without rolling back all the changes from scratch.
🌐
CoreUI
coreui.io › answers › how-to-soft-reset-in-git
How to soft reset in Git · CoreUI
October 16, 2025 - # Soft reset to previous commit git reset --soft HEAD~1 # Soft reset to specific commit git reset --soft abc1234 # Soft reset multiple commits git reset --soft HEAD~3 # Check status after soft reset git status # Shows all changes from undone commits as staged # Recommit with new message git commit -m "Improved feature implementation" # Split changes into multiple commits git reset --soft HEAD~2 # Now you can selectively commit files git commit -m "Add user authentication" git add remaining-files.js git commit -m "Add user profile management" # Soft reset to merge commits into one git reset --soft HEAD~4 git commit -m "Complete user management feature - Add authentication system - Implement user profiles - Add password reset functionality - Include user preferences" # Verify what will be reset before doing it git log --oneline -5 git diff --cached # After reset, shows staged changes
🌐
Codidact
software.codidact.com › posts › 286550
Is it possible to undo a git reset? - Software Development
All git reset does is change what commit the HEAD references. If you find the hash corresponding to the commit you'd like HEAD to reference, you could just git reset --soft <commit hash>.
🌐
Atlassian
atlassian.com › git › tutorials › undoing changes › git reset
Git Reset | Atlassian Git Tutorial
Examining the repo state with git status and git ls-files shows that nothing has changed. This is expected behavior. A soft reset will only reset the Commit History. By default, git reset is invoked with HEAD as the target commit.
🌐
Codecademy
codecademy.com › article › what-is-git-reset-explained-with-examples
What is Git Reset? Explained with Examples | Codecademy
A soft reset (git reset --soft) moves HEAD to a previous commit but keeps all changes staged, allowing us to easily recommit with modifications.
🌐
jwiegley
jwiegley.github.io › git-from-the-bottom-up › 3-Reset › 3-doing-a-soft-reset.html
Doing a soft reset | Git from the Bottom Up
If you use the --soft option to reset, this is the same as simply changing your HEAD reference to a different commit. Your working tree changes are left untouched. This means the following two commands are equivalent: $ git reset --soft HEAD^ # backup HEAD to its parent, # effectively ignoring ...