如何让Git“忘记”一个被跟踪但现在位于.gitignore的文件?

时间:2009-08-13 19:23:22

标签: git gitignore git-rm

git正在跟踪一个文件,但现在该文件位于.gitignore列表中。

但是,该文件在编辑后会一直显示在git status中。你如何强迫git完全忘记它?

30 个答案:

答案 0 :(得分:4666)

.gitignore会阻止未跟踪的文件(没有add -f)添加到git跟踪的文件集中,但git会继续跟踪已经跟踪的所有文件。

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

git rm --cached <file>

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

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

答案 1 :(得分:2344)

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

<强>首先

git rm -r --cached . 
git add .

,然后

git commit -am "Remove ignored files"

答案 2 :(得分:915)

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>

答案 3 :(得分:251)

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

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

答案 4 :(得分:68)

我总是使用此命令删除那些未跟踪的文件。 单行,Unix风格,干净的输出:

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

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

答案 5 :(得分:57)

如果您无法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 magic来为您应用和删除更改,例如将配置文件涂抹为来自备用分支的签出,并将配置文件清理为HEAD的签出。这是棘手的事情,我不建议新手用户使用。
  • 将配置文件保留在专用于它的部署分支上,该分支永远不会合并到主服务器。当您要部署/编译/测试时,您将合并到该分支并获取该文件。除了使用人工合并策略和extra-git模块之外,这基本上是涂抹/清洁方法。
  • 反推荐:不要使用假设 - 不变,它只会以泪水结束(因为让git欺骗自己会导致坏事发生,就像你的变化永远丢失一样)。

答案 6 :(得分:53)

将其移出,提交,然后将其移回。这在过去对我有用。实现这一目标可能有一种“轻微”的方式。

答案 7 :(得分:49)

在以下情况下使用此项:

1。你想要解开很多文件,或者

2。您更新了gitignore文件

  

来源链接: http://www.codeblocq.com/2016/01/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"

您的存储库是干净的:)

将更改推送到遥控器以查看更改在那里有效。

答案 8 :(得分:40)

我使用git filter-branch完成了这项工作。我使用的确切命令来自手册页:

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

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

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

答案 9 :(得分:39)

什么对我不起作用

