如何让 Git 忘记已跟踪但现在位于 .gitignore 中的文件?

git gitignore git-rm

Git 正在跟踪一个文件,但现在该文件位于 .gitignore 列表中。但是,该文件在编辑后一直显示在 git status 中。我如何强制 Git 完全忘记它?

git clean -X 听起来很相似,但不适用于这种情况(当 Git 仍在跟踪文件时)。我正在为任何寻求不走错误路线的解决方案的人写这篇文章。

唯一真正的答案在下面,请参阅 git update-index --assume-unchanged。此解决方案 1) 将文件保存在服务器(索引)上,2) 让您可以在本地自由修改它。

您需要使用 --skip-worktree,请参阅:stackoverflow.com/questions/13630849/…

一个重要的问题是:文件是否应该保留在存储库中?例如,如果有人新克隆了 repo,他们是否应该得到文件?如果 YESgit update-index --assume-unchanged <file> 是正确的,文件将保留在存储库中,并且不会使用 git add 添加更改。如果 NO(例如,它是某个缓存文件、生成的文件等),则 git rm --cached <file> 会将其从存储库中删除。

@Martin @Qwerty 每个人都应该停止为 --assume-unchanged 提供建议,这是为了防止 git 检查大型跟踪文件的状态,但更喜欢 --skip-worktree ,这是用户不想再提交的已修改跟踪文件。请参阅stackoverflow.com/questions/13630849/…

m
mbds

.gitignore 将阻止将未跟踪的文件(没有 add -f)添加到 Git 跟踪的文件集中。但是,Git 将继续跟踪任何已经被跟踪的文件。

要停止跟踪文件,您需要将其从索引中删除。这可以通过这个命令来实现。

git rm --cached <file>

如果要删除整个文件夹,则需要递归删除其中的所有文件。

git rm -r --cached <folder>

从头版本中删除文件将在下一次提交时发生。

警告:虽然这不会从您的本地计算机上删除物理文件,但会从其他开发者的下一个 git pull 上的计算机上删除文件。

对我有用的过程是 1. 首先提交挂起的更改 2. git rm --cached 并再次提交 3. 将文件添加到 .gitignore,检查 git status 并再次提交

很重要的补充。如果被忽略的文件将被修改(但尽管如此不应提交),则在修改并执行 git add . 后,它将被添加到 index.html 中。下一次提交会将其提交到存储库。为了避免这种情况在 mataal 又说了一个命令之后立即执行:git update-index --assume-unchanged <path&filename>

@AkiraYamamoto 的方法对我也很有效。在我的情况下,我抑制了输出,因为我的存储库有数千个文件:git rm -r -q --cached .

不过,这将删除 git pull 上的文件。

git rm --cached 只是从存储库中删除文件, git update-index --assume-unchanged 在未暂存的更改中不显示文件,并且不会拉取新的更改。但我希望 GIT 只是忽略文件 PLEEEEEASE 的内容

P
Peter Mortensen

下面的一系列命令将从 Git 索引中删除所有项目(而不是从工作目录或本地存储库中),然后将更新 Git 索引,同时尊重 Git 忽略。 PS。索引 = 缓存

第一的:

git rm -r --cached .
git add .

然后:

git commit -am "Remove ignored files"

或作为单行:

git rm -r --cached . && git add . && git commit -am "Remove ignored files"

要突出此答案与已接受答案之间的区别:使用此命令,您实际上不需要知道受影响的文件。 (想象一个包含大量随机文件的临时目录,应该从索引中清除)。

与接受的答案相同。文件将在 git pull 被删除。

把它作为标准的 git 命令会很好。 git rmignored 之类的东西。

@gudthing -r 代表“递归”

这样,您最终可能会添加 other 当前不在 .gitignore 中的无用文件。如果这取决于您的 git status 在此命令后的噪音程度,可能很难找出。 只删除新忽略的文件的命令会更好。这就是为什么我更喜欢thSoft's answer

r
rofrol

git update-index 为我完成这项工作:

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

注意: 此解决方案实际上独立于 .gitignore,因为 gitignore 仅适用于未跟踪的文件。

更新,更好的选择

