先看出事的那一刻
2026 年 8 月 19 日,一份学习资料要放进 Git 仓库。AI 执行了最常见的两条命令,git init 和 git add -A。屏幕上列出了 124 个要提交的文件,它看了前 5 行,提交,推送。
推送卡住了。重试,又卡住;第三次,一直停在"计数对象"这一步。查一下仓库里每个文件的大小,排在最前面的是一个 516MB 的语料压缩包:忽略规则只排除了 PDF 和 Word,没管压缩包。
这不是这两个项目唯一一次把不该提交的东西放进仓库。另一个仓库里,两个数据库日志文件一待就是两个月:
这节课要回答的是:怎样用 Git 给 AI 的改动留好退路?哪些东西一旦提交进去,就很难再拿出来?
装备几个词
为什么要懂
AI 替你做了
AI 会替你执行 git add、git commit、git push,一条命令就把所有改动存档、上传。
留给你的
看一眼到底提交了什么:哪些文件不该进仓库、这次提交是不是只做了一件事。git add -A 不会替你挑。
不懂的代价
大文件让推送卡死、仓库膨胀;数据库文件和密钥进了历史,删掉当前版本,历史里也还留着,很难清理干净。
存档、分支、退路
和 AI 一起改代码,最实用的 Git 习惯只有三个:
- 动手之前先提交一次,让工作区是干净的。改坏了,
git restore .就能回到这一刻。 - 每完成一件独立的事就提交一次。出了问题能精确找到是哪一次,用
git revert 提交号只撤回那一次,不用整个推倒重来。 - 大改动放在分支上做。这个网站的每个阶段都在单独的分支上,推送后先看预览地址,确认了才合并到
main上线。
这三件事的共同点,是给每一步留一个存档。AI 改得越快、越多,存档就越要密。
哪些东西不该进仓库
| 类别 | 例子 | 为什么 |
|---|---|---|
| 依赖 | node_modules | 体积巨大,随时能按锁文件重新装 |
| 构建产物 | dist | 每次构建重新生成 |
| 密钥和本地配置 | .env | 进了历史就要当作已经泄露(第 11 课) |
| 数据库文件 | *.db,以及旁边的 -wal、-shm | 带着用户数据,而且随时在变 |
| 大文件 | 压缩包、视频、原始语料 | 让仓库膨胀、推送变慢,应该放到别处 |
.gitignore 就是这张清单的执行者。它有两个特点要记住:
- 规则写窄了,就会漏。
data/*.db只匹配academy.db本身,SQLite 在旁边生成的academy.db-wal和academy.db-shm一个都没挡住。 - 它只管还没提交过的文件。第二天规则补成了整个
data/目录,可这两个文件已经在仓库里,Git 照样继续跟踪。
深潜文件已经提交了,怎么移出去+
git ls-files data/ # 仓库里到底跟踪着这个目录下的哪些文件
git rm --cached data/academy.db-wal # 移出仓库,但保留本地文件
git commit -m "chore: 数据库文件移出仓库"
这样之后的提交就不再包含它了。但历史里的旧版本还在,任何能访问仓库的人都能翻出来。要彻底清除,得改写全部历史再强制推送,代价很大,要不要做,取决于数据有多敏感。
E2E Review 最后选了彻底清除:先把整个仓库打包备份,再改写全部 56 个提交,把两个文件从每一个提交里删掉,然后强制推送。
第一次改写就出了岔子。这次用的是 Git 自带的 git filter-branch,命令里顺手加了 --prune-empty,想删掉"删完文件后变空"的提交;它却把一个原本就是空的检查点提交也一起删了。改写完核对提交数,56 个变成了 55 个;把新旧提交逐个配对,才找出少的是哪一个。去掉这个参数、从备份重做,56 个一个不少。
所以改写历史之后要核对两件事:该删的删干净了没有,别的是不是原样。另外,强制推送之后,GitHub 上按旧的提交号仍然能打开旧提交:平台那边的副本,要另外请平台清理。
深潜推送之前看一眼+
学习资料库那次,只要在提交前多跑一条命令,就能看到那个压缩包:
git ls-files -z | xargs -0 du -h | sort -rh | head
它按大小列出仓库里的文件,516MB 的压缩包会排在第一行。修法也很简单:把 *.zip 加进忽略规则,把压缩包移出这一次提交,再推送。前后只用了十秒,大文件从没到过 GitHub。
找茬
下面是两个仓库的真实忽略规则和命令(节选)。一个仓库用 SQLite 数据库,开着日志模式;另一个仓库的资料目录里有一个 516MB 的压缩包。找出让不该提交的东西溜进仓库的地方。
这段 gitignore / Shell 里埋了 5 处问题。点击你觉得有问题的行,至少找出 3 处再揭晓。
·第 4 行中危
规则写得太窄
data/*.db只匹配academy.db本身。SQLite 在日志模式下会在旁边生成-wal和-shm两个文件,这条规则一个都挡不住。该问的话:这个目录下会生成哪些文件?这条规则能覆盖全部吗?
·第 7 行高危
数据库日志进了提交
Bin说明这是一个二进制文件。它是数据库的日志,里面有账号数据;混在一次功能提交里,没人注意到,就这样在仓库里待了两个月。该问的话:这次提交里有没有二进制文件?它们是什么,该不该进仓库?
·第 14 行中危
清单到这里就结束了
排除了 PDF 和 Office 文档,却没想到压缩包。忽略规则最好按"不该进仓库的类别"来写,而不是按"眼下想到的几种格式"。
该问的话:这个目录里有哪些大文件?它们的格式都被忽略规则覆盖了吗?
·第 17 行中危
把所有东西一起加了进来
git add -A会把目录里所有没被忽略的文件都加进暂存区。忽略规则一有漏洞,漏网的东西就全进来了。该问的话:这次加进来的文件里,有没有不该提交的?
·第 18 行高危
124 行只看了前 5 行
head -5只显示了前 5 个文件,516MB 的压缩包藏在剩下的 119 行里。检查只做了一半,等于没做。该问的话:这次要提交的完整文件清单是什么?其中最大的几个文件是哪些?
查看代码与答案(5 处问题)
1 # E2E Review 的 .gitignore(2026-07-26,节选)
2 *.log
3 .DS_Store
4 data/*.db
5
6 # 同一次提交里新增的文件(git show --stat,节选)
7 data/academy.db-wal | Bin 0 -> 135992 bytes
8
9 # 学习资料库的 .gitignore(2026-08-19)
10 .DS_Store
11 *.pdf
12 *.xlsx
13 *.docx
14 *.pptx
15
16 # 第一次提交之前
17 git init -q && git add -A
18 git status --short | head -5- 第 4 行 · 中危 · 规则写得太窄:
data/*.db只匹配academy.db本身。SQLite 在日志模式下会在旁边生成-wal和-shm两个文件,这条规则一个都挡不住。 该问的话:这个目录下会生成哪些文件?这条规则能覆盖全部吗? - 第 7 行 · 高危 · 数据库日志进了提交:
Bin说明这是一个二进制文件。它是数据库的日志,里面有账号数据;混在一次功能提交里,没人注意到,就这样在仓库里待了两个月。 该问的话:这次提交里有没有二进制文件?它们是什么,该不该进仓库? - 第 14 行 · 中危 · 清单到这里就结束了:排除了 PDF 和 Office 文档,却没想到压缩包。忽略规则最好按"不该进仓库的类别"来写,而不是按"眼下想到的几种格式"。 该问的话:这个目录里有哪些大文件?它们的格式都被忽略规则覆盖了吗?
- 第 17 行 · 中危 · 把所有东西一起加了进来:
git add -A会把目录里所有没被忽略的文件都加进暂存区。忽略规则一有漏洞,漏网的东西就全进来了。 该问的话:这次加进来的文件里,有没有不该提交的? - 第 18 行 · 高危 · 124 行只看了前 5 行:
head -5只显示了前 5 个文件,516MB 的压缩包藏在剩下的 119 行里。检查只做了一半,等于没做。 该问的话:这次要提交的完整文件清单是什么?其中最大的几个文件是哪些?
快测
1. 你在 .gitignore 里加上了 .env,可 git status 显示它还在被跟踪。为什么?
对了。要用 git rm --cached 把它移出仓库;它要是含有密钥,还得去作废那些密钥。
你可能是这么想的:规则要重新克隆之后才生效。可重新克隆下来,这个文件照样在仓库里,因为它已经在历史里了。
你可能是这么想的:规则没写对,换个写法就行。可 .env 已经能匹配到这个文件,问题不在写法:它之前已经被提交过,忽略规则管不到已跟踪的文件。
.gitignore 只能挡住还没进来的,挡不住已经在里面的。
查看选项与答案
- A. 这个文件之前已经提交过,忽略规则管不到已跟踪的文件(正确)——要用
git rm --cached把它移出仓库;它要是含有密钥,还得去作废那些密钥。 - B. 规则要等你重新克隆一次仓库,才会重新生效——规则要重新克隆之后才生效。可重新克隆下来,这个文件照样在仓库里,因为它已经在历史里了。
- C. 规则没匹配上,得写成
*.env才会生效——规则没写对,换个写法就行。可.env已经能匹配到这个文件,问题不在写法:它之前已经被提交过,忽略规则管不到已跟踪的文件。
.gitignore 只能挡住还没进来的,挡不住已经在里面的。
2. AI 一口气改了 30 个文件,其中一处改坏了。怎样最容易只撤回那一处?
你可能是这么想的:反正能撤回提交,一个提交就够了。可撤回一个提交,撤回的是整个提交,30 个文件的改动会一起被撤掉;要只撤回那一处,得先把改动按目的拆成独立的提交。
对了。提交拆得越细,撤回得越精确。出了问题能找到是哪一次,用 git revert 提交号 只撤回那一次。
你可能是这么想的:整个退回去,再让 AI 重做最干净。可 git restore . 会把 30 个文件全部退回上一次提交,好的改动也一起丢了,等于整个推倒重来。
小而独立的提交,就是最好的退路。
查看选项与答案
- A. 把 30 个文件放进同一个提交,出问题时撤回这个提交——反正能撤回提交,一个提交就够了。可撤回一个提交,撤回的是整个提交,30 个文件的改动会一起被撤掉;要只撤回那一处,得先把改动按目的拆成独立的提交。
- B. 改动按目的分开提交,
git revert出问题的那个(正确)——提交拆得越细,撤回得越精确。出了问题能找到是哪一次,用git revert 提交号只撤回那一次。 - C. 用
git restore .回到改动之前,再让 AI 重做——整个退回去,再让 AI 重做最干净。可git restore .会把 30 个文件全部退回上一次提交,好的改动也一起丢了,等于整个推倒重来。
小而独立的提交,就是最好的退路。
3. 第一次推送一直卡住不动。最先该检查什么?
你可能是这么想的:换个客户端也许就顺了。可换工具不会让 516MB 变小;卡住的是要推送的内容,不是客户端。
对了。按大小列出仓库里的文件,一眼就能看到:git ls-files -z | xargs -0 du -h | sort -rh | head。
你可能是这么想的:推送慢,多半是网络问题。网络是可能的原因,但先看要推送的东西有多大:大文件是最常见的元凶。
推送慢,先看体积。
查看选项与答案
- A. 先换成图形界面的 Git 客户端再推一次——换个客户端也许就顺了。可换工具不会让 516MB 变小;卡住的是要推送的内容,不是客户端。
- B. 先看这次提交里有没有体积很大的文件(正确)——按大小列出仓库里的文件,一眼就能看到:
git ls-files -z | xargs -0 du -h | sort -rh | head。 - C. 先排查网络,换个网络或代理再重新推送一次——推送慢,多半是网络问题。网络是可能的原因,但先看要推送的东西有多大:大文件是最常见的元凶。
推送慢,先看体积。
判断时刻
你发现仓库里提交着两个数据库日志文件,里面可能有账号数据。仓库是私有的。AI 给了三个方案。
你会选哪一个?
考察:看起来修好了
最省事,也最没用:忽略规则管不到已经提交的文件。这个项目当时就是这么做的,结果文件又在仓库里待了两个月。
考察:止住,但历史还在
从下一个提交起不再跟踪,本地文件也保留着。但历史里的旧版本还在,能访问仓库的人都能翻出来;数据要是敏感,这一步还不够。
考察:彻底,但有代价
最彻底,但要改写全部提交、强制推送,所有协作者都得重新拉取,操作不慎还会丢提交。值不值得,取决于数据有多敏感、仓库有多少人能看到。E2E Review 最后选的就是这条,第一次改写真的少了一个提交,是核对提交数才发现的。
提交之前拦住,比提交之后清理便宜得多。把忽略规则写宽一点、每次提交前完整看一遍 git status,是最划算的两个习惯。
三个选项各自的代价
- A. 在 .gitignore 里加上规则——考察看起来修好了:最省事,也最没用:忽略规则管不到已经提交的文件。这个项目当时就是这么做的,结果文件又在仓库里待了两个月。
- B. 用 git rm --cached 移出仓库,确认忽略规则覆盖它们——考察止住,但历史还在:从下一个提交起不再跟踪,本地文件也保留着。但历史里的旧版本还在,能访问仓库的人都能翻出来;数据要是敏感,这一步还不够。
- C. 移出仓库之后,再改写历史,把它们从所有提交里抹掉——考察彻底,但有代价:最彻底,但要改写全部提交、强制推送,所有协作者都得重新拉取,操作不慎还会丢提交。值不值得,取决于数据有多敏感、仓库有多少人能看到。E2E Review 最后选的就是这条,第一次改写真的少了一个提交,是核对提交数才发现的。
提交之前拦住,比提交之后清理便宜得多。把忽略规则写宽一点、每次提交前完整看一遍 git status,是最划算的两个习惯。
带走
下次让 AI 做这件事时,问它
- 开始改动之前,工作区是干净的吗?请先提交一次当前状态。
- 这次要提交哪些文件?有没有依赖目录、构建产物、密钥、数据库文件或大文件混在里面?
- 把这次的改动按独立的目的拆成几个提交,每个都能单独构建通过。
- .gitignore 覆盖了哪些类别?仓库里有没有已经被跟踪、却本不该提交的文件?
自己验证
git status --short:提交之前完整看一遍,不要只看前几行。git ls-files -z | xargs -0 du -h | sort -rh | head:找出仓库里最大的几个文件。git ls-files data/:看某个目录下到底跟踪着哪些文件。
提交之前看一眼,比提交之后清理便宜得多。
