Git

使用Git和Gitlab进行开发

Git和Gitlab的基本使用,以及svn迁移到git和Gitlab Ci

Posted by Sun Jianjiao on January 20, 2017

简化流程,减少规范, 提高效率和质量才是我们最想要的。让复杂的事情变简单才是引入工具的目的, 而不是没增加一个工具跟着好几页的规范。

  • 工程师文华——最好的规范是没有规范——当有一个新的流程要实施, 写一个规范,搞一个checklist;都是一个非常糟糕的策略, 人总会犯错, 总有侥幸心里。
    规则需要人去学习和记忆,本质上来说是怕人出错,所以搞出了一些规则和流程,而这些规则和流程的执行,又依赖于人,换汤不换药。
    规章制度都是可以选择执行的,但是程序完全按照指令执行。 所以,为什么不把checklist和流程写成代码是一种更好的方式。
    例如Gitlab数据丢失事件,需要增加的是自动化的备份和恢复的工具。 对于掉电、磁盘损坏、中病毒等问题,设计流程、规则、人肉检查、权限系统、checklist等等统统都不是最终的解决办法,用更好的技术去设计出一个高可用的系统才是一劳永逸。
  • 通过技术和工具,让人感受不到它的存在,却按照这个最优的流程完成任务才是最高境界——自古华山一条路就不会走错,因为走出去就会付出巨大的代价。
  • 工具是在业务的驱动下,从无到有的过程, 各种系统在这种约束下逐渐被开发被使用。 更多的都是为了交付的目标, 但是会做前瞻性的考虑, 同时需要考虑实际的研发能力。 没有完美的工具和流程, 只有合适的工具和流程。

1 真的需要使用Git吗?

Git是为Linux kernel开发的,对于Linux Kernel这种巨型的项目来说,或许merge这个分支的代码还是那个分支的代码会是一个大问题,但是对于普通的项目,只要考虑是取还是舍,维护也基本只需要一个人就足够了,再不济还可以分成多个子项目多人维护,所以很难理解Git的好处。 如果就是简单的作为一个版本管理的工具,提交和更新下代码, 使用svn git或者其他的版本管理工具都没什么太大的区别, 可能svn合适, 学习门槛更低。

Github上大家一起做一个项目,然后互相merge,这种工作流程就很好。 这种收益才是最有诱惑的, 选择git主要考虑到工作流程和工具的生态系统, 并且做好了充分的准备使用这些工具和流程, git有很好用的工具可以用来使用——Gerrit, Gitlab和Github等。

分布式,分支更轻量级等都不是最吸引人的地方, 因为商业项目都会规定中心服务器,svn的分支也够用,最吸引人的是:

  • pull-request 工作流将 code review 强制纳入日常开发流程,而且足够简单
  • 社区拥有强大的工具——gerrit、github, gitlab等工具的强大, 使得代码Reivew, 持续集成,自动部署更加容易,从而保证了开发的质量。
  • 利用工具方便形成固定统一的工作流——代码静态检查, 代码review,编译,自动测试,自动部署, 最终形成闭环。
  • 良好的社区支持,Linus的名人效应导致了很多资深软件开发人员为其工作, 从而会越来越好。 这样就会有更多更好的工具出现, 从而减少工具

2 Git 基本用法

three steps

第一次使用git需要习惯分3步进行代码提交:

  1. git add 将工作区的文件添加到暂存区
  2. git commit 将暂存区的内容提交到本地仓库
  3. git push 将本地仓库提交到远程仓库

2.1 git config

查看配置的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ git config --list
core.symlinks=false
core.autocrlf=true
core.fscache=true
color.diff=auto
color.status=auto
color.branch=auto
color.interactive=true
help.format=html
http.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
diff.astextplain.textconv=astextplain
rebase.autosquash=true
credential.helper=manager
user.name=unanao
user.email=jianjiaosun@126.com
core.editor=notepad
core.repositoryformatversion=0
core.filemode=false
core.bare=false
core.logallrefupdates=true
core.symlinks=false
core.ignorecase=true
remote.origin.url=git@192.168.200.128:sunjj/git-example.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master

