如何让git”忘记”被跟踪但现在在.gitignore中的文件?

How to make Git “forget” about a file that was tracked but is now in .gitignore?

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

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


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

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

1
git rm --cached <file>

将在下一次提交时从头部修订中删除文件。

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


下面的一系列命令将从git索引中删除所有项(不是从工作目录或本地repo中),然后更新git索引,同时忽略git。ps.index=缓存

第一:

1
2
git rm -r --cached .
git add .

然后:

1
git commit -am"Remove ignored files"


git update index为我做的工作是:

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

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

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

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


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

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


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

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

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


如果由于其他人可能需要跟踪文件而无法执行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来应用和删除更改,例如,将配置文件作为签出从备用分支中清除,将配置文件作为签出从头部清除。这是很棘手的事情,我不推荐给新手用户。
  • 将配置文件保留在一个专用于它的部署分支上,该分支从未合并到master。当您要部署/编译/测试时,您将合并到该分支并获取该文件。除了使用人工合并策略和额外的Git模块之外,这基本上是一种污点/干净的方法。
  • 反建议:不要使用假设不变,它只会以眼泪结束(因为说谎本身会导致坏的事情发生,就像你的改变永远消失一样)。


把它搬出去,提交,然后再搬回来。这在过去对我很有效。可能有一种"Gittier"方法来实现这一点。


当使用:1。你想解开很多文件,或者2。你更新了你的gitignore文件

Source link: http://www.codeblocq.com/2016/01/Untrack-files-already-added-to-git-repository-based-on-gitignore/

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

步骤1:提交所有更改

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

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

要清除回购,请使用:

1
git rm -r --cached .
  • rm是remove命令
  • -R将允许递归删除
  • –缓存将只从索引中删除文件。您的文件仍将存在。

rm命令可以是不可原谅的。如果你想事先尝试一下它的功能,可以添加-n--dry-run标志来测试。

第3步:重新添加所有内容

1
git add .

步骤4:提交

1
git commit -m".gitignore fix"

您的存储库是干净的:)

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


我是通过使用git过滤器分支来实现这一点的。我使用的确切命令来自手册页:

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

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

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


什么不适合我

(在Linux下),我想使用这里建议使用ls-files --ignored --exclude-standard | xargs git rm -r --cached方法的文章。但是,(有些)要删除的文件的名称中嵌入了newline/lf/
。两种解决方案都没有:

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

处理这种情况(获取未找到文件的错误)。

所以我提供

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

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

在手册页Git LS文件(1)中,它说明:

When -z option is not used, TAB, LF, and backslash characters in
pathnames are represented as \t,
, and \\, respectively.

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

编辑:我被要求添加这一点---就像任何git rm命令---这之后必须有一个承诺,使删除永久化,例如git commit -am"Remove ignored files"


  • 更新你的.gitignore文件——例如,添加一个你不想跟踪到.gitignore的文件夹。

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

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

  • 向@akirayamamoto提供帽子提示,说明我们的方向正确。


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

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

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

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

    Git假定不变vs跳过工作树以及如何使用git忽略跟踪文件中的更改

    基于此,如果文件已被跟踪,我将执行以下操作:

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

    从现在起,此文件中的所有本地更改都将被忽略,不会转到远程。如果在远程上更改了文件,当git pull时将发生冲突。Stash不起作用。要解决此问题,请将文件内容复制到安全位置,然后执行以下步骤:

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

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

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

    如果与项目合作的每个人都将执行git update-index --skip-worktree ,那么pull的问题应该不存在。当每个开发人员都有自己的项目配置时,这个解决方案对于配置文件是可以的。

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


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

    1.从目录/存储中删除错误添加的文件。您可以使用"rm-r"(对于Linux)命令,也可以通过浏览目录来删除它们。或者将它们移动到电脑上的另一个位置。[如果正在运行以进行移动/删除,可能需要关闭IDE]

    2.现在将文件/目录添加到gitignore文件并保存。

    3.现在使用这些命令从Git缓存中删除它们(如果有多个目录,则通过重复发出此命令逐个删除它们)

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

    4.现在执行提交和推送,使用这些命令。这将从git-remote中删除这些文件,并使git停止跟踪这些文件。

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

    马特·恐惧的回答是最有效的。以下只是一个PowerShell脚本,用于Windows中的用户仅从其Git报告中删除与其排除列表匹配的文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 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 .


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

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


    将文件移动或复制到安全位置,这样就不会丢失文件。然后git rm文件并提交。如果您恢复到以前的某个提交,或者恢复到另一个尚未删除的分支,文件仍然会显示出来。但是,在将来的所有提交中,您将不会再看到该文件。如果文件在git-ignore中,那么可以将其移回文件夹中,而git将看不到该文件。


    bfg是专门为从git repos中删除不需要的数据(如大文件或密码)而设计的,因此它有一个简单的标志,可以删除任何大的历史(不在当前提交中)文件:"--strip blobs bigger than"

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

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

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

    bfg比git filter分支快10-1000倍,而且通常更容易使用-有关更多详细信息,请查看完整的使用说明和示例。

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


    如果您不想使用CLI,并且在Windows上工作,一个非常简单的解决方案是使用TortoisGit,它在菜单中有"删除(保留本地)"操作,可以正常工作。


    我喜欢琼布雷的回答,但我有足够混乱的工作目录提交-有点让我害怕,所以我做了以下的事情:

    git config—全局别名.exclude-ignored'!git ls files-z--忽略--排除标准xargs-0 git rm-r--缓存的&;git ls文件-z--忽略--排除标准xargs-0 git stage&;git stage.gitignore&;git commit-m"new gitignore and remove ignored files from index"'

    分解:

    1
    2
    3
    4
    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和刚删除的文件
    • 犯罪


    这在最新的Git中不再是一个问题(在编写时是2.17.1版)。

    .gitignore最终忽略跟踪但删除的文件。您可以通过运行下面的脚本自己测试这一点。最终的git status声明应报告"无需承诺"。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # 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


    尤其是对于基于IDE的文件,我使用以下命令:

    例如slnx.sqlite,我只是把它完全删除了,如下所示:

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

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


    已承诺的,按本合同第十一条第(三)项规定执行:

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

    忽略它们:

    1
    2
    3
    4
    5
    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

    最后,做出承诺!