There is a file that was being tracked by git, but now the file is on the .gitignore list.

However, that file keeps showing up in git status after it's edited. How do you force git to completely forget about it?

  • 11
    git clean -X sounds similar, but it doesn't apply in this situation (when the files are still being tracked by Git). I'm writing this for anyone looking for a solution not to follow the wrong route. – imz -- Ivan Zakharyaschev Feb 27 '15 at 12:14
  • 19
    The only real answer to this is down below, see git update-index --assume-unchanged. This solution 1) keeps the file on server (index), 2) lets you modify it freely locally. – Qwerty Jan 4 '16 at 14:15
  • 3
    You need to use --skip-worktree, see: stackoverflow.com/questions/13630849/… – Doppelganger Aug 5 '16 at 20:33
  • 31
    An important question is: should the file remain in the repository or not? Eg if someone new clones the repo, should they get the file or not? If YES then git update-index --assume-unchanged <file> is correct and the file will remain in the repository and changes will not be added with git add. If NO (for example it was some cache file, generated file etc), then git rm --cached <file> will remove it from repository. – Martin Nov 22 '16 at 10:45
  • 1
    @Martin @Qwerty Everyon should stop to advise for --assume-unchanged which is for performance to prevent git to check status of big tracked files but prefer --skip-worktree which is for modified tracked files that the user don't want to commit anymore. See stackoverflow.com/questions/13630849/… – Philippe Feb 15 at 11:16

19 Answers 19

up vote 3931 down vote accepted

.gitignore will prevent untracked files from being added (without an add -f) to the set of files tracked by git, however git will continue to track any files that are already being tracked.

To stop tracking a file you need to remove it from the index. This can be achieved with this command.

git rm --cached <file>

The removal of the file from the head revision will happen on the next commit.

  • 34
    the process that workd for me was 1. commit pending changes first 2. git rm --cached <file> and commit again 3. add the file to .gitignore, check with git status and commit again – mataal Aug 13 '09 at 21:07
  • 71
    Very important adding. If file that is ignored would be modified (but in spite of this should be not committed), after modifying and executing git add . it would be added to index. And next commit would commit it to repository. To avoid this execute right after all that mataal said one more command: git update-index --assume-unchanged <path&filename> – Dao Aug 24 '11 at 16:39
  • 28
    @AkiraYamamoto 's method worked well for me as well. In my case I suppressed the output since my repository had thousands of files: git rm -r -q --cached . – Aaron Blenkush Oct 11 '13 at 15:21
  • 60
    This will delete the file on git pull though. – Petr Peller May 22 '14 at 16:04
  • 12
    git rm --cached <file> just remove file from repository, git update-index --assume-unchanged <file> not shown file in unstaged changes and does not make pull a new changes. But i want GIT JUST IGNORE CONTENT OF FILE PLEEEEEASE – Igor Semin Apr 7 '15 at 9:03

The series of commands below will remove all of the items from the Git Index (not from the working directory or local repo), and then updates the Git Index, while respecting git ignores. PS. Index = Cache

First:

git rm -r --cached . 
git add .

Then:

git commit -am "Remove ignored files"
  • 137
    To highlight the difference between this answer and the accepted one: Using this commands you don't need to actually know the affected files. (Imagine a temporary dir with lots of random files that should be cleared off the index). – Ludwig Mar 27 '14 at 10:17
  • 33
    Same as the accepted answer. Files will get deleted on git pull. – Petr Peller May 22 '14 at 16:07
  • 46
    It would be nice to have this as a standard git command. Something like git rmignored. – Berik Dec 20 '14 at 11:59
  • 8
    @gudthing -r stands for "recursive" – Monkey King Jul 15 '15 at 11:24
  • 8
    With this you may end up adding other useless files that are not currently in .gitignore. Which may be difficult to find out if depending on how noise your git status is after this command. A command that only removes newly ignored files would be better. That's why I prefer thSoft's answer – KurzedMetal Sep 22 '15 at 14:27

git update-index does the job for me:

git update-index --assume-unchanged <file>

Note: This solution is actually independent on .gitignore as gitignore is only for untracked files.

