git ignore vs. exclude vs. assume-unchanged

I'm going to accept this emailed answer from Junio Hamano (the maintainer of Git) because I think it explains some things more lucidly than the official docs, and it can be taken as "official" advice:

The .gitignore and .git/info/exclude are the two UIs to invoke the same mechanism. In-tree .gitignore are to be shared among project members (i.e. everybody working on the project should consider the paths that match the ignore pattern in there as cruft). On the other hand, .git/info/exclude is meant for personal ignore patterns (i.e. you, while working on the project, consider them as cruft).

Assume-unchanged should not be abused for an ignore mechanism. It is "I know my filesystem operations are slow. I'll promise Git that I won't change these paths by making them with that bit---that way, Git does not have to check if I changed things in there every time I ask for 'git status' output". It does not mean anything other than that. Especially, it is not a promise by Git that Git will always consider these paths are unmodified---if Git can determine a path that is marked as assume-unchanged has changed without incurring extra lstat(2) cost, it reserves the right to report that the path has been modified (as a result, "git commit -a" is free to commit that change).


Adding to Junio Hamano's answer, Git 2.3.0 (February 2015) now removes from the gitignore documentation

To ignore uncommitted changes in a file that is already tracked, use 'git update-index --assume-unchanged'.

See commit 936d2c9 from Michael J Gruber (mjg):

gitignore.txt: do not suggest assume-unchanged

git-update-index --assume-unchanged was never meant to ignore changes to tracked files (only to spare some stats).
So do not suggest it as a means to achieve that.