自从发布此答案以来,已经创建了一个新选项,应该是首选。您应该使用 --skip-worktree 来处理用户不想再提交的已修改跟踪文件,并保留 --assume-unchanged 以提高性能,以防止 git 检查大型跟踪文件的状态。有关详细信息,请参阅 https://stackoverflow.com/a/13631525/717372...

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

取消

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

真正的答案。实际上很棒,非常简单,不会污染 git status 并且实际上非常直观。谢谢。

git update-index --assume-unchanged <path> … 将导致 git 忽略指定路径中的更改,而不管 .gitignore。如果您从远程提取并且该远程对此路径进行了更改,则 git 将因冲突而导致合并失败,您将需要手动合并。 git rm --cached <path> … 将导致 git 停止跟踪该路径。如果您不将路径添加到 .gitignore,您将在以后的 git status 中看到该路径。第一个选项在 git 提交历史中的噪音较小,并允许将来分发对“忽略”文件的更改。

我很困惑这不是公认的答案。这里接受的答案显然没有回答所提出的实际问题。此答案忽略了对存储库中文件的更改,而不是将其从存储库中删除。

如果它准确地解释了给定命令的作用,例如它与其他建议的解决方案有何不同,这个答案将更加有用。

这个命令只会在你的机器上有效,对吧?如果我想停止跟踪所有机器上的文件怎么办?还在将来克隆代表的机器上?

E
Eric Schoonover
git ls-files -c --ignored --exclude-standard -z | xargs -0 git rm --cached
git commit -am "Remove ignored files"

这将获取被忽略文件的列表,将它们从索引中删除,并提交更改。

如果您还需要将它们从工作目录中删除,则只需运行 git ls-files --ignored --exclude-standard | xargs git rm 。我相信这个答案是最好的!因为它非常清楚,Unix 方式,并且以直接的方式做想要的事情,而不构成其他更复杂命令的副作用。

很好的答案;但是,如果您的路径中间有空格,则该命令将失败,例如:“My dir/my_ignored_file.txt”

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

如果 ls-files 不匹配任何内容,git rm 会抱怨。如果没有匹配的文件,使用 xargs -r git rm ... 告诉 xargs 不要运行 git rm

最好使用 \0 作为分隔符:git ls-files --ignored --exclude-standard -z|xargs -0 git rm --cached

P
Peter Mortensen

将其移出,提交,然后将其移回。

这在过去对我有用,但可能有一种“gittier”方式来实现这一点。

如果您想忽略一堆以前未被忽略的文件,这非常有用。尽管就像您说的那样,但可能有更好的方法。

这正是我所做的。只需将文件移动到 git 之外的文件夹,然后执行“git add .”、“git commit”。 (这删除了文件)然后添加 gitignore,引用文件/文件夹,再次提交以将 gitignore 文件添加到 git,然后复制/移回文件夹,它们应该被忽略。注意:看起来文件已从 GIT 中删除,因此可能会将它们从其他结帐/拉取中删除,如上述解决方案中所述,但由于您最初是在制作它们的副本,恕我直言,这不是什么大问题。让团队的其他成员知道...

这是摆脱错误提交的文件夹的最简单方法。

似乎是我能看到的唯一方法。这是 git 中的一个巨大错误(不是“功能”),只要您将文件/文件夹添加到 .gitignore,它就不会从那一刻开始忽略该文件 - 永远 - 无处不在。

请注意,与大多数(所有?)其他答案一样,这会在 git pull 上删除其他人的文件。

P
Peter Mortensen

我总是使用这个命令来删除那些未跟踪的文件。一行 Unix 风格的干净输出:

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

它列出了所有您忽略的文件,将每个输出行替换为带引号的行,以处理内部带有空格的路径,并将所有内容传递给 git rm -r --cached 以从索引中删除路径/文件/目录。

很好的解决方案!工作得很好,感觉比删除所有文件然后重新添加它们更正确。

我也发现这个“最干净”。这可能很明显,但仅运行第一部分 git ls-files --ignored --exclude-standard,就可以让您首先了解/验证您的新 .gitignore 将排除/删除哪些文件,然后再继续执行最后的 git rm .

