
简介本资源是一份面向中高级Linux系统管理员与DevOps工程师的Git代码协同平台搭建实战指南聚焦于构建集版本控制Git、多仓库管理Repo与代码评审Gerrit于一体的私有化代码服务器。内容覆盖从基础环境部署、Gitosis权限体系配置、Repo manifest仓库初始化到Gerrit服务安装与评审流程打通的完整链路含详细命令行操作、配置文件修改要点及典型排错提示如gitosis-init失败处理、repo克隆地址备选方案等。资源为1个294KB的Word文档.docx结构清晰含名词解释、分步操作、配置片段截图说明及default.xml等关键模板示例便于边学边练。目前已有3136人学习下载适合需在企业内快速落地轻量级代码协作基础设施的技术人员参考实施。1. 为什么企业级代码协作不能只靠 GitHub 或 GitLabGerrit Repo 组合才是 Android/大型嵌入式项目的真实底座你手头正维护一个 300 人协同、20 子模块、每日提交超 500 次的车载系统项目分支策略复杂、代码审查必须强制、提交前需自动触发静态检查与编译验证——这时你会发现GitHub 的 PR 流程太松散GitLab 的 Merge Request 缺少原子性提交控制而git push直接进主线不行。这不是“能不能用”的问题是“敢不敢上线”的红线。Gerrit 不是另一个 Git 托管平台它是基于 Git 的代码准入门禁系统所有提交必须经 Review Verified Code-Owner Approval 三重校验后才允许合并到受保护分支Repo 则不是简单的脚本封装它是 Google 为 Android 量身打造的多仓库协同元管理工具能一键同步数百个 Git 仓库、统一版本锚点、隔离开发/发布视图。二者组合构成一套可审计、可回溯、可分级授权的企业级代码基线管控体系。适合需要强流程管控的 OS 层、芯片驱动、车规软件团队——尤其当你发现git merge --no-ff已经压不住混乱的提交历史时这套方案就不是“高级选项”而是生存必需。2. 从零部署 Gerrit不依赖 Docker纯 Java 环境下的最小可靠安装路径Gerrit 的本质是一个运行在 Jetty 上的 Java Web 应用它不托管 Git 仓库本身而是监听 Git SSH/HTTP 接口拦截所有 push 操作并注入审查逻辑。因此部署核心不是“装个服务”而是构建一个受控的 Git 仓库代理层。以下步骤基于 Ubuntu 22.04 LTS生产环境推荐 OpenJDK 17 PostgreSQL 14全程无 Docker避免容器层引入的 SSH 转发、权限映射等黑匣子问题。2.1 下载与初始化 Gerrit WAR 包Gerrit 官方不再提供传统 tar.gz 安装包而是以单文件 WAR 形式分发。注意必须使用与 Java 版本严格匹配的 Gerrit 版本如 OpenJDK 17 对应 Gerrit 3.7.x。访问 https://gerrit-releases.storage.googleapis.com/ 下载最新稳定版截至 2024 年中为gerrit-3.7.5.war# 创建独立运行用户禁止 root 运行 sudo useradd -m -s /bin/bash gerrit sudo su - gerrit # 下载并校验SHA256 值务必核对官网公告 wget https://gerrit-releases.storage.googleapis.com/gerrit-3.7.5.war sha256sum gerrit-3.7.5.war # 应输出: 9a8b7c... (官网公示值) # 初始化配置目录Gerrit 会在此生成数据库、索引、SSH 密钥 java -jar gerrit-3.7.5.war init -d /opt/gerrit提示-d /opt/gerrit是 Gerrit 的 home 目录必须由 gerrit 用户拥有且不可被其他用户写入。后续所有操作包括数据库迁移、插件安装都基于此路径。2.2 配置 PostgreSQL 替代内置 H2 数据库H2 仅用于测试生产环境必须切换至 PostgreSQL。Gerrit 初始化向导会引导你完成基础配置但关键参数需手动修正# 编辑 /opt/gerrit/etc/gerrit.config [database] type postgresql hostname localhost database gerrit username gerrit password your_strong_password [auth] type LDAP # 或 OPENID / DEVELOPMENT_BECOME_ANY_ACCOUNT仅测试然后创建数据库与用户-- 以 postgres 用户登录 psql CREATE DATABASE gerrit ENCODING UTF8 LC_COLLATE en_US.UTF8 LC_CTYPE en_US.UTF8; CREATE USER gerrit WITH PASSWORD your_strong_password; GRANT ALL PRIVILEGES ON DATABASE gerrit TO gerrit;重启 Gerrit 生效/opt/gerrit/bin/gerrit.sh restart2.3 关键网络与 SSH 配置绕过“Connection refused”玄学Gerrit 默认监听localhost:8080HTTP和localhost:29418SSH但生产环境需暴露给开发者。常见翻车点在于sshd_config与 Gerrit 的 SSH 端口冲突# /opt/gerrit/etc/sshd_config 中必须显式设置 [sshd] listenAddress *:29418 # 注意不是 0.0.0.0* 表示所有 IPv4/IPv6 接口 keysDirectory /opt/gerrit/etc/ssh_key_dir # 同时确保系统 sshd 不占用 29418检查 /etc/ssh/sshd_config 中 Port 设置 sudo ss -tuln | grep :29418 # 应显示 gerrit 进程 PID若仍连不上检查防火墙sudo ufw allow 29418 sudo ufw allow 80803. Repo 工具链落地不只是repo init而是构建可复现的仓库拓扑Repo 是 Python 脚本集合非二进制其核心价值在于通过manifest.xml文件定义整个项目的仓库树结构、分支映射与同步策略。它不替代 Git而是 Git 的“指挥官”。很多团队失败在于把 Repo 当成git clone的批量工具忽略了 manifest 的版本锚定与分组能力。3.1 安装 Repo 并初始化本地仓库组Repo 官方推荐通过 curl 下载repo脚本非 pip 安装避免 Python 环境污染mkdir -p ~/bin curl https://storage.googleapis.com/git-repo-downloads/repo ~/bin/repo chmod ax ~/bin/repo export PATH~/bin:$PATH # 创建 manifest 仓库独立于代码仓库用于管理所有子模块版本 mkdir ~/manifests cd ~/manifests git init git remote add origin ssh://gerrit.example.com:29418/manifests git checkout -b default3.2 编写 production.xml定义模块依赖与版本锁定一个健壮的default.xml必须包含三要素remoteGerrit 服务器地址、project每个子模块路径与分支、copyfile跨仓库共享配置。示例?xml version1.0 encodingUTF-8? manifest remote nameorigin fetchssh://gerrit.example.com:29418/ reviewgerrit.example.com:29418/ default revisionrefs/tags/v2.3.0 remoteorigin sync-j4/ project pathkernel/linux nameplatform/kernel/linux groupslinux,kernel/ project pathhal/sensor nameplatform/hal/sensor groupshal/ project pathapp/camera nameplatform/app/camera groupsapp/ !-- 强制所有模块使用同一 tag避免 cherry-pick 混乱 -- project pathbuild/env nameplatform/build/env revisionrefs/tags/v2.3.0/ /manifest关键参数说明sync-j4并发同步 4 个仓库避免单线程拖慢大型项目建议设为 CPU 核数 × 1.5revisionrefs/tags/v2.3.0必须用 tag 或 commit hash 锁定禁止用main或master否则repo sync会拉取最新不稳定 HEADgroups用于repo sync -g hal按组筛选同步降低 CI 构建范围3.3 初始化工作区并验证 manifest 解析# 在空目录中初始化 repo 工作区 mkdir ~/workspace cd ~/workspace repo init -u ssh://gerrit.example.com:29418/manifests -m default.xml -b default # 同步所有仓库首次耗时较长因含完整历史 repo sync -c -j8 # -c 只同步当前分支-j8 提升并发 # 验证 manifest 是否正确解析 repo manifest -o current.xml # 导出当前生效 manifest grep platform/kernel/linux current.xml # 应返回对应 project 行若repo sync报错fatal: unable to access ssh://...90% 是 SSH 密钥未正确加载# 确保 gerrit 用户的 ~/.ssh/id_rsa.pub 已添加到 Gerrit Web UI 的 Settings → SSH Public Keys ssh -p 29418 gerritgerrit.example.com # 手动测试连接4. Gerrit Repo 协同工作流从提交到合入的全链路闭环单纯部署服务只是开始真正的价值在于建立可审计、可追溯、可自动化的代码流转管道。Gerrit 的 Change-Id 机制与 Repo 的 manifest 版本绑定构成了端到端的完整性保障。4.1 开发者日常Repo 同步 → Git 提交 → Repo 上传# 1. 同步到指定 baseline而非盲目 pull repo sync -c -d # -d 强制检出 manifest 定义的 revision覆盖本地分支 # 2. 进入子模块修改代码例如 kernel/linux cd kernel/linux git checkout -b feature/camera-v2 echo new driver driver.c git add driver.c git commit -m camera: add v2 driver # 3. Repo 自动注入 Change-Id关键必须启用 commit-msg hook repo upload . # 此命令调用 git push origin HEAD:refs/for/main为什么必须用repo upload它会自动执行git dir/hooks/commit-msg由repo init注入在 commit message 末尾追加Change-Id: IxxxGerrit 依靠此 ID 关联多次 amend 提交避免重复创建 Review若手动git pushGerrit 将拒绝报错missing Change-Id4.2 Gerrit 审查界面关键配置让 Code Owner 规则真正生效默认 Gerrit 不启用 Code Owner需手动配置project.config# 在 manifests 仓库中编辑 platform/kernel/linux 的 config cd ~/manifests git checkout -b owners-update echo [access] ownerOf refs/heads/main ownerOf refs/tags/* ownerOf refs/heads/release-* projects/platform/kernel/linux/config # 提交并推送到 Gerrit git add projects/platform/kernel/linux/config git commit -m kernel: set code owner for main/release branches git push origin HEAD:refs/for/main随后在 Gerrit Web UI 中进入Projects → List → platform/kernel/linux → Access → Edit将Code-Review权限分配给Group: kernel-maintainers并勾选Require Code-Review 2 from Code-Owner。这样任何提交到main分支的变更必须获得该组成员的2才能 Submit。4.3 自动化验证用 hooks 实现提交即编译Gerrit 的verify标签需由 CI 系统如 Jenkins/GitLab CI自动打标。在/opt/gerrit/etc/hooks/下创建patchset-created脚本#!/bin/bash # /opt/gerrit/etc/hooks/patchset-created # 当新 patchset 创建时触发 Jenkins 构建 CHANGE_ID$(echo $GERRIT_CHANGE_ID | sed s/^I//) # 去掉 I 前缀 curl -X POST https://jenkins.example.com/job/gerrit-build/buildWithParameters?tokenGERRIT_HOOKchangeId$CHANGE_ID注意此脚本需chmod x且 Jenkins 必须配置GERRIT_HOOKtoken并在 job 参数中接收changeId。Gerrit 会将$GERRIT_*环境变量注入 hook无需额外解析 JSON。5. 避坑指南Gerrit Repo 生产环境踩过的 5 个血泪现场部署不是终点稳定运行才是挑战。以下是我在 3 个大型项目中反复验证的高频故障点每一条都附带真实现象、根因分析与可立即执行的修复命令。5.1 现象repo sync报错error: Cannot lock ref refs/remotes/origin/main原因多个repo sync进程并发写入同一仓库的.git/refs/文件Git 锁机制冲突。常见于 CI 脚本未加锁或开发者误开多个终端同步。解决在 CI 脚本中添加文件锁flock /tmp/repo_sync.lock -c repo sync -c -j4或强制单线程同步牺牲速度保稳定repo sync -c -j15.2 现象Gerrit Web UI 显示 Repository not found但git ls-remote可访问原因Gerrit 的repository配置未刷新或仓库目录权限错误非gerrit用户所有。解决# 1. 检查仓库目录归属 sudo chown -R gerrit:gerrit /opt/gerrit/git/ # 2. 通知 Gerrit 重新扫描仓库无需重启 ssh -p 29418 gerritgerrit.example.com gerrit ls-projects | wc -l # 先确认连接 ssh -p 29418 gerritgerrit.example.com gerrit index start --force5.3 现象repo upload后 Gerrit 显示 No new changesCommit 未出现在 Review 列表原因repo upload默认推送至refs/for/main但目标分支在 Gerrit 中被重命名如main→trunk或project.config中2权限未开放给当前用户组。解决查看 Gerrit 项目配置Projects → List → [project] → General → Branches确认main是否存在检查权限Access → Edit → refs/heads/main → Add Permission → Code-Review → Group: Registered Users强制指定分支repo upload --brtrunk .5.4 现象SSH 连接 Gerrit 时提示Permission denied (publickey)但密钥已添加原因Gerrit 使用自己的 SSH 密钥管理/opt/gerrit/etc/ssh_key_dir不读取系统~/.ssh/。且密钥格式必须为 PEMOpenSSH 格式不能是 PuTTY 的.ppk。解决# 转换密钥格式若为 ppk puttygen id_rsa.ppk -O private-openssh -o id_rsa # 复制到 Gerrit SSH 目录需重启 Gerrit sudo cp id_rsa /opt/gerrit/etc/ssh_key_dir/ sudo chown gerrit:gerrit /opt/gerrit/etc/ssh_key_dir/id_rsa sudo chmod 600 /opt/gerrit/etc/ssh_key_dir/id_rsa /opt/gerrit/bin/gerrit.sh restart5.5 现象repo forall执行命令时部分仓库报错fatal: not a git repository原因repo forall会遍历所有repo sync记录的仓库但某些仓库因网络中断未完整克隆.git目录残缺。解决# 1. 清理损坏仓库 repo forall -c if [ ! -d .git ]; then echo rm -rf $REPO_PATH; rm -rf $REPO_PATH; fi # 2. 强制重新同步跳过已存在仓库 repo sync -c --force-sync --no-clone-bundle6. 进阶技巧用repo manifest实现灰度发布与模块热插拔当你的项目演进到千级模块、多产品线共用基线时repo manifest就不再是静态配置文件而是动态策略引擎。我曾在某车厂项目中用 manifest 分组 动态 include 实现了“同一套代码三套发布形态”标准版全部模块、精简版剔除 AI 模块、定制版替换通信协议栈。核心不在代码而在 manifest 的组合能力。6.1 用include拆分 manifest实现配置复用将default.xml拆为基线 产品线两层!-- manifests/default.xml -- ?xml version1.0 encodingUTF-8? manifest include namebase.xml/ include nameproduct/standard.xml/ /manifest!-- manifests/base.xml -- manifest remote nameorigin fetchssh://gerrit.example.com:29418// default revisionrefs/tags/v3.0.0 remoteorigin/ project pathcore/kernel nameplatform/core/kernel/ project pathcore/utils nameplatform/core/utils/ /manifest!-- manifests/product/standard.xml -- manifest project pathapp/navigation nameplatform/app/navigation/ project pathhal/camera nameplatform/hal/camera/ /manifest开发者只需repo init -u ... -m default.xml即可加载完整配置。若要构建精简版新建lite.xml!-- manifests/product/lite.xml -- manifest project pathapp/navigation nameplatform/app/navigation groupslite/ !-- 不包含 hal/camera -- /manifest再执行repo init -u ... -m default.xml --reference~/manifests并通过repo sync -g lite仅同步标记为lite的模块。6.2 动态 manifest用repo manifest -r生成可追溯的构建快照每次 CI 构建成功后自动生成该次构建的精确 manifest# 在 Jenkins Pipeline 中 sh repo manifest -r -o manifest-build-${BUILD_NUMBER}.xml sh git -C ~/manifests add manifest-build-${BUILD_NUMBER}.xml sh git -C ~/manifests commit -m CI: save manifest for build ${BUILD_NUMBER} sh git -C ~/manifests push origin HEAD:refs/for/main价值当某次 OTA 升级出现故障运维可直接repo init -u ... -m manifest-build-12345.xml复现当时代码状态无需在 Gerrit 中逐个查找 commit hash。这是git bisect无法替代的基线锚定能力。6.3 Repo Hooks在repo sync后自动执行安全扫描利用 Repo 的hooks机制在每次同步完成时触发 SCASoftware Composition Analysis# 创建 ~/bin/repo-post-sync-hook #!/bin/bash # 此脚本需放在 PATH 中且 repo 会自动调用 echo Running security scan after sync... find . -name pom.xml -o -name package.json | xargs -I {} sh -c cd $(dirname {}); npm audit || true然后在~/.repoconfig中启用[repo] hooks ~/bin/repo-post-sync-hook这样开发者每次repo sync后终端会自动打印第三方组件漏洞报告无需额外命令。我坚持在每个新项目启动时先花半天时间写好manifest.xml的分组规则和repo hooks而不是等代码堆积后再补救。因为一旦基线失控重构成本是线性增长的——你永远不知道下一次repo sync会拉下来多少个不兼容的 commit。希望帮到你。本文还有配套的精品资源点击获取