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
๐ŸŒ
Gitbooks
sillevl.gitbooks.io โ€บ git โ€บ content โ€บ advanced โ€บ reset-checkout-revert
Reset, Checkout, and Revert ยท Git
Note that this removes all of the subsequent changes to the file, whereas the git revert command undoes only the changes introduced by the specified commit. Like git reset, this is commonly used with HEAD as the commit reference. For instance, git checkout HEAD foo.py has the effect of discarding unstaged changes to foo.py.
๐ŸŒ
Better Stack
betterstack.com โ€บ community โ€บ questions โ€บ how-to-undo-get-reset-hard-head1
How can I undo git reset --hard HEAD~1? | Better Stack Community
This command moves HEAD back to the commit 0123456, effectively restoring the state as it was before the accidental reset. Garbage Collection: If the commit has been garbage collected (usually after 30 days by default), it might not be possible to recover it using git reflog. Lost Uncommitted Changes: If you had uncommitted changes before the accidental reset (git reset --hard), unfortunately, those changes are not recoverable through Git commands.
๐ŸŒ
GitHub
gist.github.com โ€บ stevenyap โ€บ 7511407
Git reset and revert: Undoing changs ยท GitHub
# If you are pulling, rebasing ... files # git clean -f -d will remove newly created files and directories (BEWARE!) git reset --hard # reset to the last commit # HEAD is the current commit, HEAD^ is the last commit # HEAD~2 ...
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).

๐ŸŒ
Reddit
reddit.com โ€บ r/git โ€บ git reset head~1 didn't do what i expected it to do?!
r/git on Reddit: git reset head~1 didn't do what I expected it to do?!
June 14, 2022 -

I had a single branch 'master' in my repo and I issued the command git reset eb20f43 which was my second last commit as I wanted to get rid of my last commit but not the changes.

After issuing the command I looked in gitkraken which I only use to view my repo, I found my master was now a separate branch containing only my last commit (the one I wanted to delete). And the main branch containing all my previous commits was separate and didn't seem to have a name:

$ git branch -v
* (HEAD detached from 467d43e) 06335c4 My Commit Name

467d43e being the commit I deleted. Or at least I was led to believe the commit would be deleted.

Confused

What should I have done if I simply want to delete the last commit, keep the changes and stay on the master branch?

๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ git โ€บ how-to-undo-git-reset-hard-head1
How to Undo Git Reset --hard HEAD~1? - GeeksforGeeks
May 30, 2024 - HEAD~1 specifies the previous commit (one commit before the current HEAD). --hard resets the working directory and the staging area to match the specified commit. This means the latest commit and any changes made in the working directory are lost.
๐ŸŒ
Graphite
graphite.com โ€บ guides โ€บ how-to-use-git-reset-head
How to use Git reset HEAD - Graphite
git reset --hard HEAD~1: Resets index and working directory to previous commit, discards all changes. git reset --hard origin/main: Resets local branch to match remote main branch.
Find elsewhere
๐ŸŒ
30 Seconds of Code
30secondsofcode.org โ€บ home โ€บ git โ€บ commit โ€บ undo commit
Undo a commit in Git - 30 seconds of code
May 27, 2023 - # Syntax: git revert HEAD git revert HEAD # Reverts the last commit and creates a new commit # with the inverse of its changes
๐ŸŒ
Built In
builtin.com โ€บ software-engineering-perspectives โ€บ git-reset-soft-head
How to Undo the Last Commit Using Git Reset Command | Built In
When we execute git reset --soft HEAD~1, now HEAD points to C2, but the index (stage) will have changes from C3 and git status will show them as staged.
๐ŸŒ
Reddit
reddit.com โ€บ r/frontend โ€บ how to undo "git reset -head~"?
r/Frontend on Reddit: How to Undo "git reset -HEAD~"?
October 17, 2022 -

I was trying to revert my work to the last commit after experimenting with stuff but instead reverted it to the commit before that because I didn't know which git command I'm supposed to use. How do I move the current head forward? How do I get the work that's currently last commited on Github?

Been learning to code for over a year and I still have no idea how git works. Most stackflow results make no sense to me, tbh. I just can't ever wrap my head around how git works, other than initializing, commiting, and pushing. Thanks a lot in advance, any help is much appreciated.

