将目录添加到.gitignore后,从远程仓库中删除它们

853

我将一些目录提交并推送到了Github。之后,我更改了.gitignore文件,添加了一个应该被忽略的目录。一切都正常运行,但是(现在被忽略的)目录仍然留在Github上。

我该如何从Github和存储库历史记录中删除该目录?

10个回答

1444

在您的.gitignore文件中规则仅适用于未跟踪的文件。由于该目录下的文件已经提交到您的代码库中,您需要取消暂存它们,创建一个提交并将其推送到GitHub:

git rm -r --cached some-directory
git commit -m 'Remove the now ignored directory "some-directory"'
git push origin master
你不能删除历史记录中的文件而不重写仓库的历史记录 - 如果其他人在使用你的仓库,或者你在多台电脑上使用它,那么你不应该这样做。如果你仍然想要这样做,可以使用git filter-branch来重写历史记录 - 这里有一个有用的指南。此外,请注意git rm -r --cached some-directory的输出将会是这样的:
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'

rm是git对仓库的反馈,而文件仍然存在于工作目录中。


6
如果其他人进行了拉取操作,那么现在被忽略的文件是否会被删除,还是保持不变? - Martin Konicek
6
如果拉取这些更改的用户对这些文件没有进行任何修改,那么这些文件将被删除。 - Mark Longair
3
“-r”和“--cached”分别是什么意思?谢谢。 - Labanino
32
@Labanino:-r表示递归,如果你要处理整个目录,则这是必需的。--cached覆盖了git通常的行为,即从工作目录中删除文件,并将其标记为待提交的删除操作,而是使git仅在暂存区上操作,准备提交。这是告诉git你想要保留本地文件副本的方法。 - entheh
2
这很好用,但我必须先执行:git reset name_of_file 才能使上述内容起作用。 - Edvard Haugland
显示剩余5条评论

342
第一个解决方案:
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

这将删除所有在你的git ignore中的文件/文件夹,省去了你手动选择每一个的麻烦。
第二个解决方案:从您的本地git仓库中删除文件。
git rm -r --cached . 
git add .
git commit -m 'Removed all files that are in the .gitignore' 
git push origin main

--cached标志从您的git存储库中删除文件,但不会从文件系统中删除。

9
谢谢,这帮了我很多!如果您正在使用Windows PowerShell,可以执行以下命令:foreach ($i in iex 'git ls-files -i --exclude-from=.gitignore') { git rm --cached $i } - Matthew
20
我尝试了你的第二种方法,它删除了我本地 Git 中的所有文件! - artnikpro
3
我认为您应该导航到子目录并完成操作。如果我说错了,请纠正我。 - user4414636
23
孩子们,今天我们学到了什么?“不要运行你在Stack Overflow上找到的随机代码!” - Jonathan E. Landrum
3
Kris的第二种方法完全有效。这个命令如何删除@artnikpro报告的本地文件?它只会从索引中移除文件,而不会在驱动器上物理删除。 - Bhupiister singh
你可以将这个脚本保存到你的 .gitconfig 文件中,并创建一个类似这样的别名: clean-ignored = "!f() { for dir in $(git ls-files -i --exclude-from=.gitignore $@); do git rm -r --cached $dir; done; }; f" - aemonge

81

根据我在这里的回答:如何从git存储库中删除目录?

仅从git存储库中删除文件夹/目录而不是本地,请尝试以下3个简单步骤。


删除目录的步骤

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

忽略指定文件夹的步骤

如果想在下次提交时忽略某个文件夹,可以在根目录下创建一个名为.gitignore的文件,并将需要忽略的文件夹名称写入其中。可以写入任意数量的文件夹名称。

.gitignore 文件将如下所示:

/FolderName

删除目录


12
注意:这个解决方案仅适用于 Github Desktop GUI
通过使用 Github Desktop GUI 很简单。
1. 暂时将文件夹移动到另一个位置(移出项目文件夹)。 2. 编辑你的 .gitignore 文件并删除文件夹条目,该条目将在 github 页面上删除主存储库。 3. 提交和同步项目文件夹。 4. 将文件夹重新移回项目文件夹中。 5. 重新编辑 .gitignore 文件。
就是这样。

12

Blundell的第一个答案对我没有起作用。不过它给了我正确的方向。我做了与此类似的事情:

> 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

我建议您通过运行以下语句来首先检查要删除的文件:

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

我曾使用 Visual Studio 的默认 .gitignore 文件,但我发现它删除了项目中所有的日志和二进制文件夹,而这并不是我想要的结果。


如果您使用的是Windows Powershell,请使用“foreach ($i in git ls-files -i --exclude-from=.gitignore) {git rm --cached $i;}”(不包括引号)进行操作。 - Oncel Umut TURER

8

这种方法适用于标准的.gitignore行为,不需要手动指定需要忽略的文件

不能再使用--exclude-from=.gitignore了 :/ - 这是更新后的方法:

一般建议:从干净的仓库开始 - 所有内容都已提交,工作目录或索引中没有待处理的内容,并备份

#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

如果您还需要从分支的提交历史中清除新忽略的文件,或者如果您不希望新忽略的文件在未来的拉取操作中被删除,请参考这个答案

7

Blundell 的答案应该是可行的,但出于某种奇怪的原因,在我的机器上没有起作用。我不得不先将第一个命令输出的文件名导入文件中,然后循环遍历该文件并逐个删除。

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

3

如果你正在使用 Blundell 所描述的技术(删除 所有文件 ,然后添加 所有文件)在 Windows 机器上操作时,可能会面临修改了所有文件的问题,因为行结束符被更改。为避免此类情况,请执行以下命令:

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

这将从索引中删除所有文件,配置git不更改行尾,并重新规范化行尾,并暂存您刚刚删除的所有文件除了.gitignore中指定的文件。

然后执行git commit

参考:如何删除在.gitignore中列出的文件而不更改空格


2
对于Windows用户来说,这对我非常有用。
git ls-files -i -c --exclude-from=.gitignore | %{git rm --cached $_}
git add .
git commit -m "Remove files from .gitignore"

0
如果您正在使用PowerShell,请尝试以下命令作为单个命令。
PS MyRepo> git filter-branch --force --index-filter
>> "git rm --cached --ignore-unmatch -r .\\\path\\\to\\\directory"
>> --prune-empty --tag-name-filter cat -- --all

然后,执行git push --force --all
文档:https://git-scm.com/docs/git-filter-branch

使用git filter-branch与使用git rm有什么不同?最初我认为我必须使用git filter-branch的某个版本,但是这里的大多数评论建议使用git rm。据我所了解,git rm只会从当前工作目录和索引中删除它。但是,如果在之前的多个提交中添加了它,它仍将存在于存储库中。 - alpha_989
好的。git rm会从最新的提交中删除文件,直到未来。git filter-branch让我们从整个历史记录中删除它。另请参阅:https://help.github.com/articles/removing-sensitive-data-from-a-repository/ - Shaun Luttin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接