Git+Repo+Gerrit代码评审服务器搭建实战:多仓库协作与权限管理
简介本资源是一份面向运维工程师、后端开发及代码管理初学者的代码评审服务器搭建文档围绕 Git、Repo 与 Gerrit 三大工具讲解如何从零构建一套功能完整的代码服务器解决团队代码托管、多仓库统一管理与代码评审流程落地的问题。资源包内含1个docx文档约294KB以图文步骤形式组织涵盖名词解释、必要软件安装、Gitosis 管理员创建与公钥配置、Repo 服务器搭建、Git 守护进程启动以及 Gerrit 评审环境配置等模块并附有大量可直接复用的命令与配置文件示例。目前已有3136人学习下载适合希望快速搭建内部代码托管与评审平台、对照实操并排查配置问题的读者参考。1. 从一台裸机到可评审的 Git 服务gitrepogerrit 到底在搭什么很多团队第一次听到「gitrepogerrit 代码服务器搭建」脑子里浮现的是三套互不相干的东西Git 是版本控制repo 是谷歌那套多仓库管理脚本Gerrit 是带代码评审的 Web 服务。真正落地时你会发现它们是一条流水线上的三个环节——Git 负责存储对象repo 负责把几十个仓库按清单一次性拉齐Gerrit 负责在 push 和 merge 之间插一道评审闸门。少了任何一环多仓库协作就会退化成手工 clone 的体力活。这套组合最适合的场景是项目被拆成多个独立仓库比如一个主工程加若干公共库需要统一版本基线同时要求每次提交都经过 Code Review 才能入库。它不适合单人小项目也不适合已经重度依赖某托管平台的团队。下面按「先跑通、再调参、最后避坑」的顺序把一台干净服务器变成可用的评审服务。2. 环境准备与 Gerrit 初始化把服务先立起来2.1 选型理由为什么用 Gerrit 而不是裸 Git裸 Git 服务器git init --bare 加 SSH只能解决「代码放哪」解决不了「谁改了什么、谁批准了」。Gerrit 在 Git 之上加了一层 refs/changes 引用空间每次 push 到 refs/for/分支 的提交不会直接进分支而是生成一个 Change 等待评审。评审通过后再由 Gerrit 合入目标分支。这个机制是多仓库协作里最省心的权限与审计方案。选 Gerrit 还要接受它的代价它自带一套账户体系、SSH 端口、Web 端口初始化时如果端口和系统已有服务冲突后面会反复翻车。所以第一步不是装 Gerrit而是把端口和目录规划清楚。2.2 依赖安装与专用账户Gerrit 是 Java 服务需要 JDK 和 Git。生产环境建议用独立系统账户运行避免权限混乱。# 以 root 执行安装基础依赖 apt-get update apt-get install -y openjdk-17-jre-headless git gitweb # 创建专用账户禁止登录 shell adduser --system --group --home /home/gerrit --shell /bin/bash gerrit # 准备三个目录安装目录、站点目录、Git 仓库根目录 mkdir -p /opt/gerrit /var/gerrit/site /var/gerrit/git chown -R gerrit:gerrit /opt/gerrit /var/gerrit逻辑说明JDK 版本要和 Gerrit 版本匹配常见做法是 Gerrit 3.x 配 JDK 11 或 17装之前先确认版本对应关系别装完才发现启动报 UnsupportedClassVersionError。专用账户用--system创建没有密码、不能交互登录降低被误操作的风险。三个目录分开是为了升级时只替换/opt/gerrit下的 war 包站点配置和仓库数据原地保留。参数说明--home指定家目录Gerrit 默认会在这里找.ssh授权文件--shell /bin/bash是为了后续能用su - gerrit进去执行初始化如果设成/usr/sbin/nologin就没法切换了。2.3 初始化站点与关键参数下载 Gerrit war 包后用init子命令生成站点。这一步会交互式问一堆问题提前想好答案能少走弯路。su - gerrit cd /var/gerrit/site # 初始化-d 表示使用默认值后续再改配置文件 java -jar /opt/gerrit/gerrit.war init -d # 初始化完成后检查关键配置 grep -E listenUrl|httpd|database|auth /var/gerrit/site/etc/gerrit.config逻辑说明init -d会生成etc/gerrit.config、etc/secure.config和 Git 仓库目录。默认数据库是 H2小团队够用认证默认是 OPENID_SSO内网环境通常要改成 HTTP 或 LDAP。初始化时如果提示下载插件失败多半是网络问题可以跳过后面手动放插件。参数说明listenUrl决定 Web 和 SSH 监听地址格式如proxy-http://*:8080/database段里type可选 h2、postgresql、mysql超过二十人建议换 PostgreSQLauth.type改成HTTP后要配合反向代理传REMOTE_USER头。2.4 启动与首次验证# 前台启动方便看日志 /var/gerrit/site/bin/gerrit.sh run # 另开终端验证端口 ss -lntp | grep -E 8080|29418逻辑说明gerrit.sh run前台运行日志直接打到终端排错时比start好用。29418 是默认 SSH 评审端口8080 是 Web 端口。两个端口都监听成功说明服务起来了。首次访问 Web 会用第一个登录账户作为管理员所以别急着把地址发给全组先自己登一次。3. repo 工具接入让多仓库按清单一次拉齐3.1 repo 是什么为什么 Gerrit 场景离不开它repo 本身不是 Git 的替代品它是一层 Python 封装读一个manifest.xml清单把清单里列出的几十个 Git 仓库批量 clone 到本地并统一管理分支切换。Gerrit 管的是单个仓库的评审repo 管的是「这一堆仓库在某个版本上应该是什么状态」。两者配合才能让一个多仓库项目有统一的版本基线。常见做法是在 Gerrit 上单独建一个 manifest 仓库里面放default.xml记录每个子仓库的远程地址和默认 revision。开发者只需repo init加repo sync就能拿到完整工程。3.2 安装 repo 客户端# 下载 repo 启动器到用户 bin 目录 mkdir -p ~/bin curl -o ~/bin/repo https://storage.example.com/git-repo/repo chmod ax ~/bin/repo # 加入 PATH echo export PATH$PATH:$HOME/bin ~/.bashrc source ~/.bashrc # 验证 repo --version逻辑说明repo 是一个可执行的 Python 脚本放在 PATH 里就能全局调用。下载地址按团队实际镜像替换不要照抄示例域名。repo --version能打印版本号说明脚本可执行、Python 环境正常。参数说明如果公司内网无法直连外部地址把 repo 脚本放到内部文件服务器用统一路径分发避免每个人去外网拉。3.3 编写 manifest 清单manifest 是 repo 的核心格式是 XML。下面是一个最小可用示例。!-- default.xml多仓库清单 -- manifest !-- 远程定义name 是别名fetch 是 Gerrit 上的仓库根路径 -- remote nameorigin fetchssh://gerritgerrit.example.com:29418 / !-- 默认 revision 指向具体分支 -- default remoteorigin revisionrefs/heads/main / !-- 每个 project 对应一个 Gerrit 仓库 -- project nameplatform/core pathcore / project nameplatform/common pathcommon / project nameplatform/manifest pathmanifest / /manifest逻辑说明remote的fetch是仓库根地址repo 会把project的name拼在后面形成完整地址。default的revision可以是分支名、tag 或 commit id生产环境建议用 tag 锁定基线避免每次 sync 都拉到最新提交导致构建不稳定。path是本地目录名不写则默认用name。参数说明revision写refs/heads/main比写main更明确避免歧义如果某个仓库需要单独指定分支在project标签里覆盖revision属性即可。3.4 用 repo 拉取并验证# 初始化-u 指定 manifest 仓库地址-b 指定分支 repo init -u ssh://gerritgerrit.example.com:29418/platform/manifest -b main # 同步所有仓库 repo sync -j4 # 查看当前清单覆盖的仓库 repo list逻辑说明repo init只拉取 manifest 仓库本身repo sync才按清单拉取全部子仓库。-j4表示四个并发网络好可以调大但别超过 Gerrit 服务端的连接承受能力。repo list列出所有已同步仓库及其路径用来确认清单是否生效。参数说明-b main指定 manifest 仓库的分支不是子仓库分支子仓库分支由清单里的revision决定。如果repo sync报某个仓库权限拒绝先检查 Gerrit 上该仓库的读权限是否对当前账户开放。4. 评审流程打通从 push 到 refs/for 的完整链路4.1 配置 SSH 与 Change-Id 钩子Gerrit 的评审入口是refs/for/分支但提交信息里必须带Change-Id否则 push 会被拒绝。这个 Id 由 commit-msg 钩子生成。# 从 Gerrit 拉取 commit-msg 钩子 scp -p -P 29418 gerritgerrit.example.com:hooks/commit-msg \ .git/hooks/ # 确认钩子可执行 chmod x .git/hooks/commit-msg # 配置用户信息 git config user.name 某开发者 git config user.email devexample.com逻辑说明钩子脚本会在每次git commit时自动在提交信息末尾追加Change-Id。如果仓库是 repo 管理的每个子仓库都要单独放一份钩子或者用repo forall批量执行。用户信息里的邮箱要和 Gerrit 账户绑定的一致否则评审页面显示的作者会错乱。参数说明scp -p保留文件权限-P是大写指定 SSH 端口别和-p混淆。4.2 提交并推送到评审队列# 在某个子仓库里修改后提交 cd core git checkout -b feature/login git add . git commit -m feat: 增加登录校验逻辑 # 推送到评审队列而不是直接推分支 git push origin HEAD:refs/for/main逻辑说明HEAD:refs/for/main表示把当前提交推到 main 分支的评审队列。Gerrit 收到后会生成一个 Change 页面等待评审人打分。如果直接推refs/heads/main有权限的账户会绕过评审直接入库这正是要避免的。参数说明refs/for/后面跟目标分支名不要写成refs/for/refs/heads/main。如果目标分支不存在push 会报错先在 Gerrit 上建好分支。4.3 评审、打分与合入评审人在 Web 页面查看 diff给出 Code-Review 2 和 Verified 1 后点 Submit 合入。命令行也能完成打分。# 查看待评审的 Change ssh -p 29418 gerritgerrit.example.com gerrit query \ --formatJSON status:open # 给某个 Change 打 Code-Review 2 ssh -p 29418 gerritgerrit.example.com gerrit review \ --code-review 2 Change-Id逻辑说明gerrit query支持按状态、项目、所有者过滤--formatJSON方便脚本解析。gerrit review的Change-Id是完整的 Change-Id 字符串不是提交哈希。打分后如果满足合入条件还需要单独执行 submit 或由页面操作。参数说明--code-review取值 -2 到 2-2 是强烈反对2 是批准--verified取值 -1 到 1通常由 CI 系统打。权限不够的账户执行 review 会报错需要在 Gerrit 的权限配置里给对应组授权。5. 避坑与排查那些让服务起不来的细节5.1 端口冲突导致启动即退出现象gerrit.sh start后进程立刻消失日志里出现Address already in use。 原因8080 或 29418 被其他服务占用常见的是系统里已有 Web 服务或另一个 Gerrit 实例。 解决ss -lntp找到占用进程改gerrit.config里的listenUrl和sshd.listenAddress换成空闲端口后重启。5.2 push 被拒missing Change-Id现象git push origin HEAD:refs/for/main报missing Change-Id in commit message footer。 原因commit-msg 钩子没装或没执行权限提交信息里没有 Change-Id 行。 解决把钩子放到对应仓库的.git/hooks/commit-msg并chmod x然后用git commit --amend重新生成提交信息。注意钩子是按仓库生效的repo 下每个子仓库都要放。5.3 repo sync 卡在某个仓库现象repo sync长时间停在某个 project 不动最后超时。 原因该仓库体积过大或 Gerrit 服务端并发连接数被占满。 解决先用repo sync project-name单独同步该仓库定位问题如果是体积问题在清单里给该仓库加clone-depth属性做浅克隆如果是并发问题把-j调小到 2 再试。5.4 评审页面作者显示为匿名现象提交成功但 Gerrit 页面上作者名是Anonymous Coward或邮箱不匹配。 原因Git 的user.email和 Gerrit 账户绑定的邮箱不一致Gerrit 无法关联。 解决在 Gerrit 账户设置里添加该邮箱并验证或把本地user.email改成已绑定的地址。改完后新提交才会生效旧提交需要 amend 后重新 push。5.5 升级后仓库数据丢失现象替换 war 包重启后所有项目不见了。 原因升级时误删了站点目录或gerrit.config里gerrit.basePath指向了错误路径。 解决升级只替换/opt/gerrit下的 war 包站点目录和 Git 根目录原地不动。升级前备份etc/和git/两个目录出问题能快速回滚。这是血泪经验别问怎么知道的。6. 进阶技巧用权限组和 CI 钩子把评审管住服务跑通只是开始真正让团队少扯皮的是权限和自动化。Gerrit 的权限模型围绕「组」展开常见做法是建三个组Administrators管全局配置Reviewers负责打分Submitters负责合入。把refs/heads/*的 Submit 权限只给Submitters把refs/for/*的 Push 权限给所有开发者这样谁都不能绕过评审直接改主干。配置权限时有个容易忽略的点refs/for/refs/heads/*和refs/heads/*是两套规则前者控制评审入口后者控制直接推送。只配前者不配后者有权限的账户仍可能直接推分支。稳妥做法是把refs/heads/*的 Push 权限设为空只保留 Submit。自动化方面可以在 Gerrit 上配hooks/目录下的patchset-created钩子每次有新补丁集就触发 CI 构建构建结果通过gerrit review --verified回写。这样评审人看到 Verified 1 才动手看代码省去大量「改了没编译过」的无效评审。# patchset-created 钩子示例触发构建并回写 Verified #!/bin/bash CHANGE_ID$1 PATCHSET$2 PROJECT$3 # 调用内部构建脚本返回 0 表示通过 if /opt/ci/build.sh $PROJECT $PATCHSET; then ssh -p 29418 gerritgerrit.example.com gerrit review \ --verified 1 $CHANGE_ID else ssh -p 29418 gerritgerrit.example.com gerrit review \ --verified -1 --message 构建失败请检查日志 $CHANGE_ID fi逻辑说明钩子脚本由 Gerrit 在事件发生时调用参数顺序按 Gerrit 文档约定。构建脚本返回非零时打 Verified -1 并附上提示信息评审人一眼能看到失败原因。注意钩子脚本要以 Gerrit 运行账户的身份执行SSH 密钥要提前配好免密。参数说明--message支持多行但命令行里换行要转义--verified只有 -1、0、1 三档别写成 2。最后说个习惯每次动 Gerrit 配置前先cp etc/gerrit.config etc/gerrit.config.bak改完重启验证不行就换回来。这套服务一旦跑起来最怕的不是搭不起来而是搭起来之后没人敢改。把备份和回滚路径留好比记住任何一条命令都管用。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

