ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从零搭建Git+Repo+Gerrit代码评审服务器实战指南

从零搭建Git+Repo+Gerrit代码评审服务器实战指南

简介:这份资源面向需要自建代码评审与版本管理平台的开发者和运维人员,围绕 Git、Repo 与 Gerrit 三件套,讲解从零搭建完整代码服务器的配置流程,适合具备一定 Linux 基础、希望掌握企业级代码托管与评审环境搭建的中高级读者。资源包为单个 docx 文档,压缩后约 294KB,内容以步骤化配置说明为主,涵盖名词解释、必要软件安装、Gitosis 管理员创建与公钥配置、Repo 服务器搭建、Git 守护进程启停以及 Gerrit 代码评审配置等模块,目录结构清晰,便于按章节对照操作。目前已有 3136 人学习下载,读者可据此快速理解各组件之间的协作关系,掌握用户权限管理、manifest 仓库配置与评审服务部署的完整思路,为后续搭建团队协作开发环境提供可复用的参考方案。

1. 从零搭一套 Git + Repo + Gerrit 代码评审服务器:为什么值得折腾

如果你所在团队还在用共享目录或者 U 盘传代码,代码评审靠吼、权限靠自觉,那这套 Git + Repo + Gerrit 的组合值得认真搭一遍。它解决的核心问题就一个:把「谁能推、推到哪、推完谁审」变成服务器说了算,而不是靠人盯。Git 管版本,Repo 管多仓库批量同步,Gerrit 管代码评审和权限闸门,三者叠起来就是一套能落地的代码服务器。

这套方案适合谁?适合需要管理多个 Git 仓库、又想让每次提交都经过评审再入库的团队。尤其是做嵌入式、Android 类多模块项目的,Repo 的清单文件能让你一条命令拉齐十几个仓库,Gerrit 则保证没人能绕过评审直接改主干。下面按实际搭建顺序拆开讲,每一步都落到命令和参数上。

2. 基础环境与 Gitosis 权限层:先把 SSH 和用户体系立住

2.1 服务端与客户端的角色划分

搭建之前先把角色分清楚。服务器端(Server)是那台跑 Git 仓库、Gerrit 服务的机器,客户端(Client)是开发者日常敲命令的机器。两者之间靠 SSH 公钥认证打通,不依赖密码登录,这也是后面 Gerrit 能自动识别用户的前提。

服务端需要装的基础软件不多,一条命令能覆盖大半:

# 服务端安装 Git 核心、SSH 服务端与客户端 sudo apt-get install git-core openssh-server openssh-client

这里git-core是 Git 的主程序包,openssh-server让服务器能接受 SSH 连接,openssh-client则是服务器自己往外连时用的。三个都装上,避免后面 clone 时缺命令。

2.2 Gitosis 的安装与系统用户创建

Gitosis 是老牌但依然好用的 Git 权限管理工具,它通过一个gitosis-admin仓库来管理所有用户公钥和仓库权限。安装分两步,先克隆源码再装:

# 客户端拉取 gitosis 源码 mkdir ~/gitosis_setup cd ~/gitosis_setup git clone https://github.com/res0nat0r/gitosis.git cd gitosis # 服务端执行安装 sudo python setup.py install

如果python setup.py install报错,通常是缺python-setuptools,补一条sudo apt-get install python-setuptools再重试即可。这一步的坑在于 Python 版本,老版本 gitosis 对 Python 3 支持不好,建议在 Python 2 环境下装。

装完 gitosis 后,创建一个专用的系统用户来跑 Git 服务:

# 创建禁用密码的 git 系统用户,家目录 /home/git sudo adduser --system --shell /bin/sh --gecos 'git SCM user' \ --group --disabled-password --home /home/git git

参数逐个说:--system表示系统用户,--shell /bin/sh给它一个能执行脚本的 shell,--disabled-password禁止密码登录(只走密钥),--home /home/git指定家目录。这个git用户就是后面所有仓库的宿主。

2.3 管理员公钥生成与 gitosis-init

管理员不要用服务器上的普通用户,建议用团队负责人的账号来管权限。在管理员客户端生成密钥对:

