What happens if I stash changes in a branch and then delete that branch?
(1) Do I lose the stashed changes?
Example:
git stash
git checkout other_branch
git branch -D previous_branch
(2) Also, are the above stash and delete steps equivalent to commiting the changes in a branch and then deleting that branch (in terms of the final state achieved) ? ie:
git commit -m "Dummy commit, I am terminating this branch"
git checkout other_branch
git branch -D previous_branch
(1) No. The changes saved by git stash
are saved as a pair (or sometimes trio) of commits. Those commits are referenced by the name stash
. If you think of branch names and tags as labels for commits (which is what they are), then you can draw a picture, e.g.:
O1 - O2 <-- other_branch
/
M1 - M2 - M3 - M4 <-- master
\
B1 - B2 - B3 <-- branch
.
.......................<-- tag
(this might work better if I could color the tag differently; I used dots to suggest that the tag tag
points to commit B1
, which is "on branch branch
").
If you're on branch branch
and have some unsaved changes and run git stash
, this is what it does:
/
M1 - M2 - M3 - M4 <-- master
\
B1 - B2 - B3 <-- HEAD=branch
| \
i - w ........<-- stash
(I left other_branch
and tag
out of the diagram but they're still there too. I wrote HEAD=branch
to imply that HEAD
is pointing to branch
, and branch
is pointing to commit B3
.)
Here i
and w
are the "index" and "work-tree" states that you stash
ed. The name stash
points directly at commit w
, and w
has two parents (i.e., is a "merge commit" even though it's not really a merge at all), with B3
as its first parent and i
as its second.
When you run git branch -D
, all you are doing is erasing the label. So let's say you git checkout other_branch
and then erase the label branch
. Now you have this:
O1 - O2 <-- HEAD=other_branch
/
M1 - M2 - M3 - M4 <-- master
\
B1 - B2 - B3
| \
i - w ........<-- stash
There is no label directly on B3
but the stash points to w
, and w
points back to B3
. So everything is still there, and will remain there as long as the stash (or the reflog, or both) keep B3
on git's internal radar.
(2) No: as you can see, the stash still has a reference to the branch. However, once you drop that stash—i.e., erase the stash
label—with git stash drop
for instance—you get this:
O1 - O2 <-- HEAD=other_branch
/
M1 - M2 - M3 - M4 <-- master
\
B1 - B2 - B3
| \
i - w
Had you git add
-ed and git commit
ed all your changes, you would have gotten a (single, non-merge) commit, which we could call B4
, on branch
. The branch label would have been moved to point to B4
, and then you would check out other_branch
and delete the label, giving:
O1 - O2 <-- HEAD=other_branch
/
M1 - M2 - M3 - M4 <-- master
\
B1 - B2 - B3 - B4
which is almost (but not quite) the same.
(Note that if tag tag
still points to B1
, commit B1
will stick around until the tag is also erased. Commits B2
through B4
, or B2
through w
, will only stick around as long as they stay there-but-invisible in the reflog. After 30 days (or whatever you set for reflog expiry), the reflog entries expire, and those commits become eligible for garbage collection.)