第一次使用需要配置邮箱和用户名:

1
2
$ git config --global user.name "$your-name"
$ git config --global user.email "$your-email"

配置git commit提交添加的编辑器: 使用vim: git config –global core.editor vim

1
2
3
4
windows下配置使用记事本:
git config --global core.editor notepad

同样的防范可以配置自己喜欢的其它编辑器

2.2 Git 基本命令

2.2.1 克隆一个仓库:

1
git clone git@192.168.200.128:sunjj/git-example.git

2.2.2 查看差异

1
git diff 修改代码后, 执行这个命令,review代码后,再add和commit是一个好习惯。

2.2.3 把工作区的所有变化提交到暂存区

包括文件内容修改(modified)以及新文件(new),但不包括被删除的文件

1
git add $file-name/$dir-name

2.2.4 删除文件和目录

1
2
git rm $file-name
git rm -r $dir-name

2.2.5 重命名

1
git mv $old-name $new-name

2.2.6 提交当前暂存区的修改内容

1
git commit <-m "comment">

2.2.7 提交所有已经修改和删除文件

1
git comm -a <-m "comment"> 不包括新增文件

2.2.8 提交修改到远程主机

1
git push origin $branch-name

经常会到好多资料上写了git push -u, 这个-u主要用于pull, 可以少写点参数,如果使用git pull origin $branch-name, 这个-u没有用。

2.2.9 日志

git log 列出本分提交的日志:

1
2
3
4
5
6
7
8
9
10
11
12
$ git log
commit 46aecf1b2c56db30c35ba1cb82ce7d8a7e938727
Author: unanao <jianjiaosun@126.com>
Date:   Thu Jan 19 16:38:12 2017 +0800

    yes

commit 0c944508c6e5787984f8c0cc6f36eb09c26f60f2
Author: unanao <jianjiaosun@126.com>
Date:   Thu Jan 19 16:37:22 2017 +0800

    init

git reset 回退到某次提交:

1
2
3
4
5
6
7
$ git reset 0c944508c6e5787984f8c0cc6f36eb09c26f60f2 --hard
$ git log
commit 0c944508c6e5787984f8c0cc6f36eb09c26f60f2
Author: unanao <jianjiaosun@126.com>
Date:   Thu Jan 19 16:37:22 2017 +0800

    init

2.2.10 重返未来

git reflog几乎可以找回所有删除的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ git reflog
0c94450 HEAD@{0}: reset: moving to 0c944508c6e5787984f8c0cc6f36eb09c26f60f2
46aecf1 HEAD@{1}: checkout: moving from master to hello
0c94450 HEAD@{2}: checkout: moving from branch-1 to master
46aecf1 HEAD@{3}: commit: yes
0c94450 HEAD@{4}: checkout: moving from master to branch-1
0c94450 HEAD@{5}: commit (initial): init

git reset 46aecf1 --hard
$ git log
commit 46aecf1b2c56db30c35ba1cb82ce7d8a7e938727
Author: unanao <jianjiaosun@126.com>
Date:   Thu Jan 19 16:38:12 2017 +0800

    yes

commit 0c944508c6e5787984f8c0cc6f36eb09c26f60f2
Author: unanao <jianjiaosun@126.com>
Date:   Thu Jan 19 16:37:22 2017 +0800

    init

2.2.11 回退

恢复到某次commit-id的状态:

1
git reset $commit-id --hard

撤销工作区的修改:

1
git checkout $file

撤销某次提交:

1
git revert $commit-id

2.2.12 查看某次提交的内容

1
git show $commit-id

2.2.12.1 Intellij IDE的Local history

如果发现代码不对, 而且代码没有进行commit, 还可以通过Intellij的local history找回代码。

2.2.12.2 从Git历史中删除文件

2.2.12.3 branch-filter

