一、参考资料
官方文档:Gerrit Code Review for Git
ubuntu 20.04LTS + gerrit + git + jenkins安装指南-CSDN博客
Ubuntu 20.04 + Gerrit 3.4.0 + nginx 1.18.0 安装配置指南 - OSCHINA - 中文开源技术交流社区
Gerrit - 代码评审工具Gerrit简介与安装 - Anliven - 博客园
二、Gerrit相关介绍
1. Gerrit简介
Gerrit 是建立在 git 版本控制系统之上的,基于 web 的代码审核工具。Gerrit 是免费的,开源的,有一个可视化界面可供用户操作。主要解决的问题是代码审核。他在传统的源码工具管理协作流程中强制性引入代码审核机制,通过人工代码审核和自动化代码验证的方式,不符合要求的代码屏蔽在代码库之外,确保核心代码多人校验、多人互备和自动化构建核验。
2. Gerrit 和 Git 区别
- Git 是一种版本控制系统;而 Gerrit 是一种基于 Web 的代码审查软件。
- Git 用于代码的存储和版本控制;Gerrit 用于团队间相互审阅彼此修改后的程序代码,决定是否能够提交,退回或者继续修改。
3. Gerrit 和 Gitlab 区别
- 开发风格
gitlab 的特点是一个人维系一个分支。
gerrit 的特点是一个团队维系一个分支。 - 权限管理
gitlab 可以根据需要创建 project,每个团队可以根据自己的需求管理自己的代码,方式更加的灵活。
gerrit 比较单一,而且权限配置比较复杂,往往都是要联系管理员做出修改,每个团队很难做到对代码的个性化管理。 - 代码评审
gitlab 是以 merge request 作为一次 review,merge request 中可能包含多个 commit,如果 review 不通过也不需要发起另一次 merge request。
gerrit 是以 commit 作为一次 review,由于 changeId 的存在,可以对一次commit反复的进行review。 如果task划分的粒度够细的话,并不会影响各个团队的review习惯。 - 团队协作
gitlab 可以选择公开代码,团队间可以看到互相的代码,有利于团队的协作。
gerrit 由于权限控制问题,只能在权限范围内公开代码。 - 信息共享
gitlab 可以提供 issues,wiki 等功能方便开发者与使用者之间的沟通,并且 gitlab 可以无缝的与一些项目管理工具集成,比如:jira。
gerrit 这个方面比较欠缺。
4. Gerrit工作流程
【Gerrit】Gerrit工作流程及使用手册-CSDN博客
Gerrit工作流程及使用手册-CSDN博客
如果你使用过 git,当我们 git add --> git commit --> git push
之后,你的代码会被直接提交到 repo,也就是代码仓库中。
Gerrit 的工作流程:
- 程序员编写代码。
- push 到 gerrit 服务器。
- 审核人员,在 web 页面进行代码的审核 (review),(可以单人审核,也可以邀请其他成员一同审核)。
- 审核通过 (approve) 之后。
- 提交(submit)到代码仓库(repo)中去。
在使用过程中,有两点需要特别注意下:
- 当进行 commit 时,必须要生成一个 Change-Id,否则,push 到 gerrit 服务器时,会收到一个错误提醒。
- 提交者不能直接把代码推到远程的 master 主线(或者其他远程分支)上去。这样就相当于越过了 gerrit了。 gerrit 必须依赖于一个
refs/for/*
的分支。假如我们远程只有一个 master 主线,那么只有当你的代码被提交到refs/for/master
分支时,gerrit 才会知道,我收到了一个需要审核的代码推送,需要通知审核员来审核代码了。
三、安装Gerrit
Quickstart for Installing Gerrit on Linux
1. 安装Java
sudo apt-get update
sudo apt-get install openjdk-11-jdk
java -version
输出示例:
yoyo@yoyo:~/Downloads$ java -version
openjdk version "11.0.27" 2025-04-15
OpenJDK Runtime Environment (build 11.0.27+6-post-Ubuntu-0ubuntu120.04)
OpenJDK 64-Bit Server VM (build 11.0.27+6-post-Ubuntu-0ubuntu120.04, mixed mode, sharing)
2. 安装Git
sudo apt install git
3. 安装Nginx
Gerrit要求不能直接请求其端口,必须要使用反向代理才能正确登录。而我们知道Nginx的成功正在于其高效、轻量级以及 反向代理 ,虽然Apache也有反向代理的功能,但是如果你在安装Apache时没有开启,后续的开启过程要相对复杂一点,而Nginx就简单的多了。
sudo apt-get update
sudo apt-get install nginx
卸载Nginx:
sudo apt-get remove nginx nginx-common # 卸载删除除了配置文件以外的所有文件。
sudo apt-get purge nginx nginx-common # 卸载所有东东,包括删除配置文件。
sudo apt-get autoremove # 在上面命令结束后执行,主要是卸载删除Nginx的不再被使用的依赖包。
sudo apt-get remove nginx-full nginx-common #卸载删除两个主要的包。
4. 下载Gerrit
下载链接:https://www.gerritcodereview.com/#download,官网直接下载最新版本(不推荐)。
也可以使用wget工具命令行下载 Gerrit Code Review - Releases:
sudo wget https://gerrit-releases.storage.googleapis.com/gerrit-3.12.0.war
5. 解压Gerrti
cd ${GERRIT_SITE}
sudo unzip gerrit-3.12.0.war -d ${GERRIT_SITE}
6. 创建Gerrit目录
export GERRIT_SITE=~/gerrit_site
sudo mkdir ${GERRIT_SITE} # 创建一个目录,准备安装gerrit
sudo chown -R $USER:$USER ${GERRIT_SITE}
7. 安装Gerrit
java -jar ~/Downloads/gerrit-3.12.0.war init -d ${GERRIT_SITE}
安装过程中,选择HTTP认证模式:
Authentication method [openid/?]: HTTP
Get username from custom HTTP header [y/N]? y
安装过程中,设置 ip/port
:
Listen on address [*]:
Listen on port [8081]:
Canonical URL [http://ubuntu/]: http://localhost:8081
安装插件(推荐):
*** Plugins
***
Installing plugins.
Install plugin codemirror-editor version v3.8.10 [y/N]? y
Installed codemirror-editor v3.8.10
Install plugin commit-message-length-validator version v3.8.10 [y/N]? y
Installed commit-message-length-validator v3.8.10
Install plugin delete-project version v3.8.10 [y/N]? y
Installed delete-project v3.8.10
Install plugin download-commands version v3.8.10 [y/N]? y
Installed download-commands v3.8.10
Install plugin gitiles version v3.8.10 [y/N]? y
Installed gitiles v3.8.10
Install plugin hooks version v3.8.10 [y/N]? y
Installed hooks v3.8.10
Install plugin plugin-manager version v3.8.10 [y/N]? y
Installed plugin-manager v3.8.10
Install plugin replication version v3.8.10 [y/N]? y
Installed replication v3.8.10
Install plugin reviewnotes version v3.8.10 [y/N]? y
Installed reviewnotes v3.8.10
Install plugin singleusergroup version v3.8.10 [y/N]? y
Installed singleusergroup v3.8.10
Install plugin webhooks version v3.8.10 [y/N]? y
Installed webhooks v3.8.10
Initializing plugins.
后续可以通过配置文件($GERRIT_SITE/etc/gerrit.config
)来更新配置。
输出示例:
yoyo@yoyo:~$ java -jar ~/Downloads/gerrit-3.8.10.war init -d ${GERRIT_SITE}
Using secure store: com.google.gerrit.server.securestore.DefaultSecureStore
[2025-06-30 02:45:09,709] [main] INFO com.google.gerrit.server.config.GerritServerConfigProvider : No ~/gerrit_site/etc/gerrit.config; assuming defaults
*** Gerrit Code Review 3.8.10
***
Create '~/gerrit_site' [Y/n]? Y
*** Git Repositories
***
Location of Git repositories [git]: git
*** JGit Configuration
***
Auto-configured "receive.autogc = false" to disable auto-gc after git-receive-pack.
*** Index
***
Type [lucene]:
*** User Authentication
***
Authentication method [openid/?]: HTTP
Get username from custom HTTP header [y/N]? y
Username HTTP header [SM_USER]:
SSO logout URL :
Enable signed push support [y/N]?
Use case insensitive usernames [Y/n]?
*** Review Labels
***
Install Verified label [y/N]? y
*** Email Delivery
***
SMTP server hostname [localhost]:
SMTP server port [(default)]:
SMTP encryption [none/?]:
SMTP username :
*** Container Process
***
Run as [yoyo]:
Java runtime [/usr/lib/jvm/java-11-openjdk-amd64]:
Copy gerrit-3.8.10.war to ~/gerrit_site/bin/gerrit.war [Y/n]?
Copying gerrit-3.8.10.war to ~/gerrit_site/bin/gerrit.war
*** SSH Daemon
***
Listen on address [*]:
Listen on port [29418]:
Generating SSH host key ... rsa... ed25519... ecdsa 256... ecdsa 384... ecdsa 521... done
*** HTTP Daemon
***
Behind reverse proxy [y/N]? y
Proxy uses SSL (https://) [y/N]?
Subdirectory on proxy server [/]:
Listen on address [*]:
Listen on port [8081]:
Canonical URL [http://ubuntu/]: http://localhost:8081
*** Cache
***
*** Plugins
***
Installing plugins.
Install plugin codemirror-editor version v3.8.10 [y/N]? y
Installed codemirror-editor v3.8.10
Install plugin commit-message-length-validator version v3.8.10 [y/N]? y
Installed commit-message-length-validator v3.8.10
Install plugin delete-project version v3.8.10 [y/N]? y
Installed delete-project v3.8.10
Install plugin download-commands version v3.8.10 [y/N]? y
Installed download-commands v3.8.10
Install plugin gitiles version v3.8.10 [y/N]? y
Installed gitiles v3.8.10
Install plugin hooks version v3.8.10 [y/N]? y
Installed hooks v3.8.10
Install plugin plugin-manager version v3.8.10 [y/N]? y
Installed plugin-manager v3.8.10
Install plugin replication version v3.8.10 [y/N]? y
Installed replication v3.8.10
Install plugin reviewnotes version v3.8.10 [y/N]? y
Installed reviewnotes v3.8.10
Install plugin singleusergroup version v3.8.10 [y/N]? y
Installed singleusergroup v3.8.10
Install plugin webhooks version v3.8.10 [y/N]? y
Installed webhooks v3.8.10
Initializing plugins.
============================================================================
Welcome to the Gerrit community
Find more information on the homepage: https://www.gerritcodereview.com
Discuss Gerrit on the mailing list: https://groups.google.com/g/repo-discuss
============================================================================
Initialized ~/gerrit_site
Init complete, reindexing accounts,changes,groups,projects with: reindex --site-path ~/gerrit_site --threads 1 --index accounts --index changes --index groups --index projectsReindexed 0 documents in accounts index in 0.0s (0.0/s)
Index accounts in version 12 is ready
Reindexing groups: 100% (2/2)
Reindexed 2 documents in groups index in 0.2s (8.7/s)
Index groups in version 9 is ready
Reindexing changes: Slicing projects: 100% (2/2), done
Reindexed 0 documents in changes index in 0.0s (0.0/s)
Index changes in version 82 is ready
Reindexing projects: 100% (2/2)
Reindexed 2 documents in projects index in 0.1s (23.5/s)
Index projects in version 5 is ready
Executing ~/gerrit_site/bin/gerrit.sh start
Starting Gerrit Code Review: WARNING: Could not adjust Gerrit's process for the kernel's out-of-memory killer.
This may be caused by ~/gerrit_site/bin/gerrit.sh not being run as root.
Consider changing the OOM score adjustment manually for Gerrit's PID=77690 with e.g.:
echo '-1000' | sudo tee /proc/77690/oom_score_adj
OK
Waiting for server on ubuntu:80 ... OK
Please open the following URL in the browser: http://ubuntu/#/admin/projects/
8. 修改gerrit.sh
sudo vi ${GERRIT_SITE}/bin/gerrit.sh
添加一行:
GERRIT_SITE=~/gerrit_site
9. 修改gerrit.config
主配置文件$GERRIT_SITE/etc/gerrit.config
- Gerrit Server监听 8081端口
- 认证方式为 HTTP
8081
是默认的Gerrit Web端口。29418
是默认的Gerrit SSH端口。
完整配置:
[gerrit]
basePath = git
canonicalWebUrl = http://localhost:8081/
serverId = a6bdcde1-f741-4c7e-86fe-a62cf6ae4c23
[container]
javaOptions = "-Dflogger.backend_factory=com.google.common.flogger.backend.log4j.Log4jBackendFactory#getInstance"
javaOptions = "-Dflogger.logging_context=com.google.gerrit.server.logging.LoggingContext#getInstance"
user = root
javaHome = /usr/lib/jvm/java-11-openjdk-amd64
[index]
type = lucene
[auth]
type = HTTP
# 如果使用的是标准HTTP认证
# 可能不需要指定httpHeader,但如果需要可以尝试以下选项之一:
#httpHeader = Authorization
#httpHeader = REMOTE_USER
#httpHeader = SM_USER
#userNameCaseInsensitive = true
[receive]
enableSignedPush = false
[sendemail]
smtpServer = localhost
[sshd]
listenAddress = *:29418
[httpd]
listenUrl = proxy-http://*:8081/
[cache]
directory = cache
10. 设置Nginx反向代理
添加关于gerrit的配置:/etc/nginx/conf.d/gerrit.conf
。
添加以下内容:
server {
listen *:8088;
server_name localhost;
allow all;
deny all;
location / {
auth_basic "Welcome to Gerrit Code Review Site!";
auth_basic_user_file ~/gerrit_site/etc/gerrit.password;
proxy_pass http://localhost:8081/;
#proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $remote_addr;
#proxy_set_header X-Forwarded-Proto $scheme;
#proxy_set_header SM_USER $remote_user;
#proxy_set_header Host $host;
# 明确将REMOTE_USER设置为认证用户名
#proxy_set_header REMOTE_USER $remote_user;
# 同时传递多种认证头格式
#proxy_set_header Authorization $http_authorization;
#proxy_pass_header Authorization; # 明确传递Authorization头
# 设置其他常用头部
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header SM_USER $remote_user;
proxy_set_header X-Forwarded-User $remote_user;
# 确保原始请求头不被修改
proxy_pass_request_headers on;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
}
解释说明:
listen
:Nginx代理服务器监听的端口。auth_basic
:用于登录时弹出验证对话框所显示的内容。auth_basic_user_file
:HTTP验证用户名和密码是否匹配的文件,请参考后文【注册用户认证】。location
部分:表示当用户访问8088端口时,Nginx直接将此请求代理到8081端口上,也就是”反向代理“。8081
是默认的Gerrit Web端口。8088
是Nginx反向代理端口,也即浏览器访问的端口。
11. 启动Gerrit
# 启动
sudo ${GERRIT_SITE}/bin/gerrit.sh start
# 停止
sudo ${GERRIT_SITE}/bin/gerrit.sh stop
# 重启
sudo ${GERRIT_SITE}/bin/gerrit.sh restart
# 查看Gerrit状态
sudo netstat -ltpn | grep -i gerrit
查看Gerrit状态:
yoyo@yoyo:~/gerrit_site/logs$ sudo netstat -ltpn | grep -i gerrit
[sudo] password for yoyo:
Sorry, try again.
[sudo] password for yoyo:
tcp6 0 0 :::29418 :::* LISTEN 105670/GerritCodeRe
tcp6 0 0 :::8081 :::* LISTEN 105670/GerritCodeRe
12. 启动Nginx
# nginx服务相关的指令
ps aux | grep nginx # 查看nginx进程
service nginx start # 启动Nginx服务
service nginx stop # 停止Nginx服务
service nginx restart # 重启Nginx服务
service nginx status # 查看Nginx服务的状态
# 或者执行
sudo systemctl start nginx.service
sudo systemctl stop nginx.service
sudo systemctl restart nginx.service
sudo systemctl status nginx.service
# 也可以到nginx目录下直接操作
sudo /etc/init.d/nginx start # 启动
sudo /etc/init.d/nginx stop # 关闭
sudo /etc/init.d/nginx restart # 重启
sudo /etc/init.d/nginx status # 查看状态
service nginx reload # 在Nginx服务启动的状态下,热加载gerrit.conf配置文件
启动之后可以使用工具查看一下自己配置的端口有没有正常工作: sudo netstat -ltpn
。
ps $(fuser 8088/tcp)
这个工具可以直接查看有没有占据这个端口的进程
13. htpasswd注册用户认证
一文搞懂 htpasswd
:基础身份验证的密码管理工具-CSDN博客
我们需要用apach的 htpasswd
工具来新建这个文件,虽然我使用了nginx代替apache做反向代理,但仍然需要apache。
安装 apache htpasswd
:
sudo apt-get install apache2-utils
创建用户:第一个注册的用户默认成了管理员,所以Gerrit安装完毕第一件事要做的就是注册或者登陆,以便初始化管理员账户。
# 创建第一个用户admin,同时会生成一个gerrit.password文件
htpasswd -c ${GERRIT_SITE}/etc/gerrit.password admin
# 在gerrit.password增加用户用 -m
htpasswd -m ${GERRIT_SITE}/etc/gerrit.password master
# 在gerrit.password增加用户用 -m
htpasswd -m ${GERRIT_SITE}/etc/gerrit.password reviewer
输出示例:
yoyo@yoyo:~/gerrit_site/bin$ htpasswd -c ${GERRIT_SITE}/etc/gerrit.password admin
New password:
Re-type new password:
Adding password for user admin
yoyo@yoyo:~/gerrit_site/bin$ htpasswd -m ${GERRIT_SITE}/etc/gerrit.password master
New password:
Re-type new password:
Adding password for user master
14. 登录Gerrit
Basic HTTP认证模式不支持
Sign Out
。
需要先Sign Out
退出账号,关闭浏览器后再登录,才能出现HTTP验证密码对话框。
输入下面链接,就可以登录到gerrit页面。
http://localhost:8088
四、FAQ
Q:java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 55.0
yoyo@yoyo:~$ java -jar ~/Downloads/gerrit-3.12.0.war init -d ${GERRIT_SITE}
Error: LinkageError occurred while loading main class Main
java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 55.0
错误原因:java版本与Gerrrit版本不兼容,导致Gerrrit安装失败。
解决方法:安装低版本的Gerrit。
Q: The HTTP server did not provide the username in the Authorization header when it forwarded the request to Gerrit Code Review.
错误原因:Gerrit采用HTTP认证,如果未安装Nginx代理服务器,则无法访问Gerrit服务。
解决方法:安装Nginx代理服务器。
Q:Starting Gerrit Code Review: start-stop-daemon: matching only on non-root pidfile ~/gerrit_site/logs/gerrit.pid is insecure
yoyo@yoyo:~/gerrit_site/etc$ sudo ${GERRIT_SITE}/bin/gerrit.sh start
Starting Gerrit Code Review: start-stop-daemon: matching only on non-root pidfile ~/gerrit_site/logs/gerrit.pid is insecure
查看日志:
[2025-06-30T03:39:47.846-07:00] [main] ERROR com.google.gerrit.pgm.Daemon : Unable to start daemon
com.google.inject.ProvisionException: Unable to provision, see the following errors:
1) [Guice/ErrorInjectingConstructor]: LockObtainFailedException: Lock held by another program: ~/gerrit_site/index/changes_0082/open/write.lock
at LuceneChangeIndex.<init>(LuceneChangeIndex.java:139)
while locating ChangeIndex annotated with @UniqueAnnotations$Internal(value=7)
解决方法:
(1)关闭Gerrit:
sudo ${GERRIT_SITE}/bin/gerrit.sh stop
(2)杀死Gerrit进程:
ps aux | grep gerrit
kill -9 <PID>
(3)重启Gerrit:
yoyo@yoyo:~/gerrit_site/bin$ sudo ./gerrit.sh restart
Stopping Gerrit Code Review: No process in pidfile '~/gerrit_site/logs/gerrit.pid' found running; none killed.
OK
Starting Gerrit Code Review: OK
Q:无法Sign out
错误原因:用gerrit+HTTP认证,通过web登陆后,点击右上角的 Sign Out
无法登出。要么是依然保持登陆的状态,要么就是直接出错,这是正常的。
解决方法:
(1)直接关闭浏览器,重新登录。
(2)如果你的浏览器保存了账号密码,需要清除缓存,再重新登录。
Q:error: failed to push some refs to
yoyo@yoyo:~/share/driver/hello_world$ git push ssh://admin@localhost:29418/hello_world *:*
Enumerating objects: 1525, done.
Counting objects: 100% (1525/1525), done.
Delta compression using up to 8 threads
Compressing objects: 100% (1365/1365), done.
Writing objects: 100% (1525/1525), 216.40 MiB | 6.95 MiB/s, done.
Total 1525 (delta 298), reused 0 (delta 0)
remote: Resolving deltas: 100% (298/298)
remote: error: branch refs/heads/master:
remote: You need 'Create' rights to create new references.
remote: User: admin
remote: Contact an administrator to fix the permissions
remote: Processing changes: refs: 1, done
To ssh://localhost:29418/hello_world
! [rejected] dev -> dev (fetch first)
! [remote rejected] master -> master (prohibited by Gerrit: not permitted: create)
error: failed to push some refs to 'ssh://admin@localhost:29418/hello_world'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.