58

I'm trying to remove a previously tracked directory from git, which works, but it's being added back with each subsequent git add ., git add -A, etc. Here's what I've done:

Add to .gitignore in root of project:

node_modules

Run the following:

git rm -r --cached node_modules
git commit -a -m "removed node_modules"
git push origin master

So far so good, this removes the directory from the remote repository. The problem is when I later run git status it tells me the node_modules directory is untracked and keeps adding it back on future commits.

What am I missing and/or how do I find the root of my problem?

From here:

The git add command will not add ignored files by default. ... The git add command can be used to add ignored files with the -f (force) option.

Additional information from comments:

I am tracking .gitignore file.

git check-ignore node_modules/ returns node_modules/ as expected.

No use of submodules.

Update:

I've created a sample that appears to replicate the issue following the steps above:

https://github.com/awhitehouse104/SampleRepo

Resolution:

To summarize the answer and comments from below, the issue was in the encoding of my .gitignore file. I had used echo 'node_modules' > .gitignore to create the file on windows 8 and it came out as UTF-16 with BOM (according to answer below). After a few google searches, it seems this is the default encoding with powershell and I can confirm that saving as UTF-8 seems to have resolved the issue.

tldr; Probably don't use this method of creating .gitignore files or be prepared to change the encoding

echo 'node_modules' > .gitignore

aw04
  • 10,857
  • 10
  • 56
  • 89
  • Why `git rm -r --cached ` and not `git rm -r `? That is, what is `--cached` for? – wallyk Sep 04 '15 at 15:27
  • Did you already try the answers from: http://stackoverflow.com/questions/11451535/gitignore-not-working? What's the output of 'git status' at every point along the list of commands you provide? (before and after each git command) – Blue Sep 04 '15 at 19:38
  • @Blue Yes, the top answers to that question are more or less what I've listed as having tried. I'll dig into some of the lesser answers but nothing initially jumps out at me. – aw04 Sep 04 '15 at 19:41
  • Is there anything else in your gitignore? What is the encoding of the gitignore file? Are there any trailing or leading spaces in the file? – Tim Sep 09 '15 at 21:34
  • @TimCastelijns .idea is there on the line above, unicode, no. If it was an issue with the file, would git check-ignore work properly? – aw04 Sep 10 '15 at 12:49
  • Not sure, but I'm trying to rule out edge cases – Tim Sep 10 '15 at 12:57
  • @aw04 Can you confirm if this is the case on a fresh clone of the project? I think you might have corrupted the current clone somehow. – Anshul Goyal Sep 12 '15 at 14:00
  • @mu無 I can. I tried a fresh clone for exactly that reason. – aw04 Sep 14 '15 at 12:54
  • @TimCastelijns My apologies to you. You were right about the encoding all along. – aw04 Sep 16 '15 at 15:23
  • Thanks for letting me know – Tim Sep 16 '15 at 15:24
  • for my case, I had copied the node_modules folder to make a copy, and forgot to add the copied folder to .gitignore – Ayoub Laazazi Dec 04 '20 at 20:46

10 Answers10

18

You probably have a negative rule (include-again rule, the one that starts with an !) in your .gitignore file somewhere after the node_modules line.

git check-ignore has a bug/ambiguity in the docs. You expect that if git check-ignore node_modules/ prints node_modules/, then node_modules/ is ignored. But actually it prints a pathname if that pathname matches any ignore pattern - positive or negative. The only way to be sure is to use the -v (--verbose) option, which will make git check-ignore print the matching pattern.
Moreover, if git check-ignore -v says a directory is ignored, it doesn't necessarily mean that all files in that directory are ignored. Example repo:

/
    .git/
    .gitignore
    node_modules/
        bar
        foo
