Skip to main content
Git Version Control:

How to undo the latest local commit in Git

Summary

Undoing the latest Git commit can be done with git reset, depending on whether you want to discard, keep, or modify your changes. Explore --hard, --soft, and --mixed resets and how git reflog can help you recover lost commits before they are permanently removed.

Introduction #

In Git, commits represent snapshots of your project. Sometimes, you may need to undo your most recent local commit. Git provides several options for this, depending on whether you want to keep, discard, or modify your changes.

Understanding HEAD in Git #

HEAD is a reference that points to the latest commit in your currently checked-out branch. When you create a new commit, HEAD moves forward to point to the new commit. Resetting (git reset) affects the position of HEAD and determines what happens to your working directory and staged changes.

Options for undoing the most recent commit #

The options for undoing the most recent commit are sorted from strongest to lightest. For the sake of simplicity, examples only focus on the most recent commit, e.g. HEAD~1.

git reset --hard #

This is useful when you want to fully reset your repository to a previous state.

There is a genuine risk of losing work when using git reset.
Use git reflog to recover lost commits.

What happens when you use git reset --hard <commit>:

  1. HEAD moves:
    The branch pointer is moved to the specified commit.
  2. Staging area (index) is updated:
    The index is reset to match the specified commit (all staged changes are discarded).
  3. Working directory is updated:
    All changes in your working directory are forcibly overwritten to match the specified commit (any uncommitted changes are lost).

The git reset --hard <commit> command moves the current branch’s HEAD to the specified commit while also modifying both the staging area (index) and the working directory.

Using git reset --hard removes the last commit and discards all changes in your working directory. The --hard option resets everything, including the working tree.

git reset --hard HEAD~1

In a sequence of commits (A, B, C) on the main branch, where F are your files:

    F
A-B-C
    ⇡
    HEAD, main

After running git reset --hard HEAD~1:

  F
A-B
  ⇡
  HEAD, main

This option is irreversible unless you use git reflog to retrieve the commit. Running git status in this state, will show you no changes, commit C and changes to files after B are gone.

git reset #

git reset is useful when you want to redo commits differently while keeping all changes available in the working directory.

What happens when you use git reset <commit>:

  1. HEAD moves:
    The branch pointer is moved to the specified commit.
  2. Staging area (index) is updated:
    All changes in the index are reset to match the specified commit (staged changes are cleared).
  3. Working directory stays intact:
    Your actual files remain unchanged.

The git reset <commit> command moves the current branch’s HEAD to the specified commit while also modifying the staging area (index) but not the working directory.

By default, git reset (without options) is equivalent to git reset --mixed. It removes the commit but keeps the file changes unstaged.

git reset HEAD~1

In a sequence of commits (A, B, C) on the main branch, where F are your files:

    F
A-B-C
    ⇡
    HEAD, main

After running git reset HEAD~1:

    F
A-B
  ↑
  HEAD, main (changes unstaged)

Here, the files remain in your working directory but are no longer staged for commit. Running git status in this state, will show you the changes you had checked into C before.

git reset --soft #

git reset --soft is useful when you need to modify the last commit(s) before recommitting without losing progress. Using git reset --soft is the lightest form of reset.

What happens when you use git reset --soft <commit>:

  1. HEAD moves:
    The branch pointer is moved to the specified commit.
  2. Staging area (index) remains unchanged:
    Any changes that were staged before the reset stay staged.
  3. Working directory stays intact:
    Your actual files remain unchanged.

The git reset --soft <commit> command moves the current branch’s HEAD to the specified commit without modifying the working directory or the staging area (index).

It removes the commit but keeps the changes staged, allowing you to recommit with modifications if needed.

git reset --soft HEAD~1

In a sequence of commits (A, B, C) on the main branch, where F are your files:

    F
A-B-C
    ⇡
    HEAD, main

After running git reset --soft HEAD~1:

    F'
A-B
  ↑
  HEAD, main (changes staged)

Using git reflog to recover lost commits #

While git reset does not delete commits outright, it can make them “orphaned,” meaning they are no longer directly accessible from any reference. These orphaned commits can often be recovered using git reflog.

Git will permanently remove orphaned commits when its internal garbage collector runs. By default, Git is set to execute garbage collection every 30 days.

If you have used git reset --hard and want to recover a lost commit, git reflog allows you to find its SHA-1 (Secure Hash Algorithm 1) hash and restore it, if there was no garbage collection.

git reflog

The git reflog command displays a history of HEAD movements:

abc1234 HEAD@{0}: reset: moving to HEAD~1
def5678 HEAD@{1}: commit: Added feature X

To restore the lost commit:

git reset --hard def5678

Now, your project is back to the state of commit def5678.

FAQ's #

Most common questions and brief, easy-to-understand answers on the topic:

What is the difference between git reset --hard and git reset --soft?

git reset --hard removes the commit and changes your working directory, while git reset --soft keeps your changes staged for a new commit.

How can I recover a commit after using git reset --hard?

You can use git reflog to find the commit SHA-1 (Secure Hash Algorithm 1) hash and then use git reset --hard <SHA-1> to restore it.

Does git reset --hard affect remote repositories?

No, git reset --hard only affects your local repository. However, if you push the changes, it can impact remote repositories.

Further readings #

Sources and recommended, further resources on the topic:

Author

Jonas Jared Jacek • J15k

Jonas Jared Jacek (J15k)

Jonas works as project manager, web designer, and web developer since 2001. On top of that, he is a Linux system administrator with a broad interest in things related to programming, architecture, and design. See: https://www.j15k.com/

License

How to undo the latest local commit in Git by Jonas Jared Jacek is licensed under CC BY-SA 4.0.

This license requires that reusers give credit to the creator. It allows reusers to distribute, remix, adapt, and build upon the material in any medium or format, for noncommercial purposes only. To give credit, provide a link back to the original source, the author, and the license e.g. like this:

<p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><a property="dct:title" rel="cc:attributionURL" href="https://www.ditig.com/git-undo-most-recent-commit">How to undo the latest local commit in Git</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://www.j15k.com/">Jonas Jared Jacek</a> is licensed under <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="license noopener noreferrer">CC BY-SA 4.0</a>.</p>

For more information see the Ditig legal page.

All Topics

Random Quote

“I avoid the cesspools of the Internet – Twitter, Slashdot, whatever troll-infested things that try to get a rise out of you.”

Linus Torvalds  Finnish software engineer, creator of the Linux kernel and GitiTWire, - IT quotes