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

发布于 2024-08-02 00:40:16 字数 103 浏览 3 评论 0 原文

我将之前由 Git 跟踪的文件放入 .gitignore 列表中。 但是,该文件在编辑后仍然显示在 git status 中。 如何强制 Git 完全忘记该文件?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

亣腦蒛氧 2024-08-09 00:40:16

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

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

git rm --cached <file>

要递归删除文件夹和文件夹中的所有文件:

git rm -r --cached <folder>

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

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

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

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.

ˉ厌 2024-08-09 00:40:16

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

首先:

git rm -r --cached .
git add .

然后:

git commit -am "Remove ignored files"

或者作为单行:

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

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

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"
微暖i 2024-08-09 00:40:16

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 update-index does the job for me:

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

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


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

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

To cancel

git update-index --no-skip-worktree <file>
放手` 2024-08-09 00:40:16
git ls-files -c --ignored --exclude-standard -z | xargs -0 git rm --cached
git commit -am "Remove ignored files"

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

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.

久夏青 2024-08-09 00:40:16

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

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

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

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

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

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

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.

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

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

静待花开 2024-08-09 00:40:16

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

这在过去对我有用,但可能有一种“gittier”方法来完成此任务。

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.

夢归不見 2024-08-09 00:40:16

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

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

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

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

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.

殊姿 2024-08-09 00:40:16

在以下情况下使用此功能:

  1. 您想要取消跟踪大量文件,或者
  2. 您更新了 .gitignore 文件

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

假设您已经将一些文件添加/提交到您的 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"

您的存储库是干净的 :)

将更改推送到远程,以查看更改也在那里生效。

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

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.

Step 1: Commit all your changes

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

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.

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.

清欢 2024-08-09 00:40:16

如果您无法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 签出。 这是棘手的事情,我不推荐新手用户使用。
  • 将配置文件保留在专用于它的部署分支上,该分支永远不会合并到 master 中。 当您想要部署/编译/测试时,您可以合并到该分支并获取该文件。 除了使用人工合并策略和额外的 git 模块之外,这本质上是涂抹/清理方法。
  • 反推荐:不要使用假设不变,它只会以泪水告终(因为让 git 对自己撒谎会导致不好的事情发生,比如你的更改永远丢失)。

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.

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).
予囚 2024-08-09 00:40:16

我通过使用 git filter-branch 来完成此操作。 我使用的确切命令取自手册页:

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

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

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

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

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.

如歌彻婉言 2024-08-09 00:40:16

什么对我不起作用

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

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

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

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

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

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:

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.

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

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.

咆哮 2024-08-09 00:40:16

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

删除文件

  1. 需要将该文件添加到 .gitignore。
  2. 需要使用命令(git rm --cached file name)删除该文件。
  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. 需要将该文件夹添加到文件< em>.gitignore。
  2. 需要使用命令(git rm -r --cached 文件夹名称)删除该文件夹。
  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

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:

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

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:

First, add .idea in file .gitignore

git rm -r --cached .idea
git add .
git commit -m ".idea removed"
git push
溺孤伤于心 2024-08-09 00:40:16
  1. 更新您的 .gitignore 文件 - 例如,将您不想跟踪的文件夹添加到 .gitignore

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

  3. git add . – 所有文件都将被添加回来,除了 .gitignore 中的文件。


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

  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.

失眠症患者 2024-08-09 00:40:16

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

  1. 从目录/存储删除错误添加的文件。 您可以使用“rm -r”(适用于 Linux)命令或通过浏览目录来删除它们。 或者将它们移动到电脑上的其他位置。 (如果运行移动/删除,您可能需要关闭 IDE。)

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

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

     git rm -r --cached 这些文件的路径 
      
  4. 现在<使用以下命令进行提交和推送。 这将从 Git 远程删除这些文件并使 Git停止跟踪这些文件。

    <前><代码> git add .
    git commit -m“从 Git 中删除了不必要的文件”
    git 推送原点

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
    
我不咬妳我踢妳 2024-08-09 00:40:16

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

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

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

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

git Should-unchanged vs Skip-worktree如何使用 Git 忽略跟踪文件中的更改< /a>

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

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 ,则 pull 应该不存在。 当每个开发人员都有自己的项目配置时,此解决方案对于配置文件来说是可以的。

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

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

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.

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.

These two articles were helpful for me:

git assume-unchanged vs skip-worktree and How to ignore changes in tracked files with 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:

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.

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.

铁轨上的流浪者 2024-08-09 00:40:16

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

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

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

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.

趴在窗边数星星i 2024-08-09 00:40:16

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

如何强制 git 完全忘记[文件]?

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

强制 Git 忘记文件的正确方法由 GitHub 这里

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

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 文件中。

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

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

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!

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

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.

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

手心的海 2024-08-09 00:40:16

马特·弗雷尔的回答是最有效的恕我直言。 以下只是一个 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 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.

# 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 .
忆离笙 2024-08-09 00:40:16

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

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

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

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

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

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

#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 指南的其余部分(从步骤 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 都可以完成相同的事情,并且显然重写历史记录是 <非常敏感的话题,即使知道后果

FWIW,潜在的方法可能包括 git rebase 或 git filter-branch ,它将外部 .gitignore 复制到每个提交,就像这个问题的答案一样。

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

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


影响远程存储库的替代解决方案是 git update-index --assume-unchanged git update-index -- Skip-worktree ,其示例可以在此处找到。

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

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

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

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

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.

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.

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.

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:

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.

掐死时间 2024-08-09 00:40:16

就我而言,我需要将“.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

然后我就没有再看到内容了。

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

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.

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.

甜中书 2024-08-09 00:40:16

我喜欢JonBrave 的答案,但我的工作目录足够混乱,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"
  • 从索引
  • 阶段删除忽略的文件 .gitignore 以及刚刚删除的文件
  • commit

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:

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
凉世弥音 2024-08-09 00:40:16

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

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

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

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

BFG 比 git filter-branch 快 10-1000 倍,并且通常更容易使用 - 检查 完整使用说明示例了解更多详细信息。

来源:减少存储库大小

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'

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.

Source: Reduce repository size

过去的过去 2024-08-09 00:40:16

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

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.

走走停停 2024-08-09 00:40:16

这在最新的 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

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

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

# 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
十六岁半 2024-08-09 00:40:16

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

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

git push

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

有关更多信息,您可以参考filter-branch的手册页此处

来源:从存储库中删除敏感数据 - 使用 filter-branch

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

This is how I solved my issue:

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

git push

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.

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

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

萌逼全场 2024-08-09 00:40:16

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

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

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

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

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

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

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.

最近可好 2024-08-09 00:40:16

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

最后,进行提交!

In case of already committed 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!

骑趴 2024-08-09 00:40:16

就我而言,我需要删除多个目录中的多个 .lock 文件。 我运行了以下命令,它无需进入每个目录即可删除它们:

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

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

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:

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.

美人如玉 2024-08-09 00:40:16

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

运行这个命令:

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

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

Run this command:

git ls-files -z | xargs -0 git update-index --assume-unchanged
回忆躺在深渊里 2024-08-09 00:40:16

我将展示一个现实生活场景。

我正在提交 .env.development & .env.product 到 git,因为它包含常量,而不是环境变量,因为我使用的是 sqlite 数据库。

两者都是 .env.development & .env.development 是相同的,因此我仅使用 .env.development 作为示例。

之前,我提交了这个:

.env.development

SQLITE_DATABASE_NAME=users.sqlite

但后来,我使用 litestream 和 cloudflare r2 添加了 sqlite 数据库备份,所以我必须使用这些变量更新 .env.development 。

.env.development

SQLITE_DATABASE_NAME=users.sqlite

# Use Litestream to backup SQLite database on every insert
REPLICA_URL=https://<account_id>.r2.cloudflarestorage.com
REPLICA_BUCKET_NAME=bucket_name
CLOUDFLARE_R2_ACCESS_KEY_ID=access_key_id
CLOUDFLARE_R2_SECRET_ACCESS_KEY=secret_access_key

假设上面包含真实的环境密钥。

请参阅 2024 年 2 月 27 日在 https://github.com/deadcoder0904/easypanel-nextjs- 上的提交sqlite/ (从底部开始的前两次提交)

我首先使用这里提到的解决方案

git update-index --assume-unchanged .env.development .env.production

这保留了 <代码>.env.development & .env.product 之前的状态。 它只包含SQLITE_DATABASE_NAME

它删除了对 .env.development 的跟踪 & .env.生产。 请参阅名为使用 litestreamw 和 cloudflare r2 备份数据库的提交。 我添加了环境变量,但它们没有提交。

然后我使用了这个解决方案(请参阅名为stop track .env.development & .env.Production<的提交< /code>) 以完全停止跟踪这些环境文件。

git rm --cached .\.env.development .\.env.production

所以,下次我将只使用第二个命令 & 添加 .env.development & 将 .env.Production 更改为 .gitignore 以从下一次提交开始完全停止跟踪它们。

专业提示:始终检查 git status 以确保您没有将真实的环境变量提交到 .git 或使用 dotenvx。< /p>

I'll show a real-life scenario.

I was committing .env.development & .env.production to git because it contained constants, not environment variables as i was using sqlite database.

Both .env.development & .env.production are same so I'll just use .env.development as an example.

Previously, I was committing this:

.env.development

SQLITE_DATABASE_NAME=users.sqlite

But later on, I added sqlite database backups using litestream with cloudflare r2 so I had to update .env.development with those variables.

.env.development

SQLITE_DATABASE_NAME=users.sqlite

# Use Litestream to backup SQLite database on every insert
REPLICA_URL=https://<account_id>.r2.cloudflarestorage.com
REPLICA_BUCKET_NAME=bucket_name
CLOUDFLARE_R2_ACCESS_KEY_ID=access_key_id
CLOUDFLARE_R2_SECRET_ACCESS_KEY=secret_access_key

Assume, the above contained real environment keys.

See commits on 27th Feb 2024 on https://github.com/deadcoder0904/easypanel-nextjs-sqlite/ (the first two commits starting from bottom)

I first used the solution mentioned here:

git update-index --assume-unchanged .env.development .env.production

This kept .env.development & .env.production on its previous state. That is just containing SQLITE_DATABASE_NAME.

And it removed tracking on .env.development & .env.production. See the commit named backup database using litestreamw with cloudflare r2. I added environment variables but they weren't committed.

Then I used this solution (see the commit named stop tracking .env.development & .env.production) to stop tracking those environment files altogether.

git rm --cached .\.env.development .\.env.production

So, next time I'll just use the 2nd command & add .env.development & .env.production to .gitignore to stop tracking them altogether from the next commit.

Pro-Tip: Always check git status to make sure you are not committing real environment variables to .git or use dotenvx.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文