Gitea 是一个用 Go 语言编写的开源 Git 托管服务我接触它主要是因为要给团队搭一套完全自控的私有代码仓库。当时的需求很明确代码必须放在自己的服务器上权限由内部管理资源占用不能太高运维门槛越低越好。Gitea 几乎满足了我对这个平台的全部预期——内存常驻大约 300MB 左右一个二进制文件加一个 SQLite 数据库就能完整跑起来从部署到把第一个仓库推上去半小时内可以全部搞定。这篇文章就是我在这套平台上沉淀下来的基本操作手册覆盖部署、初始化、仓库创建、SSH 配置、分支保护、权限管理、备份与排查。刚接触自建 Git 服务的开发者可以照着做想把手头团队代码管理收拢到私有环境的技术负责人也能从中找到可以直接复用的方案。1. 先想清楚自建 Git 托管Gitea 凭什么合适代码托管这事很多人第一反应是直接用公共平台不就行了。公共平台确实方便但企业内部代码、未公开的产品原型、特殊行业合规要求下的资产通常不适合放在第三方平台。自建一套托管服务意味着代码永远留在自己的服务器上账号权限完全由自己控制还能在无外网的环境中正常使用。对研发效能团队来说自建平台还意味着可以深度集成内部的持续集成、工单系统和消息通知这种定制自由度是第三方 SaaS 给不了的。而选 Gitea核心看中的就是它在满足这些需求的同时没有被复杂度拖垮。1.1 轻量是表象真正的红利是低运维成本Gitea 用 Go 编写整个服务就是一个二进制程序部署几乎没有外部依赖。之前我试过其他开源 Git 平台安装包里有一堆组件数据库要求高内存占用动不动几个 G对没有专职运维的小团队来说光是排障就够喝一壶。Gitea 的组成非常简单一个可执行文件、一个数据库文件默认 SQLite、一个存放裸仓库的目录仅此而已。这种简单模型带来的收益用下来才真正有体会。升级就是把新版本替换掉旧版本迁移就是把数据目录整个拷贝走备份就是打一个压缩包。没有复杂依赖链意味着出故障的概率低出了问题排查链路也短。打个不一定恰当的比方它像一台傻瓜相机没有一堆镜头和配件但日常拍照完全够用而且你不用担心哪个零件年久失修。对 5 到 20 人的小团队来说这种低运维成本往往比功能齐全更重要。1.2 对比全功能平台Gitea 主动舍弃了什么市场上并非只有轻量型这一条路线。有的开源 Git 平台功能覆盖非常全面从代码托管、持续集成、制品库到监控告警全包在里面听起来很美好但代价是部署复杂度高、资源需求大、配置项多到让人头晕。我在早期选型时也心动过后来冷静评估了一下团队实际用量发现那些高级功能大概只有 20% 的日常场景会用到而为了那 20% 的功能却要为 100% 的复杂度买单不划算。Gitea 主动舍弃了这些全功能平台的重型模块把核心体验做得足够舒服仓库管理、Pull Request、Issue、Wiki、项目看板、Webhook、分支保护、代码搜索这些日常开发里真正高频的能力都覆盖到了。它支持 Git LFS 大文件存储也内置了与主流 Actions 语法兼容的 CI/CD 能力需要时可以扩展 runner 来跑流水线。也就是说它并非功能单薄而是把用不到的重给剔除了留下的都是务实选项。1.3 Gitea 的功能全景与典型使用场景我实际使用下来Gitea 的核心能力大致可以归为几类仓库层面支持公开、私有、镜像、Fork、Watch 和 Star协作层面覆盖 Pull Request、Issue、里程碑、看板和 Wiki权限层面提供用户、组织、团队、仓库四级权限模型认证层面支持本地账号、LDAP、OAuth2 和 SMTP 邮件集成扩展层面有 Webhook、Git Hooks 以及内置 Actions。这些功能加在一起足以支撑一个小团队的完整研发流程。典型场景也很有代表性。最常见的是企业内部代码托管把所有私有仓库统一迁移到内网 Gitea既满足合规要求又能集中管理权限。其次是个人知识库与笔记备份Git 本身就是版本管理利器配上 Gitea 的 Web 界面可以在任意设备上浏览和提交。还有教学场景老师在 Gitea 上建课程仓库学生通过 Pull Request 交作业评审过程透明可追溯体验很顺畅。我个人最推荐的用法是把它作为团队的代码流转中心配合轻量持续集成跑测试和构建整个链路非常清爽。2. 部署与初始化从零到可用的半小时部署方式直接决定了你后续所有维护操作的复杂度所以这一步值得认真选。我把几种常见方式的实际体验对比列出来再给出我最推荐的一套完整配置。2.1 部署形式选型三种方式怎么挑Gitea 官方支持二进制、Docker 和包管理器三种主要部署方式。包管理器部署比如通过 apt、yum 安装最省事一条命令装完但软件源里的版本往往滞后如果你想用最新功能或者指定的兼容版本这种方式的灵活性就不够我不太推荐用于正式环境。二进制部署是把官方编译好的可执行文件放到服务器上配合 systemd 管理进程。优点是资源占用最可控不依赖 Docker 环境适合极其精简的服务器缺点是升级和回滚都需要手动处理文件保留多个版本时要自己维护目录结构。Docker Compose 部署是我个人最推荐的环境隔离、配置集中、升级和回滚都只是改一下镜像版本号加一行命令数据目录挂在宿主机上备份非常透明。三种方式的取舍我整理成了一个小对比表部署方式优点缺点适合场景包管理器安装命令简单版本滞后、不易指定版本临时体验、测试环境二进制资源占用最小、无 Docker 依赖升级回滚全手动极简服务器、资源受限Docker Compose升级回滚方便、数据目录清晰需要宿主机有 Docker 环境绝大多数正式环境2.2 Docker Compose 文件逐项拆解下面这份 compose 文件是我在项目里实际使用的精简版每一行都有明确作用。先看整体version: 3 services: gitea: image: gitea/gitea:1.22 container_name: gitea environment: - GITEA__APP_NAME内部代码托管平台 - GITEA__RUN_MODEprod - GITEA__SERVER__DOMAINgit.example.local - GITEA__SERVER__SSH_PORT2222 - GITEA__SERVER__ROOT_URLhttps://git.example.local - GITEA__DATABASE__TYPEsqlite3 - TZAsia/Shanghai volumes: - ./data:/data - ./config:/config ports: - 80:3000 - 2222:22 restart: always几个关键点值得展开说。环境变量里GITEA__SERVER__ROOT_URL决定了用户在仓库页面看到的克隆地址拼出来什么样如果这里写错网页上生成的git clone链接就会跟着错。它通常应该和你实际访问的地址保持一致比如通过域名加 HTTPS 访问就写成https://git.example.local。GITEA__SERVER__SSH_PORT要格外小心容器内 Gitea 的 SSH 默认监听 22 端口但宿主机自己的 SSH 通常也占用了 22所以我把容器端口映射到宿主机的 2222同时告诉 Gitea 对外暴露的 SSH 端口是 2222。数据卷部分我习惯把数据目录和配置目录分开挂载。./data下存放所有裸仓库、SQLite 数据库、附件和 LFS 对象./config用于持久化配置文件。这样做备份的时候就非常清晰打包这两个目录就相当于完成了 90% 的备份工作。最后注意restart: always保证服务器重启后 Gitea 能自动拉起这一行在长跑环境中几乎是必须的。2.3 首次访问与初始化配置的关键选项容器起来之后浏览器访问服务器 IP 或域名就会进入初始化配置页面。这个页面有四个选项值得逐个看清楚它们决定后续使用体验。数据库类型我首推 SQLite。它的优势是零配置、单文件、迁移方便对大多数小团队来说性能完全够用。只有当你的并发写入量非常大或者团队已经有一整套 MySQL、PostgreSQL 运维体系才建议选择外部数据库。其次是域名和基础 URL直接填你在 2.2 里配置的地址即可注意保持一致。然后是管理员账号这一步虽然可以跳过但我建议立即创建。最后是关于用户注册的选项初始化完成后建议马上在站点设置里关闭自助注册改为管理员手动创建账号或通过邀请链接加入避免无关人员溜进你的代码托管平台。初始化完成后我会立刻做三件事确认管理员密码强度足够、开启禁止注册、上传第一把 SSH 公钥。这三步做完基础环境才算真正从能跑变成了能放心用。3. 日常仓库操作全流程从建仓到协作部署只是起点日常使用中频繁打交道的是仓库操作、认证配置、分支协作这些基本功。这一部分我把最常见的操作流程和容易踩的坑一起讲。3.1 仓库创建与本地初始化的正确姿势在 Gitea Web 界面新建仓库并不复杂填仓库名、写描述、选择公开或私有点一下按钮就完成了。我更想强调的是团队新项目最顺的初始化方式。假设要新建一个项目my-project我习惯先用命令行在本地把项目骨架生成好再关联到远程仓库mkdir my-project cd my-project git init git add . git commit -m chore: 初始化项目骨架 git remote add origin gitgit.example.local:username/my-project.git git push -u origin main这里有个细节很容易让新人困惑Gitea 新建仓库时默认主分支是master但很多团队为了规范统一改用main。我建议在仓库设置的分支选项里把默认分支改成 main同时让团队在本地初始化时直接用git init -b main。这样从源头就保持分支命名一致后面 Pull Request 的目标分支也不会搞混。还有一种高频场景是从已有仓库迁移。Gitea 的创建仓库页面支持从外部 Git 地址导入填一个源地址Gitea 会把历史提交整个克隆过来包括分支和标签。这个功能做临时迁移或者持续镜像同步都很方便省去手动添加 remote 再 push 的繁琐操作。3.2 SSH 与 HTTPS 认证配置详解日常推送时用 HTTPS 每次都要输入账号密码体验很差尤其当你频繁切换分支、执行 fetch 操作时光输密码就够烦的。我强烈建议团队统一走 SSH 认证一次性配置长期省心。首先生成密钥对推荐使用 ed25519 算法安全性足够并且性能更好ssh-keygen -t ed25519 -C youremail.com然后把~/.ssh/id_ed25519.pub的内容复制出来粘贴到 Gitea 的用户设置 → SSH 公钥页面保存即可。注意粘贴的是公钥.pub后缀那个文件不是私钥这是个容易手滑的低级错误。如果你的电脑同时连接多个 Git 服务器比如既用公司的 Gitea又用其他的代码托管服务那一定要在~/.ssh/config里写好区分规则Host gitea HostName git.example.local Port 2222 User git IdentityFile ~/.ssh/id_ed25519_gitea这样配置之后访问gitgit.example.local的仓库时SSH 会自动使用与 Gitea 对应的密钥文件不会跟其他平台的密钥搞混。测试连接可以用ssh -T gitgit.example.local如果返回欢迎信息说明认证链路已经打通。HTTPS 方式也不是完全没用。某些机器上没有配 SSH 的环境或者临时拉代码用带 Token 的 HTTPS 地址更方便。在 Gitea 的应用令牌页面生成一个 Token然后拼到克隆地址里或者干脆配置 Git 的 credential 存储让它记住 Token。我的建议是个人日常开发优先 SSH自动化脚本和 CI 环境优先 Token两条路都通。3.3 分支保护与代码评审流程多人协作时最怕有人图省事直接往主干分支推代码改坏了还不容易追溯。Gitea 的分支保护功能就是用来堵住这个漏洞的。在仓库设置 → 分支 → 分支保护里选择要保护的main分支然后勾选必要的规则禁止直接推送到该分支必须通过 Pull Request 才能合并允许访问该分支的成员需要至少一个评审通过合并前必须解决所有冲突我通常还会开启合并后删除源分支这样功能分支合并完自动清理分支列表保持干净不容易堆积垃圾分支。Pull Request 的实际工作流是开发者在功能分支上完成编码并推送然后到 Gitea 网页端发起一个 PR写明改动内容和测试情况指定评审人。评审人在线看 diff、留评论通过后点击合并。合并策略有三种常见选项我推荐优先使用 Squash 合并它会把整个功能分支的所有提交压缩成一个提交历史线非常干净后续做版本回滚时一目了然。Merge 提交则保留完整开发轨迹适合需要精确追溯每一步改动的场景但提交记录会显得凌乱。3.4 用户、组织与团队权限模型Gitea 的权限模型可以按两个维度来理解。一个是仓库级别从宽松到严格依次是读Read、写Write、管理Admin。读权限能克隆代码、看 Issue 和写评论写权限能推送代码和管理 Issue管理权限则能修改仓库配置、删除仓库。另一个是组织级别组织可以把多个仓库和一批成员聚在一起再通过团队來批量分配权限。实际操作中我建议先创建一个组织比如开发部然后在组织下建两个团队分别负责后端和前端各授予对应仓库的写权限。之后给新人开通权限时只需要把他拉进对应的团队不用挨个仓库去加成员。如果组织里有一个公共组件仓库不想让普通成员直接改动就给相关团队成员只分配读权限需要修改时通过 Pull Request 邀请管理员处理。权限分配尽量遵循最小权限原则新成员默认只给读权限需要写权限时单独申请管理权限只给到组长和运维人员。这个原则听起来保守但实际避免了大量因误操作导致的代码事故。4. 运维的底线工程备份、升级和排查部署完成只是开始真正考验平台的是长期运行中的稳定性和可维护性。备份、升级和问题排查这三件事是自建代码托管平台绕不开的日常。4.1 备份什么、怎么备份最可靠Gitea 的数据构成其实很清楚所有裸仓库在数据目录的git/repositories下SQLite 数据库是一个文件配置文件单独存放如果用到了 LFS还要算上 LFS 对象目录。备份就是围绕这几样东西做文章。最省事的官方方案是gitea dump命令。它会自动把配置、数据库、仓库、附件打包成一个 zip 文件。在 Docker 部署下执行docker exec -u git gitea gitea dump --file /data/gitea-dump.zip执行完成后备份文件生成在容器的 /data 目录下也就是宿主机挂载的 data 目录里直接用docker cp或 Volume 路径就能取出来。另一种更朴素的方案是直接打包数据目录和配置目录tar czvf gitea-backup-$(date %F).tar.gz ./data ./config直接打包数据目录有个前提要么先短暂停掉 Gitea 服务要么依赖数据库的一致性保障。否则打包过程中仓库和数据库可能处于不一致状态。相比之下gitea dump内部处理了顺序和一致性所以我把它作为首选。备份频率按团队的代码活跃度来定。我目前的做法是每天凌晨用 crontab 执行一次 dump每周做一次整目录归档。恢复流程也验证过多次拿到备份 zip 后先解压确认里面有 repos、gitea.db 和 app.ini然后把整个内容覆盖到对应数据目录最后重启容器Gitea 就能恢复到最后备份时的状态。这个恢复操作我已经演练过好几次整个过程十分钟以内。4.2 升级流程与回滚策略Docker 部署的升级操作非常简洁改一下镜像版本号再重新拉起即可docker compose pull gitea docker compose up -d但我要强调一条硬性规则升级前必须先做完整备份。Gitea 升级时数据库结构有迁移逻辑升上去了再降级旧版本往往无法识别新版本的数据库结构。我踩过这个坑某个版本升级后遇到一个奇怪的显示问题想回滚到旧版本结果备份没做数据库已经被迁移到新结构最后只能手动修复。从那以后我给自己定了一条铁律——凡是版本变更先执行一遍gitea dump再动镜像。升级完成后建议做一轮快速验证登录 Web 管理界面、打开几个仓库列表、拉取一次最新代码、走一遍推送和 Pull Request 流程。这些基础动作跑通说明升级没有造成功能损坏。如果新版本确实有影响团队的问题回滚时先停掉容器用老镜像还原再把升级前生成的备份文件恢复进去。4.3 常见问题速查表与避坑经验最后把我运维过程中真实遇到的高频问题整理成一个速查表按现象 → 可能原因 → 解决方式的格式列出方便大家直接对着查问题现象可能原因排查与解决方式SSH 连接超时或拒绝端口映射不对或防火墙拦截用ssh -p 2222 -T gitgit.example.local测试检查宿主机防火墙和云安全组规则推送时报权限不足用户在仓库中没有写权限检查仓库协作者列表和所在团队的权限设置克隆地址显示不对ROOT_URL 配置不正确检查配置文件中SERVER__ROOT_URL是否和实际访问地址一致推送大文件失败超出 Git 单文件传输限制或 LFS 未开启启用 Git LFS并在客户端安装 lfs 扩展忘记管理员密码密码遗忘或员工离职交接不清在容器内用gitea admin user change-password --username admin --password 新密码重置注册页面对外开放初始化时未关闭自助注册在站点管理设置中改为仅管理员创建账号仓库提交历史时区错误容器系统时区未设置在 compose 中配置环境变量TZAsia/Shanghai后重启这里挑两个最典型的展开说。第一个是 SSH 端口问题。很多人在云服务器上部署宿主机 22 端口已经被自己的 SSH 占用了容器映射到 2222但用了不带-p参数的测试命令自然连不上。记住测试时-p参数要跟映射后的端口仓库的远程地址也要用带端口的完整形式。第二个是忘记密码。Gitea 提供了命令行重置手段但需要进入容器内部以 git 用户身份执行命令这个操作本身很简单关键在于立刻重置密码后要求用户做一次强制修改避免管理员长期使用一个全员皆知的默认密码。关于大文件我的经验是尽早启用 Git LFS不要在仓库里直接塞几百兆的二进制资源。虽然 Gitea 自身能运行但仓库体积无限膨胀后克隆、备份和磁盘占用都会变得很难受。启用 LFS 后把设计稿、数据集、安装包这一类资源放到 LFS 托管让 Git 仓库只存文本和代码是长期健康的做法。这套流程是我从零开始部署 Gitea再到稳定运行半年后整理的完整记录。给我留下最深印象的其实是轻带来的维护红利——我可以很放心地把环境交接给团队里任何一位开发同学去维护因为它没有复杂的依赖链备份就是一条命令的事。最后再分享一个习惯除了每天自动 dump我每周还会手动做一次备份归档同时把备份文件同步到另一台存储机器上。这个习惯曾经帮我避免了一次意外的库误删操作线上恢复只花了五分钟。如果你也准备自建代码托管平台Gitea 是个很省心的选择希望这篇文章能帮你少绕一点路。