First of all, I do know about --keep-index
. This is not what I want because it still stashes all changes, but leaves the staged one in the worktree. I would like to only stash the unstaged files, if possible without adding all changes again with git stash --patch
.
3 Answers
If you want to store the diff between the index (what's staged) and the worktree (what's not staged yet), this simply is git diff
:
# store it :
git diff > stash.patch
# if you additionally want to put the unstaged changes away :
git stash -k
To apply at later these changes on the worktree (not on the index) : use git apply
git apply stash.patch
You could also use what gets stored in the stash to re-create that diff :
# stash the changes :
git stash -k
# to reapply them on the worktree at a later time :
# the 'unstaged changes' are the diff between
# - what the index was (stash^2)
# - and what the worktree was (stash)
git diff stash^2 stash | git apply -
# again : 'git apply' will apply the changes on the *worktree*, not the index
Best I can come up with is:
git commit -n -m temp
git stash push -u
git reset HEAD~1
This will commit without triggering any pre-commit hooks. Then it will stash the changes that remain (i.e. the unstaged changes from before). Finally, it will reset head back to the pre-commit state (before the "temp" commit).
You cannot do it direclty, but you can eventually isolate only unstaged or only staged changes, or both, without even using any git-stash
command at all :
git switch -c separated-stashes
Equivalent to the old checkout -b
: creates a new branch and switch on it. It won't change neither your worktree nor your index so you'll basically have the same git status
' output as before, but this time on the new branch. Contrary to a simple git switch
/ git checkout
, it won't warn you to stash or commit your changes before switching branches, because you are explicitly creating a brand new branch through -c
/-b
.
git commit -m "staged"
Create a first commit on the new branch containing only staged changes from the beginning.
git add -u && git commit -m "unstaged"
Create a second commit with unstaged changes from the beginning.
git switch - # == git checkout -
Go back to the previous branch you were on.
Now you have stashed everything and can cherry-pick
what you need (staged / unstaged) wherever and whenever you want.
This might look a little cumbersome but you're free to define a git alias to automate it :
git config --global alias.bratisla '!git switch -c separated-stashes; git commit -m "staged changes"; git add -u; git commit -m "unstaged changes"; git switch -' # why this name ? : youtu.be/LpE1bJp8-4w
-
So it makes it impossible to use this logic in a pre-commit hook because you have to make new commits just to stash only the unstaged changes. This is super lame.– scalyCommented Jan 20, 2021 at 4:47
-
Well, OP didn't ask about a pre-commit hook compliant solution, it seems it was more a manual command line solution, and as stated in this comment you don't necessarily want to make one, especially for stashing stuff. But if you have a way to assess the problem without having to commit so that you can make it a hook, I would love to ear it @scaly Commented Feb 1, 2021 at 21:37
commit
-- commit the things you want to keep, and after that stash the rest temporarily, if needed.pre-commit
hooks for this reason -- in my opinion it is the wrong place to put validation since it hinders workflows like the one above. If you have apre-commit
hook you can pass the-n
(--no-verify
) option togit commit
to bypass it.