$ cat .gitignore 
/node_modules/*
!/node_modules/foo

$ git check-ignore -v node_modules/
.gitignore:1:/node_modules/*    node_modules/
             ^ positive pattern => ignored

$ git check-ignore -v node_modules/foo
.gitignore:2:!/node_modules/foo node_modules/foo
             ^ negative pattern => not ignored

$ git add -A

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   node_modules/foo
#

So if git check-ignore -v node_modules/ says node_modules/ is ignored, do git add -A node_modules/ and then run git check-ignore -v --no-index against individual files that got added, to discover why they were added.


Update: I didn't expect that: your .gitignore file is in "UTF-16 with BOM (byte order mark)" encoding:

$ cat .gitignore | hexdump -vC
00000000  ff fe 6e 00 6f 00 64 00  65 00 5f 00 6d 00 6f 00  |..n.o.d.e._.m.o.|
00000010  64 00 75 00 6c 00 65 00  73 00 0d 00 0a 00        |d.u.l.e.s.....|

That's why git probably can't handle it. Save the file in UTF-8 without BOM, that should fix the problem. But I also suggest filing a bug report against git check-ignore - in this corner case its output is clearly not consistent with what git actually ignores.

Roman
  • 6,486
  • 2
  • 23
  • 41
  • There is no negative rule. The last part is very helpful to my understanding (+1), although it outputs nothing when checking the individual files. So it essentially tells me what I already knew, if I understand the expected output correctly. – aw04 Sep 14 '15 at 13:23
  • 2
    Well, that is strange. Maybe there is a bug in git... Can you show these files: `.gitignore`, `.git/info/exclude`, `$XDG_CONFIG_HOME/git/ignore` (if exists), `$HOME/.config/git/ignore` (if exists), and whatever file is reported by `git config --get-all core.excludesfile`. And maybe you could pack your entire repo using `tar` and share it here (or tell where it can be cloned from)? – Roman Sep 15 '15 at 00:01
  • It is a private repository that I do not own, but I will look at those files. – aw04 Sep 15 '15 at 13:26
  • 1
    Maybe you can create a [mcve] from that repository. – Roman Sep 15 '15 at 13:33
  • See my edit. I've created a sample that seems to replicate the issue. – aw04 Sep 16 '15 at 12:44
  • Yep, that fixed it. Thanks for all your help. I'm running windows 8, I'll have to look into this more, but because of the awkwardness of creating a .gitignore file in windows I used "echo 'node_modules' > .gitignore" to create the file. – aw04 Sep 16 '15 at 15:14
  • After one hour researching online, the encoding trick solved my issue. Thanks! – dumduke May 16 '16 at 20:07
  • Had a similar issue myself. Made my ,gitignore with the `echo` command from VSCode built-in powershell terminal. – oerdal Mar 30 '22 at 16:45
9

Add the file to git ignore, then

git update-index --assume-unchanged <file>
hspandher
  • 15,934
  • 2
  • 32
  • 45
7

You can do

git check-ignore -v --no-index path/with/unexpected/result

to see why git add did or didn't add that path.

git check-ignore docs.

In particular, the point is you want to check what's actually getting added, not a directory.

further, do find . -name .git. Submodules are nested repos, .gitmodules and the submodule command are handy but they're just there to help with them.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • 1
    This information is helpful, thank you, however git check-ignore -v --no-index on a specific file is not returning anything. It does with the folder, just not the individual files. I suppose this is telling me they are not being ignored for some reason, but it's not telling me why. – aw04 Sep 15 '15 at 13:24
4

Here is what I do to ignore node_modules folder after I tracked it.

  1. Create the .gitignore file and add node_modules to it.

  2. Commit the .gitignore file. After this point, whatever you update in the node_modules folder won't appear in git status.

  3. But this does not delete what we already have on the repo under the node_modules folder. So now we need to remove whatever we have committed previously.

    For this, use git rm --cached node_modules -r

  4. Now git status will show that the files are deleted.

  5. Use git commit -m "node_modules removed" command with any message.

Now everything should be removed from the repo and future changes will not be tracked.

Community
  • 1
  • 1
shan1024
  • 1,389
  • 7
  • 17
  • 1
    This has the same result as the steps in my question. It works but adds the files back with the next git add – aw04 Sep 10 '15 at 13:01
0

Another approach if you don't want to use git rm --cached

rm -Rf node_modules
git add -u
git commit -m "stop tracking node_modules"

npm install
# done

Also note the distinction between node_modules and node_modules/ which you seem to have correct. (Thanks umläute for the note on this)

Jonathan.Brink
  • 23,757
  • 20
  • 73
  • 115
  • 1
    what is the reasoning to *not* add `node_modules/` (with trailing-slash)? if you want to make sure that only directories matching a pattern are excluded (and not files of the same name) adding a trailing-slash is the way to go... – umläute Sep 09 '15 at 18:42
  • I forget what system I was on, but I believe in the past my gitignore hasn't worked properly if I had ending slashes in my .gitignore file. Thanks @umläute I edited my post – Jonathan.Brink Sep 09 '15 at 18:44
  • nice thought, but it doesn't keep the files from being added back – aw04 Sep 10 '15 at 13:21
0

gitignore - Specifies intentionally untracked files to ignore.

$HOME/.config/git/ignore, $GIT_DIR/info/exclude, .gitignore

Each line in a gitignore file specifies a pattern. When deciding whether to ignore a path, Git normally checks gitignore patterns from multiple sources, with the following order of precedence, from highest to lowest (within one level of precedence, the last matching pattern decides the outcome):

To ignore entire directory you should use /**,

A trailing /** matches everything inside. For example, abc/** matches all files inside directory "abc", relative to the location of the .gitignore file, with infinite depth.

Or

You can ignore the entire directory by adding this line to your root .gitignore file:

/Dir_Name

Instead, you can add a /logs/.gitignore file containing this:

[^.]*

The directory will remain in your repo, but all files inside /directory will be ignored. Easy!

The steps you need to follows are,

  1. Remove it from the project directory (without actually deleting it):

    git rm --cached folder/*

  2. If you don't already have a .gitignore, you can make one right inside of your project folder:
  3. project/.gitignore. Put folder/* (or any of the pattern you think better from above listing) in the .gitignore Commit:
  4. git commit -m "message".
  5. Push your change to github.

Example to exclude everything except a specific directory foo/bar (note the /* - without the slash, the wildcard would also exclude everything within foo/bar):

$ cat .gitignore
# exclude everything except directory foo/bar
/*
!/foo
/foo/*
!/foo/bar
Usman Maqbool
  • 3,351
  • 10
  • 31
  • 48
0

I created a repository to try and duplicate your issue, and I got the first answer from http://www.stackoverflow.com/questions/11451535/gitignore-not-working to work.

Here's my repo if you are curious: https://github.com/IAMZERG/so_project_gitignore

Try adding this to the .gitignore instead:

**/directory_to_remove

