我在我的存储库中有一些文件应该被忽略,我将它们添加到.gitignore,但是,当然,它们不会从我的存储库中删除。
所以我的问题是,是否有一个神奇的命令或脚本使用过滤器分支,可以重写我的历史,并轻松删除所有这些文件?或者只是一个创建提交并删除它们的命令?
我在我的存储库中有一些文件应该被忽略,我将它们添加到.gitignore,但是,当然,它们不会从我的存储库中删除。
所以我的问题是,是否有一个神奇的命令或脚本使用过滤器分支,可以重写我的历史,并轻松删除所有这些文件?或者只是一个创建提交并删除它们的命令?
当前回答
“git clean”(man)和git ls-files -i(man)在处理或显示被忽略目录中的被忽略路径时会混淆,这已在git 2.32 (Q2 2021)中得到更正。
这意味着2021年版本的公认答案将是:
git ls-files -i -c --exclude-from=.gitignore | xargs git rm --cached
^^
参见Elijah Newren (Newren)的commit b548f0f, commit dd55fc0, commit aa6e1b2, commit a97c7a8, commit 2e4e43a, commit b338e9f, commit 7fe1ffd, commit 7f9dd87(2021年5月12日)。 参见Derrick Stolee提交的4e689d8(2021年5月12日)。 (由Junio C Hamano—gitster—在commit 33be431中合并,2021年5月20日)
Ls-files:除非指定了-o或-c,否则在-i上出错 署名:以利亚·纽伦
ls-files --ignored(man) can be used together with either --others or --cached. After being perplexed for a bit and digging in to the code, I assumed that ls-files -i was just broken and not printing anything and I had a nice patch ready to submit when I finally realized that -i can be used with --cached to find tracked ignores. While that was a mistake on my part, and a careful reading of the documentation could have made this more clear, I suspect this is an error others are likely to make as well. In fact, of two uses in our testsuite, I believe one of the two did make this error. In t1306.13, there are NO tracked files, and all the excludes built up and used in that test and in previous tests thus have to be about untracked files. However, since they were looking for an empty result, the mistake went unnoticed as their erroneous command also just happened to give an empty answer. -i will most the time be used with -o, which would suggest we could just make -i imply -o in the absence of either a -o or -c, but that would be a backward incompatible break. Instead, let's just flag -i without either a -o or -c as an error, and update the two relevant testcases to specify their intent.
这意味着没有-c,你会得到(从Git 2.32开始,Q2 2021):
fatal: ls-files -i must be used with either -o or -c
注意:这仍然是一项正在进行的工作,因为它在Git 2.32-rc2中被恢复,但由Junio C Hamano (gitster)在commit 2c9f1bf, commit 1df046b(2021年5月27日)中修复。 参见Elijah Newren (Newren)提交的906fc55(2021年5月27日)。 参见Derrick Stolee (derrickstolee)的commit eef8148(2021年5月27日)。 (由Junio C Hamano—gitster—在commit 329d63e中合并,2021年5月28日)
Dir:引入readdir_skip_dot_and_dotdot() helper 署名:以利亚·纽伦
其他回答
不管操作系统是什么,一个更简单的方法是
git rm -r --cached .
git add .
git commit -m "Drop files from .gitignore"
你基本上删除并重新添加所有文件,但是git add会忽略.gitignore中的文件。
使用——cached选项将文件保存在文件系统中,这样就不会从磁盘中删除文件。
注意: 有些人在评论中指出,你将失去所有文件的历史记录。我在MacOS上用git 2.27.0进行了测试,结果不是这样。如果你想检查发生了什么,在你提交之前检查你的git diff HEAD~1。
由于.gitignore中的文件没有被跟踪,您可以使用git clean命令递归地删除不受版本控制的文件。
使用git clean -xdn执行一个演练,看看将删除什么。 然后使用git clean -xdf来执行它。
基本上,git clean -h或man git-clean(在unix中)将为您提供帮助。
注意,该命令还将删除暂存区域中不存在的新文件。
这个解决方案增加了回车符(我是一个WSL用户,所以这很重要)和圆括号转义(有时对LaTeX用户很重要,例如*.synctex(busy))。
受到Scott解决方案的启发:
cat .gitignore | sed "s/\r//" | sed -r "/^(#.*|\s*)$/d" | sed -r "s/([()])/\\\\\1/g" | sed "s/^/git rm -r /" | bash
Remove: carriage returns (s/\r//). Remove lines containing: comments (/^#.*$/), empty line groups (/^\s*$/, matches whitespace or empty line). Notice the pipe | character, this is standard regex, and requires -r (although I believe -E also works). Replace: parenthesis /([()])/ with its escaped version \\\1, \1 matches the group, in this case it means [()], or ( or ), whatever was matched. Notice the g flag, this is to match (and replace) all parenthesis. Could be rewritten as "s/(\(|\))/\\\\\1/g" if you're into that. Prepend git rm -r
替换看起来像s/$old/$new/$flags。删除看起来像/$old/d。Prepending替换/^/。你可以通过替换/$/来追加。当然,有些字符是转义的,因为据我所知,你不能在bash中创建原始字符串。最后,这一行可以压缩,但为了可读性,我选择将其展开。
我看到有人质疑(在Scott的解决方案中)sed是直截了当的。我喜欢把这个方法看作是最基本最简单的方法,这很好,因为如果你需要它的变化,你可以当场做出来。如果有的话,这是一个练习正则表达式的好借口。
通过使用sed操作.gitignore语句的输出,我做了一个非常简单的解决方案:
Cat .gitignore | sed '/^#。* / d ' | sed ' / ^ \ s *美元/ d ' | sed ' s / ^ / git rm - r / | bash
解释:
打印.gitignore文件 从打印中删除所有注释 删除所有空行 在行首添加'git rm -r ' 执行每一行。
“git clean”(man)和git ls-files -i(man)在处理或显示被忽略目录中的被忽略路径时会混淆,这已在git 2.32 (Q2 2021)中得到更正。
这意味着2021年版本的公认答案将是:
git ls-files -i -c --exclude-from=.gitignore | xargs git rm --cached
^^
参见Elijah Newren (Newren)的commit b548f0f, commit dd55fc0, commit aa6e1b2, commit a97c7a8, commit 2e4e43a, commit b338e9f, commit 7fe1ffd, commit 7f9dd87(2021年5月12日)。 参见Derrick Stolee提交的4e689d8(2021年5月12日)。 (由Junio C Hamano—gitster—在commit 33be431中合并,2021年5月20日)
Ls-files:除非指定了-o或-c,否则在-i上出错 署名:以利亚·纽伦
ls-files --ignored(man) can be used together with either --others or --cached. After being perplexed for a bit and digging in to the code, I assumed that ls-files -i was just broken and not printing anything and I had a nice patch ready to submit when I finally realized that -i can be used with --cached to find tracked ignores. While that was a mistake on my part, and a careful reading of the documentation could have made this more clear, I suspect this is an error others are likely to make as well. In fact, of two uses in our testsuite, I believe one of the two did make this error. In t1306.13, there are NO tracked files, and all the excludes built up and used in that test and in previous tests thus have to be about untracked files. However, since they were looking for an empty result, the mistake went unnoticed as their erroneous command also just happened to give an empty answer. -i will most the time be used with -o, which would suggest we could just make -i imply -o in the absence of either a -o or -c, but that would be a backward incompatible break. Instead, let's just flag -i without either a -o or -c as an error, and update the two relevant testcases to specify their intent.
这意味着没有-c,你会得到(从Git 2.32开始,Q2 2021):
fatal: ls-files -i must be used with either -o or -c
注意:这仍然是一项正在进行的工作,因为它在Git 2.32-rc2中被恢复,但由Junio C Hamano (gitster)在commit 2c9f1bf, commit 1df046b(2021年5月27日)中修复。 参见Elijah Newren (Newren)提交的906fc55(2021年5月27日)。 参见Derrick Stolee (derrickstolee)的commit eef8148(2021年5月27日)。 (由Junio C Hamano—gitster—在commit 329d63e中合并,2021年5月28日)
Dir:引入readdir_skip_dot_and_dotdot() helper 署名:以利亚·纽伦