# 管理员客户端生成 RSA 密钥 ssh-keygen -t rsa # 把公钥拷到服务器临时目录 scp ~/.ssh/id_rsa.pub user@192.168.1.252:/tmp/id_rsa_admin.pub

-t rsa指定密钥类型,一路回车即可。拷过去之后在服务端执行初始化:

# 服务端执行 gitosis 初始化,导入管理员公钥 sudo chmod 777 /tmp/id_rsa_admin.pub sudo -H -u git gitosis-init < /tmp/id_rsa_admin.pub # 修正 post-update 钩子权限,否则 push 会失败 sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update

sudo -H -u git是以 git 用户身份执行,-H让家目录环境变量正确。初始化完成后,/home/git/repositories/下会出现gitosis-admin.git,这就是权限管理仓库。那个chmod 755是血泪经验,少了它后面 push 配置会直接报权限拒绝。

2.4 克隆 gitosis-admin 并配置用户权限

管理员客户端把管理仓库拉下来:

mkdir -p ~/git && cd ~/git git clone git@192.168.1.252:gitosis-admin.git cd gitosis-admin

仓库里两个关键内容:gitosis.conf是权限配置文件,keydir/放所有成员公钥。要加人,就把对方id_rsa.pub拷进keydir/,再在gitosis.conf里写组和权限。典型配置长这样:

[group gitosis-admin] writable = gitosis-admin members = admin@client [group devteam] writable = project1 project2 members = admin@client alice@client

writable后面跟仓库名,members是「用户名@客户端标识」,这个标识来自公钥文件名。改完 commit 再 push,gitosis 会自动生效。注意公钥文件名必须和members里的用户名一致,否则认不出来。

3. Repo 多仓库管理:清单文件怎么配、git-daemon 怎么起

3.1 git-daemon-run 的安装与配置

Repo 要批量拉多个仓库,底层依赖git-daemon提供匿名或半匿名的 Git 协议访问。先装管理脚本:

sudo apt-get install git-daemon-run

然后编辑它的启动参数:

sudo vim /etc/sv/git-daemon/run

把最后一行改成带--export-all和--enable=receive-pack的形式:

exec 2>&1 exec chpst -ugitdaemon \ /usr/lib/git-core/git-daemon --verbose \ --export-all --enable=receive-pack \ --base-path=/home/git/repositories/

--export-all让所有仓库可被导出,--enable=receive-pack允许通过 git 协议推送,--base-path指定仓库根目录。改完重启服务:

sudo sv stop git-daemon sudo sv start git-daemon # 或者直接 sudo sv restart git-daemon

如果sv命令找不到,确认runit包已装,git-daemon-run依赖它。

3.2 下载并部署 repo 工具

Repo 本身是一个 Python 脚本,从官方仓库拉下来后把repo文件放到/usr/bin:

mkdir -p ~/gitCfg && cd ~/gitCfg git clone https://gerrit.googlesource.com/git-repo git-repo.git cd git-repo.git sudo cp repo /usr/bin/repo sudo chmod +x /usr/bin/repo

repo脚本负责解析清单文件、批量操作 Git 仓库。放到/usr/bin后全局可用。如果官方地址连不上,可以换镜像地址,但要注意镜像的版本可能滞后。

3.3 创建 manifest 清单仓库与 default.xml

Repo 的核心是清单仓库(manifest),里面一个default.xml定义了要管理哪些子仓库。先在服务端建裸仓库:

cd /home/git/repositories git init --bare manifest.git

然后在客户端克隆、写清单、推回去:

mkdir ~/repo && cd ~/repo git clone git@192.168.1.252:manifest.git cd manifest vim default.xml

default.xml内容示例,定义三个测试仓库:

<?xml version="1.0" encoding="UTF-8"?> <manifest> <remote name="origin" fetch="." /> <default remote="origin" revision="master" /> <project name="project1" path="project1" /> <project name="project2" path="project2" /> <project name="project3" path="project3" /> </manifest>

remote的fetch="."表示相对当前服务器,default里的revision是默认分支,每个project的name是仓库名、path是拉下来后的本地目录。写完提交推送:

git add default.xml git commit -m "Init default.xml" git push origin master

3.4 建立测试仓库并验证 repo sync

服务端把三个测试裸仓库建好,并放开权限:

cd /home/git/repositories git init --bare project1.git git init --bare project2.git git init --bare project3.git sudo chmod 777 -R project1.git project2.git project3.git

客户端验证:

mkdir ~/repotest && cd ~/repotest repo init -u git@192.168.1.252:manifest.git repo sync

repo init会在当前目录生成.repo,里面包含完整的 repo 工具和清单库;repo sync按default.xml把三个仓库全拉下来。跑完看到project1、project2、project3三个目录就说明通了。常见坑是repo init报清单仓库找不到,多半是 manifest 仓库路径或 SSH 权限没配对。

4. Gerrit 代码评审服务:Java 环境、反向代理与首个管理员

4.1 创建 gerrit 账户与 Java 环境

Gerrit 是 Java 写的,先建专用账户再配 JDK:

sudo adduser gerrit sudo passwd gerrit su gerrit sudo tar zxvf ./jdk-7u45-linux-i586.tar.gz -C /opt

解压后配环境变量,编辑~/.bashrc:

export JAVA_HOME=/opt/jdk1.7.0_45 export JRE_HOME=$JAVA_HOME/jre export CLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

JAVA_HOME指向 JDK 根目录,PATH里加上 bin 才能全局用java。改完source ~/.bashrc生效,用java -version确认。

4.2 初始化 Gerrit 站点

下载对应版本的 war 包后初始化:

java -jar gerrit-2.11.war init -d review_site

交互过程里几个关键选择:身份验证方式输入http,数据库默认 H2 即可,Behind reverse proxy选y。选 http 认证意味着 Gerrit 不自己管密码,交给 Apache 做 Basic Auth,这样账号体系和 Web 服务器统一。初始化完在review_site/etc/gerrit.config里能看到配置。

4.3 gerrit.config 关键参数

配置文件里几段需要按实际环境改:

[gerrit] basePath = git canonicalWebUrl = http://192.168.1.252:8081/ [database] type = h2 database = db/ReviewDB [auth] type = HTTP [sendemail] smtpServer = smtp.example.com smtpServerPort = 465 smtpEncryption = SSL smtpUser = notify@example.com smtpPass = yourpassword from = notify@example.com [container] user = gerrit javaHome = /opt/jdk1.7.0_45/jre [sshd] listenAddress = *:29418 [httpd] listenUrl = proxy-http://*:8081/

basePath是仓库存储目录,canonicalWebUrl是对外访问地址,auth.type = HTTP对应 Apache 认证,sshd.listenAddress是 SSH 端口(默认 29418),httpd.listenUrl用proxy-http表示走反向代理。邮件配置按自己 SMTP 填,不配的话注册通知发不出去。

4.4 Apache 反向代理与 htpasswd 认证

开启 Apache 的代理和重写模块:

cd /etc/apache2/mods-enabled sudo ln -s ../mods-available/proxy.load sudo ln -s ../mods-available/proxy_http.load sudo ln -s ../mods-available/rewrite.load

配置虚拟主机,把 8080 的请求转给 Gerrit 的 8081:

<VirtualHost *:8080> ServerName 192.168.1.252 ProxyRequests Off ProxyVia Off ProxyPreserveHost On AllowEncodedSlashes On RewriteEngine On RewriteRule ^/(.*) http://192.168.1.252:8081/$1 [NE,P] <Proxy *> Order deny,allow Allow from all </Proxy> <Location /login/> AuthType Basic AuthName "Gerrit Code Review" Require valid-user AuthBasicProvider file AuthUserFile /home/gerrit/review_site/etc/passwd </Location> ProxyPass / http://192.168.1.252:8081/ </VirtualHost>

ProxyPass把根路径转发,RewriteRule处理带斜杠的 URL,Location /login/段启用 Basic 认证。认证文件用htpasswd生成:

touch /home/gerrit/review_site/etc/passwd htpasswd -b /home/gerrit/review_site/etc/passwd admin admin

