Git工作流程实践

前言

上篇文章说到,选择Git作为版本控制系统,就是选择一种新的团队协作方式。Git常用的工作流程有几种:Git Flow、GitHub Flow、GitLab Flow。这三种工作流程几乎都是以功能驱动开发。先是有需求,才开始进行开发,建立对应的功能分支,完成开发后,该分支就合并到主分支,然后被删除。阮老师有一篇文章讲述得很清楚,这里我只是讲自己实践下来,觉得比较好的一种模式:GitLab Flow New。

为什么使用GitLab Flow New工作流程?

这里,我先讲讲为什么没有采用Git Flow 与 GitHub Flow的工作流程。

Git Flow的问题在于你需要花费时间去维护一个开发分支。

大部分的人都需要从开发分支新建分支,如果人数超过3个以后,你会发现需要去解决日常工作中的异常多的代码冲突。因为可能很多人,在新建的分支上进行开发,但合并开发分支的更新,却是在完成功能开发,这时候开发分支已经累计了无数的代码更新,再去合并的话,可能冲突会很多。

GitHub Flow的问题在于,你需要发起一个Pull Request,简称PR。你的PR通过了评审和讨论后,就合并到master里。可实际上合并到master的代码,也不一定是线上最新的代码。实际工作里,可能还会有预发布这一环节。

如何优雅使用GitLab Flow New工作流程

实际上,我们是这样使用GitLab Flow的。

首先定义3个主要分支。master为生产环境的分支,与线上代码保持一致。预发布的分支为prelease。开发测试分支从master里新建分支进行功能开发。

分支 作用 备注
Master 主分支,与生产环境的代码保持一致
Prelease 预发布分支,与预发布环境的代码保持一致
fea/xxx 开发分支从master创建分支

当你的功能开发完成并通过测试后,会新建一个MR(Merge Request与Pull Request类似,这是GitLab 里的叫法),请求合并到prelease分支。

发起MR后,就可以通知相关人员进行代码的Review,代码审核和讨论,没有问题后,会尝试合并到prelease。

这时自动构建工具会自动发布一个版本到预发布环境中。与此同时,根据这次改动将全部的代码打包一个全量/增量的zip压缩包,并请求发布系统获取标识唯一的版本号码,比如20190607_130102_9159

相关的开发和测试人员可以进行预发布环境的测试,当通过测试验证后,在发布系统对上述的版本号码进行发布,这样就更新到全量的线上机器了。

这里用一张图,说明该工作流程的步骤。
Git工作流程实践

常用技巧

Merge Request

我们采用GitLab的Merge Request机制进行代码Review,每一个新功能必须通过MR才能合并到prelease以及master。与GitLab Flow的上游优先,持续发布的原则类似,开发分支的代码只有在开发/测试环境通过了测试,才会允许发起MR合并到prelease。唯一例外的是,线上紧急问题的修复,是可以跳过这个流程的。

采用MR后,会利用no fast worword合并,并生成一个对应commit id,这样实现了代码线性的提交,也方便后面代码回滚。确认代码合并时,通常会选择合并后自动删除源分支的选项。

合并prelease的更新

开发人员提交MR后,可能会遇到prelease已更新,也就是落后提交的问题(x commits behind),这时,采用rebase的方式将prelease分支的代码与自己分支进行合并,并重新提交。

举例,当前你发起了一个MR,分支为fea/new,在merge_requests界面发现落后prelease几个提交,那么正确的方式是:

# 切换到prelease分支
git checkout prelease
# 拉取对应的更新
git pull --rebase origin prelease
# 切换到开发分支
git checkout fea/new
# 合并prelease的更新
git rebase prelease
# 推送到远端分支
git push -f origin fea/new

合并提交

为了方便他人阅读你的代码,也会要求开发人员将多次简短的提交,合并一个完整注释的提交,方便代码review。

举例,你会发现有这样的提交记录:

* 调试功能a x7 commitid7 author1 2019-06-15 17:00:07
* 调试功能a x6 commitid6 author1 2019-06-15 17:00:06
* 调试功能a x5 commitid5 author1 2019-06-15 17:00:07
* 调试功能a x4 commitid4 author1 2019-06-15 17:00:06
* 调试功能a x3 commitid3 author1 2019-06-15 17:00:07
* 调试功能a x2 commitid2 author1 2019-06-15 17:00:06
* 添加功能a    commitid1 author1 2019-06-15 17:00:07

你应该把这些提交合并到一起:

git checkout fea/new
git reset commitid1
git add .
git commit -m "+ 添加功能a,完成测试,参考下面的注释模板"
git push -f origin fea/new

Protected Branch

