分享IT技术,分享生活感悟,热爱摄影,热爱航天。
开发中经常会因为一些低级失误提交了一些带有语法错误的代码,然而这些错误是很容易被检测出来的,例如使用php -l就可以分析代码中的语法错误,但如果要求开发者每次都手动执行语法检测命令,会非常麻烦同时也容易遗漏,我们可以使用Git提供的钩子脚本在代码提交时进行语法错误的检测。
最为简单常用的方法是使用Git的pre-commit钩子,在开发的代码库目录的.git/hooks目录下放置一个文件名为pre-commit的可执行脚本,只要使用了可执行的标记#!以及可执行权限,使用任何语言都可以。例如使用perl实现的脚步如下。
#!/usr/bin/perl use strict; my $commit_id = `git rev-parse --verify HEAD`; my $against = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"; if ($commit_id) { $against="HEAD"; } my @list = `git diff-index --cached --name-only $against --`; my $ret = 0; for my $x (@list) { chomp $x; if ($x =~ /\.php$/) { if (-f "$x") { `php -l $x`; if ($? != 0) { $ret = 1; goto end; } } } } end: exit($ret);然而使用pre-commit脚本存在一个很大的缺陷,钩子脚本需要放置在每个开发者的每个项目中,很容易遗漏,同时代码库重新clone后也需要记得重新放置钩子脚本,没有办法从根源上禁止有语法错误的代码的提交。
这时很容易想到的方法就是在中心代码库收到push时进行语法的检测,如果存在语法错误则拒绝当前的push,如此之需要维护好中心库就可以避免存在语法错误的代码被提交。Git在接受到push时会调用pre-receive钩子,如果pre-receive返回非0的返回值,则当前的push会被拒绝。在调用pre-receive脚本时,会从标准输入传递三个参数,分别为之前的版本,push的版本和push的分支。使用perl实现的脚本如下。
#!/usr/bin/perl use File::Temp; use strict; #从标准输入中读取参数信息 my $line = <>; #处理后得到旧版本,但前版本和分支 my @argv = split(/\s/, $line); my $old = $argv[0]; my $new = $argv[1]; my $branch = $argv[2]; #比较两个版本的差异 my @out = `git diff --name-status $old $new`; for my $x (@out) { my @param = split(/\s/, $x); #如果文件不是被删除且是php文件,则进行语法检测 if ($param[0] ne 'D' and $param[1] =~ /\.php$/) { #取出文件的内容,将其写入到一个临时文件中 my $content = `git show $new:$param[1]`; my $fh = File::Temp->new(SUFFIX => '.php', UNLINK => 1); print $fh $content; #进行语法检测 my $result = `php -l $fh 2>&1`; #如果出错则输出错误,输出时需要将临时文件名替换称为原来的文件名,并拒绝push if ($? != 0) { if ($result =~ s#$fh#$param[1]#g) { print $result; } exit(1); } } } exit(0);最后我们来测试一下pre-receive钩子的效果,我们故意制造一个语法错误
<?php echo1 "Hello\n";将其提交并push
git add hello.php git commit -m "make error" git pushGit会返回如下不错,并拒绝当前的push
Counting objects: 3, done. Writing objects: 100% (3/3), 265 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) remote: PHP Parse error: syntax error, unexpected '"Hello\n"' (T_CONSTANT_ENCAPSED_STRING) in hello.php on line 3 remote: Errors parsing hello.php To file:///home/longlong/my-test.git/ ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to 'file:///home/longlong/my-test.git/'如此就从根本上保证了存在语法错误的代码不会被提交到中心库,可以避免存在语法错误的代码不小心被推到线上环境。不过由于进行了语法检测push操作要比之前明显慢一些。
Gitlab是一个用Ruby on Rails实现的开源的并且基于Git的版本管理系统,基本上实现了一个类似于Github的相关功能——更够通过网页浏览代码,并控制代码库的访问修改权限,提交缺陷说明和代码注释,便于开发团队之间的协作。相比Phabricator,其更加注重的是对于代码库的管理。由于其是用Ruby on Rails实现,因此对于只熟悉PHP环境的人来说,安装和配置要显得复杂不少,这里简单记录一下,安装基于Archlinux。
一般开源的系统对于相关运行环境的版本都有较高的要求,Ruby要求至少要在1.9以上,如果使用Centos等软件版本较旧的Linux发行版,则需要从源代码编译Ruby或手段安装相关的软件包。安装完成后修改Ruby的gem源到淘宝的源,并安装bundler。
pacman -S ruby gem sources -r https://rubygems.org/ gem sources -a http://ruby.taobao.org/ gem install --no-user-install bundler
官方的下载地址为https://gitlab.com/gitlab-org/gitlab-ce,Github的下载地址为https://github.com/gitlabhq/gitlabhq,直接git clone即可。
pacman -S git git clone https://gitlab.com/gitlab-org/gitlab-ce.git gitlab git clone https://gitlab.com/gitlab-org/gitlab-shell.git完成后需要修改一下代码中的gem源,同样修改到淘宝,即将gitlab中Gemfile文件的第一行地址修改为http://ruby.taobao.org/,并安装相关的依赖软件包,完成后开始编译和安装gitlab依赖的相关gem
pacman -S gcc make patch cmake pkg-config pacman -S icu pacman -S mysql cd gitlab && bundle install --deployment --without development test postgres aws
首先需要为gitlab创建一个系统用户,如果在安装了git后自动创建了用户则需要修改其home目录,并将gitlab和gitlab-shell移动到其home目录下,并修改权限
useradd --system --create-home --comment 'GitLab' git mv gitlab /home/git/ mv gitlab-shell /home/git/ chown git:git -R /home/git/gitlab chown git:git -R /home/git/gitlab-shell cd /home/git cp gitlab-shell/config.yml.example gitlab-shell/config.yml sudo -u git gitlab-shell/bin/install如果redis使用TCP服务,则最后需要注释掉config.yml中redis项目中的socket行
redis: bin: /usr/bin/redis-cli host: 127.0.0.1 port: 6379 # pass: redispass # Allows you to specify the password for Redis database: 0 #socket: /var/run/redis/redis.sock # Comment out this line if you want to use TCP namespace: resque:gitlab
Gitlab需要MySQL、Redis、Nginx的支持才能够正常工作,以此还需要对这些服务进行安装和配置
pacman -S redis nginx mysql cp lib/support/nginx/gitlab /etc/nginx/并在nginx.conf的http段中增加
include gitlab;同时在gitlab文件的server段结尾增加,如果使用了域名还需要修改一下server_name
error_page 404 = @gitlab;
首先初始化一些配置文件
cp config/gitlab.yml.example config/gitlab.yml cp config/database.yml.mysql config/database.ym cp config/unicorn.rb.example config/unicorn.rb然后开始运行初始化,运行前需要启动mysql,并创建gitlab的数据库,同时还需要安装一个js引擎,这里使用nodejs
systemctl start mysqld mysql -u root -e "CREATE DATABASE IF NOT EXISTS gitlabhq_production DEFAULT CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci'" pacman -S nodejs sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
启动gitlab前需要先启动mysql、redis、nginx,启动脚本在lib/support/init.d/gitlab,复制一份并增加运行权限
systemctl start mysqld systemctl start redis systemctl start nginx cp lib/support/init.d/gitlab gitlab chmod +x gitlab #注意这里必须是绝对路径 /home/git/gitlab/gitlab start第一次运行时会比较慢一些需要耐心等待一下,默认的用户名和密码为admin@example.com/password
gitlab的Merge Request使用的是–no-ff方式的进行merge的,如果合并的分支的commit记录比较乱就会导致合并之后主分支的commit记录也比较混乱,如果想将其改为–squash的方式,需要修改gitlab源代码的一个文件gitlab/lib/gitlab/git/repository.rb,如下修改rugged_merge方法即可
options = { #parents: [our_commit, their_commit], parents: [our_commit], tree: merge_index.write_tree(rugged), message: message, author: committer, committer: committer }