请注意,文件名中包含某些“讨厌”字符的文件名会失败,例如 \n。我已经发布了我的解决方案来解决这个问题。

另一个警告:在拉取时,这会导致文件在其他人的工作目录中被删除,对吗?

Git 2.32 打破了 ls-files 的行为 - 您现在需要添加 -c

y
youhans

复制/粘贴答案是:

git rm --cached -r .; git add .; git status; git commit -m "Ignore unwanted files"

此命令不会更改 .gitignore 文件的内容。它只会忽略已经提交到 Git 存储库但现在我们已将它们添加到 .gitignore 的文件。

命令 git status; 仅用于查看更改并且可以删除。

最后,它将立即提交更改并显示“忽略不需要的文件”消息。

如果您不想提交更改,请删除命令的最后一部分 (git commit -m "Ignore unwanted files")

可以读取它,就好像命令行将更改文件 .gitignore 的内容一样。您能否make it清楚事实并非如此(没有“编辑:”、“更新:”或类似内容 - 答案应该看起来好像是今天写的)。也就是说,不是直接澄清,而是通过改变它的编写方式。

P
Peter Mortensen

在以下情况下使用它:

您想取消跟踪很多文件,或者您更新了 .gitignore 文件

来源:Untrack files already added to Git repository based on .gitignore

假设您已经将一些文件添加/提交到您的 Git 存储库,然后将它们添加到您的 .gitignore 文件中;这些文件仍将存在于您的存储库索引中。这篇文章我们将看到如何摆脱它们。

第 1 步:提交所有更改

在继续之前,请确保您的所有更改都已提交,包括您的 .gitignore 文件。

第 2 步:从存储库中删除所有内容

要清除您的存储库,请使用:

git rm -r --cached .

rm 是删除命令

-r 将允许递归删除

--cached 只会从索引中删除文件。您的文件仍然存在。

rm 命令可能是无情的。如果您想预先尝试它的功能,请添加 -n--dry-run 标志来测试。

第 3 步:阅读所有内容

git add .

第 4 步:提交

git commit -m ".gitignore fix"

您的存储库很干净:)

将更改推送到您的遥控器以查看更改也在那里生效。

它不会从远程存储库中删除文件吗?如果我想将文件同时保存在本地仓库和远程仓库中,但让 git “忘记”它们怎么办?

AFAIK 这不会从历史记录中删除文件,因为我们没有使用任何历史更改命令(如果我错了,请纠正我)。这只会通过从 git 删除 gitignore 中忽略的文件来添加新提交。这些文件将在历史承诺

最佳答案在这里,但尽管有风险,但可以通过一个可用于验证一切是否按预期进行的命令来完善它。

S
Seth Robertson

如果您无法git rm跟踪文件,因为其他人可能需要它(警告,即使 git rm --cached,当其他人获得此更改时,他们的文件将在他们的文件系统中被删除)。这些通常是由于配置文件覆盖、身份验证凭据等原因而完成的。请查看 https://gist.github.com/1423106,了解人们解决此问题的方法。

总结一下:

让您的应用程序查找被忽略的文件 config-overide.ini 并在提交的文件 config.ini 上使用它(或者,查找 ~/.config/myapp.ini 或 $MYCONFIGFILE)

提交文件 config-sample.ini 并忽略文件 config.ini,如有必要,有一个脚本或类似的复制文件。

尝试使用 gitattributes clean/smudge 魔法为您应用和删除更改,例如将配置文件涂抹为来自备用分支的结帐,并将配置文件清理为来自 HEAD 的结帐。这是棘手的东西,我不建议新手用户使用。

将配置文件保存在专用于它的部署分支上,该分支永远不会合并到主控。当您想要部署/编译/测试时,您合并到该分支并获取该文件。除了使用人工合并策略和额外的 git 模块外,这本质上是涂抹/清洁方法。

反建议:不要使用假设不变,它只会以泪水告终(因为 git 对自己撒谎会导致坏事发生,比如你的更改会永远丢失)。

如果文件在删除时是脏的,git 不会删除该文件。如果它不脏,则检索文件就像 git checkout <oldref> -- <filename> 一样简单 - 但随后它将被检出并忽略。

