尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

23 — 安全实践:哪些历史能动,哪些绝对不能碰

23 — 安全实践:哪些历史能动,哪些绝对不能碰 写在前面这一章要解决什么你可能听说过这样一些「惨案」有同学一条命令把公共分支历史改了全组拉代码全报错有人把数据库密码提交进仓库服务器被清空。你是不是也有这种感觉想改点什么又怕一改就出大事干脆不敢动这一章就是帮你分清哪些地方随便改哪些地方绝对不能碰。学完你应该能说清「本地历史」和「已推送历史」的本质区别知道amend、rebase、reset什么时候能用、什么时候绝不能用碰到「共享分支上的坏提交」时知道用revert而不是reset永远不再把密钥、密码提交进仓库万一真提交了敏感信息知道第一步该干什么读者设定大一同学会基本提交和分支已开始在 GitHub/GitLab 上协作但一听到「改历史」就紧张。1. 定位为什么「安全」要单开一章1.1 一句话先记住本地历史是你日记本上写的字随时可以涂改已推送历史是已经贴在公告栏上的通知涂改会影响所有人。这条线划不清越往后协作越容易出事。1.2 生活里的类比先建立感觉日记本在你抽屉里写错了可以涂掉重写——这是「本地历史」。你已经把通知贴到班级公告栏上全班同学都看到了——这是「已推送历史」。你现在偷偷改公告栏那些抄走旧通知的同学手里还是老版本按老版本做事就会全部出错。关键点本地没推送的 → 你怎么折腾都行最多自己倒霉已经推送的 → 你的改动会影响所有人main/master这种公共分支 → 即使只是「小改」也可能害全组1.3 和你已经会的对比你已经会的容易误以为其实git commit --amend改提交说明任何时候都能改只在没推送时安全git reset退版本退回去就行了如果已推送别人那里就乱了git push --force强推解决冲突的快捷方式这是在公告栏上涂改通知删掉文件重新提交就好了密码就消失了旧提交还在历史里任何人都能翻到认知锚点Git 的历史一旦被别人拿到推送过就不属于你一个人了。1.4 本章内容目标学完能做什么目标你能做到的事画清红线说清哪些操作在本地随便用哪些在共享历史上绝对禁止选对撤销碰到「共享分支上的坏提交」用revert不用reset保护密钥不会再把.env、密钥文件提交进仓库应急处理万一提交了密钥第一步先轮换凭据再清历史2. 本质哪些历史能动哪些绝对不能碰2.1 先看总图图本地历史像日记本涂改只影响自己reflog是你的「日记修订记录」即使涂改了也能翻出来。图已推送到远程的历史就像贴在公告栏上的通知其他人已经基于它工作。2.2 两大类历史用白话拆开1本地历史 你日记本上写的字这些提交只存在于你的电脑上还没推送push过你怎么涂改、撕页、重写都只影响你自己改坏了reflog帮你找回之前的状态常见安全操作commit --amend、rebase、reset2已推送历史 已经贴在公告栏上的通知这些提交已经推送到远程仓库队友可能已经pull过了你改掉其中一笔提交队友下次拉代码就会冲突或丢东西绝对不要用reset、rebase改写已推送历史如果必须撤销用revert创建一笔「反向提交」不改历史2.3 什么算「共享」历史情况算不算共享原因你的功能分支从没推送过不算只有你一个人有你的功能分支推送了但只有你用灰色地带理论上别人可以拉但实际只有你main/master分支绝对共享全组人都在用课程作业仓库的main共享老师和助教也在看简单的判断方法git log里能看到origin/开头的远程分支就说明这份历史已经推送了。2.4 受保护分支main/master的特殊地位main或master是项目的「主干」所有功能最终都合并到这里永远不要对main执行force-push永远不要对main执行rebase需要「撤销」时在main上只能用revert或走合并请求2.5 金色法则背下来法则白话解释本地随便改日记本上写字擦了重写没人管已推送不要改公告栏上的通知不能涂改拿不准就不改不确定有没有人拉走就不动实在要撤就revert再贴一张「作废通知」不要涂改原通知main永远不 force-push这是全组人的生命线密钥永远不提交进了历史就跟泼出去的水一样2.6 新手最常踩的坑现象怎么办force-push 后队友拉代码疯狂冲突避免万一做了让队友重新克隆对main做 rebase在共享分支上 rebase 改写公共历史禁止用reset撤已推送的坏提交用revert代替提交了.env文件先配.gitignore已提交的话见应急处理3. 建议的学习顺序先建立「日记本 vs 公告栏」的直觉 → 画清红线本地随便改已推送不要动 → 学安全 amend只改没推送的最近提交 → 学安全 rebase只在你的功能分支上 → 学 revert共享分支上唯一安全的「撤销」 → 密钥安全.gitignore 钩子 应急处理 → 完成章末小实验不要急着用--force。这一章只要求知道边界在哪碰到边界就停下来。4. 动手准备可丢弃目录请找一个可以随便删的练习目录不要用正在交的作业仓库练手。mkdirlab-safetycdlab-safetygitinit-bmaingitconfig user.nameAda Examplegitconfig user.emailadaexample.comgit--version# 本文用 Git 2.43.0 验证先做几笔初始提交后面实验要用printf项目初始化\nREADME.mdgitaddREADME.mdgitcommit-mdocs: 初始化项目说明printf功能 A 的代码\nfeature-a.txtgitaddfeature-a.txtgitcommit-mfeat: 添加功能 Aprintf功能 B 的代码\nfeature-b.txtgitaddfeature-b.txtgitcommit-mfeat: 添加功能 B5. 跟着做安全改写历史5.1 安全修改最近一次提交commit --amend只在没推送时场景你刚提交完发现提交说明写了个错别字或者忘了加一个文件。gitlog--oneline-3# a2c3d4e feat: 添加功能 B# f1e2d3c feat: 添加功能 A# b0c1d2a docs: 初始化项目说明gitcommit--amend-mfeat: 添加功能 B含边界检查gitlog--oneline-3# 9k8j7i6 feat: 添加功能 B含边界检查# f1e2d3c feat: 添加功能 A白话翻译最近一笔提交的说明被替换了提交哈希从a2c3d4e变成9k8j7i6因为提交说明也是提交内容的一部分改了说明等于创建新提交这只在本机安全如果原来的提交已推送改完再推就必须 force-push条件能不能用amend提交没推送只在本机能随便用提交已推送到远程不能除非你 100% 确定只有你一个人用这个分支提交在main上即使没推送也要谨慎养成不用的习惯5.2 安全变基rebase只在你的功能分支上场景你的功能分支落后于main想把main的最新内容合进来但不想产生合并提交。gitcheckout-bmy-featureprintf我的新功能\nmy-feature.txtgitaddmy-feature.txtgitcommit-mfeat: 我的新功能gitrebase main白话翻译rebase把你的提交「搬到」了main最新位置后面原哈希全变这只在你的功能分支安全如果这个分支还有人在用他们历史就全乱了条件能不能用rebase只有你一个人在用的功能分支能已经推送到远程的共享分支绝对不能main/master绝对不能5.3 共享分支上唯一的「撤销」revert场景已经推送到main的某笔提交有问题你想「撤销」它但不能改写历史。gitlog--oneline-4# 9k8j7i6 feat: 添加功能 B含边界检查# f1e2d3c feat: 添加功能 Agitrevert f1e2d3c# 生成x5y6z7a Revert feat: 添加功能 A白话翻译revert不是「删掉那笔提交」而是「再贴一张通知说前面那张作废」原提交还在历史里但它的效果被新的「反向提交」抵消了别人拉代码不会冲突命令改不改历史适不适合共享分支reset改删掉提交不适合rebase改重写提交不适合revert不改新增反向提交适合5.4 万一要 force-push 的时候--force-with-lease有些场景确实需要强推比如自己分支 rebase 后但--force会直接覆盖别人新提交。gitpush--force# 危险不管别人有没有新提交直接覆盖gitpush --force-with-lease# 安全远程有你不了解的新提交会拒绝推送条件能不能用force-with-lease你自己的功能分支rebase 后需要推送能main/master不能共享分支不能5.5 看看你的安全网reflog即使你改了历史、做了resetGit 的reflog还记录着之前的每一次操作。gitreflog-5# a2c3d4e HEAD{0}: commit: feat: 添加功能 B# f1e2d3c HEAD{1}: commit: feat: 添加功能 Areflog是「操作日记」记录每次 HEAD 变化默认保留 90 天丢了提交可用git reset --hard HEAD{编号}找回但先防患于未然6. 命令按「用途」分组先少后多6.1 不改历史的安全命令放心用命令干什么git status看当前状态git log --oneline看提交历史git reflog看操作记录救命稻草git revert 哈希新增一笔「反向提交」不改历史6.2 只在本地安全的改写命令命令安全前提git commit --amend没推送git rebase main只在只有你用的功能分支git reset --soft HEAD~1没推送改动留在暂存区git reset --hard HEAD~1没推送且确认改动不要了6.3 远程推送相关命令风险git push低git push --force-with-lease中只在自己的功能分支安全git push --force高除非你 100% 确定后果6.4 凭据安全命令命令 / 操作干什么echo .env .gitignore把.env文件排除在版本管理外git rm --cached 文件把已跟踪的文件从仓库移除但保留在工作区git log --all --full-history -- .env检查某文件是否曾出现在历史中7. 对照表降低记忆负担7.1 本地 vs 共享操作对照操作本地没推送已推送共享amend安全危险等于 force-pushrebase安全只在自己的分支禁止reset安全禁止revert可以但没必要唯一推荐7.2resetvsrevert对照resetrevert改不改历史改删提交不改加提交适合共享分支吗不适合适合别人拉代码会冲突吗会不会像什么撕掉日记本的一页在公告栏贴张「作废通知」7.3 安全决策流程1. 这笔提交推送过吗 ├─ 没有 → 本地随便改amend / rebase / reset 都行 └─ 有 → 继续判断 2. 在共享分支上吗 ├─ 是 → 用 revert └─ 否 → 继续判断 3. 只有你一个人在用这个分支吗 ├─ 是 → 可以 force-with-lease 推送 └─ 否 → 用 revert 4. 是 main/master 吗 ├─ 是 → 只能用 revert 或合并请求 └─ 否 → 参考上面判断7.4 凭据安全对照东西能不能提交怎么处理.env文件不能写进.gitignore数据库密码不能用环境变量SSH 私钥不能写进.gitignoreAPI Token不能用环境变量.env.example不含真实密码能提交配置模板8. 安全习惯现在就能养成8.1 建议这样做每次提交前先git status避免交错密钥文件推送前先git log看一遍要推什么.gitignore在项目第一天就建好提交.env.example而不是.env功能分支开发合并请求进main不确定能不能改就不改宁多一个 revert也不 force-push密钥泄露先轮换再清历史8.2 暂时不要这样做不要git push --force不对main执行rebase不对main执行reset push不git add .然后闭眼提交不在公共分支上用amend不把密钥写在代码里8.3 推荐的安全最小循环gitcheckout-bmy-featuregitstatus# 重点确认没有密钥文件gitadd具体文件gitstatusgitcommit-mfeat: 做了什么gitpush-uorigin my-feature# 然后在 GitHub/GitLab 上开合并请求9. 真实场景没有项目经验也能懂9.1 课程大作业你提交了数据库密码你在config.py里写了DB_PASSWORDmy_super_secret_123然后git add .git commitgit push一条龙。等同学提醒你密码不能提交时你删掉重提——但旧提交里还是看得到密码。正确做法按顺序立刻轮换密码第一优先级比删历史重要把config.py加入.gitignore或改用环境变量git rm --cached config.py从仓库移除文件仍在本地提交这次移除如需彻底清理历史用 BFG Repo Cleaner进阶建议找有经验的人帮忙通知所有组员重新克隆9.2 发现main上有个严重 bug想「撤掉」那笔提交错误做法gitcheckout maingitreset--hardHEAD~1gitpush--force正确做法gitcheckout maingitrevert 有问题的提交哈希gitpushrevert创建反向提交效果等于撤销但不改写历史全组正常拉代码不会出问题。9.3 你在自己分支上 rebase 后推送被拒rebase 后本地哈希变了正常git push会被拒。因为是自己的功能分支可以用gitpush --force-with-lease白话「我知道远程版本跟我预期的不一样因为我 rebase 了但如果有人在我不知道的时候推了新东西请拒绝我。」9.4 不小心对main做了amend已经推了补救步骤先reflog找 amend 前的哈希 →git reset --hard amend 之前的哈希→git push --force两害相权取其轻→ 立刻通知组员重新克隆。更根本的办法main上永远不做amend。9.5 GitHub/GitLab 的分支保护常见的设置推送main必须走合并请求、需要审批、禁止 force-push、必须过 CI。这些不是「烦人的限制」而是安全网。管理员建议开启禁止mainforce-push、要求合并请求、要求至少一人审批。9.6 你想提交代码但怕改出问题在自己的功能分支上操作main不是你直接碰的地方功能分支随便试改坏了reset就行准备好了开合并请求让同学看一眼合并前main不会变10. 稍微多懂一点点可选10.1.gitignore最佳实践项目第一天就建好.gitignore.env .env.local *.pyc build/ dist/ .vscode/ .DS_Store *.pem *.key id_rsa*更好的做法用 gitignore.io 按项目类型生成模板。10.2 预提交钩子最后一道防线用 pre-commit 框架配置检查规则repos:-repo:https://github.com/Yelp/detect-secretsrev:v1.4.0hooks:-id:detect-secrets每次提交前自动扫描发现疑似密钥就拒绝。10.3 密钥检测工具工具干什么git-secrets扫描提交内容发现密钥就拦截detect-secrets检测代码中疑似密钥的字符串gitleaks扫描仓库历史和当前代码中的凭据建议至少用其中一个作为预提交钩子。10.4 万一真把密钥推上去了怎么办千万不要反过来先立刻轮换密钥数据库密码→改密码API Token→重新生成SSH 密钥→删旧建新再移除密钥改用环境变量、加.gitignore、git rm --cached 密钥文件、提交推送必要时用git filter-repo清历史最后通知协作者重新克隆。为什么先轮换再清历史从泄漏到发现可能已过很久公开仓库可能早被爬虫扫到。清历史不如先换密钥。10.5 签名提交与标签gitcommit-S-mfeat: 添加重要功能# 签名提交gittag-sv1.0-m版本 1.0# 签名标签gittag-vv1.0# 验证签名签名提交像在日记上按手印标签像盖章保证来源可信。大一先知道有这机制即可。10.6 分支保护规则配置GitHubSettings → Branches → Add branch protection rule勾选 “Require a pull request before merging” 和 “Do not allow force pushes”。GitLabSettings → Repository → Protected branches选择分支设置合并/推送权限开启 “No force push”。11. 小实验请一定动手实验甲安全 amend。做一笔提交用--amend改提交说明确认哈希已变。通过标准能说清 amend 前后提交哈希为什么不同。实验乙revert vs reset。三笔提交 A → B → C用git reset --soft HEAD~1退掉 C再提交 C 回来用git revert撤销 B。通过标准能用「日记本」和「公告栏」解释两种方式的区别。实验丙reflog 救命。用git reset --hard HEAD~2故意丢掉两笔提交再用git reflog找哈希恢复。通过标准明白 reflog 是最后的救命稻草但不要依赖它。实验丁.gitignore 防护。创建.env加入.gitignore确认不被跟踪故意先git add .env再用git rm --cached .env移除。通过标准会在「忘了 ignore」和「已经 add 了」两种失误中正确补救。12. 常见问题问 1对 main force-push 后全组都拉不了代码怎么办立刻通知所有人最稳的是让所有人重新克隆。然后立刻开启分支保护。问 2revert 之后想撤回 revert 怎么办再 revert 那笔 revert 提交就行了等于恢复原来的效果。问 3自己分支 rebase 后拉代码总是冲突正常吗不正常。若已推送又 force-push队友会冲突。要么功能分支只自己用要么不用 rebase 用 merge。问 4密钥已提交但还没推送安全吗本机安全但建议立刻从历史移除git reset或git rebase -i。养成提交前git status的习惯。问 5.gitignore 加了.env还是被跟踪因为.env之前已被git add过.gitignore只对未跟踪文件生效。用git rm --cached .env解决。问 6--force-with-lease和--force有什么区别--force一律覆盖--force-with-lease会检查远程是否还是你以为的状态有别人新提交就拒绝。更安全但仍只能在自己分支用。问 7实在拿不准该用哪个命令怎么办先git status/git log看清状态问自己「推送过吗在共享分支上吗」。推送过或不确定就用revert。13. 总结、学习路线与思维升华13.1 这一章请记住的点记住什么金色法则本地随便改已推送不要动核心区别日记本 vs 公告栏共享分支撤销用revert不用reset本地补救amend、rebase、reset只在没推送时安全密钥安全第一天建.gitignore提交前status检查泄露应急先轮换密钥再清历史强推替代--force-with-lease比--force安全13.2 思维升华按回车前先问自己这笔提交推送过吗有人在用吗如果不确定就当它已经推送了。宁可多一个 revert不要一次 force-push。密钥进了历史就跟泼出去的水一样——防比治重要一万倍。13.3 参考资料Pro Git 中文版 — 重写历史Pro Git 中文版 — 签署工作git revert 说明 / git reflog 说明 / gitignore 说明GitHub 分支保护规则git-secrets / gitleaks / pre-commit命令输出样例验证环境Git 2.43.0演示作者信息为虚构。13.4 本章检查清单能用「日记本 vs 公告栏」说清本地和共享历史的区别知道amend、rebase、reset只在没推送时安全碰到共享分支上的坏提交会选择revert而不是reset知道--force-with-lease比--force安全在哪知道main永远不应该 force-push会在项目第一天建.gitignore排除密钥文件知道泄露密钥后第一步是轮换凭据而不是删历史拿不准的时候会选择「不改历史」的方案学会 Git 的安全边界不是为了束缚你而是为了让你敢放心操作。知道红线在哪的人比「什么都不怕」的人更安全。下一章我们继续深入实战场景。
返回列表