第 2 章 · 03 进阶、性能与动手练习 本节摘要:本节回答两个进阶问题:跨平台团队如何用 gitattributes 消除换行符之争;十万文件的 monorepo 为什么慢、如何用 fsmonitor/manyFiles/maintenance/sparse checkout 提速。最后揭晓 git status 的内部机制(两次 diff + 哈希缓存),并以三个动手练习收尾:首次提交、创建分支、squash 提交。 学习目标 说出 gitattributes 的用途并给出换行符示例。 说出 monorepo 变慢的根因与三种优化手段。 解释 git status 如何工作、为什么还能保持较快。 独立完成三个动手练习并回答思考题。
本节摘要:本节回答两个进阶问题:跨平台团队如何用 gitattributes 消除换行符之争;十万文件的 monorepo 为什么慢、如何用 fsmonitor/manyFiles/maintenance/sparse checkout 提速。最后揭晓 git status 的内部机制(两次 diff + 哈希缓存),并以三个动手练习收尾:首次提交、创建分支、squash 提交。
Windows 用 \r\n 换行,Unix/Linux 用 \n。若不加控制,同一文件在两边反复提交会制造噪音差异。
# .gitattributes * text=auto
效果:Windows 检出 \r\n、Unix 检出 \n,仓库内统一存储——各行其道,库里归一。
许多 Git 操作依赖文件系统状态。git status 要做两次 diff(HEAD↔暂存区、暂存区↔工作目录),每次都要对海量文件执行 lstat() 系统调用——几十万文件时,一次 status 可能耗时数秒甚至分钟。
| 手段 | 机制 |
|---|---|
| fsmonitor(内置,配合 Watchman) | 起守护进程持续监视工作目录变更并缓存;git status 不再全盘扫描,直接读缓存状态 |
| feature.manyFiles true | 同时开启两项:index.version=4(索引路径前缀压缩)+ core.untrackedCache=true(记录文件 mtime,扫描时跳过未更新的文件)。开启前可 git update-index --test-untracked-cache 先验证系统支持 |
| git maintenance | 内置仓库优化命令,定期执行(如每天)让 add/fetch 更快、仓库更省磁盘 |
组合拳补充:
结合构建系统可知开发者正关注哪个组件,配合 sparse checkout,工作目录只保留一小部分文件——
git status/git add秒回。
补充知识:
git diff-index HEAD 比 git diff HEAD 快——它只看元数据(时间戳)不比较内容;目标:掌握 commit 全流程。
步骤:新建目录 → git init 建仓库 → 创建内容为 "hello commit" 的文件 → 提交 → 用命令验证提交已记录。
验证:git log --oneline(或 git show --stat HEAD)。
思考题:提交的收益是什么?还有别的方式验证提交吗?(答:提交是时间点快照,可追溯可回滚;git status 显示 clean、git cat-file -p HEAD 等均可验证。)
目标:理解分支的独立性。
步骤:准备一个至少含一次提交的仓库 → 创建分支 dev → 修改文件 → 新提交 → 验证该提交只在 dev 分支。
验证:git log --oneline dev 有而 git log --oneline main 没有;git branch -v 查看指针位置。
思考题:分支为什么有用?举一个真实场景(答:并行开发互不干扰——一个团队同时做新功能与修 bug,各自在独立分支上提交,最后合并)。
目标:把多个提交压成一个。
步骤:创建内容为 "Mario" 的文件并提交 → 改为 "Mario & Luigi" 再提交 → 验证有两个提交 → 把最近两个提交 squash 成一个。
验证:git log --oneline 只剩一个提交,内容为合并后的最终状态。
思考题:为什么要 squash?(答:合并前清理"草稿"历史,主干保持清晰有意义的提交粒度。)能 squash 超过 2 个吗?(答:能,git rebase -i HEAD~N 任意数量。)
* text=auto 一键解决跨平台换行。下一节预告:Git 打底完成,进入运行环境——Linux 系统。