☰
2025年自建Git服务选型指南:Gitea、GitLab与Gerrit部署对比
2026/9/26 1:44:39 网站建设 项目流程

1. 自建 Git 服务这件事,2025 年为什么还值得认真选一次

如果你在 2025 年还在纠结自建 Git 服务到底选 Gitea、GitLab 还是 Gerrit,说明你已经过了“随便找个能托管代码的地方就行”的阶段。我自己的经历是:最早用公共托管平台,代码放上去省心,但一旦团队规模上来、项目涉及内部交付、CI 要跑在内网机器上、审计要求留痕,公共平台就开始处处别扭。于是自建 Git 服务成了绕不开的一步。

但自建这件事,选型比部署重要十倍。部署只是几个小时的事,选型错了,后面迁移、培训、维护的成本会持续放大。Gitea、GitLab、Gerrit 这三个名字经常被放在一起比较,但它们其实不是同一类东西:Gitea 是轻量级代码托管与协作平台,GitLab 是覆盖 DevOps 全流程的一体化平台,Gerrit 则是以代码评审为核心的提交门禁系统。把它们放在一张表里比“谁更好”没有意义,真正有意义的问题是:你的团队规模、协作模式、CI 需求、硬件预算、运维人力,分别对应哪一种。

这篇内容我会按“先讲清楚三者各自解决什么问题,再讲部署实操,最后讲踩坑和长期维护”的顺序展开。适合正在做技术选型的后端负责人、DevOps 工程师,也适合第一次接触自建 Git 服务、想先跑起来再说的开发者。文中涉及的部署命令和配置都经过实际环境验证,你可以直接抄作业,但建议先看完选型逻辑再动手,避免装完才发现方向不对。

2. 三套系统的本质差异:先搞清楚它们各自在解决什么问题

2.1 Gitea:把“够用”做到极致的轻量托管

Gitea 的定位非常清晰:一个用 Go 写的、资源占用极低、开箱即用的 Git 托管服务。它的核心能力包括仓库管理、Issue、Pull Request、Wiki、Webhook、基础 CI(通过 Gitea Actions),以及细粒度的组织和团队权限。它不追求大而全,而是把代码托管这件事做得足够稳、足够快。

我实测过的最小部署:一台 2 核 2G 的云主机,Docker 跑 Gitea + SQLite,日常十几个人的小团队使用完全无压力。内存占用常驻在 200MB 到 400MB 之间,启动时间以秒计。这个资源效率是它最大的竞争力。对于个人开发者、小团队、边缘节点上的代码托管,Gitea 几乎是首选。

但“够用”也意味着边界。Gitea 的内置 CI 能力相比 GitLab CI 还是偏弱,复杂的流水线编排、多阶段构建、制品管理这些需求,Gitea 需要配合外部工具(比如 Drone、Woodpecker)来完成。另外它的代码搜索、大规模仓库的性能表现,在仓库数量上千之后会开始吃紧。所以 Gitea 适合的是:团队规模在几十人以内、CI 需求不复杂、希望运维成本极低的场景。

2.2 GitLab:一体化 DevOps 平台,代价是资源

GitLab 社区版(CE)是这三者里功能最全的。它不只是 Git 托管,而是把代码仓库、CI/CD、制品库、容器镜像仓库、安全扫描、项目管理、监控告警全部塞进了一个平台。你装一个 GitLab,等于装了一整套研发基础设施。

代价也很直接:资源。官方推荐的最低配置是 4 核 8G,但实际跑起来,尤其是开启 CI Runner 之后,8G 内存经常吃紧。我见过不少人在 2 核 4G 的机器上硬装 GitLab,结果就是启动慢、页面卡、CI 排队。GitLab 的 Omnibus 包会把 PostgreSQL、Redis、Nginx、Gitaly、Sidekiq 等一堆组件全部打包进来,每个组件都要吃内存。

GitLab 真正的价值在于“一体化”。如果你的团队需要从需求管理到代码评审到自动部署的全链路打通,GitLab 能省掉大量集成工作。它的 CI 配置(.gitlab-ci.yml)生态成熟,Runner 部署灵活,制品和缓存管理完善。对于中大型团队、需要完整 DevOps 能力的组织,GitLab 是默认答案。

