Reputation: 4105
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.
Upvotes: 24
Views: 9970
Reputation: 21399
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"
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.
Upvotes: 12
Reputation: 4105
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.
Upvotes: 9
Reputation: 4761
git stash && git stash apply
And in case you prefer your stash with a comment:
git stash save “stash comment” && git stash apply
Upvotes: 4
Reputation: 12170
Seems like you want a way to temporarily store your changes so that you don't accidentally delete them, can roll back.
The best way to do it is to actually commit your changes locally anyway.
Typical workflow is like so:
vim myfile # make some changes
git add myfile
git commit -m "temp changes 1"
vim myfile # make more changes
git commit --amend
git diff HEAD~1 # See the changes you've made compared to last HEAD.
The downside with this is that your "local changes" aren't revisioned.
The other alternative is to just keep on saving your local work as distinct commits and then simply squashing them for the sake of polish before sending out a patch/PR.
This will look something like this:
vim myfile2 # make changes
git add myfile2
git commit -m "temp changes dated X"
vim myfile2 # more changes
git add myfile2
git commit -m "temp changes dated Y"
Then simply do something like this, before sending them away.
git rebase -i HEAD~N # Where N is the number of local commits you made
# Squash them, by changing 'pick' to 'squash' in your editor.
# Send them away
git push origin dev
Upvotes: 2