Reputation: 45
I added a Web.config
file to my .git/info/exclude
. I ran git update-index --assume-unchanged path/to/Web.config
. I also tried running git update-index --skip-worktree path/to/Web.config
. Despite this, when I run git ls-files -v . | grep ^S
(which I understand is supposed to list the assume-unchanged files) I do not see the Web.config
listed.
Changes to the Web.config
do not show up in git status
, but when I try to change branches after changing the Web.config
, I get "Your local changes to the following files would be overwritten by checkout:"
For my purposes I do not want to use a .gitignore
and I do not want to git rm --cached
the Web.config
, because both require that I commit these changes. This is not an option in my situation.
Upvotes: 3
Views: 6217
Reputation: 489848
The TL;DR answer is that neither .git/info/exclude
nor .gitignore
have any effect on a tracked file. Using git update-index --skip-worktree
(or --assume-unchanged
) just make Git stop comparing the index version to the work-tree version. The file is still tracked and still goes into every new commit. This means that trying to move from a newer commit to an older one may try to change the content of the file in your work-tree. There is no workaround for this (other than moving the content out of the way so that Git can freely overwrite the file that's not there for the moment).
For a file to be tracked in Git, it must be in the index. That is, the index—the mysterious object that Git uses to build the next commit—has a copy of a file with some path name P.
If path P is in the index, no amount of fiddling with ignore files will make P stop being in the index. The only way to make P stop being in the index is to change the contents of the index.
There are several ways to change the contents of the index. Since the index is what will be in the next commit, you can:
Check out a commit that does not have a file whose path name is P.
This removes path P from the index, and removes the file whose path is P from the work-tree as well. Git will object to the git checkout
if the contents of path P do not match the contents stored in the current (HEAD) commit, telling you that you will lose these changes (which is true, you will lose these changes; though you can of course move the file out of the way first, then move it back later).
Of course, as soon as you check out another commit that does have path P in it, the file will re-appear in the index and in your work-tree, with the content as stored in that other commit. As before, Git will object to the git checkout
if it will overwrite data.
Use git rm
to remove the file. Using git rm --cached
will remove P from the index without disturbing the file in your work-tree.
You can now make a new commit that does not have a file whose path name is P.
This allows you to use the other method: you now have a commit that does not have path P in it, so any time you want to get to an index that does not have path P in it, this new commit you just made is a suitable commit for git checkout
.
That's the only way to make the path become untracked: you must remove it, either by a git checkout
of a commit that lacks the path, or by an explicit remove step. There are no other ways to make the file become untracked. Note as well that the "untracked-ness" of the file continues to depend on the index contents, which change whenever you git checkout
commits that have, or lack, P.
If you are willing to live with a file that is tracked, but rarely has any attention paid to it, you can leave path P in the index, but set the skip-worktree bit (or the assume-unchanged bit, though it has a different purpose, and the skip-worktree bit is the one you should usually use).
Setting this bit tells Git not to compare the index version of P with the work-tree version of P. This means that Git will, in general, not report that P needs to be staged with git add
. It will sometimes seem like P is not even tracked. However, since some file content is being tracked under path P, every new commit made while in this state will continue to have the (old) content for path P. This affects you when you do finally remove P from the index, in that later git checkout
operations on these commits behave as described above, putting P back into the index.
Upvotes: 9