Why is a stash represented as 2 commits?

1.2k Views Asked by At

When stashing some changes, Git creates two separate commits, 'WIP on branch' and 'index on branch':

$ git log --graph --all 

*   commit 98aac13303ca086580c1ec9ccba5fe26c2a8ef3c
|\  Merge: 7d99786 82c5c76
| | Author: Tieme <[email protected]>
| | Date:   Wed Nov 19 09:58:35 2014 +0100
| |
| |     WIP on development: 7d99786 Last real commit
| |
| * commit 82c5c763357c401135675a39bfabf9b7f6805815
|/  Author: Tieme <[email protected]>
|   Date:   Wed Nov 19 09:58:35 2014 +0100
|
|       index on development: 7d99786 Last real commit
|
|
| * commit 7d9978637a0e1ef92f2432189bdebf2317f0b2f0
| Author: Tieme <[email protected]>
| Date:   Tue Nov 18 17:32:33 2014 +0100
|
|     Last real commit
|

I looked up the documentation for this but it does not make it clearer:

A stash is represented as a commit whose tree records the state of the working directory, and its first parent is the commit at HEAD when the stash was created. The tree of the second parent records the state of the index when the stash is made, and it is made a child of the HEAD commit. The ancestry graph looks like this:

         .----W
        /    /
  -----H----I

where H is the HEAD commit, I is a commit that records the state of the index, and W is a commit that records the state of the working tree.

Why are there 2 commits created and not just a single one for the files I changed ?

1

There are 1 best solutions below

1
On BEST ANSWER

Short answer

git stash differentiates between the changes you have on your index and the one you have in the working tree and creates commits for both of them.

Long answer

Some background

Using git it's possible that the changes you have in your working tree (the files your directly work with) are different from the changes you have on the index.

Adding only a limited number of files to the index, or with git add --patch even adding single changed lines in a file will leave your index in a different state as the working tree.
This is a good thing, because it enables you to create commits which focus on one specific task/feature.

It's even possible that you have changes on your index which aren't anymore part of your working tree. You can test it by adding some changes to the index (git add), manually removing them from the file and then creating a commit (git commit).
The commit will still contain the changes you added in the first place, although they don't exist in your working tree anymore.

If you have trouble understanding the difference between the working tree and the index you can take a look at this question.

What exactly is happening?

Now the statement from the beginning should make more sense. One "stash commit" contains all changes you had in your working tree (the files you directly work with) and the other contains the changes you had added to your index.

By default git stash pop or git stash apply only tries to reinstate the changes you had in your working tree and ignores the changes you had on the index. It's possible to tell git stash to try reinstating your index too by using the --index flag (git stash (pop|apply) --index).