Preserve git –assume-unchanged files between branch checkouts

You can try (git update-index man page):

git update-index --skip-worktree -- path

Skip-worktree bit can be defined in one (long) sentence: When reading an entry, if it is marked as skip-worktree, then Git pretends its working directory version is up to date and read the index version instead.

However, as mentioned in “git assume unchanged vs skip worktree“:

Both options have problems. --assume-unchanged resets itself whenever the index gets discarded (e.g. git reset), so that will probably trip you up sooner or later. Same goes for --skip-worktree.


Plus, make sure to use Git 2.24 (Q4 2014).
Since 2012 (the OP’s question), git stash has been ported to C (it is no longer a shell script) but it had (in its new implementation) to (re-)learn to write refreshed index back to disk.

See commit 34933d0 (11 Sep 2019) by Thomas Gummerer (tgummerer).
(Merged by Thomas Gummerer — tgummerer in commit 34933d0, 20 Sep 2019)

stash: make sure to write refreshed cache

When converting stash into C, calls to ‘git update-index --refresh
were replaced with the ‘refresh_cache()‘ function.
That is fine as long as the index is only needed in-core, and not re-read from disk.

However in many cases we do actually need the refreshed index to be written to disk, for example ‘merge_recursive_generic()‘ discards the in-core index before re-reading it from disk, and in the case of ‘apply --quiet‘, the ‘refresh_cache()‘ we currently have is pointless without writing the index to disk.

Always write the index after refreshing it to ensure there are no regressions in this compared to the scripted stash.
In the future we can consider avoiding the write where possible after making sure none of the subsequent calls actually need the refreshed cache, and it is
not expected to be refreshed after stash exits or it is written somewhere else already.


Warning, that index might not be correctly rewritten when git stash is used with --quiet: With Git 2.25 (Q1 2020), Recent update to “git stash pop” made the command empty the index when run with the “--quiet” option, which has been corrected.

See commit df53c80 (13 Nov 2019) by Thomas Gummerer (tgummerer).
(Merged by Junio C Hamano — gitster in commit 3c3e5d0, 01 Dec 2019)

stash: make sure we have a valid index before writing it

Reported-by: Grzegorz Rajchman
Signed-off-by: Thomas Gummerer

In ‘do_apply_stash()‘ we refresh the index in the end.

Since 34933d0eff (“stash: make sure to write refreshed cache”, 2019-09-11, Git v2.24.0-rc0 — merge listed in batch #6), we also write that refreshed index when --quiet is given to ‘git stash apply‘.

However if ‘--index‘ is not given to ‘git stash apply‘, we also discard the index in the else clause just before.

We need to do so because we use an external ‘git update-index –add –stdin’, which leads to an out of date in-core index.

Later we call ‘refresh_and_write_cache‘, which now leads to writing the discarded index, which means we essentially write an empty index file.

This is obviously not correct, or the behaviour the user wanted.

We should not modify the users index without being asked to do so.

Make sure to re-read the index after discarding the current in-core index, to avoid dealing with outdated information.

Instead we could also drop the ‘discard_cache()‘ + ‘read_cache()‘, however that would make it easy to fall into the same trap as 34933d0eff did, so it’s better to avoid that.

We can also drop the ‘refresh_and_write_cache‘ completely in the quiet case.

Previously in legacy stash we relied on ‘git status‘ to refresh the index after calling ‘git read-tree‘ when ‘--index‘ was passed to ‘git apply‘.

However the ‘reset_tree()‘ call that replaced ‘git read-tree‘ always passes options that are equivalent to ‘-m‘, making the refresh of the index unnecessary.

Leave a Comment