Hiding local file changes from Git
How to override files in your dev environment without causing headaches.
I’m currently working on refactoring some Angular components and updating their styling for our booking confirmation screen. My colleague Matt showed me a handy way to manually stick a big object in the relevant model file so that I can directly go to the booking confirmation screen without having to click through the whole search/price/book process. However, now every time I do git status
, I get this:
This is annoying. That “modified” file is not actually modified in the sense of version control — I don’t plan to commit my changes later and push them to the upstream repo. I don’t want to see it when I do git status
, and I especially don’t want to add the changes when I do git add
.
So I’ve found a neat way to work around this.
git update-index --skip-worktree src/app/price/confirmation/confirmation-model.js
will “hide” the file from Git; it will no longer show up as a file that I’ve changed. If the file gets changed remotely and I dogit pull
, Git will give me a conflict message and explain what needs to be done to resolve it. Andgit reset --hard
will not reset the file, allowing the changes to persist for a long time (e.g. across branches).- To view a list of all files I’ve hidden in this way, I can just do
git ls-files -v . | grep ^S
. All the files listed with status codeS
(forskip-worktree
) will be displayed. - To “unhide” a file, I can simply do
git update-index --no-skip-worktree src/app/price/confirmation/confirmation-model.js
.
How is this different to .gitignore?
The most common way to “hide” files is to add them to .gitignore
. This won’t work for me: the file I’m editing is already tracked in Git, which means changes will still show up in git status
.
.gitignore
is intended for things like build artifacts, which shouldn’t be committed to the repo at all.
How is this different to assume-unchanged?
Now we’re getting somewhere! git update-index --assume-unchanged
is fairly similar in function to --skip-worktree
. The difference is that --assume-unchanged
seems to be designed for performance uses rather than for local overwriting of configs and the like. It’s meant to be used for cases where checking for file changes is very expensive. Critically, operations like git pull
are very likely to reset this flag and discard all your changes with no option to recover them.
Tips
If you plan on using these, I recommend you add some aliases to your .zshrc
/.bashrc
file:
Then you can do ghide path/to/file
to hide, gunhide path/to/file
to unhide, and ghidden
to list all hidden files.
I hope you find this useful! Do remember, if you are going to use this, just do ghidden
every so often to check whether you haven’t forgotten about a hidden file. (I’m still looking for a clever way to show this in git status
…)
Update (2017-09-14)
I don’t know why I didn’t think of this before! Even better than making these commands shell aliases, you can put them directly in your Git config (~/.gitconfig
). This “scopes” the commands to Git, allowing Git to autocomplete the commands for example, and making the commands resemble standard Git commands. It also means the commands will be available to you across multiple shells.
The commands then become git hide path/to/file
, git unhide path/to/file
, and git hidden
.
Originally published at henrebotha.github.io on August 30, 2017.