ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

git+repo+gerrit代码服务器搭建:多仓库评审与权限管理实践

git+repo+gerrit代码服务器搭建:多仓库评审与权限管理实践 简介一份基于Git、Repo与Gerrit的代码服务器搭建指南面向需要自建代码托管及评审环境的开发者、运维人员。文档从服务器端与客户端的基本概念入手涵盖Git、Gitosis、Repo、git-daemon与Gerrit的完整安装配置具体包括管理员公钥生成与导入、gitosis-init初始化、gitosis.conf权限设置、组成员公钥添加、manifest与default.xml仓库组织、Git守护进程启动、Gerrit下载与config配置等环节同时给出备用下载地址和常见命令异常提示便于读者一步步实操并排除障碍。资源为1个docx文档约294KB文字说明与命令示例集中适合按文档顺序系统搭建。已有3134人学习对希望快速构建功能完善的代码服务器并理解各组件协作关系的读者很有参考价值。1. 代码服务器不只是一台 gitrepo 与 gerrit 各管哪一段一台裸 git 服务器对多仓库团队来说只是半个答案提交推到远程之后没有评审记录几十个仓库之间的版本依赖靠口头约定出了问题找不到是谁在哪个 commit 引入的也不清楚该回滚到哪个位置。gitrepogerrit代码服务器搭建要解决的就是这半个答案——git 提供底层版本模型repo 负责按一份清单把几十上百个仓库统一拉取、统一提交gerrit 在中间加一道评审闸门。这套组合最适合 Android、嵌入式这类多仓协作团队也适合刚从 svn 或网盘协作转过来的开发者。接下来我会按一套最小可运行方案讲清楚包括服务端安装参数、repo 客户端同步命令以及最常见的认证和 Change-Id 相关坑。2. 为什么选 gerrit 配 reporefs/for、Change-Id 和权限模型2.1 三个工具的分工边界git 管版本、repo 管清单、gerrit 管评审git 本身是一个分布式版本模型它只解决“你的提交是什么、从哪里来、能合并到哪里”这个底层问题。多人协作时 git 能提供的权限粒度很粗要么能推、要么不能推并没有“推上去之后要等人批准”这个流程概念。svn 时代我们用中心库加锁来防止写冲突git 时代靠分支策略但分支策略也只是约定拦不住手滑。repo 是 Android 生态里长出来的多仓库管理工具它用 Python 实现核心是 manifest 清单。一份 default.xml 里声明了每个子仓库的路径、remote、分支或 tagrepo init 读清单repo sync 把清单里所有仓库按指定版本拉齐。这才是团队真正需要的“整体版本”概念不是某个仓库单独在某个分支而是整棵代码树处在同一个可构建的版本里。gerrit 解决的问题和前两者正交。它把自己伪装成一个 git 远端普通开发者把提交推到 refs/for/* 命名空间gerrit 把它变成一条评审单由 reviewer 打分达到门槛之后才由系统把提交合入真正的 refs/heads/*。这样一来git 仍然是底层传输协议repo 仍然是多仓库编排但“能不能合入”不再靠微信群吼而是变成代码服务器上的硬约束。2.2 refs/for 与 Change-Idgerrit 的评审如何嵌进 git 协议gerrit 最容易被新手忽略的设计是 refs/for。普通的 git 服务器上你只会看到 refs/heads/master、refs/tags/v1.0 这些正常引用gerrit 额外注册了一个 refs/for/refs/heads/master 命名空间。开发者的 push 目标不是 refs/heads/master而是 refs/for/refs/heads/mastergerrit 收到之后不会更新分支而是把这次提交内容创建为一条 Change。Change 是 gerrit 里的核心对象它的身份标识是 Change-Id。这个 ID 由客户端 hook 在 commit message 里自动生成格式是I开头的一长串哈希。同一逻辑改动即便经过了多次 git commit --amend只要 Change-Id 没变gerrit 就把它们归为同一个 Change 的不同 Patch Set评审记录、打分历史、评论都会串在一起。没有 Change-Id 的提交推到 refs/for 会被直接拒绝这也是新团队最常撞的墙。打分机制上gerrit 用的是 -2 到 2 的区间。1 表示“可以但建议修改”2 表示“我认可这个改动”并且通常还要 1 Verified验证通过才能合入。两个 2 是很多团队的默认门槛。这个设计比 GitLab 的 MR 更细因为 gerrit 管到“单个提交”而不是“一个 MR 里的一堆提交”。2.3 选型对比gerrit、GitLab、Gitea 在评审流上的差异维度gerritGitLabGitea评审粒度提交级一个 Change 一个评审MR 级一组提交合并评审PR 级一组提交合并评审权限模型引用级权限精确到 refs/for、refs/heads、refs/tags角色 分支保护规则角色 分支保护规则多仓库协调与 repo manifest 天然配套Change 间关联可见靠 Group/Subgroup 组织无清单级同步较弱适合少量仓库部署成本单个 Java 应用自带 H2可切 MySQLRails 应用栈资源占用较高单个二进制最轻典型场景Android、嵌入式、多仓强管控通用互联网研发团队小型自托管团队如果你的团队只有三五个仓库、人数在十人左右用 GitLab 或 Gitea 的 MR 流会更顺手不必上 gerrit。可一旦仓库数量到了几十个并且要求每次发布都能按同一份 manifest 把代码拉齐gerrit 与 repo 的配合几乎没有替代品。选型结论就一句话先看仓库数量再看合入管控的严格程度两个条件都偏高时再考虑 gerrit。3. 最小链路跑通gerrit 初始化、repo 安装与首次同步的落地命令3.1 用 war 包拉起 gerrit初始化参数与交互式配置常见做法是从 gerrit 官方 release 下载 war 包放到一台 Linux 服务器上。前置条件是 JDK 11 或更高推荐用普通用户运行而不是 root。我一般这样建用户和目录sudo useradd -m -s /bin/bash gerrit sudo -iu gerrit mkdir -p /opt/gerrit_site cd /opt/gerrit_site java -jar /opt/gerrit.war init -d /opt/gerrit_siteinit 是一个交互式过程会依次询问数据库类型、认证方式、监听地址等。我的推荐是数据库选 h2认证方式选 http监听地址写 0.0.0.0HTTP 端口 8080SSH 端口 29418。后面几条比如管理员邮箱可以按团队实际填其余不确定的直接回车用默认值。这条命令初始化完成后 gerrit 会自动启动可以用浏览器打开 http://服务器IP:8080 验证。首次访问会引导创建管理员账号这个账号之后要在“设置 → SSH Keys”里粘贴你的公钥。初始化目录下的 gerrit.config 是主配置secure.config 放数据库密码等敏感信息注意这两个文件都不要提交到任何 git 仓库。3.2 生产级调整数据库切换、监听端口与邮件通知H2 适合跑 demo生产环境我一般会换成 MariaDB。init 时选择 mysql 类型然后先手动建好库sudo mysql -e CREATE DATABASE gerrit CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; sudo mysql -e CREATE USER gerrit127.0.0.1 IDENTIFIED BY yourpassword; sudo mysql -e GRANT ALL ON gerrit.* TO gerrit127.0.0.1;建库时注意字符集要指定 utf8mb4否则评审意见里出现中文或 emoji 可能写入失败。库建好后在 gerrit.config 的 [database] 段核对连接信息默认会生成类似下面的配置[database] type mysql hostname 127.0.0.1 database gerrit username gerrit邮件通知也建议在早期就配好否则评审单只能靠人工刷新页面。在 gerrit.config 中补这一段[sendemail] smtpServer smtp.example.com smtpPort 465 smtpEncryption ssl from Code Review reviewexample.com实际生产环境我还会在前端用 nginx 把 80 端口转发到 gerrit 的 8080同时在 [httpd] 段设置 behindReverseProxy true。这样团队成员访问评审页面不用记端口号gerrit 生成的链接也更干净。3.3 客户端 repo 安装REPO_URL 与镜像地址repo 本身只是一个 Python 脚本需要放到 PATH 里。国内环境最常见的坑是默认下载地址不可达所以要先准备一个可访问的镜像地址。安装命令如下mkdir -p ~/bin curl -o ~/bin/repo 可访问的 repo 镜像地址 chmod 755 ~/bin/repo export PATH~/bin:$PATH echo export PATH~/bin:$PATH ~/.bashrc脚本安装好之后设置 REPO_URL 环境变量指向同一份镜像再执行 repo init。这一步决定后续所有仓库的拉取地址export REPO_URL可访问的 repo 镜像仓库地址 repo init -u ssh://gitgerrit.example.com:29418/platform/manifest.git -b masterrepo init 会在当前目录生成 .repo 目录并把 manifest 仓库克隆到 .repo/manifests 里。注意 REPO_URL 要指向镜像仓库本身而不是某个具体子仓库。如果这里配错后续 repo sync 会一直从不可达的默认地址拉代码表现就是卡在“Downloading”阶段不动。3.4 首次同步与 SSH 密钥验证repo 走的是 SSH 协议所以同步前必须验证 SSH 密钥已经加进 gerrit。先在本机生成密钥并查看公钥内容ssh-keygen -t ed25519 -C code-review cat ~/.ssh/id_ed25519.pub把公钥粘贴到 gerrit 页面 “Settings → SSH Keys” 里保存。然后通过 29418 端口验证登录ssh -p 29418 你的用户名gerrit.example.com如果返回 gerrit 的欢迎信息说明密钥链路已经通。验证通过后开始真正的首次同步repo sync -c -j4-c 表示只同步当前分支避免把远程所有分支都拉下来-j4 是并发数第一次同步建议给 4 到 8并发开太大容易把服务器磁盘 IO 打满。repo sync 是幂等的中途失败直接重跑即可已经下好的仓库会跳过。提示首次同步完成后团队里每个人都需要单独把公钥加到自己的 gerrit 账号里。不要共用一个账号否则评审记录和提交人会对不上。4. 一次改动走完流程manifest、commit-msg 与 repo upload 的操作细节4.1 manifest 的三个关键标签remote、default、projectmanifest 仓库是这套体系的版本清单。一个最小可用的 default.xml 长这样?xml version1.0 encodingUTF-8? manifest remote namegerrit fetchssh://gitgerrit.example.com:29418/ reviewhttp://gerrit.example.com:8080// default remotegerrit revisionrefs/heads/master sync-j4/ project pathapp nameplatform/app groupsapp/ project pathkernel nameplatform/kernel groupskernel/ /manifestremote 标签里的 fetch 决定了每个 project 最终拼出来的 git 地址name 是服务器上的仓库路径path 是本地工作区路径。fetch 末尾的斜杠要保留gerrit 会把 fetch 和 name 拼成完整地址。review 字段是 repo upload 的默认评审页地址不填也能上传但上传后的输出链接会是未定义的拼接结果。revision 标记是团队发版的核心默认指向 refs/heads/master发布版本时把它改成对应的 tag比如 refs/tags/v1.2.0整棵树就会切到该标签。多分支并行开发时可以用include namecommon.xml/拆分文件但拆得越多合流时越要小心我一般只做一个分支一个 manifest。4.2 commit-msg 钩子没有 Change-Id 就进不了评审通道gerrit 要求每个提交都带 Change-Id这个 ID 由客户端 hook 自动生成。钩子文件在 gerrit 服务端站点目录的 tools/hooks/commit-msg需要通过 scp 下载到本地仓库scp -p -P 29418 你的用户名gerrit.example.com:hooks/commit-msg .git/hooks/ chmod x .git/hooks/commit-msg这个钩子会在你执行 git commit 时自动往 message 里加 Change-Id。如果是本地已经提交过、后来才装钩子的情况需要用 git commit --amend 让它补上git commit --amend --no-edit常见做法是先把钩子复制到服务器端模板仓库或者用脚本批量复制到所有子仓库的 .git/hooks/ 下否则手动一个个放既慢又容易漏。Change-Id 是一行以 I 开头的哈希gerrit 只认自己生成的格式不要手写一个。4.3 repo upload把本地分支推成评审单代码改完常规步骤是先提交到本地分支再推评审。我的习惯是每次改动都从 master 拉新分支避免本地 master 落后git checkout -b feature/xxx origin/master # 修改代码 git add -A git commit repo upload --brfeature/xxx --remaster --nerepo upload 的参数有几个值得说明。--br 指定要上传的本地分支名如果当前仓库只有一条待上传分支也可以省略。--re 是目标分支评审通过之后要合入的分支。--ne 表示强制开启一个新 Change同一个本地分支上多次 upload 默认会更新已有 Change加了这个参数后每次都是新 Change适合彻底重写时用。不加参数直接跑 repo upload 会进入交互模式逐个列出待推送的仓库和分支团队里第一次接触这个流程的人用交互模式比较不容易推错。推送成功后终端会输出评审链接打开就能看到 gerrit 上的 Change 页面。如果没看输出就把窗口关了也可以通过 gerrit 页面右上角的 “Your → Changes” 找到。4.4 权限参考refs/heads 与 refs/for 的常用组合引用命名空间作用常见授权refs/heads/*直接更新分支仅管理员与集成者refs/for/refs/heads/*提交评审所有开发者refs/tags/*创建与更新标签仅管理员refs/meta/config修改仓库权限与配置文件仅仓库所有者gerrit 的权限配置在 “Projects → Access” 页面里。新仓库默认会把权限继承自 All-Projects建议在 All-Projects 里先定好全局规则子仓库只做例外覆盖。把普通开发者的 refs/heads/* 权限设成 deny只留 refs/for/refs/heads/*就能强制所有改动走评审。这个改动本身也要通过评审生效改完的配置要推到 refs/meta/config 分支在 gerrit 里提交变更。注意权限改动比代码改动更危险。改错一个 refs/for 的 deny 规则可能导致整个团队无法上传评审排查时优先看 All-Projects 的继承规则。5. 高频翻车点排查认证失败、Change-Id 缺失与库膨胀怎么办5.1 repo sync 报 git requires authentication, but repo cannot perform interactive authentication现象repo sync 跑到一半停下来终端输出git requires authentication, but repo cannot perform interactive authentication同时提示认证失败。原因repo 客户端不接受交互式密码输入它只认 SSH agent 里已经加载好的密钥。常见原因有三个密钥没有 ssh-add 进 agent私钥文件权限过宽SSH 拒绝使用push 地址写了 22 端口而不是 gerrit 的 29418 端口导致连到了系统 SSH 而不是 gerrit 自己的 SSH 服务。解决先执行ssh-add -L确认密钥在 agent 里不在就ssh-add ~/.ssh/id_ed25519再检查ls -l ~/.ssh/id_ed25519权限必须是 600目录是 700最后确认 ssh:// 地址里的端口写的是 29418。改完重新repo sync即可不会重复拉取已有仓库。5.2 终端报 fatal: not a git repository (or any of the parent directories): .git现象在某个目录下执行 git status 或 git log终端直接报fatal: not a git repository (or any of the parent directories): .git。原因当前目录不是 git 仓库也不在 repo 管理的任何一个子仓库内部。最常见的两种情况一是直接 cd 到了 manifest 仓库目录manifest 仓库通常只是用来读 default.xml本身不参与代码开发二是有人只 clone 了某个子仓库的地址而不是通过 repo sync 拉整个工程。解决确认自己所在位置。如果在 repo 工程根目录执行ls -a看有没有 .repo 目录如果只有单独一个仓库先git clone整个工程或repo sync后再进子目录。单仓操作之前先git init再拉远程也可以但要记得和 manifest 里的路径保持一致不要造成两套工作目录并存的局面。5.3 push 到 refs/for/HEAD 报 missing Change-Id现象git push 到 refs/for/refs/heads/master 时被 gerrit 拒绝提示 missing Change-Id in commit message。原因提交时仓库里没有安装 commit-msg 钩子所以 commit message 里没有生成 Change-Id 行。也有一种情况是这个提交是 git cherry-pick 过来的Change-Id 被源仓库带过来但格式不对或者 rebase 时被弄丢了。解决先确认钩子文件存在于当前仓库 .git/hooks/ 下不存在就按 4.2 的操作重新 scp。钩子补齐之后执行git commit --amend --no-edit git push origin HEAD:refs/for/refs/heads/mastergit commit --amend 会重新触发 commit-msg 钩子在不改提交内容的情况下补上 Change-Id。补好之后重新 push 同一 Revisiongerrit 能自动归并到已有 Change 或创建新 Change。如果 amend 后还是没有 Change-Id 行检查钩子文件是否有可执行权限。5.4 gerrit 运行几个月后 HTTP 和 SSH 都无响应现象gerrit 突然连不上页面打不开ssh -p 29418 也超时查看日志能看到数据库连接池相关的报错。原因默认 H2 数据库在评审量增长后会出现单文件膨胀磁盘写满或连接超时后服务直接失去响应。H2 适合验证流程不适合长期生产运行。解决搭建时就切换到 MariaDB 或 PostgreSQL按 3.2 的步骤操作。已经跑在 H2 上的站点可以把 site 目录下 h2 文件夹里的 .mv.db 文件备份出来再用 gerrit 官方文档里的迁移方式导入 MySQL。日常运维里给数据库目录做磁盘监控低于 20% 剩余空间就提前告警比出了问题再扩容从容得多。5.5 repo upload 成功但评审页面看不到这条 Change现象repo upload 命令提示上传完成也输出了 change 链接但打开页面看不到或者同事在评审列表里找不到这条记录。原因上传到了错误的目标分支或错误的项目。比较隐蔽的情况是 manifest 里的 revision 写的是 refs/heads/master但本地的 origin/master 已经落后gerrit 把变更关联到了旧分支上。解决上传前用repo upload --remaster明确指定目标分支不要完全依赖默认推完立刻打开终端输出的 change 链接确认项目名和分支名。团队内可以约定每条 Change 标题必须带模块前缀方便在 All 页面里搜索。6. 用 stream-events 把评审与构建串起来最小自动化落地gerrit 的 29418 端口除了走 git 协议还提供一组远程命令其中gerrit stream-events是最实用的自动化入口。这条命令会把服务器上的评审事件以 JSON 行形式持续推出来包括补丁上传、评审打分、合入等。用一段简单脚本监听 patchset-created 事件就能把构建触发起来ssh -p 29418 你的用户名gerrit.example.com gerrit stream-events | while read event; do echo $event | grep -q patchset-created echo $event /tmp/gerrit-events.log done这段脚本的关键在于 stream-events 是长连接ssh 进程不能中断需要在构建机上配合 nohup 或 systemd 常驻运行。生产环境我不会用 grep 做过滤而是把每行 JSON 交给 Python 解析按 project 和 refName 字段判断是否触发对应仓库的构建脚本ssh -p 29418 usergerrit.example.com gerrit stream-events | python3 /opt/build-trigger.py脚本里判断事件类型、提取 project 和 patchSet 编号然后调用 Jenkins 的 API 或直接跑本地编译脚本。这样整个链路就完整了开发者 repo upload 提交评审reviewer 打分 2gerrit 合入后 stream-events 收到 change-merged 事件构建机自动开始打包。这一套跑顺之后团队不再需要手动在构建平台上点“开始构建”发布节奏会明显变快。落到日常习惯上我有三条经验第一所有成员统一用 SSH 方式访问 gerrit避免 HTTP 和 SSH 混用导致的认证混乱第二manifest 仓库的改动也必须走评审改 manifest 比改单个仓库更影响全局谁改谁负责不是靠自觉是靠 gerrit 的 2 门槛第三权限规则改动先在临时仓库上试验不要直接在 All-Projects 上动刀等团队对 refs/for、refs/heads 的层级心里有数后再收拢权限。代码服务器搭建这件事前期把认证和权限模型想清楚后期基本不会出大乱子。希望帮到你。本文还有配套的精品资源点击获取
返回列表