gpt4 book ai didi

How do I make Git forget about a file that was tracked, but is now in .gitignore?(如何让Git忘记被跟踪但现在位于.gitignore中的文件?)

转载 作者:bug小助手 更新时间:2023-10-25 11:38:38 26 4
gpt4 key购买 nike



I put a file that was previously being tracked by Git onto the .gitignore list. However, the file still shows up in git status after it is edited. How do I force Git to completely forget the file?

我将一个先前被Git跟踪的文件放到了.gitignore列表中。然而,该文件在被编辑后仍以GIT状态显示。如何强制Git完全忘记该文件?


更多回答

git clean -X sounds similar, but it doesn't apply in this situation (when the files are still being tracked by Git). I'm writing this for anyone looking for a solution not to follow the wrong route.

git clean -X听起来很相似,但它不适用于这种情况(当文件仍然被Git跟踪时)。我写这篇文章是为了那些寻找解决方案而不走错路的人。

The only real answer to this is down below, see git update-index --assume-unchanged. This solution 1) keeps the file on server (index), 2) lets you modify it freely locally.

对于这个问题,唯一真正的答案就是下面的内容,请参见git update-index--Asmise-Untisted。此解决方案1)将文件保存在服务器(索引)上,2)允许您在本地自由修改文件。

You need to use --skip-worktree, see: stackoverflow.com/questions/13630849/…

您需要使用--SKIP-WORKTREE,请参阅:Stackoverflow.com/Questions/13630849/…

An important question is: should the file remain in the repository or not? Eg if someone new clones the repo, should they get the file or not? If YES then git update-index --assume-unchanged <file> is correct and the file will remain in the repository and changes will not be added with git add. If NO (for example it was some cache file, generated file etc), then git rm --cached <file> will remove it from repository.

一个重要的问题是:文件是否应该保留在存储库中?例如,如果有人克隆回购,他们是否应该获得文件?如果是,那么git更新-索引--假定-未更改的<文件>是正确的,并且文件将保留在存储库中,并且不会使用git add添加更改。如果不是(例如,它是某个缓存文件、生成的文件等),则Git rm--cached会将其从存储库中删除。

@Martin @Qwerty Everyon should stop to advise for --assume-unchanged which is for performance to prevent git to check status of big tracked files but prefer --skip-worktree which is for modified tracked files that the user don't want to commit anymore. See stackoverflow.com/questions/13630849/…

@Martin@Qwerty Everyon应该停下来建议--假设-未更改,这是为了提高性能,以防止GIT检查大型跟踪文件的状态,但更喜欢--跳过工作树,这是针对用户不想再提交的已修改跟踪文件的。参见Stackoverflow.com/Questions/13630849/…

优秀答案推荐

.gitignore will prevent untracked files from being added (without an add -f) to the set of files tracked by Git. However, Git will continue to track any files that are already being tracked.

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


To stop tracking a file, we must remove it from the index:

要停止跟踪文件,我们必须将其从索引中删除:


git rm --cached <file>

To remove a folder and all files in the folder recursively:

要递归删除文件夹及其中的所有文件,请执行以下操作:


git rm -r --cached <folder>

The removal of the file from the head revision will happen on the next commit.

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


WARNING: While this will not remove the physical file from your local machine, it will remove the files from other developers' machines on their next git pull.

警告:虽然这不会从您的本地计算机上删除物理文件,但它会在其他开发人员的下一次GIT拉入时从他们的计算机上删除这些文件。



The series of commands below will remove all of the items from the Git index (not from the working directory or local repository), and then will update the Git index, while respecting Git ignores. PS. Index = Cache

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


First:

首先:


git rm -r --cached .
git add .

Then:

然后:


git commit -am "Remove ignored files"



Or as a one-liner:

或者作为一句俏皮话:


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


git update-index does the job for me:

Git UPDATE-INDEX为我完成了这项工作:


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

Note: This solution is actually independent of .gitignore as gitignore is only for untracked files.

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




Update, a better option


Since this answer was posted, a new option has been created and that should be preferred. You should use --skip-worktree which is for modified tracked files that the user don't want to commit anymore and keep --assume-unchanged for performance to prevent git to check status of big tracked files. See https://stackoverflow.com/a/13631525/717372 for more details...

自发布此答案以来,已创建了一个新选项,应该优先选择该选项。对于用户不想再提交的已修改的跟踪文件,您应该使用--Skip-worktree,并为提高性能而保持--Asmise-Untify,以防止GIT检查大型跟踪文件的状态。有关更多详细信息,请参阅https://stackoverflow.com/a/13631525/717372...


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

To cancel

要取消


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


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