-b表示从命令行直接传密码,省去交互。第一个登录的用户会自动注册为 Gerrit 管理员(账号 ID 1000000)。这里有个容易翻车的点:如果 Gerrit 数据库里已经存在同名用户,htpasswd 建的账号不会和它关联,而是新建一个,导致权限错乱。所以务必保证先有 htpasswd 账号、再首次登录。

4.5 启动服务与首个管理员登录

./review_site/bin/gerrit.sh start sudo /etc/init.d/apache2 restart

浏览器访问http://192.168.1.252:8080/,用 admin 登录。登录后进 Settings 配全名和邮箱,再添加个人 SSH 公钥。测试 SSH 连通:

ssh -p 29418 admin@192.168.1.252

看到 Gerrit 的欢迎信息就说明 SSH 通道正常。之后创建项目:

ssh -p 29418 admin@192.168.1.252 gerrit create-project --empty-commit --name manifest ssh -p 29418 admin@192.168.1.252 gerrit create-project --empty-commit --name test

--empty-commit会建一个空初始提交,--name是项目名。建完在网页 Projects 列表和服务器git目录下都能看到对应仓库。

5. 避坑与排查:那些让你卡半天的权限和认证问题

5.1 push 到 gitosis-admin 报权限拒绝

现象:改完gitosis.conf执行git push提示permission denied。原因:post-update钩子没有执行权限,gitosis 无法处理推送。解决:sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update,再重新 push。

5.2 repo sync 拉不到仓库

现象:repo sync报某个 project 找不到或认证失败。原因:default.xml里remote的fetch路径不对,或者 git-daemon 没起、--export-all没加。解决:确认/etc/sv/git-daemon/run里参数完整,sv restart git-daemon重启,再检查清单里仓库名和实际裸仓库名是否一致。

5.3 Gerrit 登录后权限不对

现象:用 htpasswd 建的账号登录,却提示要手动输入用户名,且不是管理员。原因:Gerrit 数据库里已存在同名用户,htpasswd 账号被当成新用户关联。解决:首次搭建时确保数据库为空,先建 htpasswd 账号再登录;已经错乱的,清掉 H2 数据库重新初始化。

5.4 Apache 反代后页面 404 或样式丢失

现象:访问 8080 能打开但静态资源 404。原因:ProxyPreserveHost没开或RewriteRule的[NE,P]标志缺失。解决:确认虚拟主机里ProxyPreserveHost On、AllowEncodedSlashes On都配上,RewriteRule结尾带[NE,P]。

5.5 SSH 端口 29418 连不上

现象:ssh -p 29418超时。原因:防火墙没放行,或gerrit.config里sshd.listenAddress绑错地址。解决:检查listenAddress = *:29418,放行端口,确认 Gerrit 进程在跑。

6. 进阶:用 refs/for 走评审流与清单库联动

搭好之后真正要跑起来,关键是理解 Gerrit 的评审推送方式。普通git push origin master是直接入库,Gerrit 要求走refs/for/master:

git add default.xml git commit -m "add default.xml" git push origin HEAD:refs/for/master

HEAD:refs/for/master的意思是「把当前提交推到 master 分支的评审队列」,而不是直接合并。推上去后 Gerrit 网页会生成一条 Change,管理员审核通过后才真正进 master。这个机制是整套服务器的价值所在——没人能绕过评审。

清单库和 Gerrit 联动时,manifest 仓库本身也走 Gerrit 管理。客户端这样初始化:

repo init -u ssh://user@192.168.1.252:29418/manifest.git repo sync

repo init会在当前目录生成.repo,里面包含完整的 repo 工具和清单库;repo sync按清单把子仓库全拉下来。改清单同样走refs/for/master评审,保证清单变更也可追溯。

验证整套流程是否通,我一般按这个顺序走一遍:SSH 连 29418 通 →gerrit create-project建库成功 → 本地 clone 能推refs/for/master→ 网页能看到 Change → 审核合并后repo sync能拉到最新。任何一环断了,回到对应章节查配置。

从那以后我每次搭这套环境,都会先把post-update权限、git-daemon参数、htpasswd 与数据库顺序这三处强制过一遍,能省掉大半返工。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进