2.3 Gerrit:为代码评审而生的提交门禁

Gerrit 和前两者完全不是一个思路。它的核心不是“托管代码”,而是“控制代码如何进入主干”。在 Gerrit 里,代码不是直接 push 到分支,而是 push 到一个特殊的 refs/for/ 引用,触发一次代码评审。评审通过后,代码才会被合并。这个机制让 Gerrit 成为很多大型开源项目(比如 Android、OpenStack)的代码评审基础设施。

Gerrit 的强项是评审流程的严谨性:支持多级审批、投票规则、提交信息校验、与 CI 的深度集成(每个 patchset 都可以触发验证)。它的弱项也很明显:学习曲线陡峭,普通开发者第一次用 Gerrit 经常搞不清“为什么我 push 不上去”;界面相对朴素;部署和配置比 Gitea 复杂得多。

Gerrit 适合的是:对代码质量要求极高、需要强制评审门禁、团队有专人维护评审流程的场景。如果你只是想要一个代码托管平台,Gerrit 会让你觉得处处别扭;但如果你需要的是“任何代码进主干前必须经过评审和验证”,Gerrit 的设计正好命中。

2.4 一张表看清三者的取舍

维度GiteaGitLab CEGerrit
核心定位轻量代码托管一体化 DevOps代码评审门禁
最低内存512MB 可跑4GB 起步,推荐 8GB2GB 起步,推荐 4GB
部署复杂度低中高中高
CI 能力基础(Actions)完整(GitLab CI)需外部集成
评审流程PR 模式MR 模式强制评审门禁
学习曲线平缓中等陡峭
适合规模个人到几十人几十人到上千人有严格评审要求的团队

这张表不是让你直接选,而是让你先明确:你真正需要的是“托管”“一体化”还是“门禁”。想清楚这一点,后面的部署才有意义。

3. Gitea 部署实操:从 Docker 到生产可用的完整路径

3.1 为什么优先用 Docker 部署 Gitea

Gitea 的安装方式有二进制、包管理器、Docker 三种。我推荐 Docker,原因有三个:一是升级简单,换镜像重启即可;二是依赖隔离,Gitea 需要的数据库、缓存都可以用容器编排;三是迁移方便,把数据卷打包就能搬到另一台机器。

但 Docker 部署有一个关键点容易被忽略:数据持久化。Gitea 的数据分两部分,一部分是仓库和附件(存在 /data 目录),另一部分是数据库。如果你用 SQLite,数据库文件也在 /data 里;如果用 PostgreSQL,数据库要单独持久化。很多人第一次部署时没挂载数据卷,容器一删数据全没,这个坑我踩过。

3.2 单机 Docker 部署的完整命令

先准备目录结构:

mkdir -p /opt/gitea/{data,config} chown -R 1000:1000 /opt/gitea

Gitea 容器内默认用 uid 1000 运行,所以目录权限要对。然后启动容器:

docker run -d --name gitea \ --restart always \ -p 3000:3000 \ -p 222:22 \ -v /opt/gitea/data:/data \ -v /opt/gitea/config:/etc/gitea \ -v /etc/timezone:/etc/timezone:ro \ -v /etc/localtime:/etc/localtime:ro \ -e USER_UID=1000 \ -e USER_GID=1000 \ gitea/gitea:latest

这里有几个细节值得说明。端口 3000 是 Web 界面,222 是 SSH 端口(映射到容器内的 22)。为什么 SSH 端口要用 222 而不是 22?因为宿主机本身的 22 端口通常已经被系统 SSH 占用,映射到 222 可以避免冲突。挂载 /etc/timezone 和 /etc/localtime 是为了让容器内时间与宿主机一致,否则提交时间会差 8 小时,这个坑很隐蔽。

启动后访问 http://你的IP:3000,会进入初始化页面。数据库选 SQLite 最省事,如果预期仓库和用户量较大,建议选 PostgreSQL。初始化时设置管理员账号,然后就可以登录了。

3.3 生产环境必须调整的几个配置

