Git Reset

Git Reset: Soft, Mixed, and Hard Explained.

If you’re working with Git (and let’s face it, if you’re programming, you better be), understanding the different git reset types is mandatory. Whether you’re undoing a commit after a poorly timed cup of coffee or just experimenting, knowing when to go soft, mixed, or hard can save your project (and your sanity). Let’s break it down.

Git Reset Soft

Think of git reset --soft as the kindest way to reverse a commit. When you use git reset --soft, it takes all the changes from your targeted commit and moves them to the staged area (also known as the index). It’s like saying, “Hey, these changes were a good idea, but let’s pretend I haven’t committed them yet.”

Example Scenario

You committed too soon, forgetting to include a crucial file. Use git reset --soft HEAD~1, and voila! Your changes are unstuck, ready to be re-committed with the missing piece included.

Note: If you don’t specify a commit (e.g., just git reset --soft), Git will look at HEAD, which has no impact because it’s already staged.

> git log --oneline --all --graph
* a946d2c - (HEAD -> main) Commit 10: Updated file1, file2, and file3 with change 10 (Sergio Lema il y a 24 secondes)
* 1b8d288 - Commit 9: Updated file1, file2, and file3 with change 9 (Sergio Lema il y a 24 secondes)
* 4137d77 - Commit 8: Updated file1, file2, and file3 with change 8 (Sergio Lema il y a 24 secondes)
* a36ea4d - Commit 7: Updated file1, file2, and file3 with change 7 (Sergio Lema il y a 24 secondes)
* 9718f77 - Commit 6: Updated file1, file2, and file3 with change 6 (Sergio Lema il y a 24 secondes)
* 4b8adb0 - Commit 5: Updated file1, file2, and file3 with change 5 (Sergio Lema il y a 24 secondes)
* a52fa3b - Commit 4: Updated file1, file2, and file3 with change 4 (Sergio Lema il y a 24 secondes)
* 605358e - Commit 3: Updated file1, file2, and file3 with change 3 (Sergio Lema il y a 24 secondes)
* 3aa2966 - Commit 2: Updated file1, file2, and file3 with change 2 (Sergio Lema il y a 24 secondes)
* fc4b336 - Commit 1: Updated file1, file2, and file3 with change 1 (Sergio Lema il y a 24 secondes)
* 751fa4b - Initial commit with three files (Sergio Lema il y a 29 secondes)
>
> git reset --soft 4137d77
>
> git log --oneline --all --graph
* 4137d77 - (HEAD -> main) Commit 8: Updated file1, file2, and file3 with change 8 (Sergio Lema il y a 63 secondes)
* a36ea4d - Commit 7: Updated file1, file2, and file3 with change 7 (Sergio Lema il y a 63 secondes)
* 9718f77 - Commit 6: Updated file1, file2, and file3 with change 6 (Sergio Lema il y a 63 secondes)
* 4b8adb0 - Commit 5: Updated file1, file2, and file3 with change 5 (Sergio Lema il y a 63 secondes)
* a52fa3b - Commit 4: Updated file1, file2, and file3 with change 4 (Sergio Lema il y a 63 secondes)
* 605358e - Commit 3: Updated file1, file2, and file3 with change 3 (Sergio Lema il y a 63 secondes)
* 3aa2966 - Commit 2: Updated file1, file2, and file3 with change 2 (Sergio Lema il y a 63 secondes)
* fc4b336 - Commit 1: Updated file1, file2, and file3 with change 1 (Sergio Lema il y a 63 secondes)
* 751fa4b - Initial commit with three files (Sergio Lema il y a 68 secondes)
>
> git status -s
M  file1.txt
M  file2.txt
M  file3.txt

Git Reset Mixed

This one goes a step further. When you use git reset --mixed, all the changes from the commit move into your working directory. That means your files are modified, but they’re not staged. It’s like saying, “Let’s keep these changes, but I’m not ready to commit them just yet.” This is the default behavior when you use git reset without specifying an option, so git reset HEAD~1 is the same as git reset --mixed HEAD~1.

Example Scenario

Imagine you committed your code, but now you want to change a few things before staging them again. A git reset --mixed takes your code out of the commit, and it’s all sitting there, waiting for your next genius move.

