git-reset-soft-mixed-hard

Undoing History with Git Reset

  • 5 min

The git reset command is a command that allows us to undo complete sequences of work by moving the pointer of our repository to a previous commit.

We have seen how to move forward in history (create commits) and how to fix small mistakes (amend, restore).

But sometimes, the mistake is bigger. Sometimes you’ve gone down the wrong path for hours and want to go back. You want to take the time machine and return to yesterday.

git reset is that time machine. Its main function is to move the HEAD pointer (your current location) to a previous commit.

git reset is one of the most useful tools, but and also one of the most dangerous.

Use only on commits that have not been pushed to a remote.

The Concept: Moving the Pointer

Imagine your history as a row of domino tiles. HEAD is pointing to the last tile (Commit C).

If we do a git reset to commit A, we are moving the pointer.

Commits B and C become inaccessible (they become “orphaned”). But what happens to the code changes that were inside B and C? Are they deleted? Do they stay in your folder?

The answer depends on the “flavor” of reset you choose: Soft, Mixed, or Hard.

Types of Reset

To have it clear at a glance, imagine we are undoing the last commit. Where do my changes end up?

ModeMoves HEADStaging Area (Index)Working Directory
—softYESPreservedPreserved
—mixed (Default)YESEmptiedPreserved
—hardYESEmptiedDELETED 🚨

The changes that were in the undone commit now appear as Staged (green). It’s as if you had done the work and the git add, but just before doing the commit.

git reset --soft HEAD~1
Copied!

The ~1 means “go back one step”

When to use it?

  • To combine commits (Manual Squash): You made 3 small commits (“WIP”, “WIP”, “Finished”) and you want to turn them into a single one. You do a soft reset 3 steps back, and commit everything together again with a decent message.

The changes from the undone commit now appear as Modified (red). They are in your folder, safe, but Git has “not prepared them” yet.

git reset --mixed HEAD~1
Copied!

Or simply git reset HEAD~1, since Mixed is the default mode

When to use it?

  • It’s the standard for correcting course. “I made a commit, but I see I mixed two different tasks.” You do a mixed reset, and now you have the files loose to do git add in parts and separate them into two clean commits.

Everything goes back to being exactly the same as in the commit you jumped to. Any changes you had made in subsequent commits or in your working directory ARE DESTROYED.

git reset --hard HEAD~1
Copied!

When to use it?

  • When you’ve broken everything: You attempted a refactoring, nothing compiles, there are errors everywhere and you want to throw everything away and go back to the last stable point.

Danger! This is the only destructive mode. If you had unsaved code or important changes in that commit you are undoing, you will lose them. Use it only when you are sure you want to delete your recent work.

Traveling to a Specific Point

Although we have used HEAD~1 (one step back) in the examples, you can also use reset to a specific Commit using its Hash.

If you do a git log and see that the project worked well at commit a1b2c3d, you can jump directly there:

git reset --hard a1b2c3d
Copied!

Now your project is exactly the same as it was at that moment in the past. Everything that happened after has disappeared from history.

Not if you’ve pushed

I already warned before, but I’ll expand here because it’s one of the biggest and most common mess-ups in Git.

NEVER do git reset (of any type) on branches you have already pushed (Push) and that other teammates share.*

If you “delete” history on your computer, but your teammates have it on theirs, when trying to synchronize you will create a horrible conflict 💥.

git reset is a tool for cleaning up your local history before sharing it.