DEV Community

Cover image for How And When To Use Git Reset
Charlotte
Charlotte

Posted on

How And When To Use Git Reset

Most of us avoid dreaded git reset command — but actually it can be really useful, as long as you know how it works!

What does git reset do?

To put it simply, git reset will take your branch back to a certain point in the commit history, but there are 3 different levels to this:

  • soft: Moves the head back to the commit specified but leaves all the updated files in the index and working directory —all of the files after the commit that you’ve moved to have been tracked (like doing git add) and are ready to be committed as a new commit.
  • mixed: Moves the head and index back to the commit specified but leaves the files in the working directory — all of the files after the commit are in your working directory as untracked files. If you add them all now, you’ll be at the same stage as a soft reset above.
  • hard: Moves the head, index and working directory back to the commit specified — all of the updated files after the commit specified are now *GONE*!!! (uncommitted files are unrecoverable at this point)

Why would you need this?

Here are a few examples so that you will have a better idea of when to use each. You should only ever do this on your own branch, or when you're sure no one has already pulled any of the commits that you will be removing.

Soft

Let’s say you have done a few tiny commits and you want them to all be put into 1 more descriptive commit.

A -> B -> C -> D

git reset — soft A

Your branch head is now pointing at A

git commit -m “my new merged commit”
git push origin branch --force-with-lease

We now have a new commit, E but it contains all of the files that were committed in B, C, D. Note: the force-with-lease flag is because otherwise git will complain that your local branch is behind the remote. (This is a safer version of force)

A->E

Mixed

You’ve just pushed a few commits, but you want to go back and remove a couple of files in a previous commit.

A->B->C

git reset --mixed A

Your branch head and index is pointing at A

git status

This will show that all of your changes in B and C are there, but are untracked

Now you are free to add the files that you wish to add into a new commit

git add <files> git commit -m "updated commit"
git push origin branch --force-with-lease

A->D

Your head is now at the new commit D, and any files that you’ve not staged will still be in your working tree, ready to add into another commit or to do what you want with.

Hard

When would you possibly want this? Usually when things have gone wrong because it’s VERY RISKY. I’ll talk you through a scenario where I’ve needed it.

I’ve been working on my own branch, testing out a feature and I’ve changed many files, but it’s been a fail and I want to go back a few commits and get rid of every change I’ve made since.

If I’ve not made any commits or pushed any commits. I can just reset back to commit A and my working directory is now clear, all of my updated files are gone from history.

git reset --hard A

If I’ve actually pushed these commits to my remote branch, then, before doing this, you need to make sure that no one is working from those commits because they will be orphaned. But if you know that it’s safe to do, then run the command above. The only difference here is that you will need to do a FORCED push afterwards to push the remote branch to that state, otherwise it will tell you that your local branch is behind.

git reset --hard A
git push origin branchname --force-with-lease

This will delete your commits from the remote branch history, so you can see it could be very dangerous.

I have used this to get me out of reverted merge commit hell recently. I did a pull request to merge a branch into another branch, it had merge conflicts and the conflicts were not resolved correctly, so I reverted the merge. This however meant I couldn’t do the pull request again because it saw no updates, so I tried to revert that and it ended up in a bit of a mess. I then used git reset --hard to take the branches back to before this situation and get rid of these ugly reverts in the history!

Hopefully now you will see that git reset is very powerful and can help you in some situations, used with care!

Originally posted on Medium

Top comments (14)

Collapse
 
jmfayard profile image
Jean-Michel 🕵🏻‍♂️ Fayard • Edited

My best use case for git reset is when I want to update my pull request, merge master and clean up the git history

  • git fetch and git merge origin/master
  • Resolve conflicts and commit
  • git reset --soft origin/master same exact code in the repository but clean git history
  • commit and git push --force
Collapse
 
char_bone profile image
Charlotte

Interesting use case. So you're merging all of your pull requests commits into one commit. I can see that this makes the history cleaner. I personally like to keep that commit history in projects, especially for a big merge. It makes it easier to step back to a more specific point in the future after the merge. I can definitely see the benefits though :)

Collapse
 
jmfayard profile image
Jean-Michel 🕵🏻‍♂️ Fayard

On GitHub you can do the same thing with merge and squash the commits.
The history in master is kept clean but you have a link to the pull request to see the details

Thread Thread
 
char_bone profile image
Charlotte

Yeah it definitely makes sense, especially if you do lots of tiny commits then you would clutter the main branch :) I guess there is a balancing act though as to leaving enough commits to be able to cherry pick certain functionality in future (rather than looking at a pull request and manually doing things)

Collapse
 
glihm profile image
glihm

Thanks for this article @Charlotte, I want to underline that for your soft example, git rebase is also a very good choice.

Collapse
 
char_bone profile image
Charlotte

Thank you :) rebasing definitely is an option but reset works differently. Reset is much simpler if you just want to go to an earlier commit and forget about the commits after it.

Collapse
 
mihaylov profile image
Petar Petrov

Any other use for soft? Because for that use case I use rebase.

Collapse
 
char_bone profile image
Charlotte

I guess resetting should be thought of more as when you want to totally undo your commits after a certain point and re-write them into a new commit message. With rebase you'd still have all the commits after that point there and you choose what you want to do with them (pick, squash, etc). So if you do not care about those commits, reset it the easiest option.

Collapse
 
mihaylov profile image
Petar Petrov

Ah yeah, makes sense so it is for situations where you want no witnesses of your crimes. :)

Collapse
 
gihrig profile image
Glen Ihrig

I've been using git for years, and I didn't know how git reset worked, maybe even forgot that it existed. I've cleaned up many a "git mess" though. It's always been, um "messy"!

I have had many instances where a knowledge of git reset would have been very useful.

Thanks for sharing!

Collapse
 
gerardino profile image
gerardino

And there's also good old plain git reset which only unstages the staged changes.

Collapse
 
char_bone profile image
Charlotte

The default is mixed :)

Collapse
 
ameyer66 profile image
Andrew Meyer

Good article, learned a bit more about GIT. Especially from the conversations.

Collapse
 
danjconn profile image
Dan Conn

Thanks for this! I have very rarely delved into using reset!