我们是会把prelease以及master进行保护,只有管理员、拥有代码审核权限的人员才会允许进行代码的推送。开发人员只允许推送自己的开发,测试分支。这样会避免prelease以及master主干分支的代码被不小心”污染”,也就是没有通过测试的代码提交到主干分支中。

注释模板

一个较好的开发习惯是提交详细的注释。详细的注释有几个好处:

  1. 提交更多的提交信息
  2. 方便快速浏览查找。
  3. 可以直接生成改动日志。

我常用的几个小技巧:

  1. 提交信息前添加固定字符代表增删改查,比如* 代表更新 + 代表添加 – 代表文件删除。
  2. 代码注释每行限制72个字符,方便过长被自动截断。
  3. 最后空出一个行,让上面的行作为标题,再下一行提供相关的链接和关键字。

一个简单的模板如下:

* 更新 写作 Git工作流程实践

整理自己在日常工作中实践下来,有效的的Git工作流程。

还有他人提供的常用提交模板,你也可以参考https://gist.github.com/jmaxhu/8e7fb69a7dcec1b9b953、

合并最新的代码

将自己的开发分支合并master更新的代码。这是一个很重要的操作。每天上班第一件事,就是拉取最新master分支的代码,采用rebase方式,合并自己开发分支的代码,保证自己的代码提交是线性的。这样在后续代码合并会显著的减少很多不必要的冲突合并时间。

总结

在这篇文章里,我分享自己在Git工作流程的一些尝试。定义工作流程不是目的,我认为最终目的是提升整体团队的工作效率以及避免经常遇到的”代码覆盖”问题,进而引起的”环境问题”。解决在日常工作可能会遇到的问题,才是我们最终目的。

每个团队的使用习惯,业务模式,可能都不相同。一种工作流程可能也无法满足所有人的需求,大家可以根据自己的习惯或者最适合当前团队的方法去尝试,去定义适合自身团队的工作流程。

Git工作流程实践

SVN迁移Git实践

前言

Git是我工作使用得最多的代码管理工具。从毕业到现在,一直在使用Git管理我的代码,使用Git的branch分支功能进行需求开发,尝试使用GitLab进行持续构建。关于Git与SVN的对比,你可以阅读这里的文章。大多数人,可能会认为SVN已经很好的满足我的工作需要,为什么还需要去迁移到Git呢?

为什么要迁移到Git

必备技能

Git 是最流行的版本管理工具,也是程序员的必备技能之一。未来可能SVN也会变为历史。学习Git后,你可以尝试在终端命令行操作Git。使用命令行的操作几乎可以完成大部分操作,极大的提升你的工作效率。除了代码对比之外,几乎不需要GUI工具了。

分支合并

SVN的分支合并是一个老生常谈的问题。使用Git里,你可以创建无数的分支,尝试自己各种创意的想法,把代码合并到master里,也不是一件很复杂的事情。但SVN不是的,尝试过Git后,再使用SVN时,每次合并都会让你感到无力,切换分支需要花费时间,合并分支需要时间。时间对工程师来讲,可能是开发撸代码中的最大成本。

团队协作

团队协作是Git的一大特色。我认为Git是间接让GitHub已经成为最大的程序员社区网站的原因之一。假设有一个推荐系统的源代码,如果你觉得其中的算法,无法满足自己的需求,手动git clone下来,尝试建立单独的分支,尝试自己的想法,通过无数的单元测试后,对自己最后的代码调整完毕,发起一个MR说明自己的改动原因,希望自己的提交尽快可以被Review。选择Git作为版本控制系统,就是选择一种新的团队协作方式。如果要使用SVN的话,我不知道要如何去实现分布式的代码提交体验,甚至无法想象SVN的协作流程可以有这么顺畅。

好了,说了这么多,那么如何将SVN迁移到Git呢?

如何将SVN迁移到Git

准备一份提交者列表

通常需要先整理svn的全部提交者的username和email,与git进行对应。

svn log --xml |\
grep '<author>' | sed 's#<author>##' | sed 's#</author>##' | sort -u |\
sed 's/.*/& = & <&@test.com>/' > authors.txt

上面的命令为了获取全部的作者的的用户名和邮箱地址,我们来分解下每一步操作的作用:

svn log –xml 以xml的格式输出对应的日志
grep ‘‘ 搜索author为关键字的行,避免获取到注释中有author的情况
sed ‘s###’ 搜索行的替换为空
sed ‘s#
##’ 搜索行的
替换为空
sort -u 去重排序
sed ‘s/.*/& = & &@test.com/’ 将每一行进行格式化
author => author = author author@test.com

SVN版本库

假设有这样的一个SVN的版本库:

# svn url
svn+ssh://svnuser@svn.xbc.me/your_svn/
# 目录结构
branches
tags
trunk