After that, run git rm --cached directory_to_remove -r

git status should show that you deleted a bunch of files in the directory you are trying to remove. Then, commit and push to your remote, and everything should be golden... Maybe?

IAMZERG
  • 100
  • 9
  • So were you able to reproduce the issue before attempting to solve it? – aw04 Sep 16 '15 at 12:30
  • I was able to fix your problem. Initially, I tried fixing it by writing the .gitignore file in utf-8 in vim using :w ++enc=utf-8 .gitignore, but that didn't seem to solve the problem. I removed the node_modules and the .gitignore file using git rm, and created another .gitignore. I committed those changes together, added my new .gitignore, and things seemed to just work.... Don't know why I thought the leading **/ would help... that doesn't matter in the least. Here's my forked repo with the fix: [SampleRepo](https://github.com/IAMZERG/SampleRepo) – IAMZERG Sep 16 '15 at 20:31
0

I've found a way to add files to .gitignore even if they have already been commited once. It's a bit brutal but it works great.

  1. Add the different files to your .gitignore

  2. Move these files out from your git project

  3. Rescan & StageChanged, these operation will tell you that these files have been deleted

  4. Commit

  5. Move back your files to your project, they won't be tracked anymore !

Syscall
  • 19,327
  • 10
  • 37
  • 52
Mwiapfeo
  • 1
  • 1
-1

The origin has to be bare. Here is a little bash to demonstrate it. Feel free to edit it, if it does not represent your use case.

#!/bin/bash

rm -rf /tmp/git_test
mkdir /tmp/git_test/
git init --bare /tmp/git_test/primary_repo

# populate repo
cd /tmp/git_test/
git clone ./primary_repo ./secondary_repo
cd secondary_repo
echo hi_bob > some_content
mkdir node_modules
echo hi_dave > node_modules/moduleA
git add .
git commit -m "populated primary"
git push

# do the removal in tertiary 
cd /tmp/git_test/
git clone ./primary_repo ./tertiary_repo
cd tertiary_repo
echo node_modules >> .gitignore
git add .gitignore
git rm -r --cached node_modules
git commit -a -m "removed node_modules"
git push origin master
rm -r node_modules
echo --------------------------------
echo git status:
git status
Fabian
  • 11
  • 2
  • Can you expand on what you mean by 'The origin has to be bare'? – aw04 Sep 10 '15 at 12:50
  • a bare repository has no working copy. When i first set up the experiment with a non bare repository the push was rejected and primary had the directory still hanging around. Where does your origin reside? – Fabian Sep 11 '15 at 07:51
  • @aw04: Can you please present a script to replicate your problems? That would be easier, than working from a verbal description. – Fabian Sep 11 '15 at 07:53
-1

I had a similary issue. Making sure my encoding was ANSI and the line endings were Unix(LF) fixed my issue.

Austin Miller
  • 34
  • 1
  • 4