Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between reset --soft and --mixed

Tags:

git

dvcs

I'm new to GIT, and trying to understand the difference between git reset --soft and git reset --mixed. I know the latter resets the index, while the former does not, but I'm trying to understand what the material difference is: when would I use one versus the other?

I've read this Stack Overflow post, which seems to suggest that mixed lends itself to making some changes before re-committing, while soft lends itself to simply re-committing immediately. I'm using SourceTree, with the staging pane turned off, and struggling to see why this is so; I can't for the life of me see any actual real differences.

The only difference I can see is that a newly added file that I reset over shows up as added with a soft reset, but not so with mixed. But in either case I can successfully make changes to the newly added file, and re-commit. And of course any new changes I make to existing files get seamlessly added to my current un-committed changes, ready to be committed.

Do I have to use the Staging Pane with Source Tree to see any practical difference, or am I just missing something? To be clear, with how I have the tool set up now, I see un-committed changes, which I commit in one step.

like image 943
Adam Rackis Avatar asked Dec 26 '22 08:12

Adam Rackis


2 Answers

First, read the link suggested by @Ant P above.

Whats the difference between git reset --mixed, --soft, and --hard?

Let me supplement that with a bit of model of what's going on.

'git reset' works with three different things.

  1. The HEAD reference. This indicates the point of reference. This has several uses, but perhaps the most relevant to you here is that this will be the parent of your next commit (assuming you don't change it again).
  2. Your working tree.
  3. The index. (The "Staging" pane in SourceTree). This is what git uses to construct the next commit. It's not actually creating commits from your working tree directly. That's why you need to do 'git add'.

So if you create a git repo with two files, foo.txt and bar.txt.

In your first revision put 'v1' in each file. In your second revision put 'v2' in each file. Now, put 'v3' in each, and do 'git add foo.txt'.

At this point, you change your mind, and decide to reset to the first revision. What state do you want to end up in?

  • 'git reset --hard HEAD^': resets everything. Your tree is back to the first revision, with no changes queued to the index.
  • 'git reset --soft HEAD^': Just resets the HEAD pointer. The index still has the state before the reset. This means that all the changes in the second commit, PLUS anything you've already added. So it has the 'v3' you put in foo.txt, and the 'v2' you committed in your first try at the second commit.
  • 'git reset --mixed HEAD^': This just resets the index, filling it in with the current revision. In effect, it's undoing any 'git add' you may have done (or 'git rm').

So why would you want to do git reset --soft?

Let's say you create a commit, and decide you didn't get it right, and want to fix it before you push. (IMPORTANT! Once you push, you want to consider commits as permanent, or you'll make things hard for everyone else)

You could make your changes, and do 'git commit --amend'. But that only works for the last commit. Or you could do 'git rebase --interactive', and make your change to a specific commit, merge commits, etc.

Or you could do 'git reset --soft', add, change, rm, or reset any files, until you get the state you want for your new commit, and then commit it as your new commit.

'git reset --mixed' (or without the --mixed; it's the default) is just useful for undoing 'git add' or 'git rm'.

Bottom line is, in my opinion you probably don't want to use --soft in interactive usage. There's nothing wrong with using it, but 'git commit --amend' or 'git rebase --interactive' may be a more intuitive way to get what you want.

'git reset --mixed' you will use a lot.

like image 103
Bob Kerns Avatar answered Jan 06 '23 04:01

Bob Kerns


If you're using a .gitignore which is not checked into the repo or changed between the commits, you won't be able to add ignored files from a mixed reset except as manually, neither will git diff or git status show you they are there.

With a soft reset, everything you had reset will be guaranteed to be included into the commit should you make one.

Actually, either of those might be the way you need, that's why both methods (and explicit access to the index itself) are there in GIT.

like image 39
Quassnoi Avatar answered Jan 06 '23 06:01

Quassnoi