I have a habit (maybe a bad one) of occasionally making local changes to a file I never intend to commit. These can vary wildly in purpose. Maybe there is an error because a file that exists in production doesn't exist and I'm too lazy to pull that file down (and subsequently add it to .gitignore and having that committed). Or maybe I prefer to use a different tool than my coworkers and would like to maintain a local Gemfile (for Rails work) that allows me to use what I want with no accidental commits. Again, whatever the reason you have these kinds of changes there is a way to live peacefully with them.

I gave in and did some research and found out about a nice little sub command of git, update-index. I'm not very versed on the inner workings of git but what I've gathered from reading man pages is that update-index is the means by which git keeps track of which files have changed (once it determines there has been a change). I'm pretty sure things like git add and git commit modify these flags as well. Regardless of all that, there is a bit that you can enable that encourages git to turn a blind eye to any changes made locally to certain files. You do this with update-index and the flag --assume-unchanged. To ignore local changes you simply flip the bit: git update-index --assume-unchanged [FILE] and to unignore you flip it again: git update-index --no-assumed-unchanged [FILE] and you're done.

Now, I'm a programmer at heart and I pride myself in being lazy. That's a lot to type and there's no immediately easy way to see what (if anything) is currently being ignored. So I made some aliases to make using this method more pleasant.

If you're interested in using these as well then add these aliases to your ~/.gitconfig (or whereever that file is on Windows).

[alias]
  ignore = update-index --assume-unchanged
  unignore = update-index --no-assume-unchanged
  unignore-all = "!git whats-ignored | xargs git update-index --no-assume-unchanged"
  whats-ignored = "!git ls-files -v | grep '^[[:lower:]]' | awk '{ print $2 }'"

If you already have an [alias] section defined, just drop them in there.

So now that we have some nice, clean aliases here's how we go about using it!

On branch some-branch  
Your branch is up-to-date with 'origin/some-branch'.  
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:   Gemfile

no changes added to commit (use "git add" and/or "git commit -a")

$ git ignore Gemfile
$ git status
On branch some-branch  
Your branch is up-to-date with 'origin/some-branch'.  
nothing to commit, working directory clean

$ git unignore Gemfile
On branch some-branch  
Your branch is up-to-date with 'origin/some-branch'.  
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:   Gemfile

no changes added to commit (use "git add" and/or "git commit -a")  

If you forget what you've ignored locally just run git whats-ignored and if you want to just unignore everything run git unignore-all. It's really easy to toss these in a pre-commit or pre-rebase or whatever hooks if you wish to restore them or clear them before performing any of those actions.

I hope you find this useful, and if you have any other useful tidbits with git or this process let me know!