Git代码版本管理流程和团队协作规范
Git版本管理介绍
在使用Git的过程中如果没有清晰流程和规划,否则每个人都提交一堆杂乱无章的commit,项目很快就会变得难以协调和维护。Git版本管理同样需要一个清晰的流程和规范。
以下是基于Vincent Driessen提出的Git Flow 流程图 (非常清晰,图片上的英文可以翻译一下便于理解)
主分支分为master分支和develop分支,是所有开发活动的核心分支。所有的开发活动产生的输出物最终都会反映到主分支的代码中, 生命周期为常驻。
git各分支功能介绍
主分支分为master分支和develop分支,是所有开发活动的核心分支。所有的开发活动产生的输出物最终都会反映到主分支的代码中, 生命周期为常驻。
master 分支
- master分支存放的是随时可供在生产环境中部署的稳定版本代码
- master分支保存官方发布版本历史,release tag标识不同的发布版本
- 一个项目只能有一个master分支
- 仅在发布新的可供部署的代码时才更新master分支上的代码
- 每次更新master,都需对master添加指定格式的tag,用于发布或回滚
- master分支是保护分支,不可直接push到远程仓master分支
- master分支代码只能被release分支或hotfix分支合并
develop 分支
-
develop分支是保存当前最新开发成果的分支
-
一个项目只能有一个develop分支
-
develop分支衍生出各个feature分支
-
develop分支是保护分支,不可直接push到远程仓库develop分支
-
develop分支不能与master分支直接交互
辅助分支分为feature分支、release 分支、hotfix 分支,辅助分支主要用于组织软件新功能的并行开发、简化新功能开发代码的跟踪、辅助完成版本发布工作以及对生产代码的缺陷进行紧急修复工作。这些分支与主分支不同,通常只会在有限的时间范围内存在
feature 分支
使用规范:
-
命名规则:feature/*
-
develop分支的功能分支
-
feature分支使用develop分支作为它们的父类分支
-
以功能为单位从develop拉一个feature分支
-
每个feature分支颗粒要尽量小,以利于快速迭代和避免冲突
-
当其中一个feature分支完成后,它会合并回develop分支
-
当一个功能因为各种原因不开发了或者放弃了,这个分支直接废弃,不影响develop分支
-
feature分支代码可以保存在开发者自己的代码库中而不强制提交到主代码库里
-
feature分支只与develop分支交互,不能与master分支直接交互
如有几个同事同时开发,需要分割成几个小功能,每个人都需要从develop中拉出一个feature分支,但是每个feature颗粒要尽量小,因为它需要我们能尽早merge回develop分支,否则冲突解决起来就没完没了。同时,当一个功能因为各种原因不开发了或者放弃了,这个分支直接废弃,不影响develop分支。
release 分支
使用规范:
-
命名规则:release/,“”以本次发布的版本号为标识
-
release分支主要用来为发布新版的测试、修复做准备
-
当需要为发布新版做准备时,从develop衍生出一个release分支
-
release分支可以从develop分支上指定commit派生出
-
release分支测试通过后,合并到master分支并且给master标记一个版本号
-
release分支一旦建立就将独立,不可再从其他分支pull代码
-
必须合并回develop分支和master分支
release分支是为发布新的产品版本而设计的。在这个分支上的代码允许做小的缺陷修正、准备发布版本所需的各项说明信息(版本号、发布时间、编译时间等)。通过在release分支上进行这些工作可以让develop分支空闲出来以接受新的feature分支上的代码提交,进入新的软件开发迭代周期。
当develop分支上的代码已经包含了所有即将发布的版本中所计划包含的软件功能,并且已通过所有测试时,我们就可以考虑准备创建release分支了。而所有在当前即将发布的版本之外的业务需求一定要确保不能混到release分支之内(避免由此引入一些不可控的系统缺陷)。
成功的派生了release分支,并被赋予版本号之后,develop分支就可以为“下一个版本”服务了。所谓的“下一个版本”是在当前即将发布的版本之后发布的版本。版本号的命名可以依据项目定义的版本号命名规则进行。
hotfix 分支
使用规范:
-
命名规则:hotfix/*
-
hotfix分支用来快速给已发布产品修复bug或微调功能
-
只能从master分支指定tag版本衍生出来
-
一旦完成修复bug,必须合并回master分支和develop分支
-
master被合并后,应该被标记一个新的版本号
-
hotfix分支一旦建立就将独立,不可再从其他分支pull代码
除了是计划外创建的以外,hotfix分支与release分支十分相似:都可以产生一个新的可供在生产环境部署的软件版本。
当生产环境中的软件遇到了异常情况或者发现了严重到必须立即修复的软件缺陷的时候,就需要从master分支上指定的TAG版本派生hotfix分支来组织代码的紧急修复工作。
这样做的显而易见的好处是不会打断正在进行的develop分支的开发工作,能够让团队中负责新功能开发的人与负责代码紧急修复的人并行的开展工作。
使用规范
所有使用了本规范的项目,必须严格规范操作,否则不予以合并代码、提测、打包上线等后续操作
基本要求:
-
所有commit必须有注释,内容必须简洁明了的描述本次commit涵盖了哪些内容。严禁注释内容过于简单或不能明确表达提交内容的!
-
合理控制提交内容的颗粒度,一次commit含一个独立功能点。严禁一次提交涵盖多个功能项。
-
正确为每个项目设置Git提交用到的user.name和user.email信息,以公司邮箱为准,不可随意设置以影响无法正确识别。 查看当前项目配置信息的命令:git config -l
commit 的类型:
-
feat: 新功能、新特性
-
fix: 修改 bug
-
perf: 更改代码,以提高性能(在不影响代码内部行为的前提下,对程序性能进行优化)
-
refactor: 代码重构(重构,在不影响代码内部行为、功能下的代码修改)
-
docs: 文档修改
-
style: 代码格式修改, 注意不是 css 修改(例如分号修改)
-
test: 测试用例新增、修改
-
build: 影响项目构建或依赖项修改
-
revert: 恢复上一次提交
-
ci: 持续集成相关文件修改
-
chore: 其他修改(不在上述类型中的修改)
-
release: 发布新版本
-
workflow: 工作流相关文件修改
scope
commit 影响的范围, 比如: route, component, utils, build…
subject
commit 的概述
版本号(tag)
-
版本号(tag)命名规则:主版本号.次版本号.修订号,如2.1.13。(遵循GitHub语义化版本命名规范)
-
版本号仅标记于master分支,用于标识某个可发布/回滚的版本代码
-
对master标记tag意味着该tag能发布到生产环境
-
对master分支代码的每一次更新(合并)必须标记版本号
-
仅项目管理员有权限对master进行合并和标记版本号
项目权限
-
Git权限分管理员、开发者、浏览者三种类型
-
浏览者只能浏览代码,无push、pull request等所有写权限
-
开发者拥有浏览、push非主分支、提交pull request工单权限
-
管理员拥有建立和管理Git项目、合并分支和代码、给master打tag版本号等权限
分支使用
-
每个Git项目固定含有上述所有分支类型。主分支master和develop是保护分支,只能进行合并请求,均不可直接提交代码。
-
功能需求或常规Bug修复,请从develop拉取feature分支;线上紧急问题修复,请从master拉去hotfix分支。
代码提交
-
一个提交就代表解决一个问题
-
大问题适当地分解为多个小问题,以便每次小型提交都更易于理解
-
提交前本地代码需要编译成功,并检查一下提交的代码 (这一步很重要,测试代码、简单的逻辑错误都可以被发现, 可以有效解决简单粗心的bug产生)
开发阶段的实际场景与常用命令
2.1 如果是启动一个新项目,组长需要做什么?
// 2.1.1:新建gitlab仓库,复制ssh仓库地址// 2.1.2:克隆项目到本地文件夹
git clone “复制的地址”
// 2.1.3:此时默认是在maser分支上,进到拉取的本地项目目录中去,将本地仓库与远程仓库关联起来。
git remote add origin ‘复制的地址’
// 2.1.4:推送本地master分支到远程master分支
git push -u origin master
// 2.1.5:新建一个本地dev分支,并切换到本地dev分支
git checkout -b dev
// 2.1.6:在此之前远程是没有dev分支的,需要推送本地dev分支到远程dev分支
git push -u origin dev
master分支将来控制着发布到线上的稳定版本代码,普通成员不可以对master分支进行操作,不然每个组员改点东西,很有可能把线上代码搞崩。组员们只能在dev分支上进行操作。
2.2 接下来组员们需要做什么
// 组员小智:
// 2.2.1 将组长建好的仓库克隆到本地
git clone “复制的地址”
// 2.2.2 默认在master分支上,需要检出远程dev分支到本地dev
git checkout -b dev origin/dev
// 2.2.3 不直接在本地dev分支上写代码,不然就跟svn没什么两样了,基于本地dev分支建一个自己的本地分支,名为xiaozhi
git checkout -b xiaozhi dev
// 2.2.4 此时,就切换到了本地xiaozhi分支上,开始写功能,比如task0001,写完后
git status
// 查看你本地做了哪些修改
git add ‘修改的文件名(包含目录)’
// 或者
git add *
// 来把你的修改添加到暂存区去,接下来提交代码到本地xiaozhi分支
git commit -m “task0001:基础布局功能”
// 2.2.5 建议每完成一个任务的其中一个小功能就重复一次2.2.4步骤,每天下班前至少要合并推送一次到dev分支。确保你的代码不能影响别人的运行,也不会跟最新的代码相差太远。首先,切换到本地dev分支
git checkout dev
// 2.2.6 拉取最新dev分支代码,可能在你写task0001的时候,别人提交过代码了
git pull
// 2.2.7 合并本地xiaozhi分支代码到本地dev分支
git merge xiaozhi
// 2.2.8 推送你改动的代码到远程dev分支
git push
// 2.2.9 切换到本地xiaozhi分支
git checkout xiaozhi
// 2.2.10 合并本地dev分支到本地xiaozhi分支
git merge dev
// 至此,你将你的改动推送到了远程,你的本地也是最新代码了,继续去做task0003。重复2.2.4-2.2.10步骤
…
…
…
// 当你在2.2.1步骤的时候,可能你的同事小狒也要开始做task0002,他在他的电脑上又是怎么操作的呢?
git clone ‘复制的地址’
git checkout -b dev origin/dev
git checkout -b xiaofei dev
git status
git commit -a -m “task0002: 基础布局功能”
git checkout dev
git pull
git merge xiaofei
git push
git checkout xiaofei
git merge dev
// 每个组员除了基于dev分支新建的本地分支命名不一样之外,其他基本一样。
3. 测试阶段的实际场景与常用命令
终于到了开发完成,要测试的时候了。此时,所有人各自对应的本地分支代码(xiaozhi分支,xiaofei分支)都应该和dev保存一致了。
其实就可以把release分支当作dev分支,只不过开始是大家都推送到dev分支上做开发,而现在是都推送到release分支上改bug。
// 组长:
git checkout -b release dev
git push -u origin release
// 组员小智:
git checkout -b release origin/release
git checkout xiaozhi
git status
git add *
git commit -m “bug0001:修复首页xxxx的问题”
git checkout release
git pull
git merge xiaozhi
git push
git checkout xiaozhi
git merge release
// 继续解决下一个bug
// 组员小狒
git checkout -b release origin/release
git checkout xiaofei
git status
git add *
git commit -m “bug0002:修复列表页的XXXX的问题”
git checkout release
git pull
git merge xiaofei
git push
git checkout xiaofei
git merge release
// 继续解决下一个bug
// 当所有测试提出的bug都解决完后,大家应该保证dev分支,release分支,各自的本地分支(xiaozhi,xiaofei)都一样
// 组长:
// 合并release分支到dev分支上
git checkout dev
git merge release
git push
// 合并release分支到master分支上并打上标签版本号
git checkout master
git merge release
git push
git tag -a v1.0.0 -m ‘1.0.0版本’
git push origin --tags
// 组员们继续写功能开始进行下一版本的产品迭代,重复2.2.4-2.2.10步骤
4. 上线后客户反馈有bug怎么办?
有可能当组员们已经在各自的本地分支(xiaozhi, xiaofei)上去做下一版本的开发的时候,客户反馈一些测试小姐姐们当时没有测出来的bug。此时大家肯定不会直接去把dev分支再去合并到master分支了。
// 组长:
// 4.1.1 基于master分支新建一个hotfix001分支
git checkout -b hotfix001 master
// 4.1.2 与远程hotfix001分支关联起来
git push -u origin hotfix001
// 组长将这个重大而又紧急的任务指派给小智
// 组员小智:
// 4.1.3 检出远程分支hotfix001到本地分支hotfix001
git checkout -b hotfix001 origin/hotfix001
// 4.1.2 小智一顿牛逼操作之后
git commit -a -m “hotfix001: 解决线上xxxx的问题”
git push
// 4.1.3 测试通过后组长去拉取hotfix001的代码并合并回master分支
git checkout hotfix001
git pull
git checkout master
git merge hotfix001
git push
git tag -a v1.0.1 -m ‘1.0.1版本:修复XXXX等一系列的问题’
git push origin --tags
// 4.1.4 接下来判断这个线上的bug下一版本是否还要处理,如果这个功能还要的话,为了避免下一版本出现同样的问题,那组长还需要把这个hotfix001分支合并到dev分支中去
git checkout dev
git pull
git merge hotfix001
git push
// 4.1.5 线上bug分支hotfix001完成了它光荣的使命,可以删除了
git branch -d hotfix001
git push origin --delete hotfix001
团队协作开发流程图
5.后话
我也在用git图形化工具,比如sourcetree。相信很多人也在用,其实用命令行还是不如sourcetree那么方便而强大的。比如在撤销修改的时候,sourceTree可以只撤销这个文件你所改动的某一部分,而git命令行只能对某一个文件的所有改动撤销修改(当然,可能是我对git命令行操作还不那么深入的缘故,但是我相信就算git命令行能做到,也远没有图形化工具那么方便)。
不过我觉得我写这篇文章其实还是有意义的,工作了这么久,几乎天天都会用到git,一些常见git命令都不懂也说不过去,对自己要求并不那么高,并不是要强到什么都可以立刻想到用什么git命令去解决,而此篇文章中工作流常用到的命令还是要熟记于心的。
大家可以用自己的github账号并且找一个小伙伴去建一个仓库模拟体验一下上述多人协作的过程,如果有问题可以一起交流下。
另外,你可能会感兴趣的一些点:
基本shell命令使用
阮一峰:Commit message 和 Change log 编写指南
如何写好github中的readme
readme上概述文件中的图标可以怎么弄?
参考文章:
https://www.cnblogs.com/hezhi/p/10166307.html
欢迎关注,更多精彩的文章