This takes the list of the ignored files, removes them from the index, and commits the changes.

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



The copy/paste (one-liner) answer is:

复制/粘贴(一行)的答案是:


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

This command will NOT change the content of the .gitignore file. It will ignore the files already committed to a Git repository, but now we have added them to .gitignore.

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


The command git status; is to review the changes and could be dropped.

命令git Status;用于查看更改,可以删除。


Ultimately, it will immediately commit the changes with the message "Ignore unwanted files".

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


If you don't want to commit the changes, drop the last part of the command (git commit -m "Ignore unwanted files")

如果您不想提交更改,请删除命令的最后部分(git Commit-m“忽略不需要的文件”)



Move it out, commit, and then move it back in.

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


This has worked for me in the past, but there is probably a 'gittier' way to accomplish this.

这在过去对我很管用,但可能有一种“更活泼”的方式来实现这一点。



I always use this command to remove those untracked files.
One-line, Unix-style, clean output:

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


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

It lists all your ignored files, replaces every output line with a quoted line instead to handle paths with spaces inside, and passes everything to git rm -r --cached to remove the paths/files/directories from the index.

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



Use this when:



  1. You want to untrack a lot of files, or

  2. You updated your .gitignore file


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

来源:取消跟踪已基于.gitignore添加到Git存储库的文件


Let’s say you have already added/committed some files to your Git repository and you then add them to your .gitignore file; these files will still be present in your repository index. This article we will see how to get rid of them.

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


Step 1: Commit all your changes


Before proceeding, make sure all your changes are committed, including your .gitignore file.

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


Step 2: Remove everything from the repository


To clear your repository, use:

要清除存储库,请使用:


git rm -r --cached .


  • rm is the remove command

  • -r will allow recursive removal

  • –cached will only remove files from the index. Your files will still be there.


The rm command can be unforgiving. If you wish to try what it does beforehand, add the -n or --dry-run flag to test things out.

Rm命令可能是不可饶恕的。如果您希望预先尝试它所做的事情,可以添加-n或--ry-run标志来进行测试。


Step 3: Readd everything


git add .

Step 4: Commit


git commit -m ".gitignore fix"

Your repository is clean :)

你的仓库是干净的:)


Push the changes to your remote to see the changes effective there as well.

将更改推送到遥控器以查看更改是否也在遥控器上生效。



If you cannot git rm a tracked file because other people might need it (warning, even if you git rm --cached, when someone else gets this change, their files will be deleted in their filesystem). These are often done due to config file overrides, authentication credentials, etc. Please look at https://gist.github.com/1423106 for ways people have worked around the problem.

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



To summarize:

总而言之:




  • Have your application look for an ignored file config-overide.ini and use that over the committed file config.ini (or alternately, look for ~/.config/myapp.ini, or $MYCONFIGFILE)

  • Commit file config-sample.ini and ignore file config.ini, have a script or similar copy the file as necessary if necessary.

  • Try to use gitattributes clean/smudge magic to apply and remove the changes for you, for instance smudge the config file as a checkout from an alternate branch and clean the config file as a checkout from HEAD. This is tricky stuff, I don't recommend it for the novice user.

  • Keep the config file on a deploy branch dedicated to it that is never merged to master. When you want to deploy/compile/test you merge to that branch and get that file. This is essentially the smudge/clean approach except using human merge policies and extra-git modules.

  • Anti-recommentation: Don't use assume-unchanged, it will only end in tears (because having git lie to itself will cause bad things to happen, like your change being lost forever).



I accomplished this by using git filter-branch. The exact command I used was taken from the man page:

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



WARNING: this will delete the file from your entire history

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



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


This command will recreate the entire commit history, executing git rm before each commit and so will get rid of the specified file. Don't forget to back it up before running the command as it will be lost.

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



What didn't work for me


(Under Linux), I wanted to use the posts here suggesting the ls-files --ignored --exclude-standard | xargs git rm -r --cached approach. However, (some of) the files to be removed had an embedded newline/LF/\n in their names. Neither of the solutions:

(在Linux下),我想使用这里的帖子,建议使用ls-files-忽略-排除-标准|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

cope with this situation (get errors about files not found).

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


So I offer


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

This uses the -z argument to ls-files, and the -0 argument to xargs to cater safely/correctly for "nasty" characters in filenames.

它将-z参数用于ls文件,并将-0参数用于xargs,以安全/正确地处理文件名中的“讨厌”字符。


In the manual page git-ls-files(1), it states:

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



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



so I think my solution is needed if filenames have any of these characters in them.

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



Do the following steps for a file/folder:

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


Remove a File:

删除文件:



  1. need to add that file to .gitignore.

  2. need to remove that file using the command (git rm --cached file name).

  3. need to run (git add .).

  4. need to (commit -m) "file removed".

  5. and finally, (git push).


For example:

例如:


I want to delete the test.txt file. I accidentally pushed to GitHub and want to remove it. Commands will be as follows:

我想删除test.txt文件。我不小心推到了GitHub,想把它移除。命令如下:


First, add "test.txt" in file .gitignore

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


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

Remove Folder:

删除文件夹:



  1. need to add that folder to file .gitignore.

  2. need to remove that folder using the command (git rm -r --cached folder name).

  3. need to run (git add .).

  4. need to (commit -m) "folder removed".

  5. and finally, (git push).


For example:

例如:


I want to delete the .idea folder/directory. I accidentally pushed to GitHub and want to remove it. The commands will be as follows:

我想删除.ide文件夹/目录。我不小心推到了GitHub,想把它移除。这些命令如下所示:


First, add .idea in file .gitignore

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


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



  1. Update your .gitignore file – for instance, add a folder you don't want to track to .gitignore.


  2. git rm -r --cached . – Remove all tracked files, including wanted and unwanted. Your code will be safe as long as you have saved locally.


  3. git add . – All files will be added back in, except those in .gitignore.







Hat tip to @AkiraYamamoto for pointing us in the right direction.

感谢@AkiraYamamoto为我们指明了正确的方向。



Do the following steps serially, and you will be fine.

按顺序做下面的步骤,你就会没事的。



  1. Remove the mistakenly added files from the directory/storage. You can use the "rm -r" (for Linux) command or delete them by browsing the directories. Or move them to another location on your PC. (You maybe need to close the IDE if running for moving/removing.)



  2. Add the files / directories to the .gitignore file now and save it.



  3. Now remove them from the Git cache by using these commands (if there is more than one directory, remove them one by one by repeatedly issuing this command)


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


  4. Now do a commit and push by using the following commands. This will remove those files from Git remote and make Git stop tracking those files.


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




I think, that maybe Git can't totally forget about a file because of its conception (section "Snapshots, Not Differences").

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


This problem is absent, for example, when using CVS. CVS stores information as a list of file-based changes. Information for CVS is a set of files and the changes made to each file over time.

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


But in Git every time you commit, or save the state of your project, it basically takes a picture of what all your files look like at that moment and stores a reference to that snapshot. So, if you added file once, it will always be present in that snapshot.

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


These two articles were helpful for me:

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


git assume-unchanged vs skip-worktree and How to ignore changes in tracked files with Git

Git假设-未更改与跳过-工作树,以及如何使用Git忽略跟踪文件中的更改


Basing on it I do the following, if the file is already tracked:

如果已经跟踪了该文件,我将根据它执行以下操作:


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

From this moment all local changes in this file will be ignored and will not go to remote. If the file is changed on remote, conflict will occur, when git pull. Stash won't work. To resolve it, copy the file content to the safe place and follow these steps:

从现在开始,该文件中的所有本地更改都将被忽略,并且不会转到远程。如果在Remote上更改了文件,则在GIT拉取时会发生冲突。藏起来不管用。要解决此问题,请将文件内容复制到安全位置,然后执行以下步骤:


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

The file content will be replaced by the remote content. Paste your changes from the safe place to the file and perform again:

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


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

If everyone, who works with the project, will perform git update-index --skip-worktree <file>, problems with pull should be absent. This solution is OK for configurations files, when every developer has their own project configuration.

如果参与该项目的每个人都执行git更新-索引--跳过工作树<文件>,则拉入应该不会出现问题。当每个开发人员都有自己的项目配置时,这个解决方案对于配置文件是可以的。


It is not very convenient to do this every time, when the file has been changed on remote, but it can protect it from overwriting by remote content.

当文件在远程被更改时,每次都这样做不是很方便,但它可以保护它免受远程内容的破坏。



Using the git rm --cached command does not answer the original question:

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



How do you force git to completely forget about [a file]?



In fact, this solution will cause the file to be deleted in every other instance of the repository when executing a git pull!

事实上,此解决方案将导致在执行GIT Pull时从存储库的每个其他实例中删除该文件!


The correct way to force Git to forget about a file is documented by GitHub here.

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


I recommend reading the documentation, but basically:

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


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

Just replace full/path/to/file with the full path of the file. Make sure you've added the file to your .gitignore file.

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


You'll also need to (temporarily) allow non-fast-forward pushes to your repository, since you're changing your Git history.

您还需要(临时)允许非快进推送到您的存储库,因为您正在更改您的Git历史。



