Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens if I stash changes in a branch and then delete that branch

Tags:

git

git-stash

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 
like image 486
Pranjal Mittal Avatar asked Sep 18 '13 08:09

Pranjal Mittal


People also ask

Does git stash delete changes?

Re-applying your stashed changesPopping your stash removes the changes from your stash and reapplies them to your working copy. This is useful if you want to apply the same stashed changes to multiple branches.

Can I apply stashed changes to different branch?

In its simplest form, the git stash command creates a stash entry. To reapply our stashed changes at a later point, we can use git stash apply . We can apply the stash entry to a different branch – it doesn't have to be the branch that we created the stash from.

What happens if you git stash multiple times?

If you want to git stash pop twice because you want both stashes in the same commit but you encounter "error: Your local changes to the following files would be overwritten by merge:" on your 2nd git stash pop , then you can: 1) git stash pop , 2) git add . , and 3) git stash pop .


2 Answers

(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 stashed. 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 commited 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.)

like image 86
torek Avatar answered Sep 21 '22 11:09

torek


  1. Stashing takes the dirty state of your working directory and saves it on a stack. If you stash something and then delete the previous branch, your stashed changes does not vanish. You can list what's on stash stack with the command :

git stash list

In fact, You can save a stash, switch to another branch, and try reapply the stash. Applying the stash on the same branch is not necessary.

In second case, You still need to do git commit after applying stash.

like image 28
Shunya Avatar answered Sep 24 '22 11:09

Shunya