I had a conversation with a colleague today about the git reset command.
I realised that while I use git reset --hard reasonably regularly (e.g. in
order to move a branch when I've committed on the wrong one), I didn't know much
about the --mixed or --soft modes.
The documentation on each of them is a little vague, so I thought I'd just try them out and see what happens. I hope this will serve as a useful reference.
Suppose I create a repository which looks as follows.
| Initial Commit | Commit A | Commit B | Staged | Unstaged | 
|---|---|---|---|---|
| A1.txtA2.txtB1.txtB2.txtC1.txtC2.txtD1.txtD2.txt | A1.txtA2.txtA3.txt | B1.txtB2.txtB3.txt | C1.txtC2.txtC3.txt | D1.txtD2.txtD3.txt | 
(Hopefully it's clear what I mean by each of these icons.)
Here's the result of performing different types of resets.
| Commit A | Commit B | Staged | Unstaged | |
|---|---|---|---|---|
| Soft, commit B | A1.txtA2.txtA3.txt | B1.txtB2.txtB3.txt | C1.txtC2.txtC3.txt | D1.txtD2.txtD3.txt | 
| Mixed, commit B | A1.txtA2.txtA3.txt | B1.txtB2.txtB3.txt | C1.txtC2.txtC3.txtD1.txtD2.txtD3.txt | |
| Hard, commit B | A1.txtA2.txtA3.txt | B1.txtB2.txtB3.txt | D3.txt | |
| Soft, commit A | A1.txtA2.txtA3.txt | N/A | B1.txtB2.txtB3.txtC1.txtC2.txtC3.txt | D1.txtD2.txtD3.txt | 
| Mixed, commit A | A1.txtA2.txtA3.txt | N/A | B1.txtB2.txtB3.txtC1.txtC2.txtC3.txtD1.txtD2.txtD3.txt | |
| Hard, commit A | A1.txtA2.txtA3.txt | N/A | D3.txt | 
The thing that surprised me most about this is what happens when you do a hard
reset. Because the index only contains tracked files, the unstaged addition of
D3.txt remains after the hard reset. Personally I think it would make more
sense for Git to remove this file, but that's not what happens!