那么最简单的将SVN版本转为Git版本库的命令为:

git svn clone -s svn+ssh://svnuser@svn.test.com/your_svn --authors-file=authors.txt

这样将SVN的全部代码对应起来:trunk对应到master,branche以及tag都对应到Git版本库。

实际上,我们在迁移的过程中,可能遇到另外一类情况。假设有以下SVN的版本库:

# svn url
svn+ssh://svnuser@svn.test.com/your_svn/trunk/
# 目录结构
app
h5
pc

那么我们尝试将单一的版本库拆分为3个不同的版本库:

git svn clone svn+ssh://svnuser@svn.test.com/trunk/app --authors-file=authors.txt --no-metadata
git svn clone svn+ssh://svnuser@svn.test.com/trunk/h5 --authors-file=authors.txt --no-metadata
git svn clone svn+ssh://svnuser@svn.test.com/trunk/pc --authors-file=authors.txt --no-metadata

使用–no-metadata 会移除类似下面的svn id信息。

git-svn-id: https://my-project.googlecode.com/svn/trunk@94 4c93b258-373f-11de-
    be05-5f7a86268029

现在你可以添加远程分支,进行代码提交了。

git remote add origin git@git.test.com:my/app.git
git push origin master

同步SVN版本库的更新

在转为Git版本库后,可能会还有一段过渡期,也就是以SVN为主,待熟悉Git整体工作流程后才会切换到Git。那么这时,该如何同步SVN的更新到Git呢?

我会使用以下脚本进行代码的同步:

git checkout master
git svn fetch
git svn rebase 
git push origin master
git checkout -

主要的命令有2个:

git svn fetch 获取SVN版本库的更新提交

git svn rebase 将SVN的更新变基当前master代码分支,这样整体的代码提交就是线性的了。

最好把上面的做成定时任务去执行就好了,每10分钟执行一次。

*/10 * * * * bash git.up.sh

常见问题

svn: E220001: Item is not readable

出现这个问题,是由于svn log的命令参数错误导致的。

svn log ^/ --xml
改为
svn log --xml

Author: (no author) not defined in

出现这个错误,是因为在作者列表找不到该用户,需要手动添加该用户。

(no author) = no author <noauthor@test.com>

总结

将SVN转换为Git版本库,可能整体工作流程迁移中的一小步,更重要的整个工作流程是否支持Git版本库,项目的DevOps流程是否完善,比如持续集成,自动构建,代码检查,自动发布等。另外,我认为更重要的是学习并熟悉Git的开发协作流程,比如我经常使用到的GitLab Flow的变种。下一篇会尝试说明如何进行GitLab Flow的工作流程。

SVN迁移Git实践

Ubuntu常用配置指南

前言

Ubuntu是我非常喜欢的一款开源操作系统。自从在大学学习安装Ubuntu 8.04后,从此一发不可收拾,喜欢上了这个有着朋友圈图标的Linux发行版。工作多年,几乎都是在Linux/Unix 环境下工作。每次到了一个新环境都会遇到安装新系统的需求,基本上会把工作的电脑换成自己喜欢的Ubuntu系统。写这篇文章是为了记录自己经常会用到的配置。

系统安装

Ubuntu发行版每半年会发布一个新的版本,并且会为了系统取一个名字,大多数以动物的名称为代号。比如最新的18.04 长期支持版本的代号是Beaver,河狸是一种啮齿动物。你可以从官网下载到最新的镜像。建议安装选择Long Term Support的版本,比如18.04,有5年的支持周期,足够满足你的日常工作需求。下面是我的日常开发常用的配置。

常用配置

SSH

工作中经常会有登录跳板机的需求。但每次都需要输入密码的话,使用起来,不是很方便。我们需要想要一些办法来自动化这个过程。我们期望的是,只需要输入一次密码,后续直接登录,不用每次都需要输入密码。

下面通过ssh的config配置,自定义主机登录实现这个操作。

cat ~/.ssh/config
host m
    User matt
    Hostname ssh.domain.com
    Port 22
    ControlMaster auto
    ControlPath /tmp/%r@%h:%p
    ServerAliveInterval 30
    ServerAliveCountMax 60

这段配置通过ControlMaster来开启共享Session,主要应用在复用同一个网络连接的socket,而不需要每次建立新的连接。ControlPath为socket的唯一路径标识,尽量保持每一个主机是唯一的,这里我们是以%r 远程登录用户名+%h 远程主机名+%p 远程主机端口 保持唯一的。

实际应用场景是这样子的:开发或者运维通过跳板机或者堡垒机,作为跳板登录目标机器,执行相关的操作。每次跳板机都是重新输入密码的,并且通常情况下都是不支持ssh key登录的。采用上面方式,只需要第一次登录后,后续新建终端登录跳板机是不需要再次输入密码的。

