新手也能看懂的 Git 功能开发流程:从需求到 Pull Request
很多 Git 问题并不是命令不会用,而是开发顺序错了。
例如,打开项目后直接在 main 分支写代码,写到一半才想起来创建分支,就容易遇到:
- 不同功能混在一起
- 不知道哪些文件应该提交
- 切换分支时担心代码丢失
- PR 中出现无关文件
- 测试功能和未确认功能无法分开
本文不重点讲 Git 命令,而是讲清楚一次功能开发应该按照什么顺序进行。
一、先理解 main 分支是做什么的
可以把 main 理解为项目当前稳定版本。
正常情况下,main 中应该保存:
- 已经开发完成的功能
- 已经测试通过的代码
- 已经审核通过的修改
- 可以继续部署或发布的版本
因此,不建议直接在 main 上开发新功能。
正确思路是:
text
main 保存稳定代码
功能分支负责开发
功能完成后通过 PR 合并回 main
二、写代码之前,第一件事是创建功能分支
这是整个流程中最重要的一步。
不要先写代码,再创建分支。
正确顺序:
text
更新 main
→ 从 main 创建功能分支
→ 在功能分支中写代码
例如,这次开发的是"测试环境标识",分支可以命名为:
text
feature/console-environment-guard
参考命令:
bash
git switch main
git pull --ff-only origin main
git switch -c feature/console-environment-guard
开始写代码前,可以检查当前分支:
bash
git branch --show-current
如果显示 main,先不要写代码。
三、一个分支尽量只做一个明确需求
假设当前有三个需求:
text
测试环境标识
返回顶部按钮
项目表头吸顶
如果三个功能都写在同一个分支里,后面可能出现:
- 前两个已经测试通过
- 第三个还不确定
- 但三个功能修改了同一个
globals.css - 最后不知道应该提交哪些代码
更合理的方式是拆分:
text
feature/console-environment-guard
feature/back-to-top-control
feature/project-list-sticky-header
如果两个功能关联紧密,也可以放在一个分支,但必须提前确认边界。
核心原则:
text
一个分支只解决一个明确目标
未确认的功能不要混进当前分支
四、写代码前先把需求想清楚
不要一上来就修改代码。
至少先明确以下内容:
- 为什么要修改
- 用户最终会看到什么
- 哪些页面会受到影响
- 哪些文件可能需要修改
- 是否涉及后端或数据库
- 如何判断功能已经完成
- 哪些内容暂时不做
如果项目使用 OpenSpec,可以保存:
text
proposal.md:为什么修改
design.md:准备怎么实现
spec.md:功能应该满足什么行为
tasks.md:具体实施步骤
如果只是保存方案、暂时不开发,tasks.md 应保持未完成状态:
text
- [ ] 待实施任务
这样以后不会误以为代码已经完成。
五、开发过程中不要把所有样式都塞进 globals.css
globals.css 适合放:
- 全局变量
- Reset 样式
- 页面通用基础规则
具体功能的样式最好放在自己的文件中,例如:
text
console-environment-guard.tsx
environment-guard.module.css
Monorepo 项目也可以建立共享样式包:
text
libs/frontend/console-styles
这样做的好处是:
- 一个功能对应一组文件
- 提交时容易区分
- 删除功能时不影响其他页面
- 不容易把未确认功能一起提交
- 服务器构建时依赖关系更清楚
六、开发完成后,先测试,再提交
不要代码刚写完就 Push。
建议先做:
text
检查页面效果
→ 检查 TypeScript
→ 执行生产构建
→ 确认没有混入其他功能
→ 再 Commit
参考命令:
bash
pnpm install --frozen-lockfile
pnpm --filter @nova-console/web build
生产构建能够提前发现:
- 文件漏传
- TypeScript 类型错误
- Workspace 依赖缺失
- CSS Module 导入错误
- Next.js 路由错误
本地能打开页面,不代表生产构建一定能通过。
七、Commit 前要检查"这次到底提交什么"
Commit 不是把所有修改一次性塞进去。
提交前应该确认:
text
哪些文件属于当前功能
哪些文件属于其他功能
哪些文件只是本地配置
哪些内容暂时不能提交
尤其不要看到很多文件后直接"全选"。
可以检查:
bash
git status --short
git diff
需要按代码块选择时,可以使用:
bash
git add -p
提交信息应说明这次做了什么:
bash
git commit -m "feat(console): 支持测试环境标识和返回顶部控件"
常见前缀:
text
feat:新增功能
fix:修复问题
refactor:代码重构
docs:文档修改
test:测试修改
chore:依赖、脚本或配置维护
八、没有 Commit 的代码,不真正属于任何分支
这是很容易误解的地方。
文件可能有三种状态:
text
未追踪
已追踪但未提交
已经 Commit
即使文件已经被 Git 追踪,只要没有 Commit,它就没有真正进入分支历史。
切换分支时,未提交修改可能:
- 被带到其他分支
- 阻止分支切换
- 与目标分支发生冲突
- 在强制签出或还原时被覆盖
因此,准备切分支或合并代码前,应先处理工作区。
九、不想提交的代码,可以先 Stash
有些修改需要保留,但不应该进入当前功能分支。
这时可以使用 Stash。
Stash 的作用是:
text
临时保存未提交内容
→ 暂时清空工作区
→ 完成切分支或合并
→ 再恢复原来的内容
参考命令:
bash
git stash push -u -m "wip before merge main"
其中 -u 表示连未追踪的新文件一起保存。
检查工作区:
bash
git status --short
没有输出,才表示工作区已经干净。
恢复:
bash
git stash pop
需要注意:
- Stash 不会上传 GitHub
- Stash 不属于正式版本历史
- Stash 适合临时保存
- 长期内容应放到独立分支并 Commit
十、开发期间 main 更新了怎么办
开发功能时,其他人可能已经向 main 合并了新代码。
这时不要直接把旧功能分支推上去。
正确做法:
text
先保存当前修改
→ 获取最新 main
→ 把 main 合并进功能分支
→ 重新测试
参考命令:
bash
git fetch origin
git merge origin/main
也可以使用 Rebase:
bash
git rebase origin/main
简单理解:
- Merge:保留合并记录,比较直观
- Rebase:提交历史更整洁
- 已经多人使用的分支,Merge 更稳妥
- 个人且尚未推送的分支,可以考虑 Rebase
合并成功后,要重新构建,因为 main 的变化可能影响当前功能。
十一、Push 的是功能分支,不是 main
功能开发完成后,推送功能分支:
bash
git push -u origin feature/console-environment-guard
不要写成:
bash
git push origin main
如果 IDEA 同时管理多个 Git 仓库,例如:
text
nova-console
nova-common
nova-db
Push 时只勾选本次需要推送的仓库。
不要因为它们同时出现在 Push 窗口,就全部推送。
十二、Push 完成后创建 PR
Push 只是把功能分支上传到 GitHub,还不是 PR。
PR 的作用是:
text
申请把功能分支合并到 main
GitHub 中进入:
text
Pull requests
→ New pull request
选择:
text
base: main
compare: feature/console-environment-guard
其中:
base是准备合并到哪个分支compare是当前功能分支
PR 标题示例:
text
feat(console): 支持测试环境标识和返回顶部控件
PR 描述应该写清楚:
markdown
## Changes
- 增加测试环境视觉标识
- 增加返回顶部控件
- 增加共享样式包
## Verification
- pnpm install --frozen-lockfile
- pnpm --filter @nova-console/web build
十三、创建 PR 后还不能立刻合并
PR 创建后,GitHub 可能执行自动检查:
text
TypeScript 检查
构建检查
单元测试
代码规范检查
如果页面显示:
text
Waiting for status to be reported
表示检查还没有完成。
需要等待:
text
All checks have passed
第一张 PR 列表显示"Open",只代表 PR 已经创建,不代表检查通过。
十四、谁来点击 Merge
是否可以 Merge,取决于:
- 是否拥有仓库写入权限
- CI 是否通过
- 是否存在代码冲突
- 是否要求其他人审核
- main 是否配置了分支保护
团队项目中,通常建议:
text
开发者创建 PR
→ 其他人审核
→ 维护者或管理员合并
即使自己有权限,也不建议在检查未完成时直接合并。
十五、PR 合并后,本地 main 才会出现新功能
PR 创建以后,本地 main 不会自动拥有功能代码。
只有 PR 真正合并后,再更新本地 main:
bash
git switch main
git pull --ff-only origin main
这时新功能才正式出现在本地 main。
最后可以删除功能分支:
bash
git branch -d feature/console-environment-guard
十六、一套推荐的开发顺序
以后开发新功能,可以按照下面的顺序:
text
1. 明确需求
2. 更新 main
3. 从 main 创建功能分支
4. 确认当前不在 main
5. 编写功能代码
6. 本地测试和生产构建
7. 检查提交文件
8. Commit
9. 同步最新 main
10. 再次测试
11. Push 功能分支
12. 创建 PR
13. 等待 CI 和审核
14. 合并 PR
15. 更新本地 main
最需要记住的是:
text
写功能前先切分支
一个分支只做一个明确需求
未确认功能不要混入当前提交
切分支前处理未提交修改
Push 前构建
PR 前检查 Files changed
Git 命令只是工具,真正重要的是养成正确的开发顺序。