前言
Git 已经成为软件开发行业的事实标准,但很多团队在使用 Git 进行协作和版本控制时,仍然存在一些不太好的习惯或做法。本文将结合示例,阐述 Git 的一些最佳实践,帮助读者掌握 Git 的正确使用姿势,在团队协作中发挥 Git 最大的价值。
主要内容包括:
- Git 流分支管理策略
- 提交信息编写规范
- 代码review工作流
- Git 钩子的使用
- 对应用进行逻辑划分
- 合理使用 Git 工具
Git 流分支管理策略
主分支与开发分支
对于一个应用程序,通常会有两个长期分支:
- 主分支(master):用于部署到生产环境的稳定版本代码
- 开发分支(develop):用于日常开发工作,包含所有最新代码
主分支永远处于可发布状态,开发分支包含所有未完成和可能存在 Bug 的最新代码。
功能分支
对于一个新功能或修复 Bug,都应该基于 develop 分支创建功能分支,分支名可以使用 feature/xxx 或 bugfix/xxx 前缀表示。
完成开发后,再将功能分支合并回 develop,最后合并到 master 发布。
// 创建功能分支
git checkout -b feature/new_API develop
// 开发新功能
// 合并回 develop
git checkout develop
git merge --no-ff feature/new_API
// 删除功能分支
git branch -d feature/new_API
发布分支
当 develop 分支组了一组功能准备发布时,可以从 develop 分支创建发布分支,进行最后阶段的集成测试等工作。
当发布完成后,再将发布分支合并回 master 和 develop。
// 从 develop 创建发布分支
git checkout -b release/1.2 develop
// 完成发布前的准备工作
// 合并回 master 完成发布
git checkout master
git merge --no-ff release/1.2
// 合并回 develop
git checkout develop
git merge --no-ff release/1.2
// 删除发布分支
git branch -d release/1.2
紧急修复分支
当在 master 发现严重问题时,可以直接从 master 分支创建热修复分支进行修复。
修复完成后,直接合并到 master 和 develop 即可。
// 基于 master 创建热修复分支
git checkout -b hotfix/1.2.1 master
// 进行紧急修复
// 合并回 master
git checkout master
git merge --no-ff hotfix/1.2.1
// 合并回 develop
git checkout develop
git merge --no-ff hotfix/1.2.1
// 删除热修复分支
git branch -d hotfix/1.2.1
小结
- master 分支用于部署到生产环境
- develop 分支用于日常开发
- 功能分支实现新功能后合并回 develop
- 发布分支用于发布前准备工作
- 热修复分支用于紧急修复生产问题
提交信息编写规范
良好的提交信息对代码重构和日志输出都大有益处。通常要遵循以下规范:
- 使用祈使语气,例如"fix bug" 而不是 "fixed bug"或"fixes bug"
- 首行不超过 50 个字符,可以加描述,不超过 72 个字符
- 描述可分多行,每行不超过 72 个字符
- 使用
#分割提交类型、范围、主题,例如:
#fix 账单模块 提交信息示例
常用的提交类型:
- feat: 新增功能
- fix: 修复缺陷
- docs: 文档变更
- style: 代码格式调整
- refactor: 代码重构
- perf: 性能优化
- test: 测试用例修改
- build: 影响构建或依赖项的更改
- ci: 对 CI 配置或脚本的更改
- chore: 对构建过程或辅助工具和库的更改
- revert: 恢复先前的提交
代码 Review 工作流
代码评审(Code Review)是保证代码质量非常重要的一步。一般流程是:
-
开发人员在自己的分支完成代码编写,并推送到远程仓库
-
在 GitHub 等平台发起 Pull Request,请求将代码合并到
develop分支 -
由其他开发人员对修改代码进行审查,提出修改意见
-
开发人员根据意见进行调整optimize,直到PLURALITY通过审查
-
合并 Pull Request,完成代码合并
在提交 Pull Request 时,需要提供充分的提交信息和注释,方便 reviewer 理解代码的作用。审查人需要对以下方面进行检查:
- 功能代码是否实现预期的业务需求
- 是否存在安全性问题
- 是否符合项目的代码规范
- 是否存在冗余或不必要的代码
- 是否存在清晰的技术债务说明
- 代码中的注释是否到位
通常一个 Pull Request 不要包含太多的提交和改动,以保证 reviewer 可以合理分配时间进行充分查看。
如果修改涉及复杂的业务逻辑,需要在提交 PR 前与团队其他成员进行设计评审,以期望获得更好的解决方案。
Git 钩子的使用
Git 钩子可以在指定的 Git 操作执行前或执行后触发自定义脚本。
例如在提交前执行单元测试和代码规范检查:
#!/bin/sh
go test ./...
gofmt -l -w .
git add .
也可以在推送后自动部署到测试服务器:
#!/bin/sh
git push origin develop
./deploy.sh test
placing executable hook scripts in .git/hooks目录下,命名需要符合如下规范:
- pre-commit:提交前触发
- prepare-commit-msg:生成提交信息前触发
- commit-msg: 提交时触发
- post-commit:提交后触发
- pre-rebase:衍合前触发
- post-checkout:切换分支后触发
- post-merge:合并后触发
- pre-push:推送前触发
- pre-auto-gc:垃圾回收前触发
使用钩子可以很大程度地优化开发流程,提高代码质量。
对应用进行逻辑划分
随着业务复杂度增加,代码应合理地进行模块化,常见的模块划分:
- handler:用于请求的接收和响应
- service: 核心业务逻辑
- dao: 数据访问层,与数据库交互
- dto: 数据传输对象,用于不同模块间传递数据
- config: 配置相关代码
- common: 公共功能组件
- test: 测试模块
针对不同模块使用不同的包,合理划分目录结构:
├── handler
│ └── user.go
├── service
│ └── user.go
├── dao
│ └── user.go
├── dto
│ └── user.go
├── config
│ └── config.go
├── common
│ └── utils.go
└── test
└── service
└── user_test.go
通过模块化划分,可以提高代码的内聚性和复用性。handler 和 controller 负责流程控制,service 实现业务逻辑,dao 封装数据库交互,dto 定义数据结构。
合理使用 Git 工具
- Git Flow:实现 Git 流分支管理策略的工具
- Git LFS:管理大文件存储的工具
- Git Hooks:实现 Git 钩子自动化的工具
- Git Stash:保存和恢复工作目录的工具
- Git Cherry-pick:选择性地把提交应用到其他分支
- Git Rebase:合并分支时保持线性提交历史
- Git Submodule:管理项目依赖关系的工具
合理使用这些工具,可以大幅提高团队的协作效率。
思考
在日常开发和团队协作中,我们经常会遇到代码管理和版本控制的问题。使用Git可以很好地解决这些问题,但是如果没有正确的使用姿势,Git的效率和价值就无法真正发挥出来。
- 分支管理策略直接影响协作效率。常见的Git流是非常好的实践,它在保证主分支稳定性的同时,允许开发分支进行日常开发工作。但策略也不能一成不变,需要根据团队大小和项目特点进行适当调整。
- 规范的提交信息对代码管理非常重要。通过prefixes可以快速区分提交类型,从而可以方便地生成changelog和发布日志。但是也需要控制好提交粒度,过于频繁和过于庞大的提交都会降低review效率。
- 代码review是非常关键的一步。它不仅能提高代码质量,也可以增进团队成员之间的交流与理解。 reviewer需要对代码变更采取负责任的态度,确保重构或新功能的实现符合预期。同时也要CONTROL好review的工作量,避免review成为单纯的把关之举。
- Git钩子的使用可以极大地优化工作流程,比如利用pre-commit执行测试和lint可以及早发现问题,post-commit实现持续集成可以快速验证新代码。但钩子也需要慎重设计,过于频繁和复杂的钩子会成为开发阻碍。
- 模块化设计和项目目录结构直接影响多人协作的效率。合理的拆分可以减少相互依赖,同时也容易扩展和维护。除功能模块化外,代码和配置也需要区分开,测试用例需要独立存放。这些在设计时都需要考虑到。
- Git工具的使用需要因人和项目而异。比如对新手来说,Git Flow可以简化分支管理,但对于老手可能过于繁琐。子模块对依赖管理很有帮助,但也容易引入问题。正确使用需要结合实际场景。
总之,Git最佳实践并非一成不变,它需要根据团队实际情况不断进化和调整,才能发挥最大效用。同时团队成员也需要共同努力,才能将这些实践真正应用到开发过程中去。只有持续改进,我们才能在版本控制的道路上越走越顺。
总结
- 分支管理策略很重要,master 存放发布版本,develop 用于日常开发
- 编写规范的提交信息和 PR 描述对协作非常重要
- 代码评审需要仔细检查,避免引入问题
- Git 钩子可以自动执行脚本优化开发流程
- 模块化划分有助于提高内聚性和复用性
- 合理运用 Git 工具可以提效协作
掌握这些 Git 最佳实践,可以帮助开发团队建立高效的协作方式,从而更好地发挥 Git 在版本控制中的价值,实现产品的迭代开发。