GitHub永不遗忘,使用git push -f来覆盖的提交依旧保留

1.引言:你删除的提交,并没有完全消失

很多开发者(包括我在内)以为,只要强制推送**(git push -f)** 就能把上一次不小心提交的敏感信息从仓库里"抹掉"。

但现实是:即使提交在分支里消失了,它仍然存在,并且依然可访问。

这种现象意味着:

  • 误提交的密钥依旧可能被恢复

  • 只要有人知道提交哈希 ,就能找到它

  • 这类"消失的提交"可能长期存在,不会被自动删除

换句话说:删除(覆盖)提交 ≠ 删除风险。

一、什么是"被删除的提交"?

当你执行以下操作:

bash 复制代码
- `git reset --hard HEAD~1`  
- `git push --force`  

你只是让这个提交在分支历史中变得"不可见",而不是"不可访问"。

Git 的工作机制决定了:

  • 提交对象仍然存在于服务器

  • 只是没有分支引用它

  • 但只要知道哈希值,就可以访问

所以它更像是"隐藏",而非"抹除"。

二、为什么 GitHub 会保留这些提交?

原因可能包括:

  • 审计与追踪需求

  • 拉取请求(PR)历史

  • 分叉网络依赖关系

  • 代码托管的内部索引

这些系统让 GitHub 很难(也不愿意)彻底删除提交对象。

结果就是:强推后"消失"的提交仍在后台保留

这里给个简单的例子吧

1.直接创建仓库并且模仿错误提交密钥

bash 复制代码
# 初始化仓库
mkdir test-repo && cd test-repo
git init
echo "正常文件" > file1.txt
git add . && git commit -m "第一次提交"

# 不小心提交密钥
echo "SECRET_KEY=abc123" > .env
git add . && git commit -m "添加配置文件"

2.oh no,怎么吧密码提交了,尝试强制推送来删除上一次提交

bash 复制代码
# 回退到第一次提交
git reset --hard HEAD~1

# 强制推送
git push --force origin main

3.这回总没事了吧,我们尝试通过上一次提交的哈希访问提交

bash 复制代码
# 即使强制推送后,只要知道提交哈希仍可查看
git show 上一次提交的哈希值

我们记得提交哈希,我们在 GitHub 上在线检查,发现该提交仍然可以被访问 - 9eedfa00983b7269a75d76ec5e008565c2eff(甚至使用四个十六进制数字 9eef访问也足够了)。然而,这次我们收到一条消息,说该提交已被删除或不属于此仓库的任何分支。

三、如何找到这些"消失的提交"?

核心思路是:

通过 Git 或平台日志中记录的"零提交推送事件"来定位被覆盖的提交

当你执行 git push -f时,如果这次强制推送没有新增提交 ,而仅仅是将分支指针移动到了更旧的提交位置,那么这次推送事件在日志中会呈现一种特殊现象:

  • 推送事件存在

  • 但提交列表为空

这意味着: 这意味着,本次推送实质上是"丢弃"了原先在分支头部的一些提交,使分支指向了历史中的某个旧节点。而这些被跳过的提交,就是因强推而"消失"的提交。

举个例子帮助定位:

假设某分支原有提交顺序为:

bash 复制代码
A --- B --- C(分支原头部)

某次强制推送将分支指针从 C ​ 直接移回 A,那么这次推送:

  • 在 Git 服务端(如 GitHub/ GitLab)的推送日志中会被记录为一次分支更新;

  • 但提交列表中不会包含任何新的提交(因为 C→A 是回退);

  • 此时,提交 B 和 C​ 就成为"被抛弃"的提交,但它们并没有被立即从仓库中删除,而是成为"悬空对象"(dangling commits),仍可通过特定方式找回

如何利用这类日志进行恢复?

  1. **查看Git服务端推送日志(Push Logs)**​

    • 在 GitHub 上,进入仓库 → "Insights" → "Push Logs",查看分支的推送历史。如果某次推送的提交数为0,且之后分支的头部变更为更早的提交,则很可能是一次覆盖性强推。

    • 通过日志找到这次推送之前的提交哈希(即被覆盖前的分支头部),即可用于恢复

于是,只要找到这类"零提交推送事件",就能定位到被删除的提交哈希。

四、为什么这些提交仍然危险?

因为提交中可能包含:

  • 云服务密钥

  • 私有令牌

  • 数据库连接密码

  • 生产环境配置文件

即使提交被"删除",**只要能访问它,就能读取敏感信息**。

并且现实中,很多密钥在长时间内不会被撤销,这就使它们仍然有效。

五、为什么会发生这个情况

当你重置后强制推送时(即 git reset --hard HEAD~1后接 git push --force),你从分支中移除了 Git 对该提交的引用,使其无法通过正常的 Git 导航(如 git log)访问。然而,该提交在 GitHub 上仍然可以访问,因为 GitHub 存储了这些引用日志(reflogs)。

为什么?我不完全确定,但 GitHub 确实给出了一些提示。在我看来,GitHub 远比一个单纯的 git 服务器复杂。它有许多层,包括拉取请求、分支、公私设置等等。

我的猜测是,为了支持所有这些功能,GitHub 会存储所有提交并且从不删除它们。这里有一些需要考虑的情况:

  • 拉取请求是什么? ​ 这些只是临时分支,正如 Aqua Security 所写,可以通过使用 git -c "remote.origin.fetch=+refs/*:refs/remotes/origin/*" fetch origin获取所有引用来检索。

  • **GitHub 的分支网络如何工作?**​ 当你"分支"一个仓库时会发生什么?所有数据都会被复制,包括你可能删除的提交。

对于这些情况,可能还有许多其他原因(审计?监控?),GitHub 会存储所有提交,即使你强制推送头部并"删除"提交,也不会删除它们。

六、如何大规模识别这些风险?

可以归纳成一个流程模型:

  1. 获取公开事件数据

  2. 筛选"零提交推送事件 "

  3. 提取被覆盖的提交哈希

  4. 访问这些提交内容

  5. 扫描是否含敏感信息

  6. 筛选高价值目标

这套流程可以自动化,但核心原理不变。

当然还有更简单的!

claude!我准备推送代码了,帮我检查一下我的代码或者配置中有没有敏感信息

只要在推送前问问你的代码编辑器左边的ai助手一般就不会出现这个问题了

学习原文:

https://trufflesecurity.com/blog/guest-post-how-i-scanned-all-of-github-s-oops-commits-for-leaked-secrets

相关推荐
m0_694845573 小时前
music-website 是什么?前后端分离音乐网站部署实战
linux·运维·服务器·云计算·github
独自破碎E3 小时前
已经 Push 到远程的提交,如何修改 Commit 信息?
开发语言·github
Vermouth_003 小时前
git clone的时候提示access denied
git
qq_437657275 小时前
清楚本地的git并重新登录
git
jiang_changsheng5 小时前
工作流agent汇总分析 2
java·人工智能·git·python·机器学习·github·语音识别
顶点多余5 小时前
版本控制器-git
linux·git
馨谙6 小时前
Ansible 配置文件详解:让自动化管理更轻松
运维·github·ansible
夔曦6 小时前
Git工程日常下拉/上传完整流程(自用)
git
Gofarlic_OMS6 小时前
Altium许可证状态自动化监控方案
大数据·运维·服务器·人工智能·自动化·github