git 是现代软件工程的地基,但多数人的用法停留在 add/commit/push 三连,遇到冲突就慌、历史混乱、改坏东西找不回。本章从 git 的数据模型讲起(懂了模型,一切命令都是自然推论),再讲团队协作的分支策略与 review 流程。数据库课第 8 章「日志是真相之源」的思想,在版本控制里是字面意义的实现:git 就是一个内容寻址的日志系统。
git 的三个区域(工作区、暂存区、仓库)是操作层面的说法;数据层面,git 是一张有向无环图:
main: A ── B ── E ── F
\
feat: C ── D
有了这个模型,git 命令全是图的操作:checkout/switch = 移动 HEAD,merge = 造一个双父提交(汇合两条线),rebase = 把一串提交摘下来重放到另一条线上(改写历史)。「git 难」的本质是「图形结构看不见」,补上心智模型后难的是记命令,而是能推断命令。
好提交的三个标准:小(一个提交一件事,回滚和 review 的粒度)、完整(每个提交都能编译、测试过,历史里每个点都是可用状态,git bisect 靠它)、有信息(标题讲「为什么」,正文讲细节;「fix bug」式的标题 = 浪费一次考古线索)。
fix: 账单导出在时区偏移下多算一天
cellForDate 用的是 UTC 日历,导出列用的是本地时区,
跨月月底会偏一天。统一改用 Asia/Shanghai 格式化。
见 #342
暂存区的价值在此兑现:git add -p(逐块暂存)把「顺手改了两个不相关的东西」拆成两个干净的提交,review 者会感谢你。.gitignore 的清单管理(node_modules、构建产物、密钥,第 9 章前端课提过)是仓库卫生的第一课。
团队协作的分支策略演化:
选择的判据是发布节奏:按版本发布(客户端、嵌入式)用 Git Flow 变体;持续部署(互联网服务)用 GitHub Flow 或 TBD。共同铁律:分支寿命越短冲突越小(feature 分支活一个月,合并时就是灾难片)。
PR 是协作流程的枢纽,它同时完成三件事:代码审查(质量闸门)、知识流动(团队知道你在改什么)、CI 门禁(第 10 章,全绿才能合)。
review 的姿势(被审者与审者各有一半责任):PR 要小(少于 400 行 diff,review 质量随大小暴跌)、描述写清「为什么」;审者盯三样——正确性、可读性(第 7 章)、测试,风格问题交给工具(第 9 章前端课的 Prettier),人只管人该管的事。评论语气是工程文化的一部分:对事不对人(「这里可能越界」而非「你怎么连边界都不检查」),「nit:」前缀标记纯风格意见。
git 的安全网极厚,常见事故的急救:
git commit --amend # 刚提交想改信息/补文件(未 push 时)
git reset --soft HEAD~1 # 撤销提交,改动回到暂存区
git restore file # 丢弃工作区某文件的改动(危险,不可恢复)
git reflog # 全部 HEAD 移动记录:后悔药的终极大法
git reset --hard <reflog里的hash> # 回到任意历史点(包括"丢失"的提交)
git revert <commit> # 生成一个"反向提交"撤销某提交(已 push 的安全选择)
git stash # 手头的活先存起来,切分支救火
git bisect start # 二分查找引入 bug 的提交(数据结构课第 7 章在 git 里)
revert 与 reset 的分界:改写公共历史(reset 已 push 的提交)会毁掉协作者的世界,已 push 的一律 revert(向前撤销);reset 只对未 push 的本地历史安全。这条纪律救过无数团队的命。
git log --graph --oneline --all,把输出画成 DAG 图;再 git reset --soft 制造一个「改写历史」,用 reflog 找回(安全环境练习)。