836

I committed and pushed some directory to github. After that, I altered the .gitignore file adding a directory that should be ignored. Everything works fine, but the (now ignored) directory stays on github.

How do I delete that directory from github and the repository history?

melpomene
  • 84,125
  • 8
  • 85
  • 148
janw
  • 8,605
  • 3
  • 18
  • 13

10 Answers10

1423

The rules in your .gitignore file only apply to untracked files. Since the files under that directory were already committed in your repository, you have to unstage them, create a commit, and push that to GitHub:

git rm -r --cached some-directory
git commit -m 'Remove the now ignored directory "some-directory"'
git push origin master

You can't delete the file from your history without rewriting the history of your repository - you shouldn't do this if anyone else is working with your repository, or you're using it from multiple computers. If you still want to do that, you can use git filter-branch to rewrite the history - there is a helpful guide to that here.

Additionally, note the output from git rm -r --cached some-directory will be something like:

rm 'some-directory/product/cache/1/small_image/130x130/small_image.jpg'
rm 'some-directory/product/cache/1/small_image/135x/small_image.jpg'
rm 'some-directory/.htaccess'
rm 'some-directory/logo.jpg'

The rm is feedback from git about the repository; the files are still in the working directory.

Krista K
  • 21,503
  • 3
  • 31
  • 43
Mark Longair
  • 446,582
  • 72
  • 411
  • 327
  • 5
    If someone else pulls, will the now ignored files be deleted for them or stay untouched? – Martin Konicek Sep 17 '12 at 17:19
  • 5
    @Martin Konicek: if the user that's pulling those changes has no modifications to those files, then they will be removed. – Mark Longair Sep 29 '12 at 09:40
  • 30
    @Labanino: `-r` means recursive, necessary if you're doing whole directories. `--cached` overrides git's normal behaviour of deleting them from the working directory _and_ staging the deletion for committing, and makes git only operate on the staging area ready for committing. It's how you tell git you want to keep your local copies of the files. – entheh Apr 08 '15 at 18:16
  • 2
    This works nice, but I had to first do: `git reset name_of_file` for what's described above to work – Edvard Haugland Sep 24 '17 at 10:53
  • 1
    From my Git v 2.21.0 on Windows 10 x64. `git commit -m 'message'` have to be `git commit -m "message"` and `git push origin master` just use `git push`. – vee May 24 '19 at 17:42
  • This works and recursively removed the entire directory, but what if I have the same directory in multiple places (e.g. a ```.vscode``` directory)? Is there a way to recursively hunt down all such instances or do I have to do it manually? – gcr Feb 06 '21 at 04:29
  • My question is same as Martin Konicek i.e if another person pulls the changes and has the same file (No edition done) before other person deleted in the way @MarkLongair suggested, then he will get that file appearing as untracked. How to resolve it. – Sanpreet Dec 24 '21 at 18:25
  • Continuing discussion with respect to my previous comment @MartinKonicek I used the below command to remove the untracked files when i did not get the changes from the git pull `git reset --hard HEAD` `git clean -f -d` `git pull` I am doing in the right way. – Sanpreet Dec 24 '21 at 18:40
  • "git push origin main" in many cases instead of "git push origin master" – Isak La Fleur Oct 05 '22 at 22:04
338

First solution:

git rm --cached `git ls-files -i -c --exclude-from=.gitignore` 
git commit -m 'Removed all files that are in the .gitignore' 
git push origin main

Which will remove all the files/folders that are in your git ignore, saving you have to pick each one manually


Second solution: which removes files from your local git repository. git rm -r --cached . git add . git commit -m 'Removed all files that are in the .gitignore' git push origin main

The --cached flag deletes the file from your git repository but not from the filesystem.

Community
  • 1
  • 1
Blundell
  • 75,855
  • 30
  • 208
  • 233
  • 9
    Thanks, this helped me a lot! If you're using windows powershell, you can do `foreach ($i in iex 'git ls-files -i --exclude-from=.gitignore') { git rm --cached $i }` – Matthew Mar 31 '13 at 03:08
  • 19
    Tried your second approach, it removed all the files from my local git! – artnikpro Jan 24 '15 at 23:24
  • 3
    I think you're supposed to navigate to the subdirectory and do it. Correct me if I'm wrong. –  May 27 '15 at 13:46
  • 19
    So what have we learned today, children? "Don't run random code you find on Stack Overflow!" – Jonathan E. Landrum Jun 05 '20 at 19:52
  • 3
    The second approach by Kris works perfectly fine. How can this command remove local files as reported by @artnikpro . It only removes file from index and not physically on drive. – Bhupiister singh Mar 26 '21 at 04:54
  • You can save this script into your **.gitconfig** and make an alias for it like this: `clean-ignored = "!f() { for dir in $(git ls-files -i --exclude-from=.gitignore $@); do git rm -r --cached $dir; done; }; f"` – aemonge Apr 16 '21 at 10:25
80

As per my Answer here: How to remove a directory from git repository?

To remove folder/directory only from git repository and not from the local try 3 simple steps.


Steps to remove directory

