Question
How do I either
- make
git stash
error out if there are both unstaged and staged changes and I haven't specified either--staged
(-S
) or--keep-index
(-k
), or - make
git stash
default to--keep-index
if invoked without the--staged
option?
Ideally as a global config option.
Motivation
Several times now:
- I carefully
git add -p
just the changes I want to commit (sometimes with temporary edits to files beforehand, when I want to pull apart two atoms of change which happen to touch the same lines or adjacent line, whichgit
struggles with), then - I think "I'll just quickly stash those other unstaged changes before taking the time to think of a good commit message", and so
- I type
git stash
, wasting the work of step 1, becausegit
does the dumbest thing a program can do in that case - destroys user information by default without opportunity to abort or undo, by stashing all changes, both staged and unstaged changes, blended into one diff without any distinction.
Now if I was a computer program, I'd always just execute git commit -m 'TODO: --amend THIS COMMIT'
before git stash
, or I'd always remember to type git stash -k
. But I find it more natural to think "I'll stash these unstaged changes real quick for later, then focus on the larger mental task of writing good commit message"
In fact come to think of it, I've been using git
for close to a decade almost daily, and I have never wanted a git stash
to stash staged changes, let alone fuse staged and unstaged changes back together. I can see how that could be useful if you're in the middle of staging one set of changes and then you want to stash the whole thing, but to me that's an extremely tiny window of time - most of the time, if I have staged changes and unstaged changes, they're meaningfully different pieces of change which I haven't finished separating out into the best atomic commits.
CodePudding user response:
According to the documentation, the index and the working tree are well separated into separated commits after the git stash
command.
If your concern is to restore the index after a git stash pop
I suggest using the --index
option: git stash pop --index
.
An alias can make transparent the use of this option:
git config alias.pop "! git stash pop --index"
CodePudding user response:
I'm sympathetic with the first part of the question, but I don't believe there is any such automatic option or configuration. I think the best alternative is Don't Do That — that is, if you're going to give a Git command, say what you mean, explicitly. That way, you know what will happen — because you said what should happen. (For the same reason I never say git pull
, and I rarely say git rebase
without saying --onto
.)
At the same time, I'd like to push back sharply on the claims in the second part:
destroys user information
Uh, no. Only if you think that git commit
destroys user information. stash
saves user information, in a commit (actually a pair of commits) — and saves it in a way that makes it easy to restore.
blended into one diff without any distinction
That is not true. The index is saved as a separate commit. Thus it is possible to restore exactly the situation as it was, both the index and the worktree (except, of course, for the parts of the worktree that git stash
doesn't touch by default, namely untracked and ignored files).
The way stash creation actually works is that the index commit has current head as parent, and the worktree commit has the index commit and the current head as parents. (In other words, the stash’s content is a merge commit!) You can see this by doing git log
on a stash entry, and you will see the worktree commit followed by the index commit, either or both ready for you to restore.
Note that I am not defending git stash
. It's weird and I generally try to avoid it (though sometimes it is a good solution to a specific problem).