使用方法
- 这个 Git速查表打开时搜索框里已经填了 历史,用来演示按口径筛选:「会不会改写历史」一列里带判定文字的命令会被挑出来,正好 12 条,也就是全部 30 条里会改动提交历史的那些。
- 把搜索框改成
reflog、撤销、bisect之类的关键词,场景、命令、作用、判定四列都会参与匹配,大小写不敏感;清空搜索框即恢复全部 30 条。 - 右边「回退步数 n」填 1(示例值),结果区会用这个 n 生成四条
HEAD~n命令预览,方便直接复制。允许 1~50 的整数。 - 四个场景分组默认全勾:撤销与回退 9 条、变基与合并 6 条、查找与调试 7 条、清理与危险 8 条。只关心某一类时取消其余勾选即可。
- 在搜索框或 n 输入框里按 Enter 等于点「筛选命令」;「复制对照表」把当前结果以 TSV 送进剪贴板,「导出 CSV」生成带 BOM 的表格文件。改 n 只影响上面的命令预览,不影响表格内容。
Git速查表能解决什么问题
一是在动手之前先看清风险。网上抄来一条命令就敲,是这个工具最想拦住的场景。同样叫「撤销提交」,git revert 只是新增一个反向提交、历史只增不减,而 git reset --hard 会把 HEAD 往回搬、顺手丢掉工作区改动。本页把每条命令的判定写在「会不会改写历史」一列,先看那一列再决定敲不敲。
二是区分本地改写与远端改写。改写本地历史只影响你自己的仓库,git reset、git rebase、git commit --amend 都属于这一类;一旦推送到公共分支,就需要 git push --force 才能覆盖远端,而它会直接丢掉同事已经推送的提交。表格里把这两类分开标注,是这一列最关键的区分。
三是找回被误操作丢掉的东西。误执行 git reset --hard 之后,提交并没有立刻消失,只是从分支上不可达了:git reflog 默认保留 90 天,git reset --hard ORIG_HEAD 能把 HEAD 搬回去,git fsck --lost-found 还能捞回悬空对象。本页把这几条放在同一组,出事了按顺序试。
四是把二分查找当成常规手段。缺陷不知道是哪次提交引入的时候,git bisect 比逐个 checkout 快得多,1000 个提交的区间最多 10 步就能定位。这一组命令全部是只读操作,不改写任何历史,可以放心用。
本页不做这些事:不执行任何 git 命令、不连接你的仓库、不解析 .git 目录,只是一份带检索的文本速查表;也不讲 Git 的安装与远程仓库配置。要找某个正则写法请用页面底部的「正则速查表」,要查 HTTP 状态码含义请用「HTTP状态码代码速查表」。
判定原理:什么才算「改写历史」
要判断一条命令危不危险,先要知道 Git 把数据存在哪里。提交并不是「一个可以就地修改的文件夹」,而是内容寻址的不可变对象:对象内容的 SHA-1 摘要就是它的 ID。实际算法是 SHA-1("blob " + 内容字节数 + "\0" + 内容),本页复算过——对内容 hello(5 字节)求摘要得到 b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0;仅仅在末尾多一个换行,结果就变成 ce013625030ba8dba906f756967f9e9ca394464a,与前者毫无相似之处。SHA-1 输出 40 个十六进制字符、160 bit;正在推进的 SHA-256 版本会变成 64 个字符、256 bit。
因为提交对象里保存着父提交的 ID,改任何一个字节都会连锁改变它以及它所有后代的 ID。这就解释了为什么 git commit --amend 不是「改一下提交信息」那么轻——它生成的是一个全新的提交对象;也解释了 git rebase 为什么叫「重放」:把一条分支上的 12 个提交搬到新基底上,会产生 12 个全新的提交对象,12 个 ID 全部变样,旧的那 12 个只在 reflog 里还可达。
所以本页的判定标准只有一条:这条命令会不会让已经存在的提交从分支引用上脱离可达。会,就标「改写本地历史」;只影响远端引用的标「改写远程历史」;从头到尾不移动任何引用的标「不改写」;连对象库都不写的标「只读」。分支和标签本身只是仓库里一个记录提交 ID 的引用文件,内容就是 40 个十六进制字符加一个换行、共 41 字节,所以 git branch -D 删掉的是引用而不是提交,对象还在,这也是删错分支后还能救回来的原因。
反向操作也有代价边界:git reset --hard 丢弃的是工作区里从未提交过的改动,这部分内容从来没有进过对象库,reflog 里也没有记录,找不回来;而已经提交过的内容即使变成悬空对象,也能在 git 的默认回收策略生效前捞回来。默认值是 gc.reflogExpire 90 天、gc.reflogExpireUnreachable 30 天,一旦手工执行 git gc --prune=now,悬空对象可能当场消失。这就是本页把 gc 单独标成「改写仓库存储」而不是「只读」的原因。
完整示例:撤销一次已经推送出去的提交
场景:提交已经推到公共分支 main,现在要撤销它。页面默认的 n = 1 表示最近一次提交,结果区给出的预览就是下面这四条,取舍如下:
git revert HEAD~1—— 生成一个反向提交抵消它。不改写历史,历史只增不减,别人拉取后不会冲突,这是已推送提交的正确做法;git rebase -i HEAD~1—— 交互式整理最近 1 个提交,可用于把提交信息改对,但它会重写提交对象,改写本地历史,之后必须强推;git reset --soft HEAD~1—— 只把 HEAD 往回搬一位,改动退回暂存区,随后还得git push --force才能让远端同步。既然要强推,就不该在公共分支上用;git reset --hard HEAD~1—— 同上,并且连工作区的改动一起丢。远端那条提交别人可能已经拉走,强推后会出现「你的历史和别人的历史对不上」的分叉。
把这段取舍写成可执行的顺序,就是本页想表达的用法:先看「会不会改写历史」那一列,再决定用 revert 还是 reset。判断依据还是对象 ID——revert 产生的是一个父提交指向当前 HEAD 的新提交,原提交仍然可达,所以协作者的仓库不需要任何特殊处理;reset 是移动分支引用,原提交从分支上脱离,远端要同步就必须强推,而强推用 --force-with-lease 比 --force 安全:前者会先比对远端引用是否被你之外的提交改动过,后者无条件覆盖。
| 做法 | 会不会改写历史 | 已推送分支能不能用 | 丢数据风险 |
|---|---|---|---|
| git revert | 不改写 | 可以,推荐 | 无 |
| git rebase -i | 改写本地历史 | 要强推,不建议 | 无(提交内容还在) |
| git reset --soft | 改写本地历史 | 要强推,不建议 | 无(改动留在暂存区) |
| git reset --hard | 改写本地历史 | 要强推,不建议 | 丢弃未提交改动 |
| git push --force-with-lease | 改写远程历史 | 可用但需先比对 | 覆盖他人的提交 |
| git push --force | 改写远程历史 | 可用但危险 | 直接丢掉他人的提交 |
场景分组与危险等级对照表
全部 30 条命令按判定分布如下。「只读」和「不改写」加起来有 17 条,超过一半——日常排查和清理并不需要动历史,真正会改动提交历史的只有 13 条。
| 会不会改写历史 | 条数 | 典型命令 | 什么时候用 |
|---|---|---|---|
| 只读 | 9 | git log / blame / bisect / fsck | 排查与定位,随便用 |
| 不改写 | 8 | git revert / cherry-pick / stash | 已推送分支上的常规操作 |
| 改写本地历史 | 9 | git reset / rebase / commit --amend | 只在还没推送的本地分支上做 |
| 改写远程历史 | 2 | git push --force / --force-with-lease | 确认没人依赖该分支的提交后 |
| 改写全部历史 | 1 | git filter-repo | 清理误提交的密钥或大文件,需全员重新克隆 |
| 改写仓库存储 | 1 | git gc --prune=now | 清理悬空对象前想清楚还要不要它们 |
四个场景分组各有多少条、各自的关键命令是什么:
| 场景分组 | 条数 | 本组最常用的命令 | 本组标注「改写」的条数 |
|---|---|---|---|
| 撤销与回退 | 9 | git reset --soft / git revert / git reflog | 5 |
| 变基与合并 | 6 | git rebase -i / git cherry-pick | 4 |
| 查找与调试 | 7 | git bisect / git blame / git log -S | 0 |
| 清理与危险 | 8 | git clean -fd / git push --force-with-lease | 4 |
输入范围、边界与安全边界
- 回退步数 n 允许 1~50 的整数。0 没有意义(HEAD~0 就是 HEAD 本身),负数、小数与字母会被拒绝;超过 50 时会提示改用具体的提交 ID——真要点名 50 次以上的提交,写
HEAD~53远不如直接写git log里查到的短 ID 清楚。 - 四个场景分组至少要勾一个。全部取消勾选时表格会是空的,这个 Git速查表不会给出 0 行的空表,而是直接提示至少要保留一个分组。
- 搜索是纯文本匹配,不解析命令语法。输入
reset --hard会当作整串子串去匹配,因为数据里就是git reset --hard HEAD~n这样的完整写法,所以能命中;输入reset -X这类不完整的写法则可能没有结果,此时工具会提示换关键词。 - 默认结果的 12 条不是「最重要的 12 条」,而是搜索框默认值「历史」筛出来的 12 条,也就是全部会改动提交历史的命令。想看完整的 30 条,清空搜索框即可。
- 表格一次渲染 12 行,其余靠「加载更多」逐批补上,避免一次插入几十行拖慢页面;导出的 CSV 与「复制对照表」给的是全部匹配行,不只是屏幕上那 12 行。
- reflog 不是万能的。默认保留 90 天,且只记录引用的移动,不记录工作区里从未提交的文件。删掉未跟踪文件(
git clean -fd)或被git reset --hard丢弃的未提交改动,reflog 里没有任何痕迹。 - 二分查找的次数有明确上界。区间内提交数为 N 时最多需要
ceil(log2(N))步:100 个提交最多 7 步,1000 个最多 10 步,100 万个最多 20 步。忘记执行git bisect reset会让你停在游离 HEAD 上。
常见问题
为什么这一列要单列「会不会改写历史」,而不是只标危险等级?
因为「危险」是主观的,改写历史在本地分支上完全是常规操作——把三个临时提交压成一个、改掉写错的提交信息,都靠改写历史完成。真正需要拦住的只有一种情况:改写了别人已经拉走的历史。所以本页把「改本地」和「改远程」分开标注,本地随便改,远程改之前要想清楚。
git revert 和 git reset 到底差在哪?
revert 生成一个新提交,它的改动内容是被撤销提交的「反向补丁」,原提交仍然留在历史里可达,所以不需要强推,协作者无感。reset 是把分支引用往回搬,原提交从分支上脱离,远端要同步就必须强推。一句话:已经推送出去了就用 revert,只在本地没推过才用 reset。
--force 和 --force-with-lease 有什么区别?
前者无条件把远端分支指到你的本地位置,如果同事在你上次拉取后又推了新提交,那些提交会被直接丢掉。后者在推送前先比对远端引用是否仍等于你上次看到的值,只要别人动过就拒绝推送。团队协作里应该固定用 --force-with-lease,把裸 --force 当成例外。
误执行 git reset --hard 之后还能救回来吗?
分两种情况。丢掉的是已经提交过的内容:用 git reflog 找到搬运前的 HEAD 位置,再 git reset --hard <那个 ID> 就能回来,默认 90 天内有效。丢掉的是从未提交的工作区改动:找不回来,那部分内容从来没进过对象库。这也是本页把 reset --hard 备注成高危的原因。
git commit --amend 也算改写历史吗?
算,而且是连锁的。amend 会新建一个提交对象替换最近一次提交,新对象的 ID 与旧对象不同;如果这条分支已经有后代提交,所有后代的 ID 也会跟着变。所以 amend 之后如果之前推送过,就必须强推,而强推的后果按上一条处理。提交还没推送时 amend 是安全的。
git bisect 会不会影响我的工作区?
不会改写历史,但它确实会切换 HEAD,把工作区切到中间某个提交上,所以开始之前应该先清干净工作区。查完务必执行 git bisect reset 回到原来的分支,否则仓库会停在游离 HEAD 状态,看起来像「提交不见了」——其实只是 HEAD 没有指向任何分支。
git clean -fd 删掉的文件能找回吗?
不能。它删除的是没有被 Git 跟踪的文件和目录,不经过回收站,也不在 reflog 或对象库里留记录。习惯做法是先跑 git clean -n 预览一遍要删什么,确认没有 .env、日志、本地数据这类只存在于工作区的东西,再执行 -fd。
表格里的 git gc 为什么也被标成改写?
因为它不动提交,但会动对象库。默认策略下不可达对象要在 gc.reflogExpireUnreachable 规定的 30 天后才可能被回收,而 --prune=now 是要求立刻清理。清理之后,那些只靠 reflog 兜底的「误删提交」就真的没了。所以它是本页唯一的「改写仓库存储」条目,用之前先确认不再需要那些悬空对象。
相关工具
- 正则速查表:查找与替换的语法速查,和本页一样按场景分组。
- SQLJoinsVisual速查表:用图形方式讲清各种 JOIN 的结果集范围。
- HTTP状态码代码速查表:查 4xx / 5xx 状态码的含义与排查方向。
- HTTP请求头速查表:请求头字段的用途与常见取值。
- HTMLEntity速查表:特殊字符与 HTML 实体的对照表。
- CSS单位速查表:px / rem / em / vw 等单位的换算与适用场景。
- chmod权限计算器Unix权限:把 rwx 权限串和八进制数字互相换算。
- 开发者工具:查看全部开发者工具。