Why does git stash apply stage my changes?
Anything that will affect your working tree (like a git checkout -- afile
) will first affect your index.
the index is the middle-man for moving things from your work-tree to the object-store AND for moving things from the object-store to your work-tree.
The index is also used by git stash apply
for recording merge conflicts, as the index has stage-n entries. See git merge
:
For conflicting paths, the index file records up to three versions:
- stage 1 stores the version from the common ancestor,
- stage 2 from HEAD, and
- stage 3 from MERGE_HEAD (you can inspect the stages with
git ls-files -u
).
In the history of the evolution of git stash --apply
, two interesting events are to be noted:
In April 2011 (Git 1.7.5.1, commit e0e2a9c), stash
dropped the dirty worktree check on apply.
Before we apply a stash, we make sure there are no changes in the worktree that are not in the index. This check dates back to the original git-stash.sh
, and is presumably intended to prevent changes in the working tree from being accidentally lost during the merge.
However, this check has two problems:
It is overly restrictive. If my stash changes only file "foo
", but "bar
" is dirty in the working tree, it will prevent us from applying the stash.
It is redundant. We don't touch the working tree at all until we actually call merge-recursive.
But it has its own (much more accurate) checks to avoid losing working tree data, and will abort the merge with a nicer message telling us which paths were problems.
So we can simply drop the check entirely.
Using the index to manage the merge done by a git stash apply
lead to another bug, detected in April 2015, Git 2.4.2, commit ed178ef:
stash
: require a clean index to apply
If you have staged contents in your index and run "stash apply
", we may hit a conflict and put new entries into the index.
Recovering to your original state is difficult at that point, because tools like "git reset --keep
" will blow away anything staged.
We can make this safer by refusing to apply when there are staged changes.