如何让Git完全/追溯性地 * 忘记 * 一个现在在.gitignore中的文件)

6l7fqoea  于 2022-11-20  发布在  Git
关注(0)|答案(2)|浏览(189)

前言
这个问题试图澄清关于追溯性地应用.gitignore**的困惑,而不仅仅是现在/未来。1

依据

我一直在寻找一种方法,使我当前的.gitignore可以追溯执行,就像我在第一次提交时创建了.gitignore一样。
我寻求的解决方案:

    • 不 * 需要手动指定文件
    • 不 * 需要提交
  • 将追溯应用于所有分支的所有提交
  • 将 * 忽略工作目录中 * . gitignore指定的文件,不删除它们(就像最初根目录提交的.gitignore文件一样)
  • 将使用git,而不是BFG
  • 将应用于.gitignore异常,如:
*.ext
 !*special.ext

不是解决方案

git rm --cached *.ext
git commit

这需要1.手动指定文件,2.额外提交,这将导致新忽略的文件 deletion 被其他开发者拉取。(实际上它只是一个git rm-这是一个从git跟踪的 deletion-但它会将文件单独留在本地(your)工作目录中。* 其他 * git pull之后会接收文件 deletion commit的人)

git filter-branch --index-filter 'git rm --cached *.ext'

虽然这 * 做 * 清除文件追溯,它1。需要手动指定文件和2。deletes the specified files from the local working directory就像普通git rm(所以也为其他人谁git pull)!

注脚

1 SO上有许多类似的帖子,其中的问题没有明确定义,答案甚至更不准确。请参见this question with 23 answers,其中accepted answer with ~4k votes不正确的(根据“forget”as noted by one mostly-correct answer的标准定义),only 2 answers包含*required***git filter-branch命令。
This question with 21 answers被标记为前一个问题的重复,但问题的定义不同(忽略与忘记),因此,虽然答案可能是适当的,但它
不是**重复。
This question是我发现的最接近我所寻找的东西的,但是答案并不是在所有情况下都有效(带空格的路径......),并且关于创建一个外部到存储库的.gitignore文件并将其复制到每个提交中,可能比必要的要复杂一些。

xhv8bpkk

xhv8bpkk1#

这可能只是部分答案,但下面是我如何根据当前的.gitignore文件,从以前的git提交中追溯删除文件的:
1.备份您正在使用的repo文件夹。我刚刚为整个文件夹制作了一个.7z存档。
1.安装git-filter-repo
1.临时复制您的.gitignore文件到其他地方。由于我在Windows上使用命令提示符,我运行了copy .gitignore ..\,只是临时复制目录级别
1.如果.gitignore文件有通配符过滤器(如nbproject/Makefile-*),则需要编辑临时复制的.gitignore文件,使这些行显示为glob:nbproject/Makefile-*
1.运行git filter-repo --invert-paths --paths-from-file ..\.gitignore。我的理解是,这将使用临时副本作为要删除的文件/目录的列表。如果你收到一个关于你的repo不是一个干净的克隆的错误,在git-filter-repo帮助中搜索“FRESHCLONESAFETYCHECK AND --FORCE”。
如需详细信息,请参阅:git-filter-repo help(搜索“基于多路径过滤”)
免责声明:我不知道我在做什么,但这对我有用。

osh3o9ms

osh3o9ms2#

编辑 : 我 最近 发现 了 git-filter-repo 。 它 可能 是 一 个 更 好 的 选择 。 也许 是 一 个 好 主意 , 调查 的 基本 原理 和 过滤 分支 陷阱 自己 , 但 他们 不会 影响 我 的 用例 如下 。
这个 方法 可以 让 Git * * 完全 忘记 * * 被 忽略 的 文件 ( * * 过去 * */现在/将来 ) , 但 * * 不会 * * 删除 工作 目录 中 的 任何 内容 ( 即使 从 远程 重新 拉 取 ) 。
此 方法 需要 使用 /.git/info/exclude ( 首选 ) * * OR * * a * * 在 * * 所有 * * 具有 要 忽略/忘记 的 文件 的 提交 中 预先 存在 的 * * .gitignore 。 1
此 方法 * * 避免 * * 在 下 一 个 git pull 2 从 其他 开发 人员 计算机 中 删除 最近 忽略 的 文件

  • 所有 * 执行 Git 的 方法 都 忽略 了 事后 行为 , 有效 地 重写 了 历史 记录 , 因此 对 任何 可能 在 此 过程 后 被 拉 取 的 公共/共享/协作 仓库 都 有 significant ramifications 。 3

一般 建议 :* * 从 一 个 干净 的 存储 库 开始 * * - 所有 内容 都 已 提交 , 工作 目录 或 索引 中 没有 挂 起 的 内容 , * * 并 进行 备份 * * !
此外 , this answer 的 评论/revision historythis questionand revision history ) 可能 是 有用 的/启发 性 的 。

#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 开始 ) * * , 其中 包括 有关 以下 命令 的 重要 警告/信息 * * 。

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 ,其他 人 可能 不 在乎 , 因为 /.git/info/exclude 可以 完成 同样 的 事情 , 而 不管 .gitignore 存在 于 提交 历史 中 的 什么 位置 ,很 明显 , 重写 历史 是 一 个 非常 敏感 的 主题 , 即使 知道 ramifications
FWIW , 潜在 的 方法 可能 包括 git rebasegit filter-branch , 它 将 * 外部 * .gitignore 复制 到 每个 提交 中 , 就 像 this question 的 答案 一样
2 通过 提交 独立 的 git rm --cached 命令 的 结果 来 强制 git ignore 行为 可能 会 导致 新 忽略 的 文件 * * 删除 * * 在 将来 从 强制 推送 的 远程 数据 库 中 拉 取 。 git filter-branch 命令 中 的 --prune-empty 标志 ( * 或 * git reset HEAD^ 之后 ) 通过 自动 删除 之前 的 " 删除 所有 忽略 的 文件 " 仅 索引 提交 来 避免 这个 问题 。
3 重写 git 历史 记录 也 会 改变 提交 哈希 值 , 这 将 在 将来 从 公共/共享/协作 仓库 拉 取 时 产生 wreak havoc 。 在 对 这样 的 仓库 进行 重写 之前 , 请 充分 理解 ramificationsThis GitHub guide 指定 了 以下 内容 :
告诉 你 的 合作 者 不要 合并 他们 从 旧 的 ( 被 污染 的 ) 仓库 历史 中 创建 的 任何 分支 。 一 次 合并 提交 可能 会 重新 引入 一些 或 全部 被 污染 的 历史 , 而 你 刚刚 花 了 很 大 的 力气 清除 了 这些 历史 。

    • 不 * * 影响 远程 存储 库 的 替代 解决 方案 是 git update-index --assume-unchanged </path/file>git update-index --skip-worktree <file> , 其 示例 可 在 here 中 找到 。

相关问题