关于您的最后一条注释(关于 --assume-unchanged):要么这是货物崇拜,应该被解雇,要么您可以解释原因(我确信这一点)并且它变得有用。

@RomainValeri:“如果 Git 需要修改索引中的这个文件,例如合并提交时,Git 将失败(优雅地);因此,如果假定的未跟踪文件在上游发生更改,您将需要手动处理这种情况。”—git-scm.com/docs/git-update-index。您承诺: (1) 从树中备份文件; (2)重置a.-u。少量; (3) 将文件重置为其原始内容git checkout -- file; (4) git pull 或 merge,现在会成功; (5) 将文件复制回来并检查更改; (6)设置a.-u。再咬一口。这是我书中对 PITA 的定义,但 YMMV。 :)

b
bolov

我通过使用 git filter-branch 实现了这一点。我使用的确切命令取自手册页:

警告:这将从您的整个历史记录中删除该文件

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

此命令将重新创建整个提交历史记录,在每次提交之前执行 git rm,因此将删除指定的文件。不要忘记在运行命令之前备份它,因为它丢失。

这将更改所有提交 ID,从而中断来自存储库副本之外的分支的合并。

警告:这将从您的整个历史记录中删除该文件。不过,这正是我一直在寻找的,以删除很久以前在版本历史记录中提交的完全不必要且过大的文件(不应该提交的输出)。

C
Community

什么对我不起作用

(在 Linux 下),我想使用此处建议 ls-files --ignored --exclude-standard | xargs git rm -r --cached 方法的帖子。但是,(某些)要删除的文件的名称中有一个嵌入的换行符/LF/\n。两种解决方案都不是:

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

应对这种情况(获取有关未找到文件的错误)。

所以我提供

git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached
git commit -am "Remove ignored files"

这使用 ls-files-z 参数和 xargs-0 参数来安全/正确地处理文件名中的“讨厌”字符。

在手册页 git-ls-files(1) 中,它指出:

当不使用 -z 选项时,路径名中的 TAB、LF 和反斜杠字符分别表示为 \t、\n 和 \\。

所以我认为如果文件名中包含任何这些字符,则需要我的解决方案。

对我来说,这是最好的解决方案。它的性能比 git add . 好得多。它还包含上述一些评论的最佳改进。

您可以在答案之后添加 thSoft 的 git commit -am "Remove ignored files" 吗?你的答案加起来让我度过了难关:j

我不明白 git commit -a 的目的。对我来说 git rm --cached 完全影响索引,因此无需在...之后暂存文件

P
Peter Mortensen

对文件/文件夹执行以下步骤:

删除文件:

需要将该文件添加到.gitignore。需要使用命令(git rm --cached 文件名)删除该文件。需要运行(git add .)。需要(commit -m)“文件删除”。最后,(git push)。

例如:

我想删除 test.txt 文件。我不小心推送到 GitHub 并想将其删除。命令如下:

首先,在 .gitignore 文件中添加“test.txt”

git rm --cached test.txt
git add .
git commit -m "test.txt removed"
git push

删除文件夹:

需要将该文件夹添加到文件 .gitignore。需要使用命令(git rm -r --cached 文件夹名称)删除该文件夹。需要运行(git add .)。需要(commit -m)“删除文件夹”。最后,(git push)。

例如:

我想删除 .idea 文件夹/目录。我不小心推送到 GitHub 并想将其删除。命令如下:

首先,在文件 .gitignore 中添加 .idea

git rm -r --cached .idea
git add .
git commit -m ".idea removed"
git push

先生,您才是真正的MVP!

C
Chris Nolet

更新您的 .gitignore 文件——例如,将您不想跟踪的文件夹添加到 .gitignore。 git rm -r --cached 。 - 删除所有跟踪的文件,包括想要的和不需要的。只要您保存在本地,您的代码就会很安全。混帐添加。 – 所有文件都将被重新添加,除了 .gitignore 中的文件。

向@AkiraYamamoto 致敬,为我们指明了正确的方向。

由于它实际上不起作用,因为您需要 -r 以递归方式运行 rm ,所以如何否决 :) (有人没有正确复制)

