我学 Git 的经历大概是很多人的缩影:大一作业交压缩包,大二开始用 GitHub DeskTop 拖拖拽拽,直到第一次给开源项目提 PR 时才意识到——我根本不会用 Git。
第一次 PR:差点把 main 分支搞挂
我在 GitHub 上 fork 了项目,clone 到本地,直接在 main 分支上改代码,改完 commit + push,然后点 New Pull Request。结果 reviewer 第一句就问:「为什么你的 PR 包含 47 个 commit?」原来我 fork 之后没有 sync upstream,也没有开 feature branch,所有修改和原始仓库的更新全混在了一起。
正确流程其实很简单:git checkout -b feat/my-change 开分支 → 写代码 → 提交 → push 到自己的 fork → 从 feature branch 发起 PR。这个教训让我理解了 分支隔离 的重要性——永远不要在 main 上直接改代码。
Commit Message:从「update」到 Conventional Commits
我早期的 commit message 简直不堪入目:「fix bug」「update code」「改了点东西」。后来了解到 Conventional Commits 规范:
feat: 添加用户登录模块
fix: 修复 navbar 在 Safari 上的布局错位
refactor: 将认证逻辑提取为独立组件
chore: 更新 eslint 配置
格式是 type: description。type 用 feat/fix/docs/refactor/chore/test 等。养成这个习惯后 git log --oneline 读起来清爽太多,别人 review 时也能快速理解每个 commit 的目的。
Merge vs Rebase:一张图胜过千言万语
这个问题困扰我最久。merge 保留完整的分支历史——合并时会多一个 merge commit,git log 图有个「分叉再合并」的形状。rebase 把 feature 分支的 commit 「搬」到 main 的最新 commit 之后——log 变成一条完美的直线。
我的简单规则:个人 feature 分支用 rebase(git rebase main),保持历史干净;公共分支和 PR 合入用 merge,保留真实的协作痕迹。千万注意:已经 push 给别人用过的分支不要 rebase,会导致其他人的历史错乱。
git stash:没写完的代码的救星
有一次正在写一个新功能,突然被要求紧急修一个线上 bug。代码写到一半没法 commit,切分支又会把未保存的改动带过去。还好有 git stash:
git stash # 暂存当前改动
git checkout -b hotfix/xxx # 切到 bug 修复分支
# 修 bug,提交,合并...
git checkout feat/xxx # 回到功能分支
git stash pop # 恢复之前没写完的代码
stash 就像一个临时剪贴板——把没干完的活先放进去,干完急事再拿出来。
.gitignore:总是忘记的那几行
以下是我至少三次忘记加入 .gitignore 而导致尴尬的项目:
__pycache__/和*.pyc——Python 编译缓存,体积大且无意义。.env——环境变量文件,含密钥和 token。这个忘加真的会出事。node_modules/——npm 依赖,几十 MB 起跳。.DS_Store——Mac 上的隐藏文件,Windows 用户容易忘记。
建议项目开张第一件事就配好 .gitignore,用 gitignore.io 一键生成。Git 就是一个「先规范后自由」的工具——花点时间建立好习惯,后面就会越用越顺。
--- 约 680 字