ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

从GitLab迁移到Gitea:轻量级代码托管如何降低90%资源消耗

2026/9/10 17:01:09 拓冰建站 浏览量
从GitLab迁移到Gitea:轻量级代码托管如何降低90%资源消耗 1. 先交代背景GitLab 把我们的服务器压垮了1.1 事情的起因一台 4GB 内存服务器的真实困境事情得从我们团队那台“年迈”的服务器说起。去年年中我们内部代码托管一直跑在 GitLab 上版本是 13.x部署方式是最常见的 Omnibus 一键安装包。刚开始人少项目少一切正常也就偶尔重启一下。但随着前端、后端、算法三个小组加进来仓库数量突破 30 个CI 流水线开始跑起来之后问题就来了——机器内存常年飘红SSD 磁盘空间从 120GB 一路涨到只剩不到 20GB平均负载经常冲到 7、8整个服务器响应慢到令人发指。最要命的是每次 GitLab 后台跑备份任务或者 Sidekiq 处理异步队列时CPU 直接吃满前端同事 push 代码都能感受到明显的延迟。我一度以为是云厂商的问题结果登录服务器一看好家伙GitLab 的各个进程加起来占了将近 9GB 内存光是一个 PostgreSQL 就吃了 2.8GBRedis、Sidekiq、Prometheus、Grafana 这些附属组件一个不少。这还只是 13.x 版本如果继续往上升级22 版本之后的内存需求只会更高。那段时间我每天上班第一件事就是看一眼监控面板确认服务的存活状态整个运维体验基本等同于“给老破小房子做精装修”。后来我们做了一次容量评估发现如果不做迁移最直接的方案就是加钱升级服务器配置内存从 4GB 升到 16GBSSD 从 120GB 换到 500GB。云厂商给的报价不贵但问题是GitLab 的核心痛点并不是这一次性扩容就能解决的。它是一次性部署完后面每次大版本升级都像渡劫——升级前要看升级路径文档、备份、检查重启、处理依赖冲突光想到这些我就头大。于是我开始认真思考我们真的需要 GitLab 的全部功能吗有没有更轻量、更省心、完全够用的替代方案1.2 GitLab 为什么会这么“吃”资源在讨论替代方案之前得先搞清楚一件事GitLab 为什么这么吃资源这直接关系到我们选型的判断标准。GitLab 严格来说不是一个单纯的 Git 代码托管服务它更像是一整套 DevOps 平台。你装一个 GitLab等于同时装了 PostgreSQ L数据库、Redis 缓存、Nginx 反向代理、Sidekiq 异步任务队列、Gitaly 存储服务、Prometheus 监控系统、Grafana 可视化面板还有一大堆默认开启的 Background Jobs。说得直白一点它把一家人工智能公司搞 DevOps 的全家桶都塞进了你那一台小服务器里。而且 GitLab 的所有组件都是常驻进程不管你的团队是用还是不用它们都在内存里待命。比如 Prometheus 默认开启监控Grafana 默认附带仪表盘这些对 5 到 10 个人的小团队来说基本用不上但也无法在 Omnibus 模式下轻松砍掉。网上大家常说的“GitLab 最少要 4GB 内存才能跑起来”指的是能启动真正流畅使用 16GB 起步。这一点应该很多人都有体会。最让我头疼的其实是磁盘占用。我们团队代码量并不大所有仓库的 .git 目录加起来才 1.2GB但 GitLab 整体安装完包括日志、CI 缓存、备份文件、数据库文件轻轻松松突破 10GB。标题里写的“10GB vs 600MB”就是这么来的——我们当时的 GitLab 服务器真实占用超过 10GB而后来迁移到 Gitea 后整个部署的磁盘占用只有 600MB 左右。这个对比放到任何人面前答案都一目了然。1.3 我们尝试过的优化手段以及为什么最终放弃在正式迁移之前我也尝试过一些常规优化手段这里给同样被 GitLab 折磨的人分享一下。第一招关闭不需要的组件。Omnibus 模式可以在/etc/gitlab/gitlab.rb里把 Prometheus、Grafana、Mattermost 等显式设为disabled确实能省一些内存大概能砍掉 1 到 2GB 的样子但效果有限核心的 PostgreSQL、Redis、Sidekiq、Gitaly 还是得常驻。第二招调低 Sidekiq 并发数和 Puma worker 数量。把puma[worker_processes]从默认值改到 2sidekiq[max_concurrency]从 25 降到 5。这个操作能明显降低内存消耗但代价是 Web 操作和 CI 任务推送变得迟钝尤其是团队多人同时操作时卡顿感非常明显。机器小就是小怎么调都像在螺蛳壳里做道场。第三招定期清理日志和 CI 缓存。GitLab 的日志增长速度很夸张CI runner 的临时文件、构建缓存、artifacts 积攒一段时间磁盘空间就告急。我写了一个 cron 脚本每天清一次日志但效果只是延缓问题没有解决根本。最终让我彻底放弃 GitLab 的是一次大版本升级事故。从 13.x 升到 14.x升级脚本跑了将近两个小时中途 PostgreSQL 报了一个索引兼容错误整个升级流程中断。我花了一个下午查文档、跑修复命令最后虽然恢复了但那次经历让我彻底意识到我们团队的核心需求只是“托管代码 管理成员 简单的代码评审”GitLab 的 80% 功能CI/CD 平台、依赖扫描、安全合规、史诗级项目规划对我们来说都是“高级负担”。2. 替代方案选型为什么是 Gitea 而不是其他2.1 轻量级代码托管工具都有哪些选择当时我们列表里的轻量级方案主要锁定在 Gitea 和 Gogs 之间顺带也看了 Gitaly 之外的 Gitea 生态。先说 Gogs它的历史其实比 Gitea 更早到现在依然是 Go 语言编写的轻量级 Git 服务。但 Gogs 的问题是社区更新节奏明显放缓Issues、PR、Wiki 等模块的功能丰富度不如 Gitea插件生态也偏弱。Gitea 是从 Gogs 分叉出来的早期版本界面都有 Gogs 的影子但在社区活跃度、版本迭代速度、多平台支持上走得更快更稳。对了还有一个冷门选项叫 Gitness是 Harness 开源的一个代码托管服务也主打轻量和内置 CI/CD。但它的社区用户群体还比较小中文资料少团队遇到问题时排查成本会高。对于追求稳、资料多、社区活跃的团队来说Gitea 是最稳妥的选择。Gitea 官方文档支持中文社区论坛里有大量的部署案例和故障排查帖子这个“遇到问题能搜到答案”的属性在选型时非常重要。如果你的团队已经有现成的 Kubernetes 集群也可以考虑 Gitea 的 Helm Chart 部署一条命令就能拉起一个高可用实例。但我们在选型时强调“轻量级”就是想摆脱这种复杂的底层依赖——我们只想要一个纯 Go 单二进制文件跑起来的服务简单的才是最适合的。2.2 Gitea 和 Gogs我们怎么选Gitea 和 Gogs 的区别可以用一个生活化类比来解释Gogs 像一个稳定但更新频率低的老牌笔记本能用但功能就停留在那个年代Gitea 像同一块模具里打磨出来、持续迭代的升级款保留了轻量的底子但把常用功能不断做厚。具体差别体现在几个方面Gitea 支持的内置功能更多比如 ActionsCI/CD、Packages包管理、Projects看板、Releases发版、Webhooks、Migrations外部仓库迁移等。Gogs 这些功能要么没有要么比较简陋。就拿最常用的 Webhook 来说Gitea 支持仓库级和组织的 Webhook 配置事件类型非常细化而 Gogs 的 Webhook 选项少很多配起来也没那么顺手。另一个决定性的点是数据库支持。Gitea 官方支持 SQLite、MySQL、PostgreSQL迁移时兼容性更好Gogs 也支持多种数据库但在某些版本的连接稳定性、升级迁移路径上明显不如 Gitea 平滑。我们当初有一坨历史仓库数据要从 SQLite 直接迁出来用 Gitea 的官方命令很快就搞定这一点让我印象很深。社区活跃度方面Gitea 在 GitHub 上有四万多的 Star提交历史非常频繁几乎每个月都有小版本更新Gogs 的更新节奏慢得多甚至有些老用户转投了 Gitea 阵营。对我们这种想一劳永逸、不想频繁折腾平台的团队来说选择社区活跃度高、迭代稳定的项目本身就是一种保险。毕竟如果选了一个快停摆的开源项目后续维护成本会很高。2.3 600MB 到底省在哪里关于 600MB 这个数字我稍微解释一下。这其实是 Gitea 官方容器镜像的体积也是我们实际部署后整个服务目录的占用大小。为什么能做到这么小因为 Gitea 是基于 Go 语言编译的单一二进制文件启动时不依赖于任何外部运行时环境。它不需要装 JVM不需要单独的 Web 服务器不需要额外的语言解释器所有静态页面、模板、资源文件都直接编译进二进制文件里。部署的时候你只需要把这一个二进制文件丢到服务器上配上数据库它就能直接跑起来。而我们之前 GitLab 使用的是 Ruby 和 Go 混合架构还内置了 PostgreSQL、Redis、Nginx、Sidekiq 等一堆组件体积自然做不到小。Gitea 的简单架构让它的安装包只有不到 100MB加上数据库文件、日志文件整个服务目录通常都能控制在 300MB 到 600MB 这个区间。对比 GitLab 动辄几个 GB 的占用光这一点就能让我们省下不少磁盘空间。如果你担心二进制文件的安全性和可升级性官方提供了 GPG 签名校验每次发布都会有详细的安全公告。而且升级很简单——直接把老二进制文件替换成新版本运行一下迁移命令几秒钟搞定。我们实际跑下来从 Gitea 1.20 升级到 1.22整个操作不超过五分钟。这在 GitLab 时代是完全不敢想象的。2.4 功能覆盖度摸底日常开发会用到的功能是否够用选型时我们最担心的问题就是 Gitea 功能“缩水”毕竟团队日常要用到的不只是 push/pull 代码。我花了两天时间把团队 GitLab 上的核心功能逐项列出来在 Gitea 上做了一次“功能覆盖度摸底”结果比预想的好很多。代码托管的基础功能分支管理、标签管理、合并请求Pull Request、代码评审/评论、受保护分支、文件在线预览编辑Gitea 全部都有并且体验相当流畅。特别是合并请求的界面虽然交互比 GitLab 简单但该有的功能比如冲突检测、合并按钮、关闭分支选项、审查者指定都是齐的。团队成员管理方面Gitea 支持组织Organization和团队Team两级权限体系能精确控制每个仓库的可见性公开、内部、私有还能关闭 guest 访问。这个对同时管理多个项目组、有外包成员参与的团队来说特别重要。CI/CD 方面Gitea 原生支持 Actions基于 GitHub Actions 的语法团队可以把原有的 GitLab CI 配置用 act_runner 的方式平移到 Gitea不需要额外装 Jenkins。虽然 Gitea Actions 的生态没有 GitHub Actions 丰富但常用的构建、测试、部署流程都能搞定。如果不想用 Actions也可以用 Webhook 把事件推给 Jenkins 或其他构建系统。剩下的还有 Wiki、Issue 管理、里程碑、看板、Release 发布、Webhook、仓库迁移、Mirror 镜像以及近几年新增的 Package Registry。你可能会发现Gitea 在功能完整度上其实远远超过了“轻量级”这个词给人的想象。它更像是一个“做了减法的 GitLab”把核心链路做到够用、好用把对企业服务里那些复杂又占资源的高级功能去掉或做成可选插件。3. 迁移实操从 GitLab 到 Gitea 的完整过程3.1 迁移前的备份和方案设计正式动手之前我先把整个迁移方案在纸上过了一遍。迁移的本质不只是把代码仓库搬过去更要保证团队成员、Issues、Wiki、Webhooks 这些“软件资产”也能平滑过渡。GitLab 的仓库数据在服务器上的存储路径是/var/opt/gitlab/git-data/repositories里面是裸仓库目录如果直接用git clone --mirror的方式搬代码最简单但会丢失 Issues、MR、Wiki 和成员信息后期补起来非常麻烦。我们的策略是分两步走。第一步先在 Gitea 侧创建一个全新的空实例把基础配置调好第二步在确认新实例稳定后再通过 Gitea 内置的迁移功能从 GitLab 拉取完整的项目数据。这个方法的好处是并行验证——旧平台不着急关停等团队在新平台跑几周确认没有问题后再切换域名和 CI 配置。备份方面我做了三层保险第一层用git clone --mirror把所有裸仓库备份到本地 NAS第二层导出 GitLab 的数据库备份文件第三层记录所有仓库的 Webhooks 配置、成员角色设定、受保护分支策略。迁移最忌讳“边迁边忘”留一份完整的清单会让整个过程有条不紊。这里插一句题外话如果你只想快速搬仓库暂时不管 Issues 和成员其实一条命令就能搞定。Gitea 的迁移向导非常友好填一下 GitLab 的地址和 Token选择要迁移的仓库起点是代码后续还能单独跑 Issues、Wiki 的迁移任务。但建议还是全量迁移成员角色、Issues、Wiki 都是团队协作的历史沉淀丢了很可惜。3.2 在 CentOS 上部署 Gitea我们的生产服务器是 CentOS 9 StreamGitea 的部署方式多种多样官方二进制、Docker、Helm、包管理器。我在测试环境先试了 Docker 部署一条命令就能起服务非常快捷但考虑到生产环境有系统防火墙、SELinux 和多个 Web 服务共存的情况最终还是选了官方二进制方式这样对进程资源控制和管理更直接。安装的步骤很简单直接从 Gitea 官网下载对应架构的二进制文件cd /opt wget -O gitea https://dl.gitea.com/gitea/1.22.1/gitea-1.22.1-linux-amd64 chmod x gitea然后创建专用用户因为 Gitea 官方推荐不要用 root 运行这一点和 GitLab 是类似的都建议独立用户隔离权限useradd --system --shell /bin/bash --create-home --home-dir /var/lib/gitea gitea mkdir -p /etc/gitea /var/lib/gitea/{custom,data,indexers,public,log} chown -R gitea:gitea /var/lib/gitea chown -R gitea:gitea /etc/gitea这些目录都是有讲究的/var/lib/gitea/data放 SQLite 数据库和仓库数据/etc/gitea放主配置文件app.ini/var/lib/gitea/log放运行日志。我习惯把 log 目录单独挂载到一个容量较大的分区防止日志膨胀撑爆系统盘。接着写一个 systemd service 文件放在/etc/systemd/system/gitea.service里这样可以用 systemctl 管理启动、停止和开机自启[Unit] DescriptionGitea (Git with a cup of tea) Afternetwork.target [Service] Usergitea Groupgitea WorkingDirectory/var/lib/gitea/ ExecStart/opt/gitea web --config /etc/gitea/app.ini Restartalways RestartSec5 [Install] WantedBymulti-user.target启动之前有个小坑就是 SELinux 的上下文问题。CentOS 9 默认开启 SELinux如果直接启动可能会因为/opt/gitea的上下文不对导致无法执行。解决办法是把二进制文件的 SELinux 类型标记为bin_t或者把 SELinux 设为 permissive 模式但生产环境不建议关闭 SELinux所以我用了前者chcon -t bin_t /opt/gitea搞定之后systemctl start gitea systemctl enable gitea浏览器打开http://服务器IP:3000就能看到 Gitea 的首次配置页面了。3.3 Gitea 核心配置文件 app.ini 拆解Gitea 安装完成后第一次访问 Web 界面会让你填写安装配置其实它就是帮你生成/etc/gitea/app.ini。虽然向导能做基础配置但上线之前我建议还是手动过一遍 app.ini 里的关键项因为很多细节是 Web 界面照顾不到的。最关键的是server段配置站点域名、HTTP 端口和 ROOT_URL。比如我们用 Nginx 反向代理域名是git.example.com那么[server] PROTOCOL http HTTP_ADDR 127.0.0.1 HTTP_PORT 3000 DOMAIN git.example.com ROOT_URL https://git.example.com/ DISABLE_SSH false SSH_DOMAIN git.example.com SSH_PORT 22这里的ROOT_URL必须和实际的访问地址完全一致否则会出现克隆地址错误、页面跳转异常这类诡异问题。HTTP_ADDR 写成 127.0.0.1 而不是 0.0.0.0是因为我们让 Nginx 在本机反代不直接对外暴露 3000 端口。然后是repository段这里能设置默认分支、仓库默认可见性和上传限制。我们团队会把新仓库默认设为私有避免代码意外公开[repository] DEFAULT_PRIVATE private DEFAULT_BRANCH main ENABLE_PUSH_CREATE_USER true ENABLE_PUSH_CREATE_ORG true如果遇到上传大文件被拒绝的情况可以调整[server]段的LFS_START_SERVER和[repository.upload]段的FILE_MAX_SIZE。Gitea 默认单文件上传上限是 3MB团队如果要传设计稿或产物包需要调大。我设置成 20MB 时遇到过一次 Nginx 层client_max_body_size的限制所以记得同步改 Nginx 的配置。数据库选型我们用了 SQLite因为团队规模小并发量低SQLite 完全够用。如果你们有几万 Issue 或者超高频的 API 调用建议用 PostgreSQL。SQLite 的配置非常简单[database] DB_TYPE sqlite3 PATH /var/lib/gitea/data/gitea.db最后是[service]段控制注册、登录行为我们默认关闭开放注册和禁用 OpenID 登录只允许管理员手动创建账号[service] DISABLE_REGISTRATION true REQUIRE_SIGNIN_VIEW true ENABLE_NOTIFY_MAIL trueGitea 的邮箱通知功能需要一个 SMTP 服务如果你有现成的企业邮箱在[mailer]段里配置一下就能发邮件告警了。没配置邮件也不影响核心使用只是某些密码找回、邮箱验证功能会受限。3.4 数据迁移仓库、用户、Issue、Wiki 全量搬移基础环境就绪后进入重头戏——数据迁移。我强烈推荐 Gitea 自带的“创建迁移”功能入口在“站点管理 → 管理面板 → 迁移”或者在新建仓库的界面选择“从 GitLab 迁移”。只需要填三个东西GitLab 地址、Access Token、仓库名列表。GitLab 的 Access Token 需要提前在 GitLab 个人设置里创建授予api和read_repository权限。然后在 Gitea 迁移页面填入https://gitlab.example.com、TokenGitea 会自动拉取账号下有权限的项目列表勾选要迁移的即可。这里有个需要特别注意的点——如果你 GitLab 开了双因素认证2FAToken 的生成方式会略有不同最好提前拿测试仓库试一次迁移流程。实际迁移过程中我最担心的是大仓库超时。我们最大的一个 monorepo 仓库有 5.6GB包含 8 万多次提交。迁移时如果网络不稳定传输中断后 Gitea 会重新开始。我的经验是把单个仓库容量偏大的先迁网络空闲时段操作并且提前把仓库的 LFS 对象用 GitLab 的导出功能单独备份。迁移完成后记得检查三件事第一仓库的默认分支是否和原来一致第二Issues 里的按指派人、里程碑、标签是否完整第三Wiki 页面是否成功搬过去。我们当时有一个仓库的 Wiki 迁移失败排查后发现是仓库名里有一个中划线导致 Gitea 在生成 Wiki 仓库名时格式不同。解决办法是在 Gitea 界面手动创建 Wiki 后直接用git push --mirror把旧的 Wiki 仓库推上去。用户和成员的角色权限Gitea 有一套“仓库所有者Owner、写Write、读Read”三级权限体系和 GitLab 的 Owner、Maintainer、Developer、Reporter 不太一样。迁移后需要花一点时间在组织管理里把成员角色重新设定一遍。好在 Gitea 支持批量操作——进入组织页面选中多个仓库统一设置团队权限效率很高。3.5 配置 Nginx 反向代理和 HTTPS让 Gitea 在 3000 端口裸跑不是不行但生产环境要么有内部域名、要么有公网域名总归要落到 443 端口上用 Nginx 反代。我们的 Nginx 配置如下server { listen 80; server_name git.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name git.example.com; ssl_certificate /etc/nginx/ssl/git.example.com.crt; ssl_certificate_key /etc/nginx/ssl/git.example.com.key; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; } client_max_body_size 50m; }这里有几个容易踩的坑。第一client_max_body_size必须大于 Gitea 里配置的上传上限否则 push 大文件时浏览器会报 413 错误这个错我前前后后排查了一个钟头才发现是 Nginx 层的限制。第二Upgrade和Connection头必须保留因为 Gitea 的 Web 终端和内置的 SSH over HTTPS 协议需要 WebSocket 支持如果不配某些页面会一直转圈。第三X-Forwarded-Proto一定要传https否则 Gitea 在生成克隆地址时会误判为 http导致用户在命令行里复制粘贴一个错误的地址。HSTS 我也开了包括 31536000 秒的 max-age。这样浏览器访问过一次后后续所有请求都会强制走 HTTPS能防止会话被劫持。最后一个安全细节是如果 Gitea 和 Nginx 在同一台服务器上记得把 Gitea 监听地址改成 127.0.0.1避免 3000 端口暴露在公网上被扫描。我见过有人把 Gitea 默认 0.0.0.0 监听结果被人扫到端口后尝试暴力破解。4. 迁移后第一周的真实体验与问题排查4.1 资源占用前后对比这波省得很值迁移完成后我顺手做了个前后对比数据贴出来应该能说明问题。迁移前的 GitLab 13.x 部署光进程就占用了 9.2GB 内存服务器空闲时 CPU 也经常有 5% 到 10% 的波动因为后台有各种定时任务和监控采集。迁移到 Gitea 后内存占用常年稳定在 250MB 左右CPU 几乎只有请求进来时才动一下磁盘消耗也在可接受范围内。生产环境切到 Gitea 之后我做的第一件事就是减配。原来的 4 核 8GB 服务器直接降到 2 核 2GB云厂商每个月的账单少了一半左右。这在公司财务眼里是很直观的成绩。而且因为 Gitea 是单进程你完全可以把 Gitea 和 CI Runner 放同一台机器上跑节省一台 CI 专用服务器的租用成本。4.2 Webhook、API Token、上传限制等常见配置问题迁移后大家用得最多的是 WebhookGitea 的 Webhook 配置入口在仓库的设置 → Web 钩子。可以创建 HTTP 请求支持 push、pull request、issues、release 等事件类型。因为我们的内部系统需要接收 push 事件用于自动构建我配了一个 Webhook发送 JSON payload 到一个内部接口。这里有一个坑需要注意Gitea 的 Webhook 默认使用 HMAC-SHA256 签名header 里带X-Gitea-Signature。如果你的接收端不校验签名那没问题直接 POST 就行如果要校验一定要确认签名算法和密钥配置一致。我们排查过一次 webhook 回调失败服务端只返回 500最后发现是接收端程序把 header 名大小写搞错了。HTTP header 是大小写不敏感的但代码里写死了小写某些 HTTP 框架会统一转成小写某些不会这种细节最浪费时间。API Token 的问题也很多人问。Gitea 的 API Token 在用户设置的“应用”页面生成生成时要勾选权限读仓库、写仓库等。常见的报错“login failed, check api token or gitlab version”通常出现在使用旧工具连接 GitLab 的场景迁移后如果还想用之前那些 CLI 工具需要重新在 Gitea 生成 Token并且确保工具支持 Gitea API。Gitea 的 API 以/api/v1开头和 GitLab API 格式有差异写脚本时注意兼容。还有一个高频问题就是仓库上传大小限制。Gitea 默认单文件 3MB我们内部有同事要传一个 15MB 的安装包到仓库 Release 里直接被拒。除了之前说的改[repository.upload]段的FILE_MAX_SIZE还要看看用的是不是 LFS。如果仓库里已经用了 Git LFS[server]段的LFS_START_SERVER也要打开并且要确认 Nginx 的 body 大小限制。经过这几步调整大文件上传就流畅了。4.3 团队协作差异大家需要适应的几个点从 GitLab 切到 Gitea团队最大的感受是“快”但也经历了几个小阵痛期。第一个是界面语言。GitLab 有些同事习惯看英文界面Gitea 默认是跟随浏览器的语言设置新来的同事如果浏览器是英文环境看到的界面就是英文如果之前习惯了中文界面这会有点懵。可以在用户设置的“界面语言”里强制选成中文。第二个是 Merge Request 和 Pull Request 的叫法差异。GitLab 叫 Merge RequestGitea 叫 Pull Request。虽然底层都是合并请求但代码里文档、自动化脚本里的正则匹配规则都要改一下。我们内部有个机器人原来监听 GitLab MR 事件的关键字是merge_request迁移到 Gitea 后要换乘pull_request去匹配 Webhook payload否则机器人会一直静默不工作。第三个是分支保护策略的配置方式。GitLab 可以在项目的设置里按分支正则配置保护规则Gitea 也支持但需要在仓库的“分支”页面里逐条添加。保护规则支持main、release/*、dev/*这些通配符配置时注意别把dev误保护了否则开发同学都要走合并请求流程会徒增沟通成本。4.4 几个容易踩的坑和排查技巧这里整理一份我们迁移过程中真正遇到过的坑给你做个避坑参考。第一个坑是 Gitea 内置 SSH 的端口问题。Gitea 的 SSH 服务并不总是和系统 SSH 共用端口。默认情况下如果你用 systemd 部署Gitea 的 SSH 监听在 2222 端口而系统 SSH 占用了 22 端口。这会导致用户克隆代码时看到的地址是ssh://gitgit.example.com:2222/owner/repo.git。如果你的团队希望用标准的 22 端口需要把 Gitea 的SSH_PORT改成 22并且把系统 SSH 挪到其他端口或者部署时直接用内置 SSH 功能代替系统 SSH。我们当时没有改因为团队习惯用 HTTPS 克隆问题不大但对重度 SSH 用户来说这是必须考虑的。第二个坑是 CVE 类型的告警。有些安全扫描工具会检查 GitLab 的版本迁移后扫描工具会认为 Gitea 是“未知软件”或者直接忽略这个不是问题。不过 Gitea 本身也会涉及到一些安全问题建议开启 Gitea 官方安全通告邮件及时关注版本升级。第三个坑是仓库的容量和数量限制。Gitea 的默认配置对单仓库容量没有硬性限制但如果你用 SQLite高并发写入时会出现database is locked的报错。我们有一次做全量迁移几个同事同时 push 代码配合 Webhook 回调SQLite 就报过一次 write lock。解决办法是临时把并发写操作错峰或者直接换成 PostgreSQL。团队如果超过 10 人并发频繁我建议选型时就上 PostgreSQL省得后期换库。第四个坑是反向代理下的克隆地址生成。如果 Nginx 配置里没有正确传递X-Forwarded-Proto或 ROOT_URL 配置不对用户在网页上看到的仓库地址会是http://而不是https://导致 clone 失败。排查思路很简单访问一个仓库页面看地址栏和“克隆”按钮给出的 URL 前缀是否一致不一致去改 app.ini 的ROOT_URL。第五个坑是系统升级。Gitea 升级流程虽然极其简单下载新二进制 → 替换 → 重启但要注意大版本之间的升级顺序比如 1.20 到 1.22 需要先升到 1.21再升 1.22不能跨大版本直接跳。这个和 GitLab 升级路径的逻辑一样只是 Gitea 的升级速度快到可以忽略这个烦恼。升级前记得备份 SQLite 数据库直接cp gitea.db gitea.db.bak就行几秒钟搞定的备份换来的是万无一失。5. 最后想说什么场景适合迁移什么场景建议保留 GitLab写到这里很多人可能会觉得我在“黑” GitLab、吹 Gitea其实不是。GitLab 的定位是全家桶 DevOps 平台它的 CI/CD、安全扫描、合规审计、甚至 dependency bot 这类功能在企业级场景下是刚需。如果你的团队超过 50 人有复杂的权限矩阵、严格的审计需求、多环境多集群的部署流程GitLab EE 的能力边界远远超出 Gitea这时候硬换 Gitea 反而是明显的倒退。但如果你跟我当时的处境类似——团队 10 人左右代码托管是核心需求CI/CD 已经用 GitHub Actions 或者 Jenkins 替代服务器资源紧张维护能力有限——那 Gitea 就是性价比极高的选择。它不会像 GitLab 一样在凌晨两点让你爬起来修数据库也不会因为一次版本升级打断团队一整个下午的开发节奏。最后分享一个小经验迁移前给自己留三天的“过渡期”把 GitLab 停写权限设为只读、保留所有数据让团队在 Gitea 上正常开发一周。如果一周内没有重大遗漏功能再把 GitLab 的机器真正下线。这个“灰度切换”的节奏比我当初选择“一步到位”顺利得多。如果你正在 GitLab 和轻量级方案之间纠结希望这篇实操记录能帮你省掉一些试错时间。