Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git-stash changes without reverting

Tags:

git

git-stash

I work on a project using Git. Every once in a while I find myself wanting to save my changes, without committing them, just as a backup, and then continue working. What I usually do is git stash and then immediately git stash apply to bring the code back to the same state as before stashing. The problem I have with this is that git stash reverts my work directory so even though I apply the stash immediately files and projects have to be rebuilt because they appear to have changed. This is quite annoying because some of our projects take ages to build.

So my question is, is there a way to stash my changes without reverting? If stash doesn't do that, is there any other command in git that can do it? Thank you.

like image 740
opetroch Avatar asked Sep 09 '16 13:09

opetroch


People also ask

Does git stash save commited changes?

Invoking git stash encodes any changes to tracked files as two new commits in your DAG: one for unstaged changes, and one for changes staged in the index. The special refs/stash ref is updated to point to them. Using the --include-untracked option also encodes any changes to untracked files as an additional commit.

How do I get my stashed changes back?

Retrieve Stashed Changes To retrieve changes out of the stash and apply them to the current branch you're on, you have two options: git stash apply STASH-NAME applies the changes and leaves a copy in the stash. git stash pop STASH-NAME applies the changes and removes the files from the stash.

How do I stash only staged changes in git?

Stage all your files that you need to stash. Run git stash --keep-index . This command will create a stash with ALL of your changes (staged and unstaged), but will leave the staged changes in your working directory (still in state staged). Now your "good stash" has ONLY staged files.

Does git reset remove stashed changes?

No, git reset --hard origin/master does not affect your stashes in any way. Show activity on this post. The hard reset command you showed above would move the HEAD pointer of whatever the current branch might be to origin/master , but it would not affect the stash commits, which are stored in . git/refs/stash .


2 Answers

When I posted this question I was new to git and didn't understand its power in full. Now I realize that stashing is not what I needed and that git's local branches do the job much better.

Assume you are on main_branch, which you want to keep clean from experimental changes.

Simply create a new branch in order to store your experimental changes.

git checkout -b temp_branch

Assume you do some changes and want to save your progress. Simply commit, nothing to worry about, it's all on the temp_branch:

git commit -a -m "first change"

Assume you do some more changes and want to store again:

git commit -a -m "second change"

Finally, assume you are happy with your experimental changes and want to merge them to the main branch. There are two cases:

1) If you want to merge all changes, do:

git fetch . temp_branch:main_branch

This brings all changes of temp_branch into the main_branch, without switching to the main branch, which means your files are not modified and no recompilation is required. Note it's possible only if you haven't done any other changes on main_branch in the meantime. If main_branch has changed you need to use git merge or git rebase, but this scenario is beyond what the question is asking.

2) Assume you want to merge only some of the commits of temp_branch into main_branch. You can do this with git cherry-pick. First do git checkout main_branch to switch to the main_branch (this modifies the files but this is inevitable since you are dropping some of your changes), then do git cherry-pick <SHA> (where <SHA> is the hash of the commit you want to merge). You can see the list of commits by doing git log temp_branch. Note that merging only some of the changes might give conflicts which you 'll need to resolve.

like image 91
opetroch Avatar answered Oct 21 '22 19:10

opetroch


This can be achieved by manually creating a stash commit object, then storing it in the stash.

git stash store $(git stash create) -m "Stash commit message"

Explanation

I too like throwing things into the stash as a rollback point, before proceeding with a change or refactoring that I feel might not pan out. I find that throwing it onto the stash with a brief description is quicker, easier, and requires less mental context switching than using a branch does. Using a branch involves creating the branch, remembering the branch name, and then deleting the interim branch commit and the branch it self when resuming.

Git has commands to store things into the stash without removing the files from the working directory, as explained in https://stackoverflow.com/a/44330944/1108305. A stash commit object can be created with git stash create and then saved to the stash using git stash store:

git stash store $(git stash create) -m "Stash commit message"

This can be saved to a Git alias to make it more convenient:

git config --global alias.stash-keep '!git stash store $(git stash create)'

git stash-keep -m "Stash commit message"

Note that this does not do everything that git stash push does. For one, it does not append the branch name to the commit, e.g. "stash@{0}: On myBranch: Stash commit message". Secondly, the above simple alias will error with ""git stash store" requires one <commit> argument" instead of "No local changes to save" when there are no changes to stash. Those limitations could be addressed with a more complex alias or script, though the minimal version provided here will likely be sufficient.

like image 41
M. Justin Avatar answered Oct 21 '22 21:10

M. Justin