最终追溯 .gitignore(如何让 Git completely/retroactively 忘记现在在 .gitignore 中的文件)
Definitive retroactive .gitignore (how to make Git completely/retroactively forget about a file now in .gitignore)
前言
这个问题试图消除关于应用 .gitignore retroactively 的困惑,而不仅仅是 present/future.1
理由
我一直在寻找一种方法来追溯执行我当前的 .gitignore,就好像我在第一次提交时创建了 .gitignore。
我正在寻求的解决方案:
- 是否不会需要手动指定文件
- 不需要提交
- 将追溯应用于所有分支的所有提交
- 将忽略 .git忽略工作目录中指定的文件,不会删除它们(就像原来的根-committed .git会忽略文件)
- 将使用 git,不会使用 BFG
- 将适用于。git忽略例外情况,例如:
*.ext
!*special.ext
不是解决方案
git rm --cached *.ext
git commit
这需要 1. 手动指定文件和 2. 额外的提交,当其他开发人员拉取时,这将导致新忽略的文件 删除。 (它实际上只是一个 git rm
- 这是 从 git 跟踪中删除 - 但它将文件单独留在本地(你的) 工作目录。其他 git pull
之后将收到文件 删除 提交)
git filter-branch --index-filter 'git rm --cached *.ext'
虽然此 确实 追溯清除文件,但它 1. 需要手动指定文件和 2. 就像普通的 git rm
(对于其他 git pull
)!
脚注
1SO 上有很多类似的帖子,问题定义不明确,答案甚至不准确。请参阅 this question with 23 answers where the accepted answer with ~4k votes is incorrect according to the standard definition of "forget" as noted by one mostly-correct answer, and only 2 answers 包含 所需的 git filter-branch
命令。
This question with 21 answers is 被标记为与前一个重复,但问题的定义不同(忽略与忘记),所以虽然答案可能是合适的,它不是重复项。
是我发现的最接近我正在寻找的东西,但答案并非在所有情况下都有效(带空格的路径......)并且可能有点复杂比创建外部存储库所必需的。git忽略文件并将其复制到每个提交中。
编辑:我最近为自己找到了 git-filter-repo. It may be a better choice. Perhaps a good idea to investigate the rationale and filter-branch gotchas,但它们不会影响我下面的用例。
此方法使Git完全忘记忽略的文件(过去/present/future),但不 从工作目录中删除任何内容(即使从远程重新拉取)。
此方法需要使用 /.git/info/exclude
(首选)或 预先存在的 .gitignore
所有 有文件的提交ignored/forgotten。 1
此方法避免在下一个git pull
2[=39 上从其他开发人员机器上删除新忽略的文件=]
所有 方法执行 Git 忽略事后行为有效地重写历史,因此 significant ramifications 任何 public/shared/collaborative 在这个过程之后可能会被拉回的回购协议。 3
一般建议:从干净的存储库开始 - 所有内容都已提交,工作目录或索引中没有任何待处理的内容,并进行备份!
另外,评论/revision history of (and revision history of this question)可能是useful/enlightening.
#commit up-to-date .gitignore (if not already existing)
#these commands must be run on each branch
#these commands are not strictly necessary if you don't want/need a .gitignore file. .git/info/exclude can be used instead
git add .gitignore
git commit -m "Create .gitignore"
#apply standard git ignore behavior only to current index, not working directory (--cached)
#if this command returns nothing, ensure /.git/info/exclude AND/OR .gitignore exist
#this command must be run on each branch
#if using .git/info/exclude, it will need to be modified per branch run, if the branches have differing (per-branch) .gitignore requirements.
git ls-files -z --ignored --exclude-standard | xargs -r0 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
#optionally use the --amend flag to merge this commit with the previous one instead of creating 2 commits.
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 -r0 git rm -f --ignore-unmatch' --prune-empty --tag-name-filter cat -- --all
#List all still-existing files that are now ignored properly
#if this command returns nothing, it's time to restore from backup and start over
#this command must be run on each branch
git ls-files --other --ignored --exclude-standard
最后,遵循 this GitHub guide 的其余部分(从第 6 步开始),其中包括关于以下命令的重要warnings/information。
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
文件的详细信息 into 需要它的历史提交超出了这个答案的范围。我希望在根提交中有一个合适的 .gitignore
,就好像这是我做的第一件事一样。其他人可能不在乎,因为 /.git/info/exclude
可以完成相同的事情,无论 .gitignore
存在于提交历史中的什么位置,显然重写历史是一个 非常 敏感的主题,即使知道 ramifications.
FWIW,可能的方法可能包括 git rebase
或 git filter-branch
将 external .gitignore
复制到每个提交中,例如
2 通过提交独立 git rm --cached
命令的结果强制执行 git 事后忽略行为可能会导致新忽略的文件 删除 将来会从强制推送的遥控器中拉出。 git filter-branch
命令中的 --prune-empty
标志( 或 git reset HEAD^
之后)通过自动删除之前的“删除所有忽略的文件”索引来避免此问题-只提交。
3 重写 git 历史也会更改提交哈希,这将 对 以后从 public/shared/collaborative回购。在对这样的 repo 执行此操作之前,请充分理解 ramifications。 本 Git 中心指南 指定以下内容:
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.
不影响远程仓库的替代解决方案是git update-index --assume-unchanged </path/file>
或git update-index --skip-worktree <file>
,可以在here中找到示例。
这可能只是部分答案,但这是我如何根据当前的 git 提交追溯删除文件的方法。git忽略文件:
- 备份您正在处理的 repo 文件夹。我刚刚制作了整个文件夹的 .7z 存档。
- 安装git-filter-repo
- 暂时将您的 .gitignore 文件复制到其他地方。因为我在 Windows 并使用命令提示符,所以我 运行
copy .gitignore ..\
并且只是将临时副本目录升级到
- 如果您的 .gitignore 文件有通配符过滤器(如
nbproject/Makefile-*
),您将需要编辑临时复制的 .gitignore 文件,以便这些行显示为 glob:nbproject/Makefile-*
- 运行
git filter-repo --invert-paths --paths-from-file ..\.gitignore
。我的理解是,这使用临时副本作为要删除的 files/directories 列表。注意:如果您收到有关您的存储库不是干净克隆的错误,请在 git-filter-repo 帮助中搜索“FRESH CLONE SAFETY CHECK AND --FORCE”。小心。
有关详细信息,请参阅:
git-filter-repo help(搜索“基于多路径过滤”)
免责声明:我不知道自己在做什么,但这对我有用。
前言
这个问题试图消除关于应用 .gitignore retroactively 的困惑,而不仅仅是 present/future.1
理由
我一直在寻找一种方法来追溯执行我当前的 .gitignore,就好像我在第一次提交时创建了 .gitignore。
我正在寻求的解决方案:
- 是否不会需要手动指定文件
- 不需要提交
- 将追溯应用于所有分支的所有提交
- 将忽略 .git忽略工作目录中指定的文件,不会删除它们(就像原来的根-committed .git会忽略文件)
- 将使用 git,不会使用 BFG
- 将适用于。git忽略例外情况,例如:
*.ext
!*special.ext
不是解决方案
git rm --cached *.ext
git commit
这需要 1. 手动指定文件和 2. 额外的提交,当其他开发人员拉取时,这将导致新忽略的文件 删除。 (它实际上只是一个 git rm
- 这是 从 git 跟踪中删除 - 但它将文件单独留在本地(你的) 工作目录。其他 git pull
之后将收到文件 删除 提交)
git filter-branch --index-filter 'git rm --cached *.ext'
虽然此 确实 追溯清除文件,但它 1. 需要手动指定文件和 2. git rm
(对于其他 git pull
)!
脚注
1SO 上有很多类似的帖子,问题定义不明确,答案甚至不准确。请参阅 this question with 23 answers where the accepted answer with ~4k votes is incorrect according to the standard definition of "forget" as noted by one mostly-correct answer, and only 2 answers 包含 所需的 git filter-branch
命令。
This question with 21 answers is 被标记为与前一个重复,但问题的定义不同(忽略与忘记),所以虽然答案可能是合适的,它不是重复项。
编辑:我最近为自己找到了 git-filter-repo. It may be a better choice. Perhaps a good idea to investigate the rationale and filter-branch gotchas,但它们不会影响我下面的用例。
此方法使Git完全忘记忽略的文件(过去/present/future),但不 从工作目录中删除任何内容(即使从远程重新拉取)。
此方法需要使用 /.git/info/exclude
(首选)或 预先存在的 .gitignore
所有 有文件的提交ignored/forgotten。 1
此方法避免在下一个git pull
2[=39 上从其他开发人员机器上删除新忽略的文件=]
所有 方法执行 Git 忽略事后行为有效地重写历史,因此 significant ramifications 任何 public/shared/collaborative 在这个过程之后可能会被拉回的回购协议。 3
一般建议:从干净的存储库开始 - 所有内容都已提交,工作目录或索引中没有任何待处理的内容,并进行备份!
另外,评论/revision history of
#commit up-to-date .gitignore (if not already existing)
#these commands must be run on each branch
#these commands are not strictly necessary if you don't want/need a .gitignore file. .git/info/exclude can be used instead
git add .gitignore
git commit -m "Create .gitignore"
#apply standard git ignore behavior only to current index, not working directory (--cached)
#if this command returns nothing, ensure /.git/info/exclude AND/OR .gitignore exist
#this command must be run on each branch
#if using .git/info/exclude, it will need to be modified per branch run, if the branches have differing (per-branch) .gitignore requirements.
git ls-files -z --ignored --exclude-standard | xargs -r0 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
#optionally use the --amend flag to merge this commit with the previous one instead of creating 2 commits.
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 -r0 git rm -f --ignore-unmatch' --prune-empty --tag-name-filter cat -- --all
#List all still-existing files that are now ignored properly
#if this command returns nothing, it's time to restore from backup and start over
#this command must be run on each branch
git ls-files --other --ignored --exclude-standard
最后,遵循 this GitHub guide 的其余部分(从第 6 步开始),其中包括关于以下命令的重要warnings/information。
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
文件的详细信息 into 需要它的历史提交超出了这个答案的范围。我希望在根提交中有一个合适的 .gitignore
,就好像这是我做的第一件事一样。其他人可能不在乎,因为 /.git/info/exclude
可以完成相同的事情,无论 .gitignore
存在于提交历史中的什么位置,显然重写历史是一个 非常 敏感的主题,即使知道 ramifications.
FWIW,可能的方法可能包括 git rebase
或 git filter-branch
将 external .gitignore
复制到每个提交中,例如
2 通过提交独立 git rm --cached
命令的结果强制执行 git 事后忽略行为可能会导致新忽略的文件 删除 将来会从强制推送的遥控器中拉出。 git filter-branch
命令中的 --prune-empty
标志( 或 git reset HEAD^
之后)通过自动删除之前的“删除所有忽略的文件”索引来避免此问题-只提交。
3 重写 git 历史也会更改提交哈希,这将 对 以后从 public/shared/collaborative回购。在对这样的 repo 执行此操作之前,请充分理解 ramifications。 本 Git 中心指南 指定以下内容:
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.
不影响远程仓库的替代解决方案是git update-index --assume-unchanged </path/file>
或git update-index --skip-worktree <file>
,可以在here中找到示例。
这可能只是部分答案,但这是我如何根据当前的 git 提交追溯删除文件的方法。git忽略文件:
- 备份您正在处理的 repo 文件夹。我刚刚制作了整个文件夹的 .7z 存档。
- 安装git-filter-repo
- 暂时将您的 .gitignore 文件复制到其他地方。因为我在 Windows 并使用命令提示符,所以我 运行
copy .gitignore ..\
并且只是将临时副本目录升级到 - 如果您的 .gitignore 文件有通配符过滤器(如
nbproject/Makefile-*
),您将需要编辑临时复制的 .gitignore 文件,以便这些行显示为glob:nbproject/Makefile-*
- 运行
git filter-repo --invert-paths --paths-from-file ..\.gitignore
。我的理解是,这使用临时副本作为要删除的 files/directories 列表。注意:如果您收到有关您的存储库不是干净克隆的错误,请在 git-filter-repo 帮助中搜索“FRESH CLONE SAFETY CHECK AND --FORCE”。小心。
有关详细信息,请参阅: git-filter-repo help(搜索“基于多路径过滤”)
免责声明:我不知道自己在做什么,但这对我有用。