git rm -r --cached FolderName
git commit -m "Removed folder from repository"
git push origin master

Steps to ignore that folder in next commits

To ignore that folder from next commits make one file in root named .gitignore and put that folders name into it. You can put as many as you want

.gitignore file will be look like this

/FolderName

remove directory

Community
  • 1
  • 1
Suresh Karia
  • 17,550
  • 18
  • 67
  • 85
12

Note: This solution works only with Github Desktop GUI.

By using Github Desktop GUI it is very simple.

  1. Move the folder onto another location (to out of the project folder) temporarily.

  2. Edit your .gitignore file and remove the folder entry which would be remove master repository on the github page.

  3. Commit and Sync the project folder.

  4. Re-move the folder into the project folder

  5. Re-edit .gitignore file.

That's all.

efkan
  • 12,991
  • 6
  • 73
  • 106
12

Blundell's first answer didn't work for me. However it showed me the right way. I have done the same thing like this:

> for i in `git ls-files -i --exclude-from=.gitignore`; do git rm --cached $i; done
> git commit -m 'Removed all files that are in the .gitignore'
> git push origin master

I advise you to check the files to be deleted first by running the below statement:

git ls-files -i --exclude-from=.gitignore

I was using a default .gitignore file for visual studio and I noticed that it was removing all log and bin folders in the project which was not my intended action.

Oncel Umut TURER
  • 569
  • 10
  • 16
  • Use "foreach ($i in git ls-files -i --exclude-from=.gitignore) {git rm --cached $i;}" without the quotes if you are using windows powershell. – Oncel Umut TURER Apr 05 '21 at 21:38
8

This method applies the standard .gitignore behavior, and does not require manually specifying the files that need to be ignored.

Can't use --exclude-from=.gitignore anymore :/ - Here's the updated method:

General advice: start with a clean repo - everything committed, nothing pending in working directory or index, and make a backup!

#commit up-to-date .gitignore (if not already existing)
#this command must be run on each branch
git add .gitignore
git commit -m "Create .gitignore"

#apply standard git ignore behavior only to current index, not working directory (--cached)
#if this command returns nothing, ensure /.git/info/exclude AND/OR .gitignore exist
#this command must be run on each branch
git ls-files -z --ignored --exclude-standard | xargs -0 git rm --cached

#optionally add anything to the index that was previously ignored but now shouldn't be:
git add *

#commit again
#optionally use the --amend flag to merge this commit with the previous one instead of creating 2 commits.

git commit -m "re-applied modified .gitignore"

#other devs who pull after this commit is pushed will see the  newly-.gitignored files DELETED

If you also need to purge the newly-ignored files from the branch's commit history or if you don't want the newly-ignored files to be deleted from future pulls, see this answer.

Community
  • 1
  • 1
goofology
  • 914
  • 2
  • 10
  • 21
7

The answer from Blundell should work, but for some bizarre reason it didn't do with me. I had to pipe first the filenames outputted by the first command into a file and then loop through that file and delete that file one by one.

git ls-files -i --exclude-from=.gitignore > to_remove.txt
while read line; do `git rm -r --cached "$line"`; done < to_remove.txt
rm to_remove.txt
git commit -m 'Removed all files that are in the .gitignore' 
git push origin master
Aran Mulholland
  • 23,555
  • 29
  • 141
  • 228
Chris Aelbrecht
  • 2,051
  • 21
  • 25
3

If you're using the technique described by Blundell (remove everything then add everything) on a windows machine you may hit an issue with all the files being modified because the line endings change. To avoid that use the following commands:

git rm -r --cached .
git config --global core.autocrlf false
git add --renormalize .
git add .

This removes all files from the index, configures git to not change line endings, renormalises line endings and stages all the files you just removed except those specified in the .gitignore

Then git commit

Reference: How to remove files from repository listed in .gitignore without changing whitespace

Colin
  • 22,328
  • 17
  • 103
  • 197
2

For windows users, this worked great for me

git ls-files -i -c --exclude-from=.gitignore | %{git rm --cached $_}
git add .
git commit -m "Remove files from .gitignore"
Hosam Rehani
  • 490
  • 6
  • 10
0

If you're working from PowerShell, try the following as a single command.

PS MyRepo> git filter-branch --force --index-filter
>> "git rm --cached --ignore-unmatch -r .\\\path\\\to\\\directory"
>> --prune-empty --tag-name-filter cat -- --all

Then, git push --force --all.

Documentation: https://git-scm.com/docs/git-filter-branch

Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467
  • How is using `git filter-branch` different from using `git rm`? I was originally thinking I have to use a version of `git filter-branch` but most comments here recommend using `git rm`. From what I understand `git rm` only removes it from the current working directory and index. But if its added multiple commits before, it will still be in the repository. – alpha_989 Jan 21 '18 at 18:32
  • Right. `git rm` will remove the file from the latest commit into the future. `git filter-branch` lets us remove it from the entire history. See also: https://help.github.com/articles/removing-sensitive-data-from-a-repository/ – Shaun Luttin Jan 22 '18 at 00:52