零侵入监控:node_exporter、mtail 与 Prometheus、Grafana 组合实战

零侵入监控:node_exporter、mtail 与 Prometheus、Grafana 组合实战

1. 先统一认知:node_exporter、mtail、Prometheus、Grafana 各管哪一段我见过很多团队做监控,第一反应是“先装一套 Prometheus Grafana”,装上之后发现只有 CPU、内存、磁盘这些机器指标,业务到底跑得好不好完全看不见。后来有人…

2026/10/13 12:07:09 阅读更多 →
Wi-FiTestSuite Control API v10.12.0规范解析:面向Wi-Fi 6E自动化测试的会话化控制

Wi-FiTestSuite Control API v10.12.0规范解析:面向Wi-Fi 6E自动化测试的会话化控制

简介:本资源是Wi-Fi联盟官方发布的《Wi-Fi Test Suite Control API Specification Version 10.12.0》PDF规范文档,面向Wi-Fi设备认证工程师、无线协议开发者及测试工具集成人员,用于指导Wi-Fi认证测试套件的开发、调试与合规性验证。文档系统…

2026/10/13 12:07:18 阅读更多 →
安卓17 Beta版修复待机耗电:原理、实测与开发者适配指南

安卓17 Beta版修复待机耗电:原理、实测与开发者适配指南

