我的存储库中有一些文件应该被忽略,我将它们添加到 .gitignore 但是,当然,它们并没有从我的存储库中删除。
所以我的问题是,是否有一个使用 filter-branch 的神奇命令或脚本可以重写我的历史记录并轻松删除所有这些文件?或者只是一个将创建将删除它们的提交的命令?
您可以手动将它们从存储库中删除:
git rm --cached file1 file2 dir/file3
或者,如果您有很多文件:
git rm --cached `git ls-files -i -c --exclude-from=.gitignore`
但这似乎不适用于 Windows 上的 Git Bash。它会产生一条错误消息。以下效果更好:
git ls-files -i -c --exclude-from=.gitignore | xargs git rm --cached
在 Windows 上的 PowerShell 中,这效果更好(处理路径和文件名中的空格):
git ls-files -i -c --exclude-from=.gitignore | %{git rm --cached $_}
关于在没有这些文件的情况下重写整个历史,我非常怀疑是否有一种自动的方法可以做到这一点。
而且我们都知道重写历史是不好的,不是吗?:)
无论操作系统如何,一种更简单的方法是
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 中)会给你帮助。
请注意,此命令还将删除不在暂存区域中的新文件。
希望能帮助到你。
通过使用 sed 操作 .gitignore 语句的输出,我做了一个非常简单的解决方案:
cat .gitignore | sed '/^#.*/ d' | sed '/^\s*$/ d' | sed 's/^/git rm -r /' | bash
解释:
" git clean
" ( man )和( man )在处理或显示被忽略目录中的被忽略路径时感到困惑,这已在 Git 2.32(2021 年第二季度)中得到纠正。git ls-files -i
这意味着接受的答案的 2021 版本将是:
git ls-files -i -c --exclude-from=.gitignore | xargs git rm --cached
^^
参见Elijah Newren ( ) 的提交b548f0f、提交dd55fc0、提交 aa6e1b2、提交 a97c7a8、提交 2e4e43a、提交 b338e9f、提交 7fe1ffd、提交 7f9dd87(2021 年 5 月 12 日)。
请参阅Derrick Stolee ( ) 的提交 4e689d8(2021 年 5 月 12 日)。(由Junio C Hamano 合并 -- --在提交 33be431中,2021 年 5 月 20 日)newren
derrickstolee
gitster
ls-files
: 除非指定了 -o 或 -c,否则 -i 会出错签字人:以利亚·纽伦
ls-files --ignored
( man )可以与--others
or一起使用--cached
。在迷惑了一段时间并深入研究代码之后,我认为它
ls-files -i
只是坏了,没有打印任何东西,当我终于意识到-i
可以用来--cached
查找跟踪的忽略时,我准备好提交一个不错的补丁。虽然这是我的错误,仔细阅读文档可能会更清楚这一点,但我怀疑这也是其他人可能犯的错误。
事实上,在我们的测试套件中的两种用途中,我相信两者中的一种确实犯了这个错误。
在 t1306.13 中,没有跟踪文件,并且在该测试和之前的测试中建立和使用的所有排除项都必须与未跟踪文件有关。
然而,由于他们正在寻找一个空的结果,这个错误并没有被注意到,因为他们的错误命令也恰好给出了一个空的答案。
-i
将大部分时间与 一起使用-o
,这表明我们可以在没有 a或的情况下进行-i
暗示,但这将是一个向后不兼容的中断。 相反,让我们只标记没有 a或作为错误,并更新两个相关的测试用例以指定它们的意图。-o
-o
-c
-i
-o
-c
这意味着如果没有-c
,您将获得(从 Git 2.32 开始,2021 年第二季度):
fatal: ls-files -i must be used with either -o or -c
注意:这仍在进行中,因为它已在 Git 2.32-rc2 中恢复,但已通过Junio C Hamano ( )的提交 2c9f1bf和提交 1df046b(2021 年 5 月 27 日)修复。
请参阅Elijah Newren ( ) 的提交 906fc55(2021 年 5 月 27 日)。
请参阅Derrick Stolee ( ) 的提交 eef8148(2021 年 5 月 27 日)。(由Junio C Hamano 合并——在提交 329d63e中,2021 年 5 月 28 日)gitster
newren
derrickstolee
gitster
dir
: 介绍readdir_skip_dot_and_dotdot()
助手签字人:以利亚·纽伦
如果您真的想修剪.gitignore
d 文件的历史记录,请首先保存.gitignore
在 repo 之外,例如 as /tmp/.gitignore
,然后运行
git filter-branch --force --index-filter \
"git ls-files -i -X /tmp/.gitignore | xargs -r git rm --cached --ignore-unmatch -rf" \
--prune-empty --tag-name-filter cat -- --all
笔记:
git filter-branch --index-filter
在.git
我认为的目录中运行,即如果你想使用相对路径,你必须先添加../
一个。显然,由于某种原因,您不能使用../.gitignore
实际.gitignore
文件,它会产生“致命:不能使用 ../.gitignore 作为排除文件”(可能在git filter-branch --index-filter
工作目录(认为)为空期间?)git ls-files -iX <(git show $(git hash-object -w .gitignore))
来避免在.gitignore
其他地方复制,但仅此一项就已经返回一个空字符串(而cat <(git show $(git hash-object -w .gitignore))
确实.gitignore
按预期打印了 's 的内容),所以我不能使用<(git show $GITIGNORE_HASH)
in git filter-branch
....gitignore
-clean 特定分支,--all
请在最后一行替换为它的名称。那时可能无法正常工作,--tag-name-filter cat
即您可能无法直接正确传输单个分支的标签在 linux 中,您可以使用以下命令:
例如我想删除*.py~
所以我的命令应该是 ==>
find . -name "*.py~" -exec rm -f {} \;
该解决方案添加了回车符(我是 WSL 用户,所以这很重要)和括号转义(有时这对 LaTeX 用户很重要,例如*.synctex(busy)
)。
受斯科特解决方案的启发:
cat .gitignore | sed "s/\r//" | sed -r "/^(#.*|\s*)$/d" | sed -r "s/([()])/\\\\\1/g" | sed "s/^/git rm -r /" | bash
s/\r//
)。/^#.*$/
)、空行组 ( /^\s*$/
、匹配空格或空行)。注意管道|
字符,这是标准的正则表达式,并且需要-r
(尽管我相信-E
也可以)。/([()])/
及其转义版本\\\1
,\1
匹配组,在这种情况下,它表示[()]
, or (
or )
, 任何匹配的内容。注意g
标志,这是为了匹配(并替换)所有括号。可以重写,就"s/(\(|\))/\\\\\1/g"
好像你喜欢那样。git rm -r
更换的样子s/$old/$new/$flags
。删除看起来像/$old/d
。前置是替换/^/
. 你可以通过替换来追加/$/
。当然,有些字符会被转义,因为据我所知,你不能在 bash 中制作原始字符串。最后,这行可以压缩,但为了可读性,我选择将其扩展。
我看到有人质疑(在斯科特的解决方案中)这sed
是直截了当的。我喜欢将这种方法视为最基本和最猴子的方法,这很好,因为如果您需要这种方法的变体,您可以当场制作。如果有的话,这是练习正则表达式的好借口。
将 .gitignore 模式添加到 .gitignore 后,git 将忽略匹配的文件。
但是存储库中已经存在的文件仍然存在。
用于git rm files_ignored; git commit -m 'rm no use files'
删除被忽略的文件。