警告:这种技术实际上不会导致 git 忽略文件,而是会导致 git 删除文件。这意味着如果您使用此解决方案,任何时候其他人执行 git pull,该文件都会被删除。所以它实际上并没有被忽略。请参阅建议 git update-index --assume-unchanged 的解决方案以获取原始问题的解决方案。

Tks 供参考我的评论。我发现我原来的评论从 stackoverflow.com/a/1274447/475876 中删除很奇怪

我必须使用 -f 运行 rm,但这完成了工作。

P
Peter Mortensen

依次执行以下步骤,您会没事的。

从目录/存储中删除错误添加的文件。您可以使用“rm -r”(适用于 Linux)命令或通过浏览目录来删除它们。或者将它们移动到 PC 上的另一个位置。 (如果运行移动/删除,您可能需要关闭 IDE。)现在将文件/目录添加到 .gitignore 文件并保存。现在使用这些命令将它们从 Git 缓存中删除(如果有多个目录,请通过重复发出此命令将它们一一删除) git rm -r --cached path-to-those-files 现在执行提交并使用以下命令推送。这将从 Git 远程删除这些文件,并使 Git 停止跟踪这些文件。混帐添加。 git commit -m "从 Git 中删除不必要的文件" git push origin

P
Peter Mortensen

我认为,也许 Git 不能完全忘记文件,因为它的概念(section "Snapshots, Not Differences")。

例如,在使用 CVS 时,不存在此问题。 CVS 将信息存储为基于文件的更改列表。 CVS 的信息是一组文件以及随时间对每个文件所做的更改。

但是在 Git 中,每次提交或保存项目状态时,它基本上都会拍摄当时所有文件的样子,并存储对该快照的引用。因此,如果您添加了一次文件,它将始终存在于该快照中。

这两篇文章对我很有帮助:

git assume-unchanged vs skip-worktreeHow to ignore changes in tracked files with Git

在此基础上,如果文件已被跟踪,我会执行以下操作:

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

从这一刻起,该文件中的所有本地更改都将被忽略,并且不会转到远程。如果远程更改文件,则会发生冲突,当git pull。藏匿行不通。要解决它,将文件内容复制到安全的地方并按照以下步骤操作:

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

文件内容将被远程内容替换。将您的更改从安全位置粘贴到文件并再次执行:

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

如果与项目一起工作的每个人都将执行 git update-index --skip-worktree <file>,那么 pull 的问题应该不存在。当每个开发人员都有自己的项目配置时,此解决方案适用于配置文件。

每次在远程更改文件时都这样做不是很方便,但它可以保护它不被远程内容覆盖。

P
Peter Mortensen

使用 git rm --cached 命令不会回答原始问题:

你如何强制 git 完全忘记 [a file]?

事实上,当执行 git pull! 时,此解决方案将导致文件在存储库的所有其他实例中删除

GitHub here 记录了强制 Git 忘记文件的正确方法。

我建议阅读文档,但基本上:

git fetch --all
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch full/path/to/file' --prune-empty --tag-name-filter cat -- --all
git push origin --force --all
git push origin --force --tags
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now

只需将 full/path/to/file 替换为文件的完整路径即可。确保您已将该文件添加到您的 .gitignore 文件中。

您还需要(暂时)allow non-fast-forward pushes to your repository,因为您要更改 Git 历史记录。

G
Good Pen

git rm --cached -r <YOUR_files_or_folders>

--缓存 |仅从索引中删除文件

虽然这可能有效......它会因为 -r . 而删除所有文件

这个答案应该被删除。

@Hache_raw 没有 -r ,我们无法删除目录

P
Peter Mortensen

answer from Matt Frear 是最有效的恕我直言。以下只是一个 PowerShell 脚本,供 Windows 用户仅从其 Git 存储库中删除与其排除列表匹配的文件。

# 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 .

在什么情况下这个文件列表不等于递归--cached?

P
Peter Mortensen

将文件移动或复制到安全位置,以免丢失。然后“git rm”文件并提交。