edit: Since this answer was posted, a new option has been created and that should be prefered. You should use --skip-worktree which is for modified tracked files that the user don't want to commit anymore and keep --assume-unchanged for performance to prevent git to check status of big tracked files. See https://stackoverflow.com/a/13631525/717372 for more details...

  • 119
    This IS the real answer. Awesome actually, very simple, doesn't pollute git status and actually very intuitive. Thanks. – Pablo Olmos de Aguilera C. Jan 12 '14 at 23:57
  • 4
    I went for the good enough rm [...] . solution, as at least I could grok how it worked. I found no great documentation on what update-index & --assume-unchanged do. Can anyone add how this compares to the other, in that I would like to remove all files that would have been ignored? (Or a link to clear explanation?) – Brady Trainor Mar 1 '14 at 0:12
  • 17
    git update-index --assume-unchanged <path> … will cause git to ignore changes in the specified path(s), regardless of .gitignore. If you pull from a remote and that remote has changes to this path, git will fail the merge with a conflict and you will need to merge manually. git rm --cached <path> … will cause git to stop tracking that path. If you do not add the path to .gitignore you will see the path in future git status. The first option has less noise in the git commit history and allows changes to the "ignored" file to be distributed in the future. – ManicDee Jun 25 '14 at 2:02
  • 46
    Undo by using: git update-index --no-assume-unchanged <file> – xgMz Aug 7 '14 at 19:20
  • 18
    I'm quite confused as to how this isn't the accepted answer. The accepted answer here clearly isn't answering the actual question being asked. This answer ignores changes to the file that is in the repository whilst not removing it from the repository. – Dave Cooper Dec 2 '15 at 22:46
git ls-files --ignored --exclude-standard -z | xargs -0 git rm --cached
git commit -am "Remove ignored files"

This takes the list of the ignored files and removes them from the index, then commits the changes.

  • 4
    If you need to remove them from the working directory, too, then simply run git ls-files --ignored --exclude-standard | xargs git rm . I believe this answer is the best! Because it's very clear, Unix-way, and does the wanted thing in a direct manner, without composing the side-effects of other, more complex commands. – imz -- Ivan Zakharyaschev Feb 27 '15 at 12:23
  • 4
    Great answer; however, the command will fail if you have paths with spaces on the middle, e.g.: "My dir/my_ignored_file.txt" – David Hernandez Jun 19 '15 at 15:29
  • 6
    git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm --cached – David Hernandez Jun 19 '15 at 15:36
  • 2
    git rm will complain if ls-files didn't match anything. Use xargs -r git rm ... to tell xargs not to run git rm if no files matched. – Wolfgang Jan 6 '16 at 19:15
  • 8
    It would be better to use \0 as separator: git ls-files --ignored --exclude-standard -z|xargs -0 git rm --cached – Nils-o-mat Feb 2 '16 at 10:05

I always use this command to remove those untracked files. One-line, Unix-style, clean output:

git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached

It lists all your ignored files, replace every output line with a quoted line instead to handle paths with spaces inside, and pass everything to git rm -r --cached to remove the paths/files/dirs from the index.

  • 2
    Great solution! Worked perfectly and feels more correct that removing all files then adding them back in. – Jon Catmull Sep 9 '15 at 8:59
  • 3
    I too found this "cleanest". It might be obvious, but just running the first part, git ls-files --ignored --exclude-standard, on its own lets you first understand/verify what files your new .gitignore is going to exclude/remove, before you go ahead and execute the final git rm. – JonBrave Dec 29 '15 at 11:56
  • Be aware, fails on filenames with certain "nasty" characters in them, e.g. \n. I have posted my solution to cater for this. – JonBrave Dec 29 '15 at 13:01
  • 1
    Another caveat: on pull, this will cause the file to be deleted in others' working directories, right? – LarsH Aug 19 '16 at 15:46

If you cannot git rm a tracked file because other people might need it (warning, even if you git rm --cached, when someone else gets this change, their files will be deleted in their filesystem) please look at https://gist.github.com/1423106 for ways people have worked around the problem.

  • 6
    git wouldn't remove the file, if it were dirty at the time of deletion. And if it's not dirty, retrieving the file would be as easy as git checkout <oldref> -- <filename> - but then it would be checked out and ignored. – amenthes Jul 24 '14 at 14:05
  • 1
    Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference. See here for instructions how to write better "link-based" answers. Thanks! – GhostCat Sep 28 '17 at 12:47
  • 1
    Just saying. 5 year old answer, and 45 upvotes, but nobody dare to tell "link only answers are bad?" – GhostCat Sep 28 '17 at 12:47

move it out, commit, then move it back in. This has worked for me in the past. There is probably a 'gittier' way to accomplish this.

  • This worked great if you want to ignore a bunch of files that weren't previously ignored. Though like you said, there is probably a better way for this. – Oskar Persson May 28 '13 at 16:19
  • This is exactly what I did. Simply move the files to a folder outside of git, then do "git add .", "git commit". (This removed the files) then add the gitignore, referencing the files/folders, commit again to add the gitignore file to git, then copy/move back in the folders, and they should be ignored. NB: it will appear that the files were deleted from GIT, so would probably remove them from other checkouts/pulls, as mentioned in above solutions, but since you are making copies of them initially, this isnt as much of an issue IMHO. just let the rest of the team know... – Del Sep 23 '16 at 12:04
  • This is the easiest way to get rid of wrongly committed folders. – Martlark Jan 14 '17 at 8:01
  • Seems to be the only way, that I can see. It's a massive bug (not 'feature') in git that as soon as you add a file/folder to .gitignore, it doesn't just ignore that file from that point on - forever - everywhere. – JosephK Sep 24 '17 at 9:09

