ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Gerrit集成Gitweb完整指南:配置、联动与排错实战

Gerrit集成Gitweb完整指南:配置、联动与排错实战 最近团队内部的Gerrit服务器要做一次配置升级顺带把Gitweb集成进去。这个需求很常见Gerrit管代码审查很舒服但要看仓库整体历史、分支结构还是Gitweb效率更高。折腾了一下午把配置链路理清楚了也踩了几个不算坑的坑。这套思路适用于大多数自建代码托管环境的同学尤其是那些已经用Gerrit、又想白嫖Gitweb浏览能力的团队。先说结论Gerrit和Gitweb集成本质上就是两件事。一是让Gerrit知道你的Gitweb服务在哪二是让Gitweb能正确读到Gerrit管理的仓库目录。这两点只要有一处含糊出来的不是链接404就是页面压根不显示入口。下面从选型、配置、联动到排查一条条讲透。1. 为什么要在Gerrit里集成Gitweb1.1 代码审查和仓库浏览的互补Gerrit的核心是代码审查它的diff视图和inline comment做得确实好用但你要在Gerrit里看一条分支的演化轨迹、比对两个tag之间的全部提交、或者翻某个文件的老旧历史体验就比较难受。Gerrit的列表页偏重“变更”而不是“仓库”。Gitweb恰恰补上这一环它有summary、shortlog、log、commit、tree、blob、blame、tags、heads等一整套视图而且不需要额外插件Git源码里自带。实际工作中最常见的场景是评审一个改动时评审者想知道这个commit在主干上有哪些前置提交或者在回溯线上问题时需要快速切到某个tag对比历史。典型做法是打开Gerrit的change页面点一下旁边的Gitweb链接整个仓库的全貌就出来了。省去切换系统、重新登录、手动拼URL的麻烦。对于非研发角色如测试、运维Gitweb也特别友好大家不熟悉Gerrit的操作逻辑但Gitweb就是“点着看”的网页学习成本极低。1.2 两种接入模式选型cgi与urlGerrit集成Gitweb最核心的决策是选模式。gerrit.config里可以配置两类后端一类是cgi让Gerrit直接在自身Web容器里调用服务器上的gitweb.cgi另一类是urlGerrit只负责拼出外部Gitweb服务的链接点击后跳转。两者没有绝对好坏但适用场景差别很大。cgi模式的优点是不用额外维护一个Apache或nginx服务Gerrit自己包办了Gitweb的HTTP出口缺点也明显它依赖运行Gerrit的JVM进程外调Perl脚本对Perl模块、CGI环境、文件权限都很挑剔。我见过不少同事配完之后页面白屏最后发现是缺CGI.pm或者URI::Escape。如果只想在开发环境快速看一眼cgi能跑生产环境我还是更倾向url模式让Apache和Gitweb各司其职干净、稳定、好排查。url模式的缺点是你要先有一个外部Gitweb站点。不过现在公司内部一般都有现成的Gitweb或是cgit服务如果没有用Apache挂一个Gitweb也就十分钟的事。所以我的建议很简单只要是正式环境就用url模式实在不想搭站点再考虑cgi。文章后面也主要按url模式展开cgi模式会在调试章节单独讲。2. Gerrit侧配置Gitweb的完整步骤2.1 动手前先确认环境与配置文件任何配置改动前先确认Gerrit安装目录和配置文件位置。Gerrit站点目录是你初始化的时候用init指定的通常里面有个etc/gerrit.config。你可以在服务器上执行ls $GERRIT_SITE/etc/gerrit.config没有这个文件的话说明站点路径不对。如果你不确定站点目录用ps aux | grep gerrit看进程参数能找到-Dgerrit.site_path这类启动参数。接着检查Gerrit版本。不同版本的[gitweb]配置项有小差异但大方向一致。稳妥起见先备份配置文件cp $GERRIT_SITE/etc/gerrit.config $GERRIT_SITE/etc/gerrit.config.bak.$(date %Y%m%d)备份是好习惯尤其在生产环境。之后可以用git config --file直接读取当前配置确认还没有[gitweb]段落避免重复配置git config --file $GERRIT_SITE/etc/gerrit.config --list | grep -i gitweb2.2 修改gerrit.config中的[gitweb]段url模式的核心配置就三行。打开gerrit.config加入如下内容[gitweb] url http://git.example.com/gitweb type gitweb注意几点url写的是Gitweb站点的根地址末尾不要带斜杠Gerrit在拼链接时会在后面追加查询参数。以标准Gitweb为例Gerrit会生成类似http://git.example.com/gitweb/?pmyproject.git;acommit;habcdef的地址。type必须设为gitweb不然Gerrit不知道用哪种链接生成器。如果你的Gitweb是放在Apache的某个子路径下比如http://git.internal/cgi-bin/gitweb.cgi那url就写这个完整路径。我在实际配置里遇到过一种情况Gitweb的URL前缀末尾带了/Gerrit拼出来后变成了双斜杠Apache开启了压缩或重写之后直接404。所以写URL时一定要统一不带尾部斜杠。如果你实在想省掉外部Web服务也可以用cgi模式。配置如下[gitweb] cgi /usr/lib/cgi-bin/gitweb.cgi type gitweb这里cgi必须是服务器上真实存在的脚本路径。配置完后需要重启Gerrit并且保证Gerrit运行用户对该脚本有执行权限。cgi模式不推荐生产使用但开发机应急确实方便。2.3 重启Gerrit并验证生效修改配置后需要重启Gerrit才能让[gitweb]段生效。站点目录下一般有重启脚本$GERRIT_SITE/bin/gerrit.sh restart如果Gerrit是运行在容器或systemd里就按对应的方式重启。重启后先看启动日志有没有异常tail -f $GERRIT_SITE/logs/error_log然后随便找一个项目打开一个change页面找到commit信息区域。正常情况会出现Gitweb字样的链接点击后跳转到Gitweb的commit视图。我验证时习惯直接在浏览器里手工拼一个URL比如http://git.example.com/gitweb/?pmyproject.git;asummary手工能打开说明Gitweb本身没问题Gerrit页面能点出链接则说明解析和拼接都没问题。两条链路先分别验证再合起来排错会快很多。3. Gitweb侧的环境准备与联动细节3.1 用Apache把Gitweb服务架起来url模式的前提是有一个正常运行的Gitweb。这里把标准搭建流程走一遍以Debian/Ubuntu为例先装包apt-get update apt-get install -y apache2 gitwebDebian系的gitweb包会自动在Apache下注册/gitweb路径。如果安装后访问http://服务器IP/gitweb能看到目录列表或gitweb页面说明基础服务起来了。接着要调整gitweb.conf告诉Gitweb去哪里找仓库。这个文件通常在/etc/gitweb.conf内容类似$projectroot /data/gerrit/git; $git_dir_list []; $project_list []; $projects_max_depth 1;$projectroot必须指向Gerrit实际存放仓库的目录。如果Gerrit和Gitweb在同一台机器这个目录就是$GERRIT_SITE/git。如果不在同一台机器就要考虑NFS同步或用远程仓库的镜像但我会尽量避免这种部署排查权限问题太痛苦。修改完重启Apachesystemctl restart apache2之后在浏览器里访问http://git.example.com/gitweb能看到项目列表。如果列表是空的多半是$projectroot设错了或目录权限不对。3.2 仓库目录与权限设置这是集成里最容易被忽略的坑。Gerrit的仓库目录通常是站点目录/git里面每个项目是一个项目名.git文件夹。Gitweb默认会遍历$projectroot下所有符合规则的git目录来生成项目列表。如果你的Gerrit创建了新项目Gitweb列表会延迟出现或压根不出现先检查权限。Apache运行用户通常是www-dataGerrit运行用户一般是专有用户如gerrit。Gitweb要读取$projectroot下的目录和文件但未必需要写权限。正确的权限设置是chmod ox /data chmod ox /data/gerrit chmod ox /data/gerrit/git对git目录内部的objects、refs也要有读权限。如果你用了Git的updateServerInfo还需要info/refs可读。很多团队图省事直接chmod -R 777结果仓库裸奔被扫描风险极高别这么干。正确做法是把Gitweb运行用户加到一个组然后把git目录按组授权。补充一个细微点Gerrit仓库文件夹名是myproject.git但Gerrit的项目名是myproject。Gerrit拼接Gitweb链接时会负责把项目名转成带.git后缀的路径。如果你在Gitweb端设置了$strict_export或用了$project_list白名单请确保myproject.git在允许名单里否则Gerrit能跳过去Gitweb却拒绝显示。3.3 链接拼接参数与Gerrit端模板Gerrit的url模式并不是简单在root URL后面拼字符串。它内部有一套链接生成器针对type gitweb会采用默认的Gitweb查询格式比如 commit 视图生成.../gitweb/?p项目名.git;acommit;hcommitIddiff视图会转成acommitdiff;h...tag视图则转成atag;p...。我们在配置时不需要手动写查询模板。不过有些新版本Gerrit支持自定义模板可以在url里使用占位符例如[gitweb] url http://git.example.com/gitweb?p${project}.git;acommit;h${commit} type gitweb这个写法和默认生成效果类似但给了你更多控制权。要注意的是a参数必须和实际使用的Gitweb版本兼容。Gitweb这么多年核心参数没大改但有些老版本对hash参数的支持有差异。如果你发现点击链接后进入了Gitweb的首页而不是commit页面检查一下这个URL模板的a和h参数是否被Gitweb端接受。另外如果你想用一种更贴近现代代码托管平台的外观其实不一定要绑死Gitweb。Gerrit还支持cgit、Bitbucket等类型但那就偏离主题了。从运维角度讲Gitweb最省心因为它就是Git官方维护的Perl脚本没有复杂的Node或Ruby依赖。4. 实操中的常见问题与排查心得4.1 点击Gitweb链接总是跳404这个问题我遇到过不下三次。现象是Gerrit页面上的链接能点但点过去要么Apache默认页要么404。先别怀疑Gerrit第一步在浏览器里直接访问http://git.example.com/gitweb/?pmyproject.git;asummary看能不能打开项目摘要。手工能打开说明Gitweb服务正常问题出在Gerrit生成的链接和实际URL不一致。常见原因有三个一是gerrit.config里的url带了尾部斜杠拼接后出现双斜杠二是项目名大小写不一致Gerrit里叫MyProjectGitweb端路径大小写敏感三是Apache对查询字符串里的;做了拦截或重写导致acommit;h...被截断。如果手工也打不开大概率是Gitweb的$projectroot没有指向Gerrit仓库目录或者目录权限不够。这时候去查看Apache错误日志tail -f /var/log/apache2/error.log日志里能看到No such directory或Permission denied这类明确提示。按图索骥就能解决。4.2 页面上压根不出现Gitweb链接这种问题比404更隐蔽因为配置改了、Gerrit也重启了但change页面没有任何入口。先确认你是否有权限查看该项目。Gerrit的权限模型里如果某条ref对匿名用户不可读而登录用户也没有相关权限页面上的Gitweb链接会被隐去。说白了Gerrit不太愿意在评审页给一个大家都没权限的仓库暴露浏览入口。再检查gerrit.config有没有写对段落名。注意是[gitweb]不是[git-web]也不是[gitweb]写错大小写。Git的配置项一般是大小写敏感的Gitweb和gitweb会被视作两个不同段落。确认无误后重启。还有一个细节在老版本Gerrit里type不写也能启动但链接生成会走默认逻辑可能生成的是cgit样式导致跳转格式混乱。所以我建议无论如何都显式写type gitweb。同时检查canonicalWebUrl这是Gerrit生成自身页面URL的基础如果它没配好有些附属链接也会跟着错乱。4.3 CGI模式的白屏与Perl环境问题如果你坚持用cgi模式白屏是最大的痛点。Gerrit内部通过CGI协议调用外部的gitweb.cgi本质上是在Java容器里跑Perl环境依赖非常苛刻。遇到白屏先手工在命令行执行一次perl /usr/lib/cgi-bin/gitweb.cgi如果命令行报错比如Cant locate CGI.pm说明系统缺少Perl模块。Debian上可以装libcgi-pm-perl另外Gitweb还依赖libgit-wrapper-perl、libcgi-fast-perl等记得一起装上。如果命令行执行能输出HTML但Gerrit页面依然白屏检查Gerrit运行用户的PATH和环境变量。JVM里调用外部CGI时环境变量可能被清空导致Perl找不到模块。可以在gerrit.config中为cgi模块设置环境变量或者干脆在启动脚本里export完整的PATH。这个过程很折腾我现在一般直接建议同事用url模式。4.4 权限边界与安全提示Gitweb直连Gerrit仓库目录这意味着如果你不加保护所有能访问Gitweb的人都能浏览全部仓库。这在内部环境可能无所谓但如果Gerrit部分项目包含敏感代码你需要在Gitweb端做访问控制。最简单的做法是利用Apache的Require指令限制访问来源IP比如只允许办公网段访问/gitwebLocation /gitweb Require ip 10.0.0.0/8 /Location如果你需要更细粒度的项目级权限Gitweb本身不支持建议用cgit或自研前端甚至直接用Gerrit的REST API做一个网关。集成Gitweb本来是为了方便千万别因权限开放引入安全风险。5. 集成后的真实使用场景与经验建议5.1 日常开发与排查中的高频玩法配置好之后最大的收益反而不是每天点链接而是把Gitweb嵌入到工作流里。比如我可以从Gerrit的邮件通知里直接提取commit哈希然后在Gitweb里快速查看这个提交的完整patch比在Gerrit里翻diff更快预算。尤其是改动涉及几十个文件时Gitweb的侧边栏和文件跳转比Gerrit的diff视图顺手很多。另一个高频场景是分支和tag比对。Gerrit本身不擅长展示仓库级引用关系但Gitweb的shortlog和tags视图一目了然。我习惯在发版前打开Gitweb比较release/1.2和master之间的提交差异确认合入范围没有漏。这个动作用Gerrit做要写查询用Gitweb就是点两下的事。所以这套配置对团队的实际影响不是多了一个链接而是让“审查变更”和“理解仓库”解耦。Gerrit专注高强度的代码评审Gitweb专注低门槛的浏览和追溯各干各擅长的事。5.2 配置维护的避坑清单总结一下我自己的维护经验写成一份清单供参考修改gerrit.config之前一定备份用git config --file校验格式避免手工编辑时引入不可见字符。url模式时url结尾不要带斜杠cgi模式时确认Perl模块完整生产环境慎用。每次升级Gerrit版本后重新检查[gitweb]配置是否兼容个别大版本升级会改配置结构。Gitweb的$projectroot和Gerrit的仓库目录要严格一致用软链接容易引发遍历问题。权限遵循最小化原则不随意chmod -R 777让Apache通过辅助组权限读仓库目录。重启Gerrit后别急着完事用logs/error_log和Apache错误日志双端确认。最后再分享一个小技巧在Gerrit的change页面能看到Gitweb链接之后我在浏览器书签里把Gitweb地址存了一份但更多时候是直接在Gerrit页面点。集成这个事最烦的不是配置本身而是你根本不知道它有没有生效。用一个简单的shell脚本把gerrit.config里所有gitweb相关行、Gitweb站点响应码、仓库目录权限一起打出来几分钟就能定位问题。遇到配置出错记住“先分开验证再合起来看”大多数问题都能迎刃而解。
返回列表