如果您恢复到其中一个较早的提交或另一个尚未删除它的分支,该文件仍将显示。但是,在以后的所有提交中,您将不会再次看到该文件。如果文件在 Git 忽略中,那么您可以将其移回文件夹中,Git 不会看到它。

git rm --cached 将从索引中删除文件而不将其从磁盘中删除,因此无需移动/复制它

P
Peter Mortensen

就我而言,我需要将“.envrc”放入 .gitignore 文件中。

然后我用:

git update-index --skip-worktree .envrc
git rm --cached .envrc

并且该文件已被删除。

然后我再次提交,告诉文件已被删除。

但是当我使用命令 git log -p 时,文件的内容(这是 Amazon S3 的秘密凭据)显示已删除的内容,我不想在 Git 的历史记录中显示此内容存储库。

然后我使用了这个命令:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch .envrc' HEAD

而且我再也看不到内容了。

git update-index --skip-worktree .idea/ git rm -r --cached .idea/ 在我不小心点击 add 之后成功了。使用新生成的 IDE 文件夹

P
Peter Mortensen

我喜欢 JonBrave's answer,但是我的工作目录很乱,commit -a 让我有点害怕,所以这就是我所做的:

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"'

分解它:

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"

从索引中删除被忽略的文件

stage .gitignore 和你刚刚删除的文件

犯罪

P
Peter Mortensen

接受的答案不会“让Git“忘记”文件......”(历史上)。它只会让 Git 忽略当前/未来的文件。

这种方法使 Git 完全忘记被忽略的文件(过去/现在/未来),但它不会从工作目录中删除任何内容(即使从远程重新拉出)。

此方法需要使用文件 /.git/info/exclude(首选)一个预先存在的 .gitignore所有有文件的提交忽略/忘记。 1

所有强制执行 Git 的方法都会忽略事后行为,从而有效地重写历史记录,因此对于可能在此过程之后提取的任何公共/共享/协作存储库具有 significant ramifications2

一般建议:从一个干净的存储库开始——所有内容都已提交,工作目录或索引中没有任何待处理的内容,并进行备份!

此外,this answer 的评论/revision historythis questionand revision history)可能有用/有启发性。

#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 the current index, not the 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

#Commit to prevent working directory data loss!
#This commit will be automatically deleted by the --prune-empty flag in the following command
#This command must be run on each branch

git commit -m "ignored index"

#Apply standard git ignore behavior RETROACTIVELY to all commits from all branches (--all)
#This step WILL delete ignored files from working directory UNLESS they have been dereferenced from the index by the commit above
#This step will also delete any "empty" commits.  If deliberate "empty" commits should be kept, remove --prune-empty and instead run git reset HEAD^ immediately after this command

git filter-branch --tree-filter 'git ls-files -z --ignored --exclude-standard | xargs -0 git rm -f --ignore-unmatch' --prune-empty --tag-name-filter cat -- --all

#List all still-existing files that are now ignored properly
#If this command returns nothing, it's time to restore from backup and start over
#This command must be run on each branch

git ls-files --other --ignored --exclude-standard

最后,按照本 GitHub guide 的其余部分(从第 6 步开始)其中包括有关以下命令的重要警告/信息

git push origin --force --all
git push origin --force --tags
git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now

从现在修改的远程存储库中提取的其他开发人员应该进行备份,然后:

#fetch modified remote

git fetch --all

#"Pull" changes WITHOUT deleting newly-ignored files from working directory
#This will overwrite local tracked files with remote - ensure any local modifications are backed-up/stashed

git reset FETCH_HEAD

脚注

1 因为可以使用上述说明将 /.git/info/exclude 应用于所有历史提交,也许有关将 .gitignore 文件放入需要它的历史提交的详细信息超出了这个答案的范围。我想要一个正确的 .gitignore 文件在根提交中,就好像它是我做的第一件事一样。其他人可能不在乎,因为无论 .gitignore 文件存在于提交历史记录中的哪个位置,/.git/info/exclude 都可以完成同样的事情,并且显然重写历史记录是一个非常敏感的主题,即使知道 {1 }。

FWIW,潜在的方法可能包括 git rebase 或将 external .gitignore 复制到每个提交中的 git filter-branch,例如 this question 的答案。