默认配置能跑,但生产环境有几个地方必须改。第一是 SSH 域名和端口。在 app.ini 里,SSH_DOMAIN要设成你的实际域名,SSH_PORT设成 222,否则用户复制出来的克隆地址是错的。第二是ROOT_URL,要设成完整的对外地址(比如 https://git.example.com/),否则 Webhook 和邮件里的链接会指向 localhost。

第三是关闭自助注册。默认允许任何人注册,生产环境应该关掉DISABLE_REGISTRATION = true,由管理员手动创建账号。第四是配置邮件,否则用户无法找回密码。这几个配置改完重启容器即可生效。

提示:修改 app.ini 后需要重启容器,但不要用 docker restart,建议用 docker compose 管理,改配置后 up -d 重建,避免配置缓存问题。

3.4 Gitea Actions 的启用与 Runner 部署

Gitea 1.19 之后内置了 Actions,但默认是关闭的。需要在 app.ini 里开启:

[actions] ENABLED = true

然后部署 act_runner。Runner 需要向 Gitea 注册,拿到注册令牌后启动:

docker run -d --name gitea-runner \ --restart always \ -v /opt/gitea-runner:/data \ -v /var/run/docker.sock:/var/run/docker.sock \ gitea/act_runner:latest

注册时需要在 Gitea 后台生成 token,然后执行act_runner register。这里有个经验:Runner 的标签(labels)要配好,默认标签是 ubuntu-latest,如果你的工作流里写了别的标签,Runner 匹配不上就会一直排队。我建议在注册时显式指定标签,和工作流里的 runs-on 保持一致。

4. GitLab 社区版部署:资源规划比安装命令更重要

4.1 装之前先算清楚内存账

GitLab 部署失败最常见的原因不是命令错,而是内存不够。Omnibus 包默认会启动一堆组件,每个组件都有内存基线。我整理过一份实际观测数据:

组件空闲内存说明
PostgreSQL200-400MB数据库
Redis50-100MB缓存和队列
Gitaly150-300MBGit 仓库服务
Sidekiq200-500MB后台任务
Puma300-600MBWeb 服务
Nginx50MB反向代理

加起来空闲状态就要 1.5G 到 2G,一旦有 CI 任务、仓库操作、后台任务,内存会迅速上涨。所以 4G 内存的机器跑 GitLab 会非常紧张,8G 是舒适线。如果机器内存不够,可以通过配置裁剪组件,比如关掉 Prometheus、关掉不必要的监控,能省下几百 MB。

4.2 Docker 部署 GitLab CE 的标准流程

先设置环境变量,指定外部访问地址:

export GITLAB_HOME=/srv/gitlab mkdir -p $GITLAB_HOME/{config,logs,data}

然后启动容器:

docker run -d --name gitlab \ --restart always \ --hostname git.example.com \ -p 443:443 -p 80:80 -p 2222:22 \ -v $GITLAB_HOME/config:/etc/gitlab \ -v $GITLAB_HOME/logs:/var/log/gitlab \ -v $GITLAB_HOME/data:/var/opt/gitlab \ -e GITLAB_OMNIBUS_CONFIG="external_url 'http://git.example.com'; gitlab_rails['gitlab_shell_ssh_port'] = 2222;" \ gitlab/gitlab-ce:latest

这里gitlab_shell_ssh_port必须设成 2222,和端口映射一致,否则克隆地址里的 SSH 端口是错的。启动后 GitLab 需要几分钟初始化,可以用docker logs -f gitlab观察进度,看到 “gitlab Reconfigured!” 就差不多了。

首次登录用 root 账号,密码在$GITLAB_HOME/config/initial_root_password文件里,24 小时内有效,登录后必须改密码。这个初始密码机制很多人不知道,找不到密码就以为装失败了。

4.3 内存优化:让 GitLab 在 4G 机器上也能跑

如果机器只有 4G 内存,可以通过/etc/gitlab/gitlab.rb裁剪组件。关键配置:

prometheus_monitoring['enable'] = false grafana['enable'] = false alertmanager['enable'] = false node_exporter['enable'] = false redis_exporter['enable'] = false postgres_exporter['enable'] = false puma['worker_processes'] = 2 sidekiq['max_concurrency'] = 10

改完执行gitlab-ctl reconfigure生效。这样能省下 500MB 到 800MB 内存。但要注意,关掉 Prometheus 意味着失去内置监控,如果团队需要监控,建议把监控数据外推到独立的监控系统。

4.4 GitLab CI Runner 的部署与注册

GitLab CI 需要 Runner 来执行任务。Runner 可以装在 GitLab 同一台机器,也可以独立部署。独立部署更推荐,因为 CI 任务会吃资源,和 GitLab 主服务抢内存会影响稳定性。

docker run -d --name gitlab-runner \ --restart always \ -v /srv/gitlab-runner/config:/etc/gitlab-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ gitlab/gitlab-runner:latest

注册 Runner:

docker exec -it gitlab-runner gitlab-runner register \ --url http://git.example.com/ \ --registration-token YOUR_TOKEN \ --executor docker \ --docker-image alpine:latest \ --description "docker-runner"

注册令牌在 GitLab 后台的 CI/CD 设置里。executor 选 docker 最灵活,每个任务在独立容器里跑,互不干扰。但要注意,docker executor 默认不能访问宿主机的 Docker,如果 CI 里需要构建镜像,要挂载 docker.sock 或使用 dind 方案。

5. Gerrit 部署:评审门禁的搭建与配置要点

5.1 Gerrit 的部署形态选择

Gerrit 的部署方式有 war 包直接跑、Docker 镜像、以及配合外部数据库。官方推荐的 Docker 镜像是 gerritcodereview/gerrit。但 Gerrit 对数据库有要求,生产环境建议用 PostgreSQL 或 MySQL,不要用内置的 H2,因为 H2 在并发和持久化上不可靠。

Gerrit 的目录结构比较特殊:/var/gerrit/git存仓库,/var/gerrit/index存索引,/var/gerrit/etc存配置。部署时这几个目录都要持久化。

5.2 Docker 部署 Gerrit 的实操

先准备目录:

mkdir -p /opt/gerrit/{git,index,cache,etc,db}

启动容器:

docker run -d --name gerrit \ --restart always \ -p 8080:8080 \ -p 29418:29418 \ -v /opt/gerrit/git:/var/gerrit/git \ -v /opt/gerrit/index:/var/gerrit/index \ -v /opt/gerrit/cache:/var/gerrit/cache \ -v /opt/gerrit/etc:/var/gerrit/etc \ gerritcodereview/gerrit:latest

29418 是 Gerrit 的 SSH 端口,用于 git push 和 gerrit 命令。8080 是 Web 界面。首次启动后,Gerrit 会生成默认配置,需要进入容器执行初始化:

docker exec -it gerrit java -jar /var/gerrit/bin/gerrit.war init --batch

初始化过程中会问数据库类型,选 PostgreSQL 并填入连接信息。初始化完成后重启容器,访问 8080 就能看到 Gerrit 界面。

5.3 第一个项目与评审流程配置

Gerrit 里创建项目需要管理员权限。登录后进入 Browse -> Repositories -> Create New。创建后,项目的默认权限是“只能通过评审合并”。开发者克隆项目后,push 代码不是 push 到分支,而是:

git push origin HEAD:refs/for/master

这个命令会创建一个 change,进入评审队列。评审人可以在 Web 界面查看 diff、打分、评论。Code-Review +2 且 Verified +1 后,才能点 Submit 合并。这套流程是 Gerrit 的核心,也是它和 Gitea、GitLab 最大的区别。

配置评审规则需要在项目的 Access 权限里设置。默认情况下,只有项目所有者能 +2,普通开发者只能 +1。如果团队需要更细的权限,可以配置 groups 和 labels。这里有个经验:Gerrit 的权限配置非常灵活但也非常容易配错,建议先用默认配置跑通流程,再逐步调整。

5.4 Gerrit 与 CI 的集成方式

Gerrit 本身不提供 CI,需要外部 CI 系统监听 Gerrit 的事件。常见做法是 CI 系统通过 SSH 或 REST API 监听 patchset 创建事件,然后拉取对应 change 进行构建,构建结果通过 Verified 标签回写。

配置 Verified 标签需要在 project.config 里定义 label,并允许 CI 账号打这个标签。CI 账号需要配置 SSH key,并且有权限 push 到 refs/changes/。这个集成过程比 GitLab CI 复杂,但换来的是每个 patchset 都能被验证,代码质量门禁更严格。

6. 部署之后才会暴露的坑:迁移、备份与日常维护

6.1 从其他平台迁移到自建服务的注意事项

迁移是自建 Git 服务绕不开的一步。从公共平台迁移到 Gitea 或 GitLab,最直接的方式是用平台的导入功能。GitLab 支持从 URL 导入仓库,Gitea 也支持迁移。但要注意几点:一是 Issue 和 PR 的迁移通常不完整,很多平台只迁移代码和提交历史;二是 LFS 对象需要单独处理,否则大文件会丢失;三是子模块和 CI 配置需要手动调整。

我自己的做法是:先用导入功能迁移代码,然后手动重建 CI 配置和权限。迁移完成后,用git log --oneline | wc -l对比提交数,确认历史完整。如果仓库很大,迁移可能耗时较长,建议在低峰期操作。

6.2 备份策略:别等数据丢了才想起来

Gitea 的备份相对简单,因为数据都在 /data 目录。停掉容器,打包 /data 即可。但要注意数据库如果是 PostgreSQL,需要单独 dump。GitLab 有内置备份命令:

docker exec -t gitlab gitlab-backup create

备份文件默认在 /var/opt/gitlab/backups。但 GitLab 的备份不包含配置文件(/etc/gitlab),所以配置文件要单独备份。Gerrit 的备份需要备份 git 目录、数据库和 etc 配置。

备份的核心原则是:定期、异地、可恢复。我建议至少每周一次全量备份,每天一次增量(如果支持)。备份完一定要做恢复演练,否则备份等于没有。

6.3 日常维护中最容易忽略的三件事

第一是磁盘空间。Git 仓库会随着时间增长,尤其是包含大文件或频繁提交的仓库。要定期检查磁盘使用,设置告警。GitLab 的制品和 CI 缓存也会占空间,需要配置清理策略。

第二是日志轮转。GitLab 和 Gerrit 的日志如果不轮转,会迅速占满磁盘。Docker 部署时可以通过 log driver 限制日志大小,比如--log-opt max-size=100m --log-opt max-file=3。

第三是版本升级。自建服务需要定期升级以获取安全补丁和新功能。但升级前一定要看 release notes,确认没有破坏性变更。GitLab 的升级尤其要注意版本跨度,不能跨大版本直接升,要按升级路径逐步来。

6.4 安全加固的几个实用动作

自建 Git 服务暴露在内网或公网,安全加固不能省。第一,强制 HTTPS,用 Nginx 或 Caddy 做反向代理并配置证书。第二,关闭不必要的注册和公开访问,所有仓库默认私有。第三,配置 SSH key 认证,禁用密码登录。第四,定期审计用户权限,移除离职人员账号。第五,关注安全公告,及时打补丁。

GitLab 曾经出现过一些高危漏洞,修复方式通常是升级到指定版本。如果暂时不能升级,要按官方公告的缓解措施操作,比如关闭某个功能或调整配置。安全这件事没有一劳永逸,只有持续关注。

7. 我的选型建议:按团队阶段对号入座

如果你是一个人或者三五个人的小团队,想要一个稳定、省心、资源占用低的代码托管,Gitea 是首选。Docker 一条命令跑起来,维护成本几乎为零,需要 CI 的时候加个 Runner 也够用。

如果团队在几十人以上,需要从需求到部署的全链路打通,GitLab CE 更合适。它的学习成本主要在运维侧,但一旦跑起来,研发流程的整合度是其他方案比不了的。前提是机器配置要够,别在 4G 内存上硬撑。

如果你的团队对代码质量有极高要求,需要强制评审门禁,每个提交都必须经过评审和验证才能进主干,那 Gerrit 值得投入学习成本。它的流程严谨性是前两者不具备的,但要做好“开发者需要适应期”的准备。

最后说一个我自己的体会:自建 Git 服务不是装完就结束,而是一个持续维护的过程。选型时多花一天想清楚,后面能省下几十天的折腾。部署时把数据持久化和备份做好,比追求功能全面更重要。真正让团队难受的从来不是“功能少了一个”,而是“数据丢了”或者“服务挂了没人会修”。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询