What didn't work for me

(Under Linux), I wanted to use the posts here suggesting the ls-files --ignored --exclude-standard | xargs git rm -r --cached approach. However, (some of) the files to be removed had an embedded newline/LF/\n in their names. Neither of the solutions:

git ls-files --ignored --exclude-standard | xargs -d"\n" git rm --cached
git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached

cope with this situation (get errors about files not found).

So I offer

git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached

This uses the -z argument to ls-files, and the -0 argument to xargs to cater safely/correctly for "nasty" characters in filenames.

In the manual page git-ls-files(1), it states:

When -z option is not used, TAB, LF, and backslash characters in pathnames are represented as \t, \n, and \\, respectively.

so I think my solution is needed if filenames have any of these characters in them.

EDIT: I have been asked to add that --- like any git rm command --- this must be followed by a commit to make the removals permanent, e.g. git commit -am "Remove ignored files".

  • 1
    For me this is the best solution. It has much better performance than a git add .. It also contains the best improvements from some comments above. – Nils-o-mat Feb 2 '16 at 12:08
  • 1
    Great solution and works very well – smac89 Jun 15 '16 at 22:34
  • 1
    Worked a treat - removed files with whitespace in names correctly. – Dave Walker Mar 9 '17 at 16:46
  • Can you add thSoft's git commit -am "Remove ignored files" afterward to your answer? Your answers combined got me through things : j – kando Oct 6 '17 at 0:07

I accomplished this by using git filter-branch. The exact command I used was taken from the man page:

WARNING: this will delete the file from your entire history

git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD

This command will recreate the entire commit history, executing git rm before each commit and so will get rid of the specified file. Don't forget to back it up before running the command as it will be lost.

  • 6
    This will change all commit IDs, thus breaking merges from branches outside of your copy of the repository. – bdonlan Aug 13 '09 at 19:56
  • 15
    WARNING: this will delete the file from your entire history. This was what I was looking for though, to remove a completely unnecessary and oversized file (output that should never have been committed) that was committed a long time ago in the version history. – zebediah49 Mar 13 '13 at 5:49

Use this when:

1. You want to untrack a lot of files, or

2. You updated your gitignore file

Source link: http://www.codeblocq.com/2016/01/Untrack-files-already-added-to-git-repository-based-on-gitignore/

Let’s say you have already added/committed some files to your git repository and you then add them to your .gitignore; these files will still be present in your repository index. This article we will see how to get rid of them.

Step 1: Commit all your changes

Before proceeding, make sure all your changes are committed, including your .gitignore file.

Step 2: Remove everything from the repository

To clear your repo, use:

git rm -r --cached .
  • rm is the remove command
  • -r will allow recursive removal
  • –cached will only remove files from the index. Your files will still be there.

The rm command can be unforgiving. If you wish to try what it does beforehand, add the -n or --dry-run flag to test things out.

Step 3: Re add everything

git add .

Step 4: Commit

git commit -m ".gitignore fix"

Your repository is clean :)

Push the changes to your remote to see the changes effective there as well.

  1. Update your .gitignore file – for instance, add a folder you don't want to track to .gitignore.

  2. git rm -r --cached . – Remove all tracked files, including wanted and unwanted. Your code will be safe as long as you have saved locally.

  3. git add . – All files will be added back in, except those in .gitignore.


Hat tip to @AkiraYamamoto for pointing us in the right direction.

  • 1
    How about downvoted due to the fact that it won't actually work as you need a -r to run rm recursively anyway :) (Someone didn't copy correctly) – Aran Mulholland Jul 28 '16 at 1:55
  • 1
    Warning: This technique doesn't actually cause git to ignore the file, instead it actually causes git to delete the file. That means if you use this solution, any time anyone else does a git pull, the file will get deleted. So it isn't actually ignored. See the solution suggesting git update-index --assume-unchanged instead for a solution to the original question. – orrd Sep 15 '17 at 17:33

I think, that maybe git can't totally forget about file because of its conception (section "Snapshots, Not Differences").

This problem is absent, for example, when using CVS. CVS stores information as a list of file-based changes. Information for CVS is a set of files and the changes made to each file over time.