安卓17最新Beta版的推送消息出来后,论坛上不少刷过测试版的人开始讨论同一个话题:这次官方终于对“待机耗电”动手了。说实话,“Beta版更新修复耗电”并不是新闻,每代大版本更新都会经历类似的阶段,但这次修复的幅度和…

2026/10/13 12:07:21 阅读更多 →

最新新闻

Unity水下波光Shader:动态折射与材质自适应光照实现

Unity水下波光Shader:动态折射与材质自适应光照实现

1. 这个效果到底在解决什么问题:水面光影的“动态欺骗”本质很多人看到“Unity Shader实现水中波光照射动物身上的效果”这个标题,第一反应是:“不就是加个高光贴图或者用个Blinn-Phong算一下反射吗?”——这恰恰是踩进第一个认知…

2026/10/13 13:00:12 阅读更多 →
MATLAB水果识别实战:从图像处理到STM32部署

MATLAB水果识别实战:从图像处理到STM32部署

简介:本资源是一个基于MATLAB实现的轻量级水果图像识别程序,面向图像处理初学者、自动化专业学生及农业智能化应用开发者,解决常见水果(如香蕉、梨、西红柿、青椒等)的自动分类识别问题,适用于课程设计、小…

2026/10/13 13:00:12 阅读更多 →
金山毒霸卸载后残留弹窗的根源与彻底清理指南

