Today I learned about the --skip-worktree command in git which will treat a file like it hasn’t been modified. This is useful if you have to modify a file locally but don’t ever want to commit it (config files are a common scenario).

Like me you have seen --assume-unchanged used in this way but that’s not what it’s meant for since it’s “designed for cases where it is expensive to check whether a group of files have been modified”. As a result you’re likely to lose the changes you have made to those files. This post shows a good summary of the outcomes of common operations with each command.

The advantage of --skip-worktree is that git really tries to preserve the changes you’ve made to those files. This works pretty well if the files aren’t changed very often but it can be pretty tedious if they change frequently even when those changes wouldn’t have caused merge conflicts as git will refuse to modify the files.

Say for example you need to make a change to a config file for your environment. You would run:

git update-index --skip-worktree config/local.conf

If changes are rarely committed to this than you may not have to think about it again.

However, if you need to switch to a branch with changes to this file then you’ll get an error like:

error: Your local changes to the following files would be overwritten by checkout: path/to/file

If you run git stash now, that file won’t be affected.

So now you need to run:

git update-index --no-skip-worktree config/local.conf

# now you can run stash
git stash

git switch other-branch

git stash pop

# you'll need to resolve conflicts if any otherwise skip the file again

git update-index --skip-worktree config/local.conf

# you can run this to see which files have skip-worktree set
git ls-files -v | grep '^S'

Depending on how frequently you have to deal with this, you’ll quickly end up making an alias or script for it.