Hiding local file changes from git
I’m currently working on refactoring some Angular components and update 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:
$ gst
On branch FE-1169_book_confirm_info
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: src/app/price/confirmation/confirmation-model.js
no changes added to commit (use "git add" and/or "git commit -a")
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:
alias ghide='git update-index --skip-worktree'
alias gunhide='git update-index --no-skip-worktree'
alias ghidden='git ls-files -v . | grep ^S'
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
…)