(在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

这会使用 ls-files -z参数,以及 xargs -0参数来安全/正确地使用&#34 ;讨厌&#34;文件名中的字符。

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

  

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

因此,如果文件名中包含任何这些字符,我认为我的解决方案是必需的。

编辑:我被要求添加 - 就像任何git rm命令一样 - 必须后跟提交以使删除永久化,例如git commit -am "Remove ignored files"

答案 10 :(得分:20)

  1. 更新您的.gitignore文件 - 例如,将您不想跟踪的文件夹添加到.gitignore

  2. git rm -r --cached . - 删除所有跟踪的文件,包括有意和无意的文件。只要您在本地保存,您的代码就是安全的。

  3. git add . - 所有文件都将重新添加,但.gitignore中的文件除外。

  4. 向@AkiraYamamoto提示,指出我们正确的方向。

答案 11 :(得分:14)

我想,也许git因为它的概念(section "Snapshots, Not Differences")而无法完全忘记文件。

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

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

这两篇文章对我有帮助:

git assume-unchanged vs skip-worktree  和How 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的问题应该不存在。当每个开发人员都有自己的项目配置时,此解决方案适用于配置文件。

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

答案 12 :(得分:11)

依次执行以下步骤,就可以了。

1. 删除从目录/存储中错误添加的文件 。您可以使用“ rm -r”(对于linux)命令或通过浏览目录将其删除。或将它们移动到PC上的另一个位置。[如果运行用于移动/删除 ,则可能需要关闭IDE]

2。立即将文件/目录添加到gitignore文件中并保存。

3.now现在通过使用以下命令从 git缓存中将其删除(如果存在多个目录,请通过反复发出此命令来将它们一个一个地删除)< / p>

git rm -r --cached path-to-those-files

4.now 一个提交并推送,请使用以下命令。这将从git remote删除这些文件,并使git 停止跟踪这些文件。

git add .
git commit -m "removed unnecessary files from git"
git push origin

答案 13 :(得分:7)

Matt Fear的答案是最有效的恕我直言。以下只是一个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 .

答案 14 :(得分:7)

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

删除文件:

  1. 需要将该文件添加到.gitignore。
  2. 需要使用命令( git rm-缓存的文件名)删除该文件。
  3. 需要运行( git add。)。
  4. 需要( commit -m )“文件已删除”。
  5. 最后,( git push )。

例如:

我要删除test.txt文件。我不小心将其推到GitHub,想要删除的命令将遵循:

首先在.gitignore中添加test.txt

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

删除文件夹:

  1. 需要将该文件夹添加到.gitignore。
  2. 需要使用命令( git rm -r-缓存的文件夹名称)删除该文件夹。
  3. 需要运行( git add。)。
  4. 需要( commit -m )“已删除文件夹”。
  5. 最后,( git push )。

例如:

我要删除.idea文件夹/目录。我不小心将其推到GitHub,想要删除的命令将遵循:

首先在.gitignore中添加.idea

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

答案 15 :(得分:7)

复制/粘贴答案为git rm --cached -r .; git add .; git status

此命令将忽略已经提交到Git存储库的文件,但是现在我们将它们添加到.gitignore

答案 16 :(得分:6)

将文件移动或复制到安全位置,这样就不会丢失它。然后git rm文件并提交。如果您还原到其中一个早期提交,或者另一个尚未删除的分支,该文件仍将显示。但是,在以后的所有提交中,您都不会再次看到该文件。如果文件在git中忽略,那么你可以将它移回文件夹,git将看不到它。

答案 17 :(得分:4)

我喜欢JonBrave的回答,但是我的工作目录杂乱无章,可以提交-a让我有些害怕,所以这就是我所做的:

git config --global alias.exclude-ignored'!git ls文件-z --ignored --exclude-standard | xargs -0 git rm -r --cached && git ls文件-z --ignored --exclude-standard | xargs -0 git stage && git stage .gitignore && git commit -m“新的gitignore并从索引中删除被忽略的文件”'

分解:

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和您刚刚删除的文件
  • 提交

答案 18 :(得分:4)

如果您不想使用CLI并且正在使用Windows,一个非常简单的解决方案是使用TortoiseGit,它有&#34;删除(保持本地)&#34;菜单中的操作正常。

答案 19 :(得分:4)

BFG专门用于从Git repos中删除大文件或密码等不需要的数据,因此它有一个简单的标志,可以删除任何大型历史(不在当前提交)文件: &#39; - 带状斑点-更大-比&#39;

$ 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了解更多详情。

来源:https://confluence.atlassian.com/bitbucket/reduce-repository-size-321848262.html

答案 20 :(得分:2)

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

.gitignore最终忽略了已删除但已删除的文件。您可以通过运行以下脚本来自行测试。最终的git status语句应报告“无需提交”。

# Create empty repo
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

答案 21 :(得分:2)

  

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

     

此方法使git 完全忘记被忽略的文件(过去 /现在/将来),但是从工作目录中删除任何内容(甚至从远程重新拉动时。

     

此方法要求使用全部中的/.git/info/exclude(首选) 预先存在的 .gitignore提交的文件被忽略/遗忘的提交。 1

     

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

     

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

     

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

#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

#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

最后,请遵循this 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,好像这是我所做的第一件事。其他人可能不在乎,因为/.git/info/exclude可以完成相同的操作,而不管.gitignore在提交历史记录中的什么位置,并且显然,重写历史记录是非常的敏感主题,即使了解ramifications

FWIW,可能的方法可能包括git rebasegit filter-branch,它们将外部 .gitignore复制到每个提交中,例如对this question的回答

2 通过提交独立git rm --cached命令的结果来强制git事后忽略行为,将来可能会导致新忽略的文件删除从受力推动的遥控器上拉出。以下--prune-empty命令中的git filter-branch标志通过自动删除以前的“删除所有被忽略的文件”仅索引提交来避免此问题。重写git历史记录也会更改提交哈希,这将wreak havoc用于将来从公共/共享/协作存储库中提取的信息。在进行此类回购之前,请先全面了解ramificationsThis GitHub guide指定以下内容:

  

告诉您的合作者rebase合并,合并他们从旧的(受污染的)存储库历史中创建的任何分支。一次合并提交可能会重新引入您刚刚遇到清除麻烦的部分或全部历史记录。

不影响的其他解决方案是git update-index --assume-unchanged </path/file>git update-index --skip-worktree <file>,可以在here中找到示例。

答案 22 :(得分:1)

如果已经提交了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

最后,提交一份!

答案 23 :(得分:1)

特别是对于基于IDE的文件,我使用以下代码:

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

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

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

答案 24 :(得分:1)

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

  

您如何迫使git完全忘记[文件]?

实际上,此解决方案将导致在执行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

由于您要更改自己的git历史记录,因此您还需要(临时)allow non-fast-forward pushes to your repository

答案 25 :(得分:0)

如果任何人在Windows上遇到麻烦,而您想忽略整个文件夹,请单击“ cd”以获取“文件夹”,然后执行“在此处Git Bash”。

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

答案 26 :(得分:0)

在这里,我需要删除几个目录中的几个.lock文件。我运行了以下程序,但无需进入每个目录即可将其删除:

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

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

希望这对其他人有帮助!

答案 27 :(得分:0)

我是这样解决我的问题的:

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

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

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

的手册页

来源:https://docs.github.com/en/github/authenticating-to-github/removing-sensitive-data-from-a-repository#using-filter-branch

来源:https://thomas-cokelaer.info/blog/2018/02/git-how-to-remove-a-big-file-wrongly-committed/

答案 28 :(得分:0)

就我而言,我需要将 .envrc 文件放在 .gitignore 文件中。 然后我使用了:

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

并且文件已被删除。

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

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

然后我使用了这个命令:

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

我再也看不到内容了。

答案 29 :(得分:0)

如果您使用 echo node_modules >> .gitignore 之类的命令创建了 gitignore 文件,它将不起作用。

Windows 终端将文件保存在 UCS-2 LE BOM 中,而 git 似乎不接受这一点。

您可以通过在 Notepad 中打开并使用 UTF-8 编码重新保存来解决此问题

notepad save utf-8 encoding

现在可以使用了。

我认为他们需要解决这个问题,因为 echo "filetoignore" >> .gitignore 实际上看起来很方便