Difference between reset --soft and --mixed
Asked Answered
P

2

4

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.

Parakeet answered 14/6, 2014 at 21:31 Comment(7)
Does this help? stackoverflow.com/questions/3528245/…Blemish
@AntP - thanks for that. I did read that also, but I still fail to see the material, real, down-to-earth difference for someone using GIT through a nice GUI like SourceTree—especially with the staging pane turned off.Parakeet
I can't post this as an answer because I don't know SourceTree very well but it may well be that, to a GUI user, there is no difference; Git GUI tools tend to do more than just provide an interface and actually abstract away from what's really going on and make assumptions about what you want to do (the GitHub client is particularly guilty of this), which is the main reason I avoid them.Blemish
@AntP - thanks much. Appreciate your comments. I suspect that may very well be the case, but I wanted to post here to be sure. And to be fair to SourceTree, it does give you the option of using a staging pane, but I wound up turning it off, as I didn't see a purpose in taking an extra step between adding changes to the index, and committing them. With the staging pane off, I see un-committed changes, which I just commit in one step.Parakeet
The benefit of the staging area is that you can do things like stage a file for commit at a stable point, continue work on it before actually committing, think "****, I messed that up," check out again and have your staged changes remain intact - it gives you the flexibility to pick and choose what's committed without it necessarily having to reflect what's currently in your working copy without forcing you to just commit and then revert things later if you change your mind (leaving behind potentially broken or incomplete revisions).Blemish
What you're doing with SourceTree, though, is effectively the equivalent of just staging everything you want to stage just before you commit, which is the most common use case although it limits flexibility.Blemish
Possible duplicate of What's the difference between git reset --mixed, --soft, and --hard?Shipshape
J
3

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.

Joyajoyan answered 14/6, 2014 at 22:27 Comment(1)
I think your answer would benefit from including an example; as it is, I don't find it very clear.Gangrel
D
7

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.

Dioptrics answered 14/6, 2014 at 22:12 Comment(4)
+1 as this is very comprehensive but I'm not sure it's overly useful to a user who is interested primarily in the implications within his GUI environment (not to say that it's not important to understand the underlying model regardless but certain things don't have direct relevance above a certain level of abstraction).Blemish
'git reset --mixed' (or without the --mixed; it's the default) is just useful for undoing 'git add' or 'git rm'. - so from the sounds of it, it does seem as though GUI tools like SourceTree abstract away the things that make a difference, like this (I can easily undo an add after a soft reset in SourceTree).Parakeet
@AdamRackis The key difference (as I've just added to my answer) is that when you run a reset in SourceTree, you won't have anything staged because you are letting SourceTree just stage everything you've selected when you commit - if there's nothing in the index, the two flags are identical.Blemish
I referenced the command-line options, because that's the best documented and is useful information for a wider audience. Here's an Atlassian answer that speaks specifically to SourceTree. answers.atlassian.com/questions/112557/….Dioptrics
J
3

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.

Joyajoyan answered 14/6, 2014 at 22:27 Comment(1)
I think your answer would benefit from including an example; as it is, I don't find it very clear.Gangrel

© 2022 - 2024 — McMap. All rights reserved.