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

有一个文件被git一次跟踪,但现在这个文件在.gitignore列表中。

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

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

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

 git rm --cached <file> 

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

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

第一:

 git rm -r --cached . git add . 

然后:

 git commit -am "Remove ignored files" 

git update-index为我做的工作:

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

注意:这个解决scheme实际上是独立于.gitignore因为gitignore只适用于未跟踪的文件。

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

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

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

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

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

如果因为其他人可能需要这个文件(如警告,即使你是 git rm --cached ,当其他人得到这个改变,他们的文件将被删除到他们的文件系统) .github.com / 1423106为人们解决问题的方式。

把它搬出来,承诺,然后把它移回去。这对我来说是过去的工作。 有可能是一个“gittier”的方式来实现这一点。

什么不适合我

(在Linux下),我想在这里使用提示ls-files --ignored --exclude-standard | xargs git rm -r --cached的post ls-files --ignored --exclude-standard | xargs git rm -r --cached方法。 但是,(某些)要删除的文件的名称中包含换行符/ LF / \n 。 这两个解决scheme都不是:

 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 

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

所以我提供

 git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached 

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

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

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

所以我认为我的解决scheme是需要的,如果文件名中有任何这些字符。

编辑:我已经被要求添加—就像任何git rm命令—这必须跟一个提交使删除永久性,例如git commit -am "Remove ignored files"

我通过使用git filter-branch完成了这个任务。 我使用的确切命令是从手册页获取的:

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

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

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

  1. 更新你的.gitignore文件 – 例如,添加一个你不想跟踪的文件夹.gitignore

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

  3. git add . – 所有文件将被重新添加,除了.gitignore


给@AkiraYamamoto的帽子给我们指出了正确的方向。

我认为,也许git不能完全忘记文件,因为它的概念( “快照,不差异”部分 )。

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

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

这两篇文章对我有帮助:

git假设 – 不变vs skip-worktree和如何忽略跟踪文件中的变化与Git

基于它,我做了以下,如果文件已被跟踪:

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

从这一刻起,这个文件中的所有本地更改都将被忽略,不会进入远程。 如果文件在远程更改,当git pull时会发生冲突。 藏匿不起作用。 要解决该问题, 请将文件内容复制到安全的地方,然后执行以下步骤:

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

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

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

如果每个使用项目的人都会执行git update-index --skip-worktree <file> ,那么就会出现pull问题。 当每个开发人员都有自己的项目configuration时,该解决scheme对于configuration文件是可以的。

每次在远程更改文件时都不太方便,但可以防止远程内容被覆盖。

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

从马特恐惧的答案是最有效的恕我直言。 以下是仅用于Windows中的PowerShell脚本,只能从其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 . 

BFG专门用于从Git仓库中删除不需要的数据,如大文件或密码,所以它有一个简单的标志,可以删除任何大的历史(不在你当前提交的)文件:–strip-blobs-降幅高于”

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

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

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

BFG比git filter-branch快10-1000倍,而且使用起来更容易 – 查看完整的使用说明和示例以获取更多详细信息。

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

在mac上:

 $ git --version git version 2.6.4 $ uname -a Darwin MUSRV186016-382 14.5.0 Darwin Kernel Version 14.5.0: Sun Sep 25 22:07:15 PDT 2016; root:xnu-2782.50.9~1/RELEASE_X86_64 x86_64 

1.从分支foo中git跟踪的文件列表中删除DS_Store文件:

 $ for file in $(git ls-tree -r foo --name-only | grep -i DS_Store); do git rm --cached $file; done 

2.承诺:

 $ git commit -m "Removed .DS_Store files" 

3.validation文件不再被跟踪

 $ git ls-tree -r foo --name-only # There should not be anything coming back 

4.按下以从远程删除它们:

 $ git push