Reputation: 150593
As far as I'm aware, git stash
saves a diff between the working tree and , the state of the working tree, as well as the index. You can see this by running HEAD
, it doesn't save the indexgit log --graph stash@{0}
after creating a stash.
git stash pop
has an option --index
, with this documentation:
If the --index option is used, then tries to reinstate not only the working tree’s changes, but also the index’s ones. However, this can fail, when you have conflicts (which are stored in the index, where you therefore can no longer apply the changes as they were originally).
I don't understand this documentation. The second sentence in the quoted documentation is confusing to me.
Why do merge conflicts unexpectedly happen? For example:
$ git init test
$ cd test
$ echo initial > file
$ git add file
$ git commit -m initial
$ echo a >> file
$ git add file
$ echo b >> file
$ git stash save --keep-index
$ git stash pop --index
Auto-merging file
CONFLICT (content): Merge conflict in file
I don't understand why a merge conflict happens in the last step. What I want to happen is for git stash pop --index
to recognise that the index is already in the correct state, and to change the working tree files to match the stashed files.
Upvotes: 2
Views: 6536
Reputation: 1258
'git stash' indeed saves the index - even with --keep-index that leaves your staged changes (but saves them at the same time).
If not adding line 'b', git stash pop should add 'a' to 'a' (still there because of the --keep-index), but is smart enough to realize it is the same modification, and does not do anything and does not trigger a conflit.
When adding line 'b' after the stage, git stash pop thinks the modifications are different, and tries bluntly to add 'a' + 'b' on top of 'a' (as 'a' is still on your tree), raising a conflit.
NB: if 'b' was farther in the code, it would be okay.
So to avoid conflict when restoring the stash, you could first reset your current tree (thus removing the staged modifications), and then pop your stash (which will put you back in the initial state, since the index was saved)
git stash push --keep-index --include-untracked -m "cleaning_before_git_hook"
# here you can for example check your commit with git hooks, run tests, etc.
git reset --hard # to avoid any conflict when popping
git stash pop --index # without --index you will find back your initial code, but it will forget about the staged modifications you had
Upvotes: 2