共计 6432 个字符,预计需要花费 17 分钟才能阅读完成。
本文从前端工程,团队合作,生产部署的角度,介绍架构人员须要把握的 git 实际能力。
纲要预览
本文介绍的内容包含以下方面:
- 分支管理策略
- commit 标准与提交验证
- 误操作的撤回计划
- Tag 与生产环境
- 永恒杜绝 443 Timeout
- hook 实现部署?
- 终极利用: CI/CD
分支管理策略
git 分支弱小的同时也非常灵活,如果没有一个好的分支管理策略,团队人员随便合并推送,就会造成分支凌乱,各种笼罩,抵触,失落等问题。
目前最风行的分支管理策略,也称工作流(Workflow),次要蕴含三种:
- Git Flow
- GitHub Flow
- GitLab Flow
我司前端团队结合实际状况,制订出本人的一套分支管理策略。
咱们将分支分为 4 个大类:
- dev-*
- develop
- staging
- release
dev-*
是一组开发分支的统称,包含集体分支,模块分支,修复分支等,团队开发人员在这组分支上进行开发。
开发前,先通过 merge
合并 develop 分支的最新代码;开发实现后,必须通过 cherry-pick
合并回 develop
分支。
develop
是一个独自分支,对应开发环境,保留最新的残缺的开发代码。它只承受 cherry-pick
的合并,不容许应用 merge。
staging
分支对应测试环境。当 develop 分支有更新并且筹备公布测试时,staging 要通过 rebase
合并 develop 分支,而后将最新代码公布到测试服务器,供测试人员测试。
测试发现问题后,再走 dev-* -> develop -> staging 的流程,直到测试通过。
release
则示意生产环境。release 分支的最新提交永远与线上生产环境代码放弃同步,也就是说,release 分支是随时可公布的。
当 staging 测试通过后,release
分支通过 rebase
合并 staging 分支,而后将最新代码公布到生产服务器。
总结下合并规定:
- develop -> (merge) -> dev-*
- dev-* -> (cherry-pick) -> develop
- develop -> (rebase) -> staging
- staging -> (rebase) -> release
为什么合并到 develop 必须用 cherry-pick?
应用 merge 合并,如果有抵触,会产生分叉;dev-*
分支多而杂,间接 merge 到 develop 会产生盘根错节的分叉,难以理清提交进度。
而 cherry-pick 只将须要的 commit 合并到 develop 分支上,且不会产生分叉,使 git 提交图谱(git graph)永远放弃一条直线。
再有,模块开发分支实现后,须要将多个 commit 合为一个 commit,再合并到 develop 分支,防止了多余的 commit,这也是不必 merge 的起因之一。
为什么合并到 staging/release 必须用 rebase?
release 译为变基,合并同样不会产生分叉。当 develop 更新了许多性能,要合并到 staging 测试,不可能用 cherry-pick 一个一个把 commit 合并过来。因而要通过 rebase 一次性合并过来,并且保障了 staging 与 develop 齐全同步。
release 也一样,测试通过后,用 rebase 一次性将 staging 合并过来,同样保障了 staging 与 release 齐全同步。
commit 标准与提交验证
commit 标准是指 git commit 时填写的形容信息,要合乎对立标准。
试想,如果团队成员的 commit 是随便填写的,在合作开发和 review 代码时,其他人基本不晓得这个 commit 是实现了什么性能,或是修复了什么 Bug,很难把控进度。
为了直观的看出 commit 的更新内容,开发者社区诞生了一种标准,将 commit 依照性能划分,加一些固定前缀,比方 fix:
,feat:
,用来标记这个 commit 次要做了什么事件。
目前支流的前缀包含以下局部:
build
:示意构建,公布版本可用这个ci
:更新 CI/CD 等自动化配置chore
:杂项,其余更改docs
:更新文档feat
:罕用,示意新增性能fix
:罕用:示意修复 bugperf
:性能优化refactor
:重构revert
:代码回滚style
:款式更改test
:单元测试更改
这些前缀每次提交都要写,刚开始很多人还是记不住的。这里举荐一个十分好用的工具,能够主动生成前缀。地址在这里
首先全局装置:
npm install -g commitizen cz-conventional-changelog
创立 ~/.czrc
文件,写入如下内容:
{"path": "cz-conventional-changelog"}
当初能够用 git cz
命令来代替 git commit
命令,成果如下:
而后高低箭抉择前缀,依据提醒即可不便的创立符合规范的提交。
有了标准之后,光靠人的自觉遵守是不行的,还要在流程上对提交信息进行校验。
这个时候,咱们要用到一个新货色 —— git hook
,也就是 git 钩子。
git hook 的作用是在 git 动作产生前后触发自定义脚本。这些动作包含提交,合并,推送等,咱们能够利用这些钩子在 git 流程的各个环节实现本人的业务逻辑。
git hook 分为客户端 hook 和服务端 hook。
客户端 hook 次要有四个:
pre-commit
:提交信息前运行,可查看暂存区的代码prepare-commit-msg
:不罕用commit-msg
:十分重要,查看提交信息就用这个钩子post-commit
:提交实现后运行
服务端 hook 包含:
pre-receive
:十分重要,推送前的各种查看都在这post-receive
:不罕用update
:不罕用
大多数团队是在客户端做校验,所以咱们用 commit-msg
钩子在客户端对 commit 信息做校验。
侥幸的是,不须要咱们手动去写校验逻辑,社区有成熟的计划:husky + commitlint
husky 是创立 git 客户端钩子的神器,commitlint 是校验 commit 信息是否合乎上述标准。两者配合,能够阻止创立不合乎 commit 标准的提交,从源头保障提交的标准。
husky + commitlint 的具体应用办法请看这里
误操作的撤回计划
开发中频繁应用 git 拉取推送代码,难免会有误操作。这个时候不要慌,git 反对绝大多数场景的撤回计划,咱们来总结一下。
撤回次要是两个命令:reset
和 revert
git reset
reset 命令的原理是依据 commitId
来复原版本。因为每次提交都会生成一个 commitId,所以说 reset 能够帮你复原到历史的任何一个版本。
这里的版本和提交是一个意思,一个 commitId 就是一个版本
reset 命令格局如下:
$ git reset [option] [commitId]
比方,要撤回到某一次提交,命令是这样:
$ git reset --hard cc7b5be
下面的命令,commitId 是如何获取的?很简略,用 git log
命令查看提交记录,能够看到 commitId 值,这个值很长,咱们取前 7 位即可。
这里的 option 用的是 --hard
,其实共有 3 个值,具体含意如下:
--hard
:撤销 commit,撤销 add,删除工作区改变代码--mixed
:默认参数。撤销 commit,撤销 add,还原工作区改变代码--soft
:撤销 commit,不撤销 add,还原工作区改变代码
这里要分外留神 --hard
,应用这个参数复原会删除工作区代码。也就是说,如果你的我的项目中有未提交的代码,应用该参数会间接删除掉,不可复原,谨慎啊!
除了应用 commitId 复原,git reset 还提供了复原到上一次提交的快捷方式:
$ git reset --soft HEAD^
HEAD^
示意上一个提交,可屡次应用。
其实素日开发中最多的误操作是这样:刚刚提交完,忽然发现了问题,比方提交信息没写好,或者代码更改有脱漏,这时须要撤回到上次提交,批改代码,而后从新提交。
这个流程大抵是这样的:
# 1. 回退到上次提交
$ git reset HEAD^
# 2. 批改代码...
...
# 3. 退出暂存
$ git add .
# 4. 从新提交
$ git commit -m 'fix: ***'
针对这个流程,git 还提供了一个更便捷的办法:
$ git commit --amend
这个命令会间接批改以后的提交信息。如果代码有更改,先执行 git add
,而后再执行这个命令,比上述的流程更快捷更不便。
reset 还有一个十分重要的个性,就是 真正的后退一个版本。
什么意思呢?比如说以后提交,你曾经推送到了近程仓库;当初你用 reset 撤回了一次提交,此时本地 git 仓库要落后于近程仓库一个版本。此时你再 push,近程仓库会回绝,要求你先 pull。
如果你须要近程仓库也后退版本,就须要 -f
参数,强制推送,这时本地代码会笼罩近程代码。
留神,-f
参数十分危险!如果你对 git 原理和命令行不是十分相熟,切记不要用这个参数。
那撤回上一个版本的代码,怎么同步到近程更平安呢?
计划就是上面要说的第二个命令:git revert
git revert
revert 与 reset 的作用一样,都是复原版本,然而它们两的实现形式不同。
简略来说,reset 间接复原到上一个提交,工作区代码天然也是上一个提交的代码;而 revert 是新增一个提交,然而这个提交是应用上一个提交的代码。
因而,它们两复原后的代码是统一的,区别是一个新增提交(revert),一个回退提交(reset)。
正因为 revert 永远是在新增提交,因而本地仓库版本永远不可能落后于近程仓库,能够间接推送到近程仓库,故而解决了 reset 后推送须要加 -f
参数的问题,进步了安全性。
说完了原理,咱们再看一下应用办法:
$ git revert -n [commitId]
把握了原理应用就很简略,只有一个 commitId 就能够了。
Tag 与生产环境
git 反对对于历史的某个提交,打一个 tag 标签,罕用于标识重要的版本更新。
目前广泛的做法是,用 tag 来示意生产环境的版本。当最新的提交通过测试,筹备公布之时,咱们就能够创立一个 tag,示意要公布的生产环境版本。
比方我要发一个 v1.2.4
的版本:
$ git tag -a v1.2.4 -m "my version 1.2.4"
而后能够查看:
$ git show v1.2.4
> tag v1.2.4
Tagger: ruims <2218466341@qq.com>
Date: Sun Sep 26 10:24:30 2021 +0800
my version 1.2.4
最初用 git push 将 tag 推到近程:
$ git push origin v1.2.4
这里留神:tag 和在哪个分支创立是没有关系的,tag 只是提交的别名。因而 commit 的能力 tag 均可应用,比方下面说的 git reset
,git revert
命令。
当生产环境出问题,须要版本回退时,能够这样:
$ git revert [pre-tag]
# 若上一个版本是 v1.2.3,则:$ git revert v1.2.3
在频繁更新,commit 数量宏大的仓库里,用 tag 标识版本显然更清新,可读性更佳。
再换一个角度思考 tag 的用途。
下面分支管理策略的局部说过,release 分支与生产环境代码同步。在 CI/CD(上面会讲到)继续部署的流程中,咱们是监听 release 分支的推送而后触发主动构建。
那是不是也能够监听 tag 推送再触发主动构建,这样版本更新的直观性是不是更好?
诸多用途,还待大家思考。
永恒杜绝 443 Timeout
咱们团队外部的代码仓库是 GitHub,家喻户晓的起因,GitHub 拉取和推送的速度十分慢,甚至间接报错:443 Timeout。
咱们开始的计划是,全员开启 VPN。尽管大多时候速度不错,然而的确有偶然的一个小时,甚至一天,代码死活推不下来,重大影响开发进度。
起初忽然想到,速度慢超时是因为被墙,比方 GitHub 首页打不开。再究其根源,被墙的是拜访网站时的 http 或 https 协定,那么其余协定是不是就不会有墙的状况?
想到就做。咱们发现 GitHub 除了默认的 https
协定,还反对 ssh
协定。于是筹备尝试一下应用 ssh 协定克隆代码。
用 ssh 协定比拟麻烦的一点,是要配置免密登录,否则每次 pull/push 时都要输出账号密码。
GitHub 配置 SSH 的官网文档在这里
英文吃力的同学,能够看这里
总之,生成公钥后,关上 GitHub 首页,点 Account -> Settings -> SSH and GPG keys -> Add SSH key,而后将公钥粘贴进去即可。
当初,咱们用 ssh 协定克隆代码,例子如下:
$ git clone git@github.com:[organi-name]/[project-name]
发现霎时克隆下来了!再测几次 pull/push,速度飞起!
不论你用哪个代码治理平台,如果遇到 443 Timeout 问题,请试试 ssh 协定!
hook 实现部署?
利用 git hook 实现部署,应该是 hook 的高级利用了。
当初有很多工具,比方 GitHub,GitLab,都提供了继续集成性能,也就是监听某一分支推送,而后触发主动构建,并主动部署。
其实,不论这些工具有多少花色,外围的性能(监听和构建)还是由 git 提供。只不过在外围性能上做了与自家平台更好的交融。
咱们明天就抛开这些工具,寻根究底,应用纯 git 实现一个 react 我的项目的主动部署。把握了这套外围逻辑,其余任何平台的继续部署也就没那么神秘了。
因为这一部分内容较多,所以独自拆出去一篇文章,地址如下:
纯 Git 实现前端 CI/CD
终极利用: CI/CD
下面的一些中央也提到了继续集成,继续部署这些字眼,当初,千呼万唤始进去,配角正式退场了!
能够这么说,下面写到的所有标准规定,都是为了更好的设计和实现这个配角 ——— CI/CD。
首先理解一下,什么是 CI/CD?
外围概念,CI(Continuous Integration)译为继续集成,CD 包含两局部,继续交付(Continuous Delivery)和继续部署(Continuous Deployment)
从全局看,CI/CD 是一种通过 自动化流程 来频繁向客户交付利用的办法。这个流程贯通了利用的集成,测试,交付和部署的整个生命周期,统称为“CI/CD 管道”。
尽管都是像流水线一样自动化的管道,然而 CI 和 CD 各有分工。
继续集成 是频繁地将代码集成到骨干分支。当新代码提交,会主动执行构建、测试,测试通过则主动合并到骨干分支,实现了产品疾速迭代的同时放弃高质量。
继续交付 是频繁地将软件的新版本,交付给品质团队或者用户,以供评审。评审通过则能够公布生产环境。继续交付要求代码(某个分支的最新提交)是随时可公布的状态。
继续部署 是代码通过评审后,主动部署到生产环境。继续部署要求代码(某个分支的最新提交)是随时可部署的。
继续部署与继续交付的惟一区别,就是部署到生产环境这一步,是否是自动化。
部署自动化,看似是小小的一步,然而在实际过程中你会发现,这反而是 CI/CD 流水线中最难落实的一环。
为什么?首先,从继续集成到继续交付,这些个环节都是由开发团队施行的。咱们通过团队外部合作,产出了新版本的待发布的利用。
然而将利用部署到服务器,这是运维团队的工作。咱们要实现部署,就要与运维团队沟通,然而开发同学不理解服务器,运维同学不理解代码,沟通起来困难重重。
再有,运维是手动部署,咱们要实现主动部署,就要有服务器权限,与服务器交互。这也是个大问题,因为运维团队肯定会顾虑平安问题,因此推动起来节节碰壁。
目前社区成熟的 CI/CD 计划有很多,比方老牌的 jenkins,react 应用的 circleci,还有我认为最好用的 GitHub Action 等,咱们能够将这些计划接入到本人的零碎当中。
这篇文章篇幅曾经很长了,就到这里完结吧。接下来我会基于 GitHub Action 独自出一篇具体的 react 前端我的项目 CI/CD 实际,记得关注我的专栏哦。
我的专栏:前端 devops