๐ŸŒ
Git
git-scm.com โ€บ docs โ€บ git-revert.html
Git - git-revert Documentation
This requires your working tree to be clean (no modifications from the HEAD commit). Note: git revert is used to record some new commits to reverse the effect of some earlier commits (often only a faulty one). If you want to throw away all uncommitted changes in your working directory, you should see git-reset[1], particularly the --hard option.
Top answer
1 of 10
111

The safest and probably cleanest way to go is to rebase interactively.

git rebase -i HEAD^^

Or,

git rebase -i baf8d5e7da9e41fcd37d63ae9483ee0b10bfac8e^

From there you can squash commits, which puts one or more commits together into the previous commit. To completely delete a commit from the history, delete the line from the list.

You can revert a commit with git revert but its going to add more commit messages to the history, which may be undesirable. Use the -n parameter to tell Git not to commit the revert right away. You can rebase interactively and squash those on up to a previous commmit to keep things clean.

If the two commits you're working with here affect the same file(s), you may see a merge conflict.

Resetting the repository with git reset --hard should be done with care, as it cannot be undone.

Rewriting history should be done with care.

2 of 10
70

This if from http://nakkaya.com/2009/09/24/git-delete-last-commit/ and it worked for me

Git Delete Last Commit

Once in a while late at night when I ran out of coffee, I commit stuff that I shouldn't have. Then I spend the next 10 - 15 minutes googling how to remove the last commit I made. So after third time I wanted to make a record of it so I can refer to it later.

If you have committed junk but not pushed,

git reset --hard HEAD~1

HEAD~1 is a shorthand for the commit before head. Alternatively you can refer to the SHA-1 of the hash you want to reset to. Note that when using --hard any changes to tracked files in the working tree since the commit before head are lost.

If you don't want to wipe out the work you have done, you can use --soft option that will delete the commit but it will leave all your changed files "Changes to be committed", as git status would put it.

Now if you already pushed and someone pulled which is usually my case, you can't use git reset. You can however do a git revert,

git revert HEAD

This will create a new commit that reverses everything introduced by the accidental commit.

๐ŸŒ
devconnected
devconnected.com โ€บ home โ€บ software engineering โ€บ how to git reset to head
How To Git Reset to HEAD โ€“ devconnected
December 16, 2020 - $ git reset --hard HEAD (going back to HEAD) $ git reset --hard HEAD^ (going back to the commit before HEAD) $ git reset --hard HEAD~1 (equivalent to "^") $ git reset --hard HEAD~2 (going back two commits before HEAD)
๐ŸŒ
Opensource.com
opensource.com โ€บ article โ€บ 18 โ€บ 6 โ€บ git-reset-revert-rebase-commands
How to reset, revert, and return to previous states in Git | Opensource.com
The effect is most easily seen by looking at Figure 1 again. If we add a line to a file in each commit in the chain, one way to get back to the version with only two lines is to reset to that commit, i.e., git reset HEAD~1.
๐ŸŒ
Git Examples
gitexamples.com โ€บ examples โ€บ 5504e8b5-5d06-4a38-8bb9-3f790a50cb5d
git reset --hard HEAD~1 - Git Examples
The HEAD~1 part specifies the commit to reset to, which is one commit before the current HEAD; this can be adjusted to HEAD~2 to go back two commits, or replaced with a specific commit hash.
๐ŸŒ
Git
git-scm.com โ€บ docs โ€บ git-reset
Git - git-reset Documentation
The index is modified using the chosen changes. This means that git reset -p is the opposite of git add -p, i.e. you can use it to selectively unstage changes. See the "Interactive Mode" section of git-add[1] to learn how to use the --patch option. See "Reset, restore and revert" in git[1] ...
๐ŸŒ
Graphite
graphite.com โ€บ guides โ€บ how-to-use-git-reset-hard-head
How to use git reset --hard HEAD - Graphite
git reset --hard HEAD~1: Use when you want to completely remove the last commit from history (before pushing to remote). This rewrites history. git revert: Use when you want to undo a commit that's already been pushed to a shared repository.