> git log --oneline --all --graph
* a946d2c - (HEAD -> main) Commit 10: Updated file1, file2, and file3 with change 10 (Sergio Lema il y a 24 secondes)
* 1b8d288 - Commit 9: Updated file1, file2, and file3 with change 9 (Sergio Lema il y a 24 secondes)
* 4137d77 - Commit 8: Updated file1, file2, and file3 with change 8 (Sergio Lema il y a 24 secondes)
* a36ea4d - Commit 7: Updated file1, file2, and file3 with change 7 (Sergio Lema il y a 24 secondes)
* 9718f77 - Commit 6: Updated file1, file2, and file3 with change 6 (Sergio Lema il y a 24 secondes)
* 4b8adb0 - Commit 5: Updated file1, file2, and file3 with change 5 (Sergio Lema il y a 24 secondes)
* a52fa3b - Commit 4: Updated file1, file2, and file3 with change 4 (Sergio Lema il y a 24 secondes)
* 605358e - Commit 3: Updated file1, file2, and file3 with change 3 (Sergio Lema il y a 24 secondes)
* 3aa2966 - Commit 2: Updated file1, file2, and file3 with change 2 (Sergio Lema il y a 24 secondes)
* fc4b336 - Commit 1: Updated file1, file2, and file3 with change 1 (Sergio Lema il y a 24 secondes)
* 751fa4b - Initial commit with three files (Sergio Lema il y a 29 secondes)
>
> git reset --mixed 4137d77
>
> git log --oneline --all --graph
* 4137d77 - (HEAD -> main) Commit 8: Updated file1, file2, and file3 with change 8 (Sergio Lema il y a 3 minutes)
* a36ea4d - Commit 7: Updated file1, file2, and file3 with change 7 (Sergio Lema il y a 3 minutes)
* 9718f77 - Commit 6: Updated file1, file2, and file3 with change 6 (Sergio Lema il y a 3 minutes)
* 4b8adb0 - Commit 5: Updated file1, file2, and file3 with change 5 (Sergio Lema il y a 3 minutes)
* a52fa3b - Commit 4: Updated file1, file2, and file3 with change 4 (Sergio Lema il y a 3 minutes)
* 605358e - Commit 3: Updated file1, file2, and file3 with change 3 (Sergio Lema il y a 3 minutes)
* 3aa2966 - Commit 2: Updated file1, file2, and file3 with change 2 (Sergio Lema il y a 3 minutes)
* fc4b336 - Commit 1: Updated file1, file2, and file3 with change 1 (Sergio Lema il y a 3 minutes)
* 751fa4b - Initial commit with three files (Sergio Lema il y a 3 minutes)
>
> git status -s
 M file1.txt
 M file2.txt
 M file3.txt

Git Reset Hard

Now we’re getting serious. git reset --hard takes the changes from your commit and obliterates them. They’re not staged, they’re not in your working directory: they’re gone. This is Git’s “throw it in the trash and take out the bin” mode.

Example Scenario

You’re sure that the changes in a commit (or in your working directory) are total garbage and need to go. Enter git reset --hard HEAD~1: boom, changes gone, and you’re back to a clean slate.

Warning: This is the one reset where you will lose data. If you reset hard without realizing its consequences, you’re in for a fun afternoon of regret.