Move or copy the file to a safe location, so you don't lose it. Then 'git rm' the file and commit.

将文件移动或复制到安全位置,这样就不会丢失。然后‘git rm’文件并提交。


The file will still show up if you revert to one of those earlier commits, or another branch where it has not been removed. However, in all future commits, you will not see the file again. If the file is in the Git ignore, then you can move it back into the folder, and Git won't see it.

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



The answer from Matt Frear was the most effective IMHO. The following is just a PowerShell script for those on Windows to only remove files from their Git repository that matches their exclusion list.

马特·弗里尔的回答是最有效的IMHO。以下只是一个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 .


The accepted answer does not "make Git "forget" about a file..." (historically). It only makes Git ignore the file in the present/future.

公认的答案并不是“让Git”忘记“文件...”(历史上)。这只会使Git忽略当前/未来的文件。


This method makes Git completely forget ignored files (past/present/future), but it does not delete anything from the working directory (even when re-pulled from remote).

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


This method requires usage of file /.git/info/exclude (preferred) or a pre-existing .gitignore in all the commits that have files to be ignored/forgotten. 1

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


All methods of enforcing Git ignore behavior after-the-fact effectively rewrite history and thus have significant ramifications for any public/shared/collaborative repositories that might be pulled after this process. 2

所有实施Git的方法都忽略了事后行为,有效地重写了历史,因此对任何可能在此过程后被拉出的公共/共享/协作存储库都有重大影响。2.


General advice: start with a clean repository - everything committed, nothing pending in working directory or index, and make a backup!

一般建议:从干净的存储库开始-提交的所有内容,工作目录或索引中没有挂起的内容,并进行备份!


Also, the comments/revision history of this answer (and revision history of this question) may be useful/enlightening.

另外,这个答案的评论/修订历史(以及这个问题的修订历史)可能是有用的/有启发性的。


#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



Finally, follow the rest of this GitHub guide (starting at step 6) which includes important warnings/information about the commands below.

