javadba javadba - 1 month ago 15
Git Question

git status is showing "Changes not staged for commit" for files listed in .gitignore?

Let is look at the .gitignore file - to which I added mllib/pom.xml and pom.xml and even .gitignore (which should not be necessary - so something is amiss..):

$head .gitignore
.gitignore
mllib/pom.xml
pom.xml


So then let's see what files git wants to add:

$ git status
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: .gitignore
modified: mllib/pom.xml
modified:


UPDATE There are two comments about not "ignoring the .gitignore". But after removing the .gitignore again we get this:

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: .gitignore
modified: mllib/pom.xml


So (a) .gitignore is showing up and (b) the specific file that really is important not to add to a commit - mllib/pom.xml - also shows up.

Answer

The .gitignore file doesn't mean what you think it means.1

In particular, once you have made a file "known" to git, in that it's in the index, adding that file's name to .gitignore has no effect. Git already tracks the file, and it will continue to track it.

In essence, the .gitignore file is not actually a list of files to ignore. Instead, when git comes across a case of an "untracked" file and is about to report it to you, the .gitignore contents are a list of names it should suppress.

For the .gitignore file itself you probably just want to git add the changes and commit them, since as a general rule, anyone cloning your repository probably wants to ignore the same set of untracked files, so .gitignore should be tracked and version-controlled.

For the XML file, however, it may be "generated content" that you don't want version-controlled, but you still want to keep it in the work-tree. This is a bit of a problem, because git is already tracking it and will insist on continuing to version-control the file.

What you can do at this point is remove it from git's index, but not from the work-tree:

git rm --cached mllib/pom.xml

That's fine as far as it goes (git removes the file from the index and the next commit will lack that file), but it creates problems if you ever go back to a commit that does have the file, because git will see that it needs to create the file—you're moving from a commit in which the file does not exist (a recent one) to a commit in which it does exist (an old one)—and may complain that the contents of that file will be clobbered. Or, even if this part works, if you then move back to a recent version, getting away from the old version, git will compare the old and new versions and see that the file has been removed ... and will remove mllib/pom.xml.

Re-edit, 20 Oct 2016: Use git update-index --skip-worktree, not git update-index --assume-unchanged. This sets a more powerful bit in the index. See Git - Difference Between 'assume-unchanged' and 'skip-worktree'. Edit: as Schwern noted in a comment below, you can use git update-index --assume-unchanged to make git not even look at the file for changes, rather than using git rm --cached to take it out of the index (see this answer for details). This is also fine as far as it goes, you just may have to do it again (or have all your co-workers do it themselves) on any other/new clones.

(You can recover from the latter by using git show <oldrev>:mllib/pom.xml > mllib/pom.xml to dump the file to standard output, and redirect standard output to re-create the file.)


1Inconceivable!

(More seriously, everyone makes this mistake. Probably gitignore was the wrong name, and something like git-screen-away-untracked might have been better, if klunkier. However, listing a file in .gitignore has other side effects as well: specifically, it permits Git to clobber such files in some cases.)