2 通过提交独立 git rm --cached 命令的结果来强制执行 Git 事后忽略行为可能会导致将来从强推遥控器。以下 git filter-branch 命令中的 --prune-empty 标志通过自动删除先前的“删除所有忽略的文件”仅索引提交来避免此问题。重写 Git 历史记录还会更改提交哈希,这将wreak havoc在未来从公共/共享/协作存储库中提取。在对此类存储库执行此操作之前,请充分理解 ramificationsThis GitHub guide 指定以下内容:

告诉你的合作者对他们从旧的(受污染的)存储库历史创建的任何分支进行变基,而不是合并。一次合并提交可能会重新引入部分或全部受污染的历史记录,而这些历史记录是您刚刚费力清除的。

影响远程存储库的替代解决方案是 git update-index --assume-unchanged </path/file>git update-index --skip-worktree <file>,可以在 here 中找到示例。

P
Peter Mortensen

BFG 专为从 Git 存储库中删除不需要的数据(如大文件或密码)而设计,因此它有一个简单的标志,可以删除任何大型历史(不在您的当前提交中)文件:'--strip- blobs-big-than'

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

如果您想按名称指定文件,您也可以这样做:

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

BFG 比 git filter-branch 快 10-1000 倍,并且通常更易于使用 - 查看 full usage instructionsexamples 了解更多详细信息。

来源:Reduce repository size

P
Peter Mortensen

如果您不想使用 CLI 并且在 Windows 上工作,一个非常简单的解决方案是使用 TortoiseGit。它在菜单中有“删除(保留本地)”操作,效果很好。

P
Peter Mortensen

这在最新的 Git(撰写本文时为 v2.17.1)中不再是问题。

.gitignore 文件最终会忽略已跟踪但已删除的文件。您可以通过运行以下脚本自行测试。最后的 git status 语句应报告“没有要提交的内容”。

# Create an empty repository
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

我很高兴 git 现在这样做了。但是,OP 询问是否不跟踪 .gitignore 中存在的文件中的修改,未删除的文件仍显示状态。

P
Peter Mortensen

这就是我解决问题的方法:

git filter-branch --tree-filter 'rm -rf path/to/your/file' HEAD
git push

在这方面,我们基本上也试图在以前的提交中重写该特定文件的历史记录。

更多信息,您可以参考 filter-branch hereman page

来源:Removing sensitive data from a repository - using filter-branch

来源:Git: How to remove a big file wrongly committed

佚名

如果已经提交 DS_Store

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

通过以下方式忽略它们:

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

最后,做出承诺!

什么是“DS_Store”(或“.DS_Store”?)?特定于 Mac 的文件?

P
Peter Mortensen

特别是对于基于 IDE 的文件,我使用这个:

例如,对于 slnx.sqlite 文件,我完全摆脱了它,如下所示:

git rm {PATH_OF_THE_FILE}/slnx.sqlite -f
git commit -m "remove slnx.sqlite"

请记住,其中一些文件存储了一些本地用户设置和项目首选项(例如您打开了哪些文件)。因此,每次您在 IDE 中导航或进行一些更改时,该文件都会更改,因此它会检查它并显示为未提交的更改。

R
RajVimalC

如果有人在 Windows 上遇到困难并且您想忽略整个文件夹,请转到文件资源管理器上所需的“文件夹”,右键单击并执行“Git Bash Here”(应该已经安装了 Windows 版 Git)。

运行此命令:

git ls-files -z | xargs -0 git update-index --assume-unchanged

“做Git Bash Here”是什么意思?它是如何连接到命令行的?请通过 editing (changing) your answer 回复,而不是在评论中(没有“编辑:”、“更新:”或类似内容 - 答案应该看起来好像是今天写的)。

P
Peter Mortensen

在我的例子中,我在几个需要删除的目录中有几个 .lock 文件。我运行了以下命令,它无需进入每个目录即可删除它们:

git rm -r --cached **/*.lock

这样做会进入我所在的“根”下的每个文件夹,并排除所有与模式匹配的文件。

.lock 文件从何而来?是什么创造了他们?