最后,遵循本GitHub指南的其余部分(从步骤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



Other developers that pull from the now-modified remote repository should make a backup and then:

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


#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



Footnotes


1 Because /.git/info/exclude can be applied to all historical commits using the instructions above, perhaps details about getting a .gitignore file into the historical commit(s) that need it is beyond the scope of this answer. I wanted a proper .gitignore file to be in the root commit, as if it was the first thing I did. Others may not care since /.git/info/exclude can accomplish the same thing regardless where the .gitignore file exists in the commit history, and clearly rewriting history is a very touchy subject, even when aware of the ramifications.

1由于/.git/INFO/EXCLUDE可以应用于使用上述说明的所有历史提交,因此有关将.gitignore文件放入需要它的历史提交(S)的详细信息可能超出了本答案的范围。我希望在根提交中有一个适当的.gitignore文件,就好像这是我做的第一件事。其他人可能并不关心,因为无论.gitignore文件位于提交历史记录中的哪个位置,/.git/info/exclude都可以完成相同的任务,而且显然重写历史记录是一个非常敏感的主题,即使知道其后果也是如此。


FWIW, potential methods may include git rebase or a git filter-branch that copies an external .gitignore into each commit, like the answers to this question.

另外,潜在的方法可能包括git rebase或将外部.gitignore复制到每次提交中的git过滤器分支,就像这个问题的答案一样。


2 Enforcing Git ignore behavior after-the-fact by committing the results of a stand-alone git rm --cached command may result in newly-ignored file deletion in future pulls from the force-pushed remote. The --prune-empty flag in the following git filter-branch command avoids this problem by automatically removing the previous "delete all ignored files" index-only commit. Rewriting Git history also changes commit hashes, which will wreak havoc on future pulls from public/shared/collaborative repositories. Please understand the ramifications fully before doing this to such a repository. This GitHub guide specifies the following:

2通过提交独立的git rm--cached命令的结果来强制Git事后忽略行为可能会导致在将来从强制推送的远程拉入时删除新忽略的文件。下面的git过滤器分支命令中的--prune-Empty标志通过自动删除之前的“删除所有忽略的文件”--仅索引提交来避免这个问题。重写Git历史还会更改提交散列,这将对未来从公共/共享/协作存储库中提取数据造成严重破坏。在对这样的存储库执行此操作之前,请充分了解其后果。本GitHub指南指定了以下内容:



Tell your collaborators to rebase, not merge, any branches they created off of your old (tainted) repository history. One merge commit could reintroduce some or all of the tainted history that you just went to the trouble of purging.



Alternative solutions that do not affect the remote repository are git update-index --assume-unchanged </path/file> or git update-index --skip-worktree <file>, examples of which can be found here.

不影响远程仓库的替代解决方案是git update-index --assume-unchanged </path/file>或git update-index --skip-worktree ,可以在这里找到示例。



In my case I needed to put ".envrc" in the .gitignore file.

在我的例子中,我需要在.gitignore文件中放入“.envrc”。


And then I used:

然后我用了:


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

And the file was removed.

文件被删除了。


Then I committed again, telling that the file was removed.

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


But when I used the command git log -p, the content of the file (which was secret credentials of the Amazon S3) was showing the content which was removed and I don't want to show this content ever on the history of the Git repository.

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


Then I used this command:

然后,我使用了以下命令:


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

And I don't see the content again.

我再也看不到里面的内容了。



I liked JonBrave's answer, but I have messy enough working directories that commit -a scares me a bit, so here's what I've done:

我喜欢JonBrave的回答,但我有足够杂乱的工作目录来提交-有点吓到我了,所以我做了以下工作:


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

Breaking it down:

分析一下:


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"


  • remove ignored files from the index

  • stage .gitignore and the files you just removed

  • commit



The BFG is specifically designed for removing unwanted data like big files or passwords from Git repositories, so it has a simple flag that will remove any large historical (not-in-your-current-commit) files: '--strip-blobs-bigger-than'

BFG是专门为从Git存储库中删除不需要的数据而设计的,比如大文件或密码,所以它有一个简单的标志,可以删除任何大的历史(不在您的当前提交中)文件:


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

If you'd like to specify files by name, you can do that too:

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


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

The BFG is 10-1000x faster than git filter-branch and is generally much easier to use - check the full usage instructions and examples for more details.

BFG比GIT过滤器分支快10-1000倍,而且通常更容易使用-查看完整的使用说明和示例以了解更多详细信息。


Source: Reduce repository size

来源:减少存储库大小



If you don't want to use the CLI and are working on Windows, a very simple solution is to use TortoiseGit. It has the "Delete (keep local)" Action in the menu which works fine.

如果您不想使用CLI,而是在Windows上工作,一个非常简单的解决方案是使用TortoiseGit。它在菜单中有“Delete(Keep Local)”操作,运行良好。



This is no longer an issue in the latest Git (v2.17.1 at the time of writing).

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


The .gitignore file finally ignores tracked-but-deleted files. You can test this for yourself by running the following script. The final git status statement should report "nothing to commit".

.gitignore文件最终忽略已跟踪但已删除的文件。您可以通过运行以下脚本亲自测试这一点。最后的GIT状态语句应该报告“Nothing to Commit”。


# 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


This is how I solved my issue:

这是我如何解决我的问题的:


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

git push

Git Filter-BRANCH--tree-Filter‘rm-rf路径/to/you/file’head git推送


In this, we are basically trying to rewrite the history of that particular file in previous commits also.

在这种情况下,我们基本上也尝试在以前的提交中重写该特定文件的历史。


For more information, you can refer to the man page of filter-branch here.

有关更多信息,您可以参考此处的Filter-BRANCH手册页。


Source: Removing sensitive data from a repository - using filter-branch

来源:使用筛选器分支从存储库中删除敏感数据


Source: Git: How to remove a big file wrongly committed

来源:Git:如何删除错误提交的大文件



In case of already committed DS_Store:

如果已提交DS_Store:



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


Ignore them by:

忽略它们:



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


Finally, make a commit!

最后,做出承诺!



Especially for the IDE-based files, I use this:

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


For instance, for the slnx.sqlite file, I just got rid off it completely like the following:

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


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

Just keep that in mind that some of those files store some local user settings and preferences for projects (like what files you had open). So every time you navigate or do some changes in your IDE, that file is changed and therefore it checks it out and show as uncommitted changes.

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



In my case here, I had several .lock files in several directories that I needed to remove. I ran the following and it worked without having to go into each directory to remove them:

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


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

Doing this went into each folder under the 'root' of where I was at and excluded all files that matched the pattern.

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



If anyone is having a hard time on Windows and you want to ignore the entire folder, go to the desired 'folder' on file explorer, right click and do 'Git Bash Here' (Git for Windows should have been installed).

如果任何人在Windows上遇到困难,而您想要忽略整个文件夹,请转到文件资源管理器中所需的‘文件夹’,右击并执行‘Git Bash here’(应该已经安装了Git for Windows)。


Run this command:

运行以下命令:


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


For me, the file was still available in the history and at first, I needed to squash the commits that added the removed files: https://gist.github.com/patik/b8a9dc5cd356f9f6f980

对我来说,该文件在历史中仍然可用,起初,我需要挤压添加了已删除文件的提交:https://gist.github.com/patik/b8a9dc5cd356f9f6f980



  1. Combine the commits. The example below combines the last 3 commits


git reset --soft HEAD~3
git commit -m "New message for the combined commit"


  1. Push the squashed commit
    if the commits have been pushed to the remote:


git push origin +name-of-branch

更多回答

the process that workd for me was 1. commit pending changes first 2. git rm --cached <file> and commit again 3. add the file to .gitignore, check with git status and commit again

我工作过程是1.首先提交挂起的更改2.git rm--缓存并再次提交3.将文件添加到.gitignore,检查git状态,然后再次提交

Very important adding. If file that is ignored would be modified (but in spite of this should be not committed), after modifying and executing git add . it would be added to index. And next commit would commit it to repository. To avoid this execute right after all that mataal said one more command: git update-index --assume-unchanged <path&filename>

非常重要的补充。如果被忽略的文件将被修改(但尽管如此,不应提交),则在修改并执行git add之后。它将被添加到索引中。下一次提交将把它提交到存储库。为了避免出现这种情况,mataal又说了一个命令:git更新-索引--假定-未更改<路径和文件名>

@AkiraYamamoto 's method worked well for me as well. In my case I suppressed the output since my repository had thousands of files: git rm -r -q --cached .

@AkiraYamamoto的S方法对我也很有效。在我的例子中,我隐藏了输出,因为我的存储库有成千上万的文件:git rm-r-q--cached。

This will delete the file on git pull though.

这将删除git Pull上的文件。

git rm --cached <file> just remove file from repository, git update-index --assume-unchanged <file> not shown file in unstaged changes and does not make pull a new changes. But i want GIT JUST IGNORE CONTENT OF FILE PLEEEEEASE

Git RM--缓存的<文件>只是从存储库中删除文件,Git更新-索引--假定-未更改的<文件>不会在未暂存的更改中显示文件,也不会拉出新的更改。但我想让git忽略文件内容,请

To highlight the difference between this answer and the accepted one: Using this commands you don't need to actually know the affected files. (Imagine a temporary dir with lots of random files that should be cleared off the index).

为了强调这个答案和公认的答案之间的区别:使用这个命令,您不需要实际知道受影响的文件。(设想一个临时目录,其中包含许多应该从索引中清除的随机文件)。

Same as the accepted answer. Files will get deleted on git pull.

与公认的答案相同。文件将在GIT拉取时被删除。

It would be nice to have this as a standard git command. Something like git rmignored.

如果把它作为标准的git命令来使用,那就太好了。像Git这样的东西被忽略了。

@gudthing -r stands for "recursive"

@gudthing-r代表“递归”

With this you may end up adding other useless files that are not currently in .gitignore. Which may be difficult to find out if depending on how noise your git status is after this command. A command that only removes newly ignored files would be better. That's why I prefer thSoft's answer

这样,您最终可能会添加当前不在.gitignore中的其他无用文件。这可能很难找出,这取决于您的GIT状态在此命令后的噪音。只删除新忽略的文件的命令会更好。这就是为什么我更喜欢thSoft的答案

This IS the real answer. Awesome actually, very simple, doesn't pollute git status and actually very intuitive. Thanks.

这才是真正的答案。很棒,实际上,非常简单,不会污染GIT状态,而且实际上非常直观。谢谢。

git update-index --assume-unchanged <path> … will cause git to ignore changes in the specified path(s), regardless of .gitignore. If you pull from a remote and that remote has changes to this path, git will fail the merge with a conflict and you will need to merge manually. git rm --cached <path> … will cause git to stop tracking that path. If you do not add the path to .gitignore you will see the path in future git status. The first option has less noise in the git commit history and allows changes to the "ignored" file to be distributed in the future.

Git更新-索引-假定-未更改<路径>…将导致GIT忽略指定路径(S)中的更改,而不考虑.gitignore。如果您从遥控器拉入,而该遥控器更改了此路径,则Git将因冲突而导致合并失败,您将需要手动合并。Git RM--缓存的<路径>…会导致Git停止跟踪这条路径。如果您不将路径添加到.gitignore,您将在未来的GIT状态中看到该路径。第一个选项在GIT提交历史记录中的噪音较小,并允许在将来分发对“忽略的”文件的更改。

I'm quite confused as to how this isn't the accepted answer. The accepted answer here clearly isn't answering the actual question being asked. This answer ignores changes to the file that is in the repository whilst not removing it from the repository.

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

This answer would be a lot more useful if it explained exactly what the given command does, e.g. how it's different from the other suggested solutions.

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

this command will only be effective on your machine right? what if i want to stop tracking the file on all machines ? also on the machines that will clone the rep in the future?

此命令仅在您的计算机上有效,对吗?如果我想停止跟踪所有计算机上的文件,该怎么办?也在将来克隆代表的机器上吗?

If you need to remove them from the working directory, too, then simply run git ls-files --ignored --exclude-standard | xargs git rm . I believe this answer is the best! Because it's very clear, Unix-way, and does the wanted thing in a direct manner, without composing the side-effects of other, more complex commands.

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

Great answer; however, the command will fail if you have paths with spaces on the middle, e.g.: "My dir/my_ignored_file.txt"

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

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

Git ls-文件--忽略--排除标准|sed‘S/.*/“&”/’|xargs git rm--已缓存

git rm will complain if ls-files didn't match anything. Use xargs -r git rm ... to tell xargs not to run git rm if no files matched.

如果ls-file与任何内容都不匹配,Git RM将会发出警告。使用xargs-r git rm...如果没有匹配的文件,则告诉xargs不要运行git rm。

It would be better to use \0 as separator: git ls-files --ignored --exclude-standard -z|xargs -0 git rm --cached

最好使用\0作为分隔符:git ls-文件--忽略--排除-标准-z|xargs-0 git rm--缓存

It can be read as if the command lines will change the content of file .gitignore. Can you make it clear that is not the case (without "Edit:", "Update:", or similar - the answer should appear as if it was written today). That is, not a direct clarification, but by changing the way it is written.

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

This worked great if you want to ignore a bunch of files that weren't previously ignored. Though like you said, there is probably a better way for this.

如果你想忽略一大堆以前没有被忽略的文件,这个功能非常有用。尽管如你所说,可能还有更好的办法。

This is exactly what I did. Simply move the files to a folder outside of git, then do "git add .", "git commit". (This removed the files) then add the gitignore, referencing the files/folders, commit again to add the gitignore file to git, then copy/move back in the folders, and they should be ignored. NB: it will appear that the files were deleted from GIT, so would probably remove them from other checkouts/pulls, as mentioned in above solutions, but since you are making copies of them initially, this isnt as much of an issue IMHO. just let the rest of the team know...

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

This is the easiest way to get rid of wrongly committed folders.

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

Seems to be the only way, that I can see. It's a massive bug (not 'feature') in git that as soon as you add a file/folder to .gitignore, it doesn't just ignore that file from that point on - forever - everywhere.

这似乎是我能看到的唯一办法。这是Git的一个大错误(不是‘功能’),当你在.gitignore中添加一个文件/文件夹时,它不会从那时起-永远-无论在哪里忽略那个文件。

Please note that, as most (all?) other answers, this removes other people's file upon git pull.

请注意,正如大多数(所有?)其他答案,这会在GIT拉出时删除其他人的文件。

Great solution! Worked perfectly and feels more correct that removing all files then adding them back in.

伟大的解决方案!工作完美,感觉更正确,删除所有文件,而不是重新添加它们。

I too found this "cleanest". It might be obvious, but just running the first part, git ls-files --ignored --exclude-standard, on its own lets you first understand/verify what files your new .gitignore is going to exclude/remove, before you go ahead and execute the final git rm.

我也觉得这是“最干净的”。这可能是显而易见的,但只要运行第一部分git ls-files-忽略-排除-标准,就可以让您在继续执行最后的git rm之前,首先了解/验证新的.gitignore将排除/删除哪些文件。

Be aware, fails on filenames with certain "nasty" characters in them, e.g. \n. I have posted my solution to cater for this.

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

Another caveat: on pull, this will cause the file to be deleted in others' working directories, right?

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

Git 2.32 broke the behaviour of ls-files - you now need to add -c.

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

It won't delete the files from the remote repository? What if I want to keep the files both in local repo and remote repo but make git "forget" about them?

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

AFAIK this won't delete files from history because we're not using any history changing commands (correct me if I"m wrong). This only adds a new commit by deleting files ignored in gitignore from git. Those files will be there in the historical commits

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

git wouldn't remove the file, if it were dirty at the time of deletion. And if it's not dirty, retrieving the file would be as easy as git checkout <oldref> -- <filename> - but then it would be checked out and ignored.

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

Concerning your last note (about --assume-unchanged) : either this is cargo cult and should be dismissed, or you can explain why (which I'm convinced of) and it becomes useful.

关于你的最后一个注释(关于-假设不变):要么这是货物崇拜,应该被驳回,要么你可以解释为什么(我相信),它变得有用。

@RomainValeri: “Git will fail (gracefully) in case it needs to modify this file in the index e.g. when merging in a commit; thus, in case the assumed-untracked file is changed upstream, you will need to handle the situation manually.”—git-scm.com/docs/git-update-index. You commit to: (1) backup the file out of the tree; (2) reset the a.-u. bit; (3) reset the file to its original content git checkout -- file; (4) git pull or merge, which will now succeed; (5) copy the file back and examine changes; (6) set the a.-u. bit again. That's a definition of PITA in my book, but YMMV. :)

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

This will change all commit IDs, thus breaking merges from branches outside of your copy of the repository.

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

WARNING: this will delete the file from your entire history. This was what I was looking for though, to remove a completely unnecessary and oversized file (output that should never have been committed) that was committed a long time ago in the version history.

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

For me this is the best solution. It has much better performance than a git add .. It also contains the best improvements from some comments above.

对我来说,这是最好的解决方案。它的性能比GIT Add要好得多。它还包含了从上面的一些评论中得到的最佳改进。

Can you add thSoft's git commit -am "Remove ignored files" afterward to your answer? Your answers combined got me through things : j

你能在答案后面加上thSoft的git Commit-am“删除忽略的文件”吗?你的答案结合在一起,让我经历了很多事情:J

I don't understand the purpose of git commit -a. For me git rm --cached affect exactly the index so no need to stage the files after...

我不明白Git Commit-a的目的。对我来说,git rm--cached正好影响索引,因此不需要在...

You Sir are the real MVP!

先生,你才是真正的MVP!

How about downvoted due to the fact that it won't actually work as you need a -r to run rm recursively anyway :) (Someone didn't copy correctly)

因为你需要a-r来递归地运行rm,所以它实际上不会工作,所以否决如何:)(有人没有正确复制)

Warning: This technique doesn't actually cause git to ignore the file, instead it actually causes git to delete the file. That means if you use this solution, any time anyone else does a git pull, the file will get deleted. So it isn't actually ignored. See the solution suggesting git update-index --assume-unchanged instead for a solution to the original question.

警告:这种技术实际上并不会导致git忽略该文件,而是实际上会导致git删除该文件。这意味着,如果您使用此解决方案,任何其他人执行GIT拉取操作时,该文件都将被删除。因此,它实际上并没有被忽视。有关原始问题的解决方案,请参阅建议的git更新-索引--假设-未更改的解决方案。

Tks for the reference to my comment. I find it weird that my original comment was deleted from stackoverflow.com/a/1274447/475876

谢谢参考我的评论。我觉得奇怪的是,我最初的评论被从Stackoverflow.com/a/1274447/475876删除了

I had to run the rm with -f but this did the job.

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

but will it remove the file from other devs machines when they git pull ?

但当其他DEVS机器拉出Git时,它会从这些机器上删除该文件吗?

git rm --cached will remove the file from the index without deleting it from disk, so no need to move/copy it away

Git RM--CACHED将从索引中删除文件,而不会将其从磁盘中删除,因此无需移动/复制它

@bdonlan This doesn't work. It throws fatal: No pathspec was given. Which files should I remove? (exit code 128)

@bdonlan这不管用。它抛出了致命的一击:没有给出任何病理规格。我应该删除哪些文件?(退出代码128)

In what situation won't this list of files be equal to the recursive --cached?

在什么情况下,此文件列表不等于递归缓存?

+1 for git update-index --assume-unchanged </path/file> which I assume is what a good portion of devs are looking for (files that should be overwritten by neither push or pull)

+1对于git更新-索引--假定-未更改,我认为这是很大一部分开发人员正在寻找的(不应该被推送或拉出覆盖的文件)

git update-index --skip-worktree .idea/ git rm -r --cached .idea/ did the trick after I accidentally hit add . with newly generated IDE folder

在我不小心按下Add之后,Git update-index--跳过-worktree.dea/git rm-r--cached.dea/就成功了。使用新生成的IDE文件夹

I'm glad git now does this. However, the OP was asking about not tracking modifications in files present in the .gitignore, not deleted files still showing a status.

我很高兴Git现在做到了这一点。然而,OP询问的是不跟踪.gitignore中存在的文件中的修改,而不是仍显示状态的已删除文件。

What is "DS_Store" (or ".DS_Store"?)? A Mac-specific file?

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

Where did the .lock files come from? What created them?

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

What do you mean by "do Git Bash Here"? How is it connected to the command-line? Please respond by editing (changing) your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).

你说的“在这里痛击吗”是什么意思?它是如何连接到命令行的?请通过编辑(更改)您的答案来回复,而不是在此处的评论中(不包括“编辑:”、“更新:”或类似的内容-答案应该显示为今天写的)。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com