Reputation: 820
echo "a" > file1.txt
git add file1.txt
git commit -m "add file1"
echo "b" > file1.txt
git stash
Now
echo "c" > file1.txt
git stash apply
Results in:
error: Your local changes to the following files would be overwritten by merge:
file1.txt
Please commit your changes or stash them before you merge.
Aborting
Cool! now let's stage file1.txt
and apply the stash again:
git add file1.txt
git stash apply
And we have a conflict:
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
What's the conflict (cat file1.txt
):
<<<<<<< Updated upstream
c
=======
b
>>>>>>> Stashed changes
In both cases, the stash was b
and file1.txt
in the working directory was c
.
So why git stash apply
was aborting when file1.txt
was not staged and then threw a conflict when it was staged?
Comprehensive responses are appreciated.
I read the whole stashing and cleaning chapter in the git book but couldn't make sense of why this happens.
The question is NOT how to fix this. Just wondering what happens behind the scenes in this scenario.
Upvotes: 2
Views: 427
Reputation: 534966
A stash stores both the state of the index and the state of the working tree, because those are both things you might have in an incoherent or unfinished state. Making a stash puts both the index and the work area into commits and rolls both back to the head commit state; the index commit then has the current head as parent, and the work tree commit has the index commit and the current head as parents, making the stash’s content a merge commit. You can actually see this structure by doing a git log on your stash entry (your identifier numbers will be different of course):
* 501bd7e (refs/stash) WIP on master: f2c4178 add file1
|\
| * 37ca60e index on master: f2c4178 add file1
|/
* f2c4178 (HEAD -> master) add file1
Applying a stash, just the other way, requires that Git should update both the state of the index and the state of the working tree. Clearly Git must therefore reconcile stash index with your index and stash working tree with your working tree, and it uses merge logic to do so — so a conflict is perfectly possible.
So:
After your "c"
change to file1.txt, we have a situation where you have changed the working tree but applying the stash would also change the working tree, so we abort. I think you understand that part.
You then copy the "c"
change into the index (with git add
). I think you understand that part too! Applying the stash would now also change the index in a way that conflicts with that. That's okay, but we enter the same state as with any merge conflict; nothing can now happen until that conflict is resolved or the merge is aborted.
This is one of the reasons that stash is often not the best choice. If the index is in a good state, in particular, it is often better to just to make a real commit to store the current state of things.
Upvotes: 4