But in Git every time you commit, or save the state of your project, it basically takes a picture of what all your files look like at that moment and stores a reference to that snapshot. So, if you added file once, it will always be present in that snapshot.

These 2 articles were helpful for me:

git assume-unchanged vs skip-worktree and How to ignore changes in tracked files with Git

Basing on it I do the following, if file is already tracked:

git update-index --skip-worktree <file>

From this moment all local changes in this file will be ignored and will not go to remote. If file is changed on remote, conflict will occure, when git pull. Stash won't work. To resolve it, copy file content to the safe place and follow these steps:

git update-index --no-skip-worktree <file>
git stash
git pull 

File content will be replaced by the remote content. Paste your changes from safe place to file and perform again:

git update-index --skip-worktree <file>

If everyone, who works with project, will perform git update-index --skip-worktree <file>, problems with pull should be absent. This solution is OK for configurations files, when every developer has their own project configuration.

It is not very convenient to do this every time, when file has been changed on remote, but can protect it from overwriting by remote content.

Move or copy the file to a safe location, so you don't lose it. Then git rm the file and commit. The file will still show up if you revert to one of those earlier commits, or another branch where it has not been removed. However, in all future commits, you will not see the file again. If the file is in the git ignore, then you can move it back into the folder, and git won't see it.

  • 26
    git rm --cached will remove the file from the index without deleting it from disk, so no need to move/copy it away – bdonlan Aug 13 '09 at 19:56

The answer from Matt Fear was the most effective IMHO. The following is just a PowerShell script for those in windows to only remove files from their git repo that matches their exclusion list.

# Get files matching exclusionsfrom .gitignore
# Excluding comments and empty lines
$ignoreFiles =  gc .gitignore | ?{$_ -notmatch  "#"} |  ?{$_ -match  "\S"} | % {
                    $ignore = "*" + $_ + "*"
                    (gci -r -i $ignore).FullName
                }
$ignoreFiles = $ignoreFiles| ?{$_ -match  "\S"}

# Remove each of these file from Git 
$ignoreFiles | % { git rm $_}

git add .
  • In what situation won't this list of files be equal to the recursive --cached? – John Zabroski Jan 10 '14 at 18:47

The BFG is specifically designed for removing unwanted data like big files or passwords from Git repos, so it has a simple flag that will remove any large historical (not-in-your-current-commit) files: '--strip-blobs-bigger-than'

$ java -jar bfg.jar --strip-blobs-bigger-than 100M

If you'd like to specify files by name, you can do that too:

$ java -jar bfg.jar --delete-files *.mp4

The BFG is 10-1000x faster than git filter-branch, and generally much easier to use - check the full usage instructions and examples for more details.

Source: https://confluence.atlassian.com/bitbucket/reduce-repository-size-321848262.html

If you don't want to use the CLI and are working on Windows, a very simple solution is to use TortoiseGit, it has the "Delete (keep local)" Action in the menu which works fine.

I liked JonBrave's answer but I have messy enough working directories that commit -a scares me a bit, so here's what I've done:

git config --global alias.exclude-ignored '!git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached && git ls-files -z --ignored --exclude-standard | xargs -0 git stage && git stage .gitignore && git commit -m "new gitignore and remove ignored files from index"'

breaking it down:

git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached 
git ls-files -z --ignored --exclude-standard | xargs -0 git stage 
git stage .gitignore 
git commit -m "new gitignore and remove ignored files from index"
  • remove ignored files from index
  • stage .gitignore and the files you just removed
  • commit

In case of already committed DS_Store:

find . -name .DS_Store -print0 | xargs -0 git rm --ignore-unmatch

Ignore them by:

echo ".DS_Store" >> ~/.gitignore_global
echo "._.DS_Store" >> ~/.gitignore_global
echo "**/.DS_Store" >> ~/.gitignore_global
echo "**/._.DS_Store" >> ~/.gitignore_global
git config --global core.excludesfile ~/.gitignore_global

Finally, make a commit!

This is no longer an issue in the latest git (v2.17.1 at the time of writing).

The .gitignore finally ignores tracked-but-deleted files. You can test this for yourself by running the following script. The final git status statement should report "nothing to commit".

# Create empty repo
mkdir gitignore-test
cd gitignore-test
git init

# Create a file and commit it
echo "hello" > file
git add file
git commit -m initial

# Add the file to gitignore and commit
echo "file" > .gitignore
git add .gitignore
git commit -m gitignore

# Remove the file and commit
git rm file
git commit -m "removed file"

# Reintroduce the file and check status.
# .gitignore is now respected - status reports "nothing to commit".
echo "hello" > file
git status

protected by Josh Crozier Sep 7 '17 at 17:36

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.