金山毒霸卸载后残留弹窗的根源与彻底清理指南

卸载金山毒霸之后还在被弹窗骚扰,这事儿太常见了。我见过不少用户重装了系统才解决问题,其实根本不用这么极端。这篇内容就把残留弹窗的来源、手工清理步骤和常见坑一次性说清楚。 先说明白一个核心事实:金山毒霸的卸载程序只会移除主体程序…

2026/10/13 13:00:12 阅读更多 →
深度学习图像预处理:transforms 核心技术与实战指南

深度学习图像预处理:transforms 核心技术与实战指南

1. 图像预处理到底在解决什么问题 做过深度学习项目的人都有一个共识:模型效果不好,八成不是网络结构的问题,而是数据没喂对。我刚开始接触计算机视觉那会儿,拿到一批图片就直接往网络里塞,结果训练loss震荡得厉害&…

2026/10/13 13:00:12 阅读更多 →
Linux内核模块入门:从Hello World驱动到加载卸载全流程

Linux内核模块入门:从Hello World驱动到加载卸载全流程

1. 项目概述:从“Hello World”开始,真正摸到Linux内核驱动的脉搏你点开这个标题,大概率不是想看教科书式的定义,而是手痒了——想亲手敲几行代码,让自己的程序跑进内核空间,亲眼看着insmod命令执行后&…

2026/10/13 13:00:12 阅读更多 →
Windows下Claude Code安装配置与避坑全攻略

Windows下Claude Code安装配置与避坑全攻略

“Claude Code 在 Windows 上到底能不能用?”——这恐怕是过去一个月我在各种技术群里被问最多的问题。一方面,这个命令行形态的 AI 编程代理确实很香,直接在终端里让它读仓库、改代码、跑测试、提 PR,整个工作流都在一个地方流转…

2026/10/13 12:59:11 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →