Why does the remote see local changes to a file I've excluded when my expectation is that the remote will not be aware of changes to an excluded file?
Because that's not what assume-unchanged
does; in fact, it's for the very opposite purpose (bold added):
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).
Yes, there are lots of resources recommending assume-unchanged
to ignore local changes to a tracked file. They're almost all wrong, and the issue you're asking about is one of the ways that this can fail.
Unfortunately, assume-unchanged
often looks like it's ignoring changes to files so people continue to use it and to recommend it.
How do I get around this problem?
skip-worktree
is a better option, but it's not a perfect fit either. A much better solution is to coordinate with your team to rename the tracked file to td_config.template.php
or similar and properly ignore td_config.php
.
Don't fight Git; use it the way it's meant to be used. It doesn't provide a mechanism for ignoring a tracked file, and all of the current workarounds are flawed in one way or another.
(If you really want to ignore this advice, you should be able to git update-index --no-assume-unchanged
the file, then stash your changes, then pull, then apply your changes, then re-apply the bit. But do so knowing that it doesn't do what you want it to.)
Edit:
OP commented that
When I originally set this up, I tried update-index, skip-worktree, and the exclude file… so at this point it's pretty hard to understand how exactly git is or isn't tracking the file.
Running git ls-files -v config/td_config.php
helps us figure out which of these settings is active on that file. In this case we got
S config/td_config.php
The capital S shows us that skip-worktree
is set, and that assume-unchanged
is unset on the file. Running git update-index --no-skip-worktree config/td_config.php
should return it to "regular status", at which point any of the preceding suggestions can be used.