那么正确的使用方式如下:

  1. 首先打开你的终端,新建2个标签页面
  2. 在第一个标签页面,输入ssh m
  3. 第一次会要求你输入密码,输入正确的密码登录。
  4. 然后在第二个标签页面,直接ssh m,这时候你就不需要输入密码了。
  5. 这样就达到了免输入密码的操作。

Git

设置常用的git配置,当前使用的用户以及常用命令别名等。

#配置用户名和邮箱
git config --global user.name "username"
git config --global user.email "email"

git config --global core.editor "vim"
git config --global core.filemode false
git config --global core.quotepath false
git config --global color.ui true

git config --global gui.spellingdictionary none

#alias 创建命令别名
git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.cp cherry-pick
git config --global alias.st status
git config --global alias.br branch
git config --global alias.r rebase
git config --global alias.ri rebase -i
git config --global alias.l '!git --no-pager log --graph --pretty=format:"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset" --abbrev-commit --date=relative'
git config --global alias.lg 'log --graph --pretty=format:"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset" --abbrev-commit --date=relative'

我觉得几个比较重要配置 :

core.editor vim

命令行经常使用的编辑器是vim

core.filemode false

不记录文件的属性变更

core.quotepath false

对中文名的文件或路径不进行转义

color.ui true

对git diff 进行颜色显示

gui.spellingdictionary none

不对提交进行拼写检查,主要用于解决Git GUI的错误提示”Spell checking is unavable”。

另外对一些常用的命令进行别名,这样就可以少输入几个字符了。

Sublime Text

我最喜欢的编辑器是Sublime Text 3,下面是我的日常工作设置:

{
  "default_line_ending": "unix",
  "draw_white_space": "all",
  "ensure_newline_at_eof_on_save": true,
  "font_face": "Ubuntu Mono",
  "font_size": 14,
  "rulers":[80],
  "show_encoding": true,
  "show_line_endings": true,
  "translate_tabs_to_spaces": true,
  "trim_trailing_white_space_on_save": true,
  "word_wrap": true
}

编辑器是日常工作用得最多的工具。

default_line_ending unix

设置默认为unix的回车符LF only。

draw_white_space all

显示所有不可见的字符

ensure_newline_at_eof_on_save true

保证每一个文件最后一行有一个空行

show_encoding true

显示文件的编码

translate_tabs_to_spaces true

转换tab键为空格

trim_trailing_white_space_on_save true

保存时删除行尾的空格

word_wrap true

自动换行

常用软件安装

#!/bin/bash
# Program:
#   从0开始,一键安装常用开发软件
# History:
# 2019-05-27 geekwho First release.
sudo apt install build-essential

sudo apt install curl zsh

sudo apt install vim

sudo apt install git
sudo apt install gitk
sudo apt install git-gui
sudo apt install git-svn

# svn
sudo apt install subversion

# php
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php
sudo apt install php-xml
sudo apt install php-mbstring
sudo apt install php-xdebug
sudo apt install php-curl

# php-cs-fixer
curl -L https://cs.symfony.com/download/php-cs-fixer-v2.phar -o php-cs-fixer
sudo chmod a+x php-cs-fixer
sudo mv php-cs-fixer /usr/local/bin/php-cs-fixer

# composer
wget https://raw.githubusercontent.com/composer/getcomposer.org/76a7060ccb93902cd7576b67264ad91c8a2700e2/web/installer -O - -q | php -- --quiet
sudo mv composer.phar /usr/local/bin/composer
sudo chmod +x /usr/local/bin/composer

sudo apt install gnome-tweak-tool

#typora
wget -qO - https://typora.io/linux/public-key.asc | sudo apt-key add -
sudo add-apt-repository 'deb https://typora.io/linux ./'
sudo apt-get update
sudo apt-get install typora

#sublime text
wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add -
sudo apt-get install apt-transport-https
echo "deb https://download.sublimetext.com/ apt/stable/" | sudo tee /etc/apt/sources.list.d/sublime-text.list
sudo apt-get update
sudo apt install sublime-text

总结

每次配置新的开发环境,通常是耗时较长的步骤。为此,我将日常开发的常用配置建立了一个单独版本库进行记录,避免自己下一次用到时花费更多时间去查找相关的信息。另外一方面,我把常用的软件安装SHELL命令,优化为一键安装的脚本,方便下次直接运行。这样,下次如果初始化环境的话,会帮助我节约部分时间,不过,有可能这个脚本很久都不会用到了,但提前做些准备总是好的。所谓,万事都是可以提前准备的。

Ubuntu常用配置指南