> git log --oneline --all --graph
* a946d2c - (HEAD -> main) Commit 10: Updated file1, file2, and file3 with change 10 (Sergio Lema il y a 24 secondes)
* 1b8d288 - Commit 9: Updated file1, file2, and file3 with change 9 (Sergio Lema il y a 24 secondes)
* 4137d77 - Commit 8: Updated file1, file2, and file3 with change 8 (Sergio Lema il y a 24 secondes)
* a36ea4d - Commit 7: Updated file1, file2, and file3 with change 7 (Sergio Lema il y a 24 secondes)
* 9718f77 - Commit 6: Updated file1, file2, and file3 with change 6 (Sergio Lema il y a 24 secondes)
* 4b8adb0 - Commit 5: Updated file1, file2, and file3 with change 5 (Sergio Lema il y a 24 secondes)
* a52fa3b - Commit 4: Updated file1, file2, and file3 with change 4 (Sergio Lema il y a 24 secondes)
* 605358e - Commit 3: Updated file1, file2, and file3 with change 3 (Sergio Lema il y a 24 secondes)
* 3aa2966 - Commit 2: Updated file1, file2, and file3 with change 2 (Sergio Lema il y a 24 secondes)
* fc4b336 - Commit 1: Updated file1, file2, and file3 with change 1 (Sergio Lema il y a 24 secondes)
* 751fa4b - Initial commit with three files (Sergio Lema il y a 29 secondes)
>
> git reset --hard 4137d77
>
> git log --oneline --all --graph
* 4137d77 - (HEAD -> main) Commit 8: Updated file1, file2, and file3 with change 8 (Sergio Lema il y a 4 minutes)
* a36ea4d - Commit 7: Updated file1, file2, and file3 with change 7 (Sergio Lema il y a 4 minutes)
* 9718f77 - Commit 6: Updated file1, file2, and file3 with change 6 (Sergio Lema il y a 4 minutes)
* 4b8adb0 - Commit 5: Updated file1, file2, and file3 with change 5 (Sergio Lema il y a 4 minutes)
* a52fa3b - Commit 4: Updated file1, file2, and file3 with change 4 (Sergio Lema il y a 4 minutes)
* 605358e - Commit 3: Updated file1, file2, and file3 with change 3 (Sergio Lema il y a 4 minutes)
* 3aa2966 - Commit 2: Updated file1, file2, and file3 with change 2 (Sergio Lema il y a 4 minutes)
* fc4b336 - Commit 1: Updated file1, file2, and file3 with change 1 (Sergio Lema il y a 4 minutes)
* 751fa4b - Initial commit with three files (Sergio Lema il y a 4 minutes)
>
> git status -s
>

Reflog

Here’s the twist: unless you’ve done reset --hard without a commit, your changes aren’t really gone. With git reset --soft or git reset --mixed, you can usually recover using git reflog. This command keeps a record of where your HEAD has been, so you can roll back and pretend the last 10 minutes never happened.

> git reflog
4137d77 (HEAD -> main) HEAD@{0}: reset: moving to 4137d77
a946d2c HEAD@{1}: checkout: moving from a946d2c6019462c48d558d3867af9bbb96279123 to main
a946d2c HEAD@{2}: checkout: moving from main to a946d2c
4137d77 (HEAD -> main) HEAD@{3}: reset: moving to HEAD
4137d77 (HEAD -> main) HEAD@{4}: reset: moving to 4137d77
a946d2c HEAD@{5}: checkout: moving from a946d2c6019462c48d558d3867af9bbb96279123 to main
a946d2c HEAD@{6}: checkout: moving from main to a946d2c
4137d77 (HEAD -> main) HEAD@{7}: reset: moving to 4137d77
a946d2c HEAD@{8}: commit: Commit 10: Updated file1, file2, and file3 with change 10
1b8d288 HEAD@{9}: commit: Commit 9: Updated file1, file2, and file3 with change 9
4137d77 (HEAD -> main) HEAD@{10}: commit: Commit 8: Updated file1, file2, and file3 with change 8
a36ea4d HEAD@{11}: commit: Commit 7: Updated file1, file2, and file3 with change 7
9718f77 HEAD@{12}: commit: Commit 6: Updated file1, file2, and file3 with change 6
4b8adb0 HEAD@{13}: commit: Commit 5: Updated file1, file2, and file3 with change 5
a52fa3b HEAD@{14}: commit: Commit 4: Updated file1, file2, and file3 with change 4
605358e HEAD@{15}: commit: Commit 3: Updated file1, file2, and file3 with change 3
3aa2966 HEAD@{16}: commit: Commit 2: Updated file1, file2, and file3 with change 2
fc4b336 HEAD@{17}: commit: Commit 1: Updated file1, file2, and file3 with change 1
751fa4b HEAD@{18}: commit (initial): Initial commit with three files

Conclusion

git reset is powerful, and like any power tool, it can either save your project or decimate it. The soft and mixed options are generally safe, with any misplaced changes recoverable via git reflog. But git reset --hard? Use it wisely or prepare for some time-traveling in the Git reflog.

In summary: git responsibly, and always double-check before hitting that hard button.


Never Miss Another Tech Innovation

Concrete insights and actionable resources delivered straight to your inbox to boost your developer career.

My New ebook, Best Practices To Create A Backend With Spring Boot 3, is available now.

Best practices to create a backend with Spring Boot 3

Leave a comment

Discover more from The Dev World - Sergio Lema

Subscribe now to keep reading and get access to the full archive.

Continue reading