Reputation: 11130
$ git init
$ git commit -m 'initial commit needed to stash' --allow-empty
$ touch test
$ git add --intent-to-add test # aka -N
$ git stash
error: Entry 'test' not uptodate. Cannot merge.
Cannot save the current worktree state
It's not untracked, so --include-untracked
has no impact. Is there any way to stash an added but never committed file?
Upvotes: 1
Views: 405
Reputation: 487775
Is there any way to stash an added but never committed file?
Only if it's truly added, i.e., there's an actual version in the index. Then git stash
will work.
There have, in the past, been some bugs in Git around the --intent-to-add
flag. Supposedly they are all fixed now, making it safe to use, but I'd recommend avoiding it unless it's doing something particularly important and/or useful for you today. What it does internally is create an index entity with a flag set, and each Git command that deals with the index is supposed to have special handling for this entity if / as needed:
$ git add --intent-to-add test
$ git ls-files --stage --debug
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 test
ctime: 0:0
mtime: 0:0
dev: 0 ino: 0
uid: 0 gid: 0
size: 0 flags: 20004000
The hash ID here, e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
, is the hash of an empty file:
$ git hash-object -t blob --stdin < /dev/null
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
The flags: 20004000
shows the CE_INTENT_TO_ADD
flag from cache.h
:
/*
* Extended on-disk flags
*/
#define CE_INTENT_TO_ADD (1 << 29)
#define CE_SKIP_WORKTREE (1 << 30)
What git stash
does is to make two (or sometimes three) commits that are not on any branch, then—in effect—run git reset --hard
to set your index and work-tree back to the state they would have if you hadn't started working with the index and work-tree.1 The two commits hold the index (staging-area) state, as an ordinary commit / snapshot, and your work-tree state, as another commit / snapshot. The third commit, if it exists, holds any untracked files, possibly including ignored files. None of these commits have any room for these extended flags shown by git ls-files --debug
, so the CE_INTENT_TO_ADD
flag simply cannot be preserved.
Perhaps git stash
could try to handle the flag by pretending it's not set at all (so that it writes an empty test
file instead, then removes the index entry entirely). This would be mostly consistent: the file is, after all, tracked as an empty file. It just has this special "intent to add" status, plus the all-zero cache information since it doesn't exist as a file-system file. You would lose the special "intent to add" status in the process, of course. So the end result would be the same as if you'd just added empty files instead.
1This used to be exactly what it did, but then git stash
got fancied up to allow for pathspec arguments. For several Git versions afterward, this kind of git stash
could occasionally lose data. All the bugs here have been fixed—I think—but in general I don't recommend doing this kind of pathspec-based stash. In fact, I recommend avoiding git stash
entirely except for some very short-term purposes. Stashes are, after all, just commits that don't have a lot of nice ways to find them again later. Make real commits, which do have good ways to find them again later.
Upvotes: 2