我学 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 而导致尴尬的项目:

建议项目开张第一件事就配好 .gitignore,用 gitignore.io 一键生成。Git 就是一个「先规范后自由」的工具——花点时间建立好习惯,后面就会越用越顺。

--- 约 680 字