不小心把一个不该加入版本管理的文件加进去了,有时候这个文件很大,也许我们整个版本库才几百K,但加进去这个没用的文件却有好几百M,不想因为这么个破烂东西把整个版本库整个硕大无比,以后维护备份都不方便;还有时候是不小心把一个敏感文件 加进去了,比如里面写了信用卡密码的文本文件。 这时候我们希望能把它从版本库中永久删除不留痕迹,不仅要让它在版本历史里看不出来,还要把它占用的空间也释放出来。

1
git filter-branch --tree-filter 'rm -f filename' HEAD [更多详细信息](https://git-scm.com/docs/git-filter-branch)

2.2.12.4 bfg

1
$ bfg --delete-files id_{dsa,rsa}  my-repo.git [详细使用文档](https://rtyley.github.io/bfg-repo-cleaner/)

2.3 git 分支

有了分支就要频繁的提交代码, 因为这个分支可能只有一个人在写代码, 每天至少提交一次, 有一点进展就提交到远程仓库才是最好的方式, 否则遇到那天倒霉,代码丢了就太悲哀了。

2.3.1 分支创建和切换

创建名字为feature的分支:

1
git branch feature  

切换到feature分支:

1
git checkout feature  

创建并切换分支,如分支名字为dev

1
2
$ git checkout -b dev
Switched to a new branch 'dev'

基于指定分支创建新分支, 源分支为dev, 新分支为new-dev:

1
2
$ git checkout -b new-dev dev
Switched to a new branch 'new-dev'

2.3.1.1 将远程分支信息获取到本地

方法一:

1
2
3
$ git fetch
From 192.168.200.128:sunjj/git-example
 * [new branch]      new-feature -> origin/new-feature

方法二:

1
2
3
4
$ git pull origin
	From 192.168.200.128:sunjj/git-example
	 * [new branch]      feature    -> origin/feature
	 * [new branch]      new-dev    -> origin/new-dev

2.3.2 列出分支:

2.3.2.1 列出本地已经checekout的分支,git branch 不带参数, 并且在当前分支的前面加“*”号标记:

1
2
$ git branch
* master

2.3.2.2 列出所有分支, 本地分支和远程分支:

1
2
3
$ git branch -a
* master
  remotes/origin/master

2.3.2.3 获取远程分支

1
2
3
4
$ git pull origin
	From 192.168.200.128:sunjj/git-example
	 * [new branch]      feature    -> origin/feature
	 * [new branch]      new-dev    -> origin/new-dev

2.3.2.4 列出更新后的所有分支:

1
2
3
4
5
6
7
$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/dev
  remotes/origin/feature
  remotes/origin/master
  remotes/origin/new-dev

2.3.2.5 列出更新后的本地分支:

1
2
$ git branch
* master

2.3.2.6 check 分支到本地, 再列出本地分支:

1
2
3
4
5
6
7
8
$ git checkout dev
Branch dev set up to track remote branch dev from origin.
Switched to a new branch 'dev'

unanao@DESKTOP-FSBVPHM MINGW64 /f/code/git-example (dev)
$ git branch
* dev
  master

2.3.3 远程分支

2.3.3.1 添加远程分支:

1
$ git remote add origin git@192.168.200.128:sunjj/git-example.git

2.3.3.2 查看远程分支:

1
2
3
$ git remote -v
origin  git@192.168.200.128:sunjj/git-example.git (fetch)
origin  git@192.168.200.128:sunjj/git-example.git (push)

2.3.3.3 删除分支

1
git branch -d | -D branchname 删除branchname分支

2.3.3.4 分支重命名

如果newbranch名字分支已经存在,则需要使用-M强制重命名,否则,使用-m进行重命名。

1
git branch -m | -M oldbranch newbranch

2.3.3.5 清除远程已经删除的本地分支

1
git remote prune origin

2.3.4 代码合并

2.3.4.1 合并某次提交

例如对于已经发布的产品分支, 只需要合入某个bug修改。 可以使用git cherry-pick命令, 相当于只合入某个补丁。
切换到对应需要的分支, 执行cherry-pick命令:

1
2
git checkout <branch name>
git cherry-pick <commit id>

2.3.5 解决冲突

2.3.5.1 二进制文件冲突解决

使用自己的修改:

1
2
git checkout --ours binary.dat
git add binary.dat

使用远程的修改:

1
2
git checkout --theirs binary.dat
git add binary.dat

2.4 git 客户端

2.4.1 命令行客户端

  • git for windows, 下载慢可以直接在360, 腾讯管家等搜索git,安装即可。 git for windows也有图形界面。

    在对应的项目目录下, 右键,选择:”git bash here”, 可以省着使用cd 进行切换。

  • Linux, apt-get/yum 直接install 就好了。

2.4.2 SourceTree

在360上直接搜sourcetree安装接可以了, 支持mac和windows。 估计使用linux的人不会使用图形化界面的工具。 使用SourceTree因为TortoiseGit, 需要单独要装git, 搞一个ssh key还要配置putty,实在太不人性化了。

Source设置SSH Key容易, 而且还自带了内置的git。

如果已经有ssh key,导入方法如下: “工具”->”选项”:

three steps

3 分支模型

本来想总结一下分支模型, 查资料过程中发现gitlab已经做了这个事情。 简单的分享一下。

3.1 一个复杂的模型:

git-branch-model

使用独立的develope分支, 用户特性,Bugfix和发布。 所有的开发在都develop分支进行,然后release分支基于develop, 然后经过bugfix后,合入master, 再将修改的bug合入develop分支。 这个模型太复杂了, 而且随着持续集成和程序的微服务化, 这个模型更加不合适。
详细介绍

3.2 Github flow

github flow model
只有特性分支和master分支。
详细介绍

3.3 增加测试环境的模型

测试环境的模型

3.4 发布分支

release branches model
如果产品要发布到外面, 那么就需要增加发布分支

随着持续集成和微服务模型的普及, 复杂的分支模型会被逐渐废弃掉, 后两种模型的结合会更适合开发模式。

4 SVN迁移到Git

建议:当完成迁移后,所有的开发人员立即使用Git仓库, 锁住SVN仓库。 否则很难保证2个仓库的一致性。

可以使用_svn2git_将SVN仓库迁移到Git. svn2git 使用git-svn 克隆SVN仓库, 并且保证分支,标签和日志的导入以及将trunk转换为master.

4.1 安装


首先需要有git, git-svn和ruby, 因为svn2git是一个ruby脚本, 并且依赖git-svn。 Debian/Ubuntu 安装_svn2git_的依赖:

1
$ sudo apt-get install git-core git-svn ruby

通过rubygems安装_svn2git_

1
$ sudo gem install svn2git

[可选]转换SVN的用户名到Git用户名

可以为_svn2git_提供一个名字映射的文件, 保证SVN用户的log对应到Git用户。 下面的命令能找到所有的SVN用户。
通过本地仓库查找:

1
$ svn log --quiet | grep -E "r[0-9]+ \| .+ \|" | cut -d'|' -f2 | sed 's/ //g' | sort | uniq

或者通过SVN仓库的URL:

1
$ svn log --quiet http://path/to/root/of/project | grep -E "r[0-9]+ \| .+ \|" | cut -d'|' -f2 | sed 's/ //g' | sort | uniq

将上面命令的输出的名字按照下面的方式进行对应, 等号左边为SVN的名字, 右边为Git的名字和邮箱, 一行一个, 例如:

1
2
jcoglan = James Coglan <jcoglan@never-you-mind.com>
stnick = Santa Claus <nicholas@lapland.com>

例如文件名字叫authors.txt, 可以放在任何svn2git能够访问的地方都可以。

4.2 迁移

4.2.1 Git仓库初始化

  1. 如果 SVN 仓库的是一个标准的格式 (trunk, branches, tags)

    1
    
     $svn2git https://svn.example.com/path/to/repo --authors /path/to/authors.txt
    
  2. SVN 经常追踪了很多工程,如果只想迁移指定的路径下的项目: 例如: Using higher level of URL: path-to-repo/myrepo/myproject => path-to-repo/myrepo, 可以使用 –no-minimize-url 参数禁止向上更目录进行查找。

    1
    
     $ svn2git http://svn.example.com/path/to/repo/nested_project --no-minimize-url --authors /path/to/authors.txt
    

如果提示如下错误,可以忽略:

1
2
command failed
git gc

如果不是标准的SVN格式, 参考svn2git的官方文档

4.2.2 提交到Git中心仓库

1
2
3
git remote add origin git@xxxxxx:<project>.git
git push --all origin
git push --tags origin

5 Gitlab使用方法

一个开发过程主要就分为设计,编码, 编译, 代码review, 测试, 发布。 Gitlab可以满足从代码版本管理, 代码review和测试,以及发布的功能。 如果执行的好, 可以优化开发过程, 提高质量。

本文只是描述使用工具来减化开发流程, 简单的对用到的gitlab的功能进行介绍,作为日常使用和简单操作的入门文档。 更加详细的介绍参考gitlab的官方文档。

5.1 代码Review

Making small and non-consequential decisions is fine, and makes you look like you know what you’re doing, so what a kernel manager needs to do is to turn the big and painful ones into small things where nobody really cares. –Linus
摘自 Linus on kernel management style

模块如何划分, 模块间如何写作可能是架构师最重要工作,比选择先进的技术重要。 代码Review更是如此,小功能, 每次Review的代码不超过200行,Review效果才好, 一次Merge Request成千上完行, 这种Review将是一个十分痛苦的过程。

5.1.1 管理员操作

5.1.1.1 锁主分支

branch lock

5.1.1.2 代码review和接受Merge request

accept merge request

5.1.2 代码提交

5.1.2.1 创建分支和上传代码

创建分支:

1
git checkout -b $branch-name

提交修改:

1
2
git add $file/$dir
git commit

提交merge请求前, 最好先Merge为最新的目标分支,如目的分支为 $targe_branch :

1
git pull origin $target_branch

提交代码到gitlab: git push origin $branch_name

5.1.2.2 登陆gitlab , 创建merge request

creat merge request

assign merge request

5.2 测试——Bug和Bugfix分支

Gitlab上提交Bug, 然后基于issu创建关联的分支, 最终merge代码的时候会直接关闭bug。

5.2.1 在issu里面创建分支

create branch from issu

5.2.2 创建后会显示分支关联

isse and branch

但是gitlab缺省版本缺少了一个状态——Fixed, Merger后由测试将Fixed修改为Closed。 Gitlab提供了修改的方式——help/administration/issue_closing_pattern.md

6 Gitlab CI

虽然是用Gitlab管理代码很久了, 一直仅限于代码管理。 最开始写了一个release.sh用于编译和发布版本, 然后又加了一个build-run.sh用于编译, 部署到测试环境和发布版本到samba服务器。 但是随着服务越来越多, 登录到服务器执行脚本也变成一个很麻烦的事情, 最重要的是有时会忘记更新最新的版本到测试环境。所以需要把持续集成用起来, 只需要在提交代码时出发编译和部署就可以了, 还没有做自动化测试。

从 GitLab 8.0 开始,GitLab CI 就已经集成在 GitLab 中,只要在项目中添加一个 .gitlab-ci.yml 文件,然后添加一个 Runner,即可进行持续集成。 而且随着 GitLab 的升级,GitLab CI 变得越来越强大,本文将介绍如何使用 GitLab CI 进行持续集成。

6.1 基本概念

6.1.1 Pipeline

一次 Pipeline 其实相当于一次构建任务,里面可以包含多个流程,如安装依赖、运行测试、编译、部署测试服务器、部署生产服务器等流程。

任何提交或者 Merge Request 的合并都可以触发 Pipeline。

6.1.2 Stages

Stages 表示构建阶段,说白了就是上面提到的流程。

我们可以在一次 Pipeline 中定义多个 Stages,这些 Stages 会有以下特点:

  • 所有 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始
  • 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功
  • 如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败

6.1.3 Jobs

Jobs 表示构建工作,表示某个 Stage 里面执行的工作。

我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:

  • 相同 Stage 中的 Jobs 会并行执行
  • 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功
  • 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败

6.2 GitLab Runner

由谁来执行这些构建任务呢? —— 就是 GitLab Runner 了!

想问为什么不是 GitLab CI 来运行那些构建任务?因为构建任务都会占用很多的系统资源 (譬如编译代码),而 GitLab CI 又是 GitLab 的一部分,如果由 GitLab CI 来运行构建任务的话,在执行构建任务的时候,GitLab 的性能会大幅下降。GitLab CI 最大的作用是管理各个项目的构建状态,因此,运行构建任务这种浪费资源的事情就交给 GitLab Runner了!

GitLab Runner 可以安装到不同的机器上,所以在构建任务运行期间并不会影响到 GitLab 的性能。

6.2.1 安装

安装 GitLab Runner 很简单,官方教程

粘贴一个Debian/Ubuntu/Mint 的安装方法,

1
2
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-runner

6.2.2 注册 Runner

  1. 查看register需要的信息 打开你 GitLab 中的项目页面,”Settings” -> “Pipelines”, 在“Specific Runners”中“How to setup a specific Runner for a new project”有url和token。用于执行register时输入。如下图:

注册信息

  1. 注册项目到gitlab runner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
unanao@unanao-dell:~$ sudo gitlab-runner register
Running in system-mode.                            

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
http://192.168.200.128/                                                         //上面图片中的url
Please enter the gitlab-ci token for this runner:
jjmQ2UGEhJQ2P4sd_xUL                                                            //上面图片中的token
Please enter the gitlab-ci description for this runner:
[unanao-dell]: example for gitlab ci description                                //Runner的描述信息
Please enter the gitlab-ci tags for this runner (comma separated):
example-tag                                                                     //tag用于和.gitlab-ci.yml中的tags比较, 只想用相同的tag才会执行
Whether to run untagged builds [true/false]:
[false]:                                                                        //默认即可, 直接回车
Whether to lock the Runner to current project [true/false]:
[true]:                                                                         //默认即可, 直接回车
Registering runner... succeeded                     runner=jjmQ2UGE
Please enter the executor: docker, ssh, virtualbox, kubernetes, docker-ssh, parallels, shell, docker+machine, docker-ssh+machine:
shell                                                                           //shell比较简单
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

6.3 添加.gitlab-ci.yml

配置好 Runner 之后,我们要做的事情就是在 项目根目录 中添加 .gitlab-ci.yml 文件了。 当我们添加了.gitlab-ci.yml 文件后,每次提交代码或者合并 MR 都会自动运行构建任务了。 那么 Pipeline 和 .gitlab-ci.yml 有什么关系呢?其实 .gitlab-ci.yml 就是在定义Pipeline。

6.3.1 基本写法

我们先来看看 .gitlab-ci.yml 是怎么写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 定义 stages
stages:
- build
- test
# 定义 job
job1:
  stage: test
  script:
  - echo "I am job1"
  - echo "I am in test stage"
# 定义 job
job2:
  stage: build
  script:
  - echo "I am job2"
  - echo "I am in build stage"
  • 用 stages 关键字来定义 Pipeline 中的各个构建阶段,然后用一些非关键字来定义 jobs。
  • 每个 job 中可以可以再用 stage 关键字来指定该 job 对应哪个 stage。
  • job 里面的 script 关键字是最关键的地方了,也是每个 job 中必须要包含的,它表示每个 job 要执行的命令。

回想一下我们之前提到的 Stages 和 Jobs 的关系,上面例子的运行结果:

1
2
3
4
I am job2
I am in build stage
I am job1
I am in test stage

根据我们在 stages 中的定义,build 阶段要在 test 阶段之前运行,所以 stage:build 的 jobs 会先运行,之后才会运行 stage:test 的 jobs。

6.3.2 其他常用的关键字

  • before_script
    定义任何 Jobs 运行前都会执行的命令。

  • after_script
    定义任何 Jobs 运行后都会执行的命令。

6.4 实际的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
stages:
- build

build:
    stage: build
    script:
    - bash ./release.sh master
    - bash ./deploy.sh
    tags:
    - hmi-service
    only:
    - master

所有的shell脚本和yaml文件文件链接

本例子实现了编译, 部署和发布。