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.txt A2.txt B1.txt B2.txt C1.txt C2.txt D1.txt D2.txt |
A1.txt A2.txt A3.txt |
B1.txt B2.txt B3.txt |
C1.txt C2.txt C3.txt |
D1.txt D2.txt D3.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.txt A2.txt A3.txt |
B1.txt B2.txt B3.txt |
C1.txt C2.txt C3.txt |
D1.txt D2.txt D3.txt |
Mixed, commit B | A1.txt A2.txt A3.txt |
B1.txt B2.txt B3.txt |
C1.txt C2.txt C3.txt D1.txt D2.txt D3.txt |
|
Hard, commit B | A1.txt A2.txt A3.txt |
B1.txt B2.txt B3.txt |
D3.txt |
|
Soft, commit A | A1.txt A2.txt A3.txt |
N/A | B1.txt B2.txt B3.txt C1.txt C2.txt C3.txt |
D1.txt D2.txt D3.txt |
Mixed, commit A | A1.txt A2.txt A3.txt |
N/A | B1.txt B2.txt B3.txt C1.txt C2.txt C3.txt D1.txt D2.txt D3.txt |
|
Hard, commit A | A1.txt A2.txt A3.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!