TT Lab
开始
学习 学习路径 课程

Git 实战

令牌进了历史 —— 删了还是能打出来

在 TT Lab 中继续学习

目标

把机密文件和大文件真正从历史中移除,并确认移除之后还会残留什么。

为什么重要

git 是内容寻址存储。每个文件都会成为一个 blob 对象,只要还有指向该 blob 的树和提交,对象就一直存活。所以 git rm 只表示“从今以后没有”,并不等于“从未发生过”。机密进入仓库时,如果不懂这个区别,就会在删除并提交之后放下心来,继续使用那个令牌。本实验通过命令输出展示这个区别,并让你熟悉真正清除的顺序(重写、移除备份引用、让 reflog 过期、gc)。最后一步是结论——已经扩散出去的副本里仍然存在,所以对机密来说,撤销比清理更优先。

步骤

  1. 在 /root/gitx6/repo 创建一段混有令牌文件和 900KB 大块数据的历史,并加入在工作树中删除它们的提交。
  2. 备好同事副本 /root/gitx6/peer,并把当前状态保存到 notes/before.txt。
  3. 用 git filter-branch 重写所有 ref。
  4. 把对象仍然残留的原因写入 notes/original.txt,并清除那个引用。
  5. 让 reflog 过期,用 gc --prune=now 真正删除之后,把体积保存到 notes/after.txt。
  6. 把所有哈希都已改变的事实保存到 notes/rewrite.txt。
  7. 让 /root/gitx6/peer 跟进新历史,并把该副本中是否仍留有机密写入 notes/collab.txt。
  8. 在 notes/report.md 中整理事故响应的顺序。

参考

创建混有令牌和大块数据的历史

在 /root/gitx6/repo 创建一段混有令牌文件和 900KB 大块数据的历史,并加入在工作树中删除它们的提交。

堆叠五个提交——应用文件、conf/prod.env、assets/blob.bin、修改应用、以及 git rm conf/prod.env 提交。中途创建一个 side 分支,并打上带注释的标签 v1。要在后面看到重写会动到所有 ref,就必须有分支和标签。conf/prod.env 的内容必须与实验说明中 ## 참고(韩文,意为“参考”)一节所写的两行完全一致——因为后面的步骤要通过内容来确认那个 blob 是否已经消失。

明明删了,原文还是能取出来

备好同事副本 /root/gitx6/peer,并把当前状态保存到 notes/before.txt。

先用 git clone /root/gitx6/repo /root/gitx6/peer 备好重写之前的副本(第 7 步要用)。然后用 git count-objects -vH 测量体积,在 git rev-list --objects --all 中查看这两个路径是否出现,并把 git cat-file -p <커밋>:conf/prod.env(占位符为提交)能原样取出令牌原文这一点也写进文件。还要记下当前的 HEAD 哈希,第 6 步要做比较。

重写所有 ref

用 git filter-branch 重写所有 ref。

给 --index-filter 传入 git rm -r --cached --ignore-unmatch <경로들>(占位符为路径列表),并同时使用 --prune-empty、--tag-name-filter cat、-- --all。如果只指定一个分支,side 和 v1 就会抓着旧提交残留下来。10 秒警告用 FILTER_BRANCH_SQUELCH_WARNING=1 跳过。

一个都还没有消失

把对象仍然残留的原因写入 notes/original.txt,并清除那个引用。

重写结束了,但 git rev-list --objects --all 里那两个路径依然存在。查看 git for-each-ref refs/original 就能看出原因——filter-branch 为了能够撤销,把原来的 ref 全部做了备份。列出清单,再用 git update-ref -d 逐个删除。

清空 reflog,真正删除

让 reflog 过期,用 gc --prune=now 真正删除之后,把体积保存到 notes/after.txt。

reflog 也是引用——用 git reflog expire --expire=now --expire-unreachable=now --all 清空。然后运行 git gc --prune=now。没有 --prune=now 的话,要等默认宽限期过后才会被删除。把前后两次 git count-objects -vH 并排写出,让人看清体积缩小了多少。

哈希全部变了

把所有哈希都已改变的事实保存到 notes/rewrite.txt。

用 git cat-file -e 在当前仓库中查找第 2 步记下的旧 HEAD 哈希——找不到。提交哈希是连同父提交和树一起计算的,所以只要改动历史前面的一处,后面的全都会变。还要写下标签 v1 现在指向哪个提交。

已经被带走的副本里依然存在

让 /root/gitx6/peer 跟进新历史,并把该副本中是否仍留有机密写入 notes/collab.txt。

在 peer 里执行 git fetch,origin/main 会变成新历史。用 git reset --hard origin/main 让它跟进。然后在那个副本里用 git cat-file -e 查找机密 blob。从中得出的结论就是本实验的要点——写下因此应该先做什么。

整理成事故响应的顺序

在 notes/report.md 中整理事故响应的顺序。

请用带编号的顺序来写。最重要的是什么排在第一位,同时每行说明清理的四个步骤(重写、移除备份引用、让 reflog 过期、gc)为什么是这个顺序。也别漏掉需要向团队通知什么。