Not a complete solution to the more generic problem you described, but enough for me most of the time:
1. I try to arrange things in a way that I can keep my local changes in files that are not in the repo. For example: If your software loads a file from several places and the more specific one (current dir) wins over a more generic one ($HOME or /etc) you can try to keep a local one.
All these files end up being .gitignored from a place that is not in the repo itself and not shared: Either in the global .gitignore or .git/info/exclude. If the files don't have to be in a specific place I put them in a subdir called aux, which also contains a .gitignore with just an asterisk (*) on the first line. That way it never gets added and it doesn't leave a trace in any .gitignore outside of aux.
2. Files that are checked in but need local modifications are marked with `git update-index --assume-unchanged`
1. I try to arrange things in a way that I can keep my local changes in files that are not in the repo. For example: If your software loads a file from several places and the more specific one (current dir) wins over a more generic one ($HOME or /etc) you can try to keep a local one.
All these files end up being .gitignored from a place that is not in the repo itself and not shared: Either in the global .gitignore or .git/info/exclude. If the files don't have to be in a specific place I put them in a subdir called aux, which also contains a .gitignore with just an asterisk (*) on the first line. That way it never gets added and it doesn't leave a trace in any .gitignore outside of aux.
2. Files that are checked